Ticket #257: infer-out-param.patch
File infer-out-param.patch, 8.4 KB (added by hopscc, 14 years ago) |
---|
-
Source/Expr.cobra
561 561 _transformToEnumDecl(dotNode, enumDefi) 562 562 return 563 563 564 hasErrors = _bindImpArgs 564 needInferOutArgs = false 565 hasErrors = _bindImpArgs(out needInferOutArgs) 565 566 definition as IMember? 566 567 type as IType? 567 568 … … 586 587 if not .hasError and not hasErrors 587 588 args = _args 588 589 if definition inherits MemberOverload 590 #TODO: Correct this dependency; Need args bindImp done to calc bestOverload, 591 # but need best overload to infer (undefined out) variable type 592 if needInferOutArgs 593 moDefn = definition.members[0] # not guaranteed to have the best param list 594 if moDefn.hasParams 595 params = moDefn.params 596 _inferOutArgs(args, params, true) 597 589 598 # Note that overloads can have different return types (even if more than just the return type is needed to distinguish them). Example: Math. 590 599 # Plenty of info here: 591 600 # http://www.google.com/search?hl=en&q=C%23+overloaded+method+resolution … … 602 611 else 603 612 params = definition.params 604 613 if _checkParamsCount(definition, args, params) 614 if needInferOutArgs, _inferOutArgs(args, params, false) 605 615 _checkArgsAssignable(definition, args, params) 606 616 _checkInOutArguments 607 617 else … … 681 691 _type = postCall.type 682 692 transformTarget._transformTo(postCall) 683 693 684 def _bindImpArgs as bool 694 def _undefinedOutArg(arg as Expr) as bool 695 if arg.direction == Direction.Out 696 if arg inherits IdentifierExpr 697 if not arg.findDefinition 698 return true 699 return false 700 701 #do bindImp on callExprs args. 702 #Defer binding on undefined out args but flag that inference needed (later see _bindImp) 703 def _bindImpArgs(needInferOutArgs as out bool) as bool 685 704 hasErrors = false 705 needInferOutArgs = false 686 706 num = 1 687 707 for arg in List<of Expr>(_args) 688 708 try 689 709 if arg inherits AssignExpr 690 710 arg.right.bindImp # 'x=y' has special treatment in arguments 691 711 else 692 boundArg = arg.bindImp 693 if boundArg is not arg # transformation 694 _args[num-1] = boundArg 695 assert boundArg.didBindImp 712 if needInferOutArgs == false and _undefinedOutArg(arg) 713 #print 'No explicit prior definition for out-arg [arg.name]' 714 needInferOutArgs = true 715 continue 716 _bindImpArg(num, arg) 696 717 catch ne as NodeException 697 718 ne.prefixMessage('For "[_name]" arg [num]: ') 698 719 .compiler.recordError(ne) … … 700 721 num += 1 701 722 return hasErrors 702 723 724 def _bindImpArg(num as int, arg as Expr) 725 boundArg = arg.bindImp 726 if boundArg is not arg # transformation 727 _args[num-1] = boundArg 728 assert boundArg.didBindImp 729 703 730 def _didVariArgs(definition as BoxMember) as bool 704 731 hasVari = false 705 732 for param in definition.params … … 729 756 .throwError('The method "[definition.name]" is expecting [params.count] argument[Utils.plural(params)], but [args.count] are being supplied in this call.') 730 757 return true 731 758 759 def _inferOutArgs(args as IList<of Expr>, params as IList<of Param>, warn as bool) 760 num = 0 761 for arg in args 762 if _undefinedOutArg(arg) 763 #inferredType = .compiler.nilableType(params[num].type) # always nilable? (e.g. dict.tryGetValue) 764 inferredType = params[num].type 765 newDefn = LocalVar(arg.token, inferredType).bindAll to LocalVar 766 .compiler.codeMemberStack.peek.addLocal(newDefn) 767 (arg to IdentifierExpr).setDefinition(newDefn) 768 arg.type = newDefn.type 769 _bindImpArg(num, arg) 770 # the warning below is temporary till we sort out arg.bindImp vs calculating Best overload 771 if warn 772 sugg = 'You may want to disambiguate this by declaring the variable explicitly.' 773 .compiler.warning(this, 'Cobra has implicitly declared a variable "[newDefn.name] as [newDefn.type.name]" for an undefined out parameter variable but the type inferred may not be correct as the method called is overloaded. [sugg]') 774 775 num += 1 776 732 777 def _checkArgsAssignable(definition as BoxMember, args as IList<of Expr>, params as IList<of Param>) 733 778 for i in args.count 734 779 arg = args[i] … … 1025 1070 def _bindImp is override 1026 1071 base._bindImp 1027 1072 if _definition is nil 1073 _definition = .findDefinition 1028 1074 canBeUndottedMember = _name.canBeUndottedMemberName 1029 if canBeUndottedMember1030 # assert .compiler.boxStack.count TODO: identifier expr is being used by PostCallExpr which is used for attribute calls1031 _definition = .compiler.symbolForName(_name, false)1032 else1033 # local var ref: foo1034 if .compiler.codeMemberStack.count # could be: var _x = y or: has foo1035 _definition = .compiler.findLocal(_name)1036 if _definition is nil1037 _definition = .compiler.symbolForName(_name, false, true) # 3rd party DLLs have lowercase class names like iConnection1038 1075 if _definition is nil and not canBeUndottedMember 1039 1076 if _superNode inherits BinaryOpExpr 1040 1077 if _superNode.right is this … … 1059 1096 .throwUnknownIdError 1060 1097 throw FallThroughException() 1061 1098 1099 def findDefinition as INamedNode? 1100 definition as INamedNode? 1101 canBeUndottedMember = _name.canBeUndottedMemberName 1102 if canBeUndottedMember 1103 # assert .compiler.boxStack.count TODO: identifier expr is being used by PostCallExpr which is used for attribute calls 1104 definition = .compiler.symbolForName(_name, false) 1105 else 1106 # local var ref: foo 1107 if .compiler.codeMemberStack.count # could be: var _x = y or: has foo 1108 definition = .compiler.findLocal(_name) 1109 if definition is nil 1110 definition = .compiler.symbolForName(_name, false, true) # 3rd party DLLs have lowercase class names like iConnection 1111 return definition 1112 1062 1113 def bindImp as dynamic 1063 1114 base.bindImp 1064 1115 if _definition and not (.superNode inherits AbstractAssignExpr and .binarySuperNode.left is this) -
Tests/300-type-inference/610-out-param.cobra
1 # Implicit creation of an undefined out param variable. 2 # The warnings generated below are intended to be a temporary situation 3 class DefaultOut 4 5 var _x = '' 6 7 def main 8 # User method 9 x = .getX( true, out s0) 10 assert x 11 assert s0 == '.BigWalla' 12 x =.getX( false, out s0) 13 assert not x 14 assert s0 == '.' 15 16 s1='something Ignored' 17 x = .getX( true, out s1) 18 assert x 19 assert s1 =='.BigWalla' 20 x =.getX( false, out s1) 21 assert not x 22 assert s1 == '.' 23 24 # (nilable) variable in a system method 25 d= {'a':'A1', 'b':'B2', 'c':'See3'} 26 #result as String? 27 x = d.tryGetValue('b', out result) 28 assert x 29 assert result =='B2' 30 x = d.tryGetValue('d', out result) 31 assert not x 32 assert not result #nil 33 result = nil 34 35 # out to a method Parameter 36 r = '' 37 .testParam(d, r) 38 assert r == '' 39 40 # out to a field 41 assert _x == '' 42 ok = d.tryGetValue('a', out _x) 43 assert ok 44 assert _x == 'A1' 45 46 # out in an overloaded method successfully 47 ok = int.tryParse('986', out iVal) # .warning. implicitly declared a variable 48 assert ok 49 assert iVal == 986 50 51 # out in an overloaded method unsuccessfully 52 ok = int.tryParse('noway', out iVal1) # .warning. implicitly declared a variable 53 assert not ok 54 assert iVal1 == 0 55 56 57 def getX( flag as bool, z as out String) as bool 58 z='.' 59 if flag 60 z = z + 'BigWalla' 61 return true 62 return false 63 64 def testParam(d as Dictionary<of String, String>, x as String) 65 ok = d.tryGetValue('a', out x) 66 assert ok 67 assert x == 'A1' 68 -
Developer/IntermediateReleaseNotes.text
66 66 67 67 * Structs have implicit parameterless initializers and do not allow explicit ones to be declared. 68 68 69 * First use of a variable as an out parameter in a method call implicitly declares the variable: ticket 257 69 70 70 71 ================================================================================ 71 72 Library