Ticket #39: ref-lambda-type-inference-target-local.patch
File ref-lambda-type-inference-target-local.patch, 41.2 KB (added by hopscc, 14 years ago) |
---|
-
Source/Members.cobra
596 596 get shouldBeVirtual as bool is override 597 597 return false 598 598 599 def lambdaReturnTypeas IType599 def inferLambdaReturnType # as IType 600 600 """ This is a service method for LambdaExpr. """ 601 601 require .didBindInt and .didBindImp 602 602 stmt = _stmts[0] 603 603 if stmt inherits ReturnStmt 604 return stmt.expr.type to ! 604 if stmt.expr.type 605 _returnType = stmt.expr.type to ! 605 606 else 606 607 throw FallThroughException(stmt) 607 608 609 def inferReturnType 610 """ 611 Infer returntype from (first) return statement if type not already explicitly set. 612 This is a service method for AnonymousMethodExpr. 613 """ 614 require .didBindInt and .didBindImp 615 if _returnType == .compiler.passThroughType 616 for stmt in _stmts 617 if stmt inherits ReturnStmt 618 if stmt.expr.type 619 _returnType = stmt.expr.type to ! 620 break 621 608 622 def _bindInt is override 609 623 base._bindInt 610 624 if _returnTypeNode is nil 611 _returnType = .compiler.passThroughType # TODO: infer return type from return statement like C# does625 _returnType = .compiler.passThroughType 612 626 613 627 # uu 614 628 def _bindImp is override … … 628 642 break 629 643 if hasYield, .throwError('Cannot yield inside an anonymous method.') 630 644 631 632 645 class AbstractMethod 633 646 is abstract, partial 634 647 inherits BoxMember -
Source/Expr.cobra
210 210 body 211 211 base._bindImp 212 212 213 def _findMatchingSig(aSig as MethodSig, container as Box, searchHier as bool) as MethodSig? 214 """ 215 Look for a compatible matching Sig for asig in container. 216 Check in only the container if searchHier is false or that and all of containers ancestor inheritance hierarchy 217 if searchHier is true. 218 Return any matching sig if found otherwise return nil 219 220 Support method for type inference on RefExpr and AnonymousMethod and LambdaExpr 221 """ 222 223 compatSig = container.sigForMethodSig(aSig, searchHier) 224 return compatSig 225 226 227 def _actionMissingSig(aSig as MethodSig, container as Box, tag as String) 228 msg = 'No signature matching the signature of the [tag] ([aSig.toCobraSource]) in the inheritance tree or used namespaces.' 229 sugg = 'Did you leave out a sig statement in scope for this method reference?' 230 action = 'Adding generated sig "[aSig.toCobraSource]" to [container.name]' 231 .compiler.warning(this, '[msg]\n[sugg]\n[action]') 232 container.addDecl(aSig) # It may be preferable to not do this and defer back to non inference 233 213 234 def _suggestionsMessage(suggs as List<of String>) as String 214 235 """ 215 236 Shared by MemberExpr, CallExpr and IdentifierExpr to give suggestions in an error message about an unknown member. … … 328 349 base.addSubFields 329 350 .addField('params', .params) 330 351 352 def _makeAnonSig(tag as String, resultType as IType, isNames as String*) as MethodSig 353 """ 354 Make an anonymous methodSig for this anonymous expr (lambda or anonMethod) 355 and return a declared match for it or instantiate it into its containing box. 356 """ 357 sigToken = .token.copy('ID', 'sigFor[tag]') 358 nameToken = .token.copy('ID', 'SigFor[tag]_[.token.lineNum]_[.serialNum]') 359 docString = '' to ? 360 aSig = MethodSig(sigToken, nameToken, .curCodeMember.parentBox, nameToken.text, .params, 361 resultType, isNames, AttributeList(), docString) 362 aSig.bindInh 363 aSig.bindInt 364 aSig.bindImp 365 #print aSig 366 return _matchingOrNewSig(aSig, .curCodeMember.parentBox, tag) # in Expr 367 368 def _matchingOrNewSig(aSig as MethodSig, container as Box, tag as String) as MethodSig 369 """ 370 Return a compatible matching Sig for asig found in container and containers ancestor inheritance hierarchy 371 if one is not found warn, insert (instantiate) aSig into container and return it. 372 373 Support method for type inference on AnonymousMethod and LambdaExpr 374 """ 375 compatSig = _findMatchingSig(aSig, container, true) 376 if not compatSig # not found 377 _actionMissingSig(aSig, container, tag) 378 else 379 aSig = compatSig to ! 380 return aSig 381 382 331 383 def toCobraSource as String is override 332 384 sb = StringBuilder('do(') 333 385 sep = '' … … 343 395 class AnonymousMethodExpr inherits AnonymousExpr is partial 344 396 implements HasAddStmt 345 397 """ 398 do(a as int, b as int) as int 399 ... 400 return a.compareTo(b) 401 346 402 Also called "closures". 347 403 """ 348 404 … … 362 418 363 419 def _bindImp is override 364 420 base._bindImp 365 _method = AnonymousMethod(.token, .curCodeMember, .params, _returnTypeProxy, if(.curCodeMember.isShared, ['shared'], List<of String>())) 421 isNames = if(.curCodeMember.isShared, ['shared'], List<of String>()) 422 _method = AnonymousMethod(.token, .curCodeMember, .params, _returnTypeProxy, isNames) 366 423 for stmt in .stmts, _method.addStmt(stmt) 367 424 _method.bindInt 368 425 _method.bindImp 369 _type = _method.resultType 426 _method.inferReturnType 427 #print .token.lineNum, _method.resultType 428 _type = _makeAnonSig('AnonMthd', _method.resultType, List<of String>()) 429 370 430 371 372 431 class LambdaExpr inherits AnonymousExpr is partial 373 432 """ 374 433 ... do(a as int, b as int)=a.compareTo(b) ... … … 400 459 401 460 def _bindImp is override 402 461 base._bindImp 403 _method = AnonymousMethod(.token, .curCodeMember, .params, .compiler.dynamicType, if(.curCodeMember.isShared, ['shared'], List<of String>())) 462 isNames = if(.curCodeMember.isShared, ['shared'], List<of String>()) 463 _method = AnonymousMethod(.token, .curCodeMember, .params, .compiler.dynamicType, isNames) 404 464 ret = ReturnStmt(.token.copy('RETURN', 'return'), .expr) 405 465 _method.addStmt(ret) 406 466 _method.bindInt 407 467 _method.bindImp 408 468 # the expression may have been transformed, but if so, only the containing ReturnStmt got the notice 409 469 _expr = ret.expr to ! 410 _type = .compiler.passThroughType # TODO: Set a real type such as .compiler.delegateType 411 # method.lambdaReturnType 470 _type = .compiler.passThroughType 471 _method.inferLambdaReturnType 472 _type = _makeAnonSig('Lambda', _method.resultType, isNames) 412 473 413 474 414 475 class AsExpr … … 1913 1974 ref obj.foo 1914 1975 ref _foo 1915 1976 """ 1916 1977 1978 var _refSig as MethodSig? 1979 1917 1980 cue init(token as IToken, expr as Expr) 1918 1981 base.init(token) 1919 1982 # TODO: can the types of expressions be limited? … … 1947 2010 throw 1948 2011 finally 1949 2012 .compiler.refExprLevel -= 1 2013 _checkRefExpr 2014 _type = .compiler.passThroughType # something if refSig make signature fails 2015 refSig = _makeSignatureOfExpr 2016 if refSig 2017 refSig.bindInh 2018 refSig.bindInt 2019 refSig.bindImp 2020 container = .compiler.curCodeMember.parentBox 2021 sigType as IType? = _findMatchingSig(refSig, container, true) # container and inheritance chain 2022 if sigType # match found 2023 _type = sigType 2024 else 2025 # Defer search till post assignment and target is another Box member 2026 # Hack for (forward) access to local sig in unrelated class 2027 _refSig = refSig # stash for later 2028 _type = .compiler.passThroughType 2029 if _inSimpleAssignment 2030 .missingSig(container) 2031 assert _type 2032 2033 def _inSimpleAssignment as bool 2034 assert _expr.superNode inherits RefExpr 2035 node = _expr.superNode.superNode 2036 if node inherits AssignExpr 2037 if node.left inherits IdentifierExpr 2038 return true 2039 return false 2040 2041 2042 def _checkRefExpr 1950 2043 if _expr inherits DotExpr 1951 2044 right = _expr.right 1952 2045 if right inherits MemberExpr … … 1962 2055 else 1963 2056 throw FallThroughException([this, _expr, right]) 1964 2057 else if _expr inherits IdentifierExpr 1965 if _expr.definition inherits AbstractMethod 1966 pass 1967 else 2058 if not ( _expr.definition inherits AbstractMethod ) 1968 2059 .throwError('Only methods can be referenced, not [Utils.pluralize(_expr.definition.englishName)].') 1969 2060 else 1970 2061 .throwError('Unexpected reference. Refer to methods after `ref` or remove `ref`.') 1971 _type = .compiler.passThroughType # TODO: Set a real type such as .compiler.delegateType1972 # TODO: need to do something more sophisticated like overriding: def canBeAssignedTo(type as IType) as bool1973 2062 2063 def _makeSignatureOfExpr as MethodSig? 2064 """Auto generate a signature for type of expression being 'ref'd""" 2065 if _expr inherits DotExpr 2066 right = _expr.right 2067 if right inherits MemberExpr 2068 if right.definition inherits AbstractMethod 2069 am = right.definition to AbstractMethod 2070 signature = _makeSig(am, _expr.right.token) 2071 else if right.definition inherits MemberOverload 2072 mo = right.definition to MemberOverload 2073 if mo.members[0] inherits AbstractMethod 2074 am = mo.members[0] to AbstractMethod 2075 signature = _makeSig(am, _expr.right.token) 2076 else if _expr inherits IdentifierExpr 2077 if _expr.definition inherits AbstractMethod 2078 am = _expr.definition to AbstractMethod 2079 signature = _makeSig(am, _expr.token) 2080 return signature 2081 2082 def _makeSig(am as AbstractMethod, token as IToken) as MethodSig 2083 """Make an (anonymously named) signature corresponding to the provided method""" 2084 sigToken= token.copy('ID', 'sigForRef') 2085 nameToken = token.copy 2086 container = .compiler.curCodeMember.parentBox 2087 name = 'SigFor_'+nameToken.value to String 2088 isNames = List<of String>() 2089 attribs = AttributeList() 2090 docString = '' to ? 2091 returnType = am.resultType 2092 params = List<of Param>(am.params) 2093 return MethodSig(sigToken, nameToken, container, name, params, returnType, isNames, attribs, docString) 2094 2095 def tryForLocalSig(container as Box) 2096 """ 2097 Look for matching sig in given container (one level lookup). 2098 Use it if found otherwise use synthesized sig of expr 2099 2100 call only after bindImp already done 2101 This is support for methodType inference for a class local sig decl 2102 """ 2103 assert _refSig 2104 refSig = _refSig to ! 2105 sigType = _findMatchingSig(refSig, container, false) # container only 2106 if sigType # match found 2107 _type = sigType 2108 else 2109 .missingSig(container) 2110 2111 def missingSig(container as Box) 2112 """ No matching sig found, setup to use synthesized Sig.""" 2113 assert _refSig 2114 refSig = _refSig to ! 2115 _actionMissingSig(refSig, container, _expr.definition.name) 2116 _type = refSig 2117 1974 2118 def toCobraSource as String is override 1975 2119 return 'ref ' + _expr.toCobraSource 1976 2120 -
Source/BackEndClr/ScanClrType.cobra
55 55 if type.isClass 56 56 if type.name.startsWith('Extend_') and type.name.count(c'_') >= 2 57 57 curNameSpace.addDecl(Extension(clrType)) 58 else if _shouldBeMethodSig(type) 59 #print curNameSpace.name, type.name 60 curNameSpace.addDecl(MethodSig(clrType)) 58 61 else 59 62 curNameSpace.addDecl(Class(clrType)) 60 63 else if type.isInterface … … 70 73 throw FallThroughException(type) 71 74 finally 72 75 _curModule = saveModule 76 77 def _shouldBeMethodSig(type as Type) as bool 78 if not type.isSubclassOf(System.MulticastDelegate) 79 return false 80 #if type.isGenericType 81 # print type.namespace, type.name 73 82 83 # Below delegates are generic types in System that are 'too' general re params and return types 84 # and give 'false' matches for simple common cases (min params and (no) return types) 85 # so we suppress them. 86 #Inferred uses will probably either need an explicit compatible signature or will get a warning generated... 87 if type.name in ['CrossAppDomainDelegate', 'Converter`2', 'Action`1', 'EventHandler`1'] 88 return false # other possible candidates include Predicate`1 89 return true 90 74 91 def fixNilableMemberSigs 75 92 # TODO: this really needs to go in a separate file that the compiler reads each time 76 93 … … 479 496 480 497 def _memberTypeProxy(clrType as Type?, notNullAttr as bool) as ITypeProxy 481 498 """ 482 Returns a type proxy for a member type such as a parameter type or me thod returntype.499 Returns a type proxy for a member type such as a parameter type or member type. 483 500 In CLR, reference types are nilable by default, but you can pass `true` for `notNullAttr` to indicate there was a NotNullAttribute in the DLL. 484 501 """ 485 502 if clrType is nil … … 495 512 496 513 def _memberTypeResultProxy(member as MemberInfo, clrType as Type?) as ITypeProxy 497 514 """ 498 Returns a type proxy for a member type such as a parametertype or method return type.515 Returns a type proxy for a member result type such as a property or field type or method return type. 499 516 In CLR, reference types are nilable by default. 500 517 """ 501 if clrType is nil 518 if clrType is nil or clrType is sharp'typeof(void)' # C# null data vs null code return 502 519 return .compiler.voidType 503 520 else if clrType.isValueType 504 521 return ClrTypeProxy(clrType) … … 585 602 # the first argument is implicit in an Extension 586 603 results = base._scanParams(paramInfos) 587 604 return results[1:] 605 606 class MethodSig 607 is partial 608 609 def _scanNativeType 610 base._scanNativeType 611 _scanIsNames 612 #_scanImplements 613 #_scanNestedTypes 614 #_scanFields 615 _scanInitializers 616 #_scanProperties 617 _scanMethods 618 #_scanEvents 619 620 # reflect on invoke method to find signature 621 methInfo = .clrType.getMethod('Invoke', BindingFlags(Instance, Static, DeclaredOnly, Public, NonPublic)) 622 if methInfo and _methOK(methInfo to !) 623 _params = _scanParams(methInfo.getParameters) 624 _returnTypeProxy = _memberTypeResultProxy(methInfo to !, methInfo.returnType) 625 #if .clrType.isGenericType 626 # print .name, methInfo.returnType, _params 627 628 def _methOK( methInfo as System.Reflection.MethodInfo) as bool 629 if methInfo.isSpecialName or methInfo.isAssembly or methInfo.isPrivate 630 return false 631 if methInfo.declaringType is not .clrType, return false 632 if _badRelatedType(methInfo.returnType) 633 return false 634 for paramInfo in methInfo.getParameters 635 if _badRelatedType(paramInfo.parameterType) 636 return false 637 return true -
Source/Boxes.cobra
430 430 _declsByName[ol.name] = ol 431 431 _declsByNameCI[ol.name.toLower] = ol 432 432 433 def addDecl(decl as IBoxMember) is override 434 base.addDecl(decl) 435 # overridden to explicitly store methodSigs separately 436 if decl inherits MethodSig 437 base.addSig(decl) 438 433 439 def addDeclFromOverload(decl as IBoxMember, ol as MemberOverload) 434 440 require 435 441 ol in .overloads … … 1535 1541 The "sig" keyword fits nicely with other declaration keywords like "var" "def" and "get". 1536 1542 And "sig" is a more platform neutral term should we have other non-CLI backends. 1537 1543 1538 MethodSigs are only created when parsing. When reading from a DLL, delegates are merely 1539 subclasses of Delegate or MulticastDelegate. 1544 MethodSigs are created when parsing. When reading from a DLL, delegates are merely 1545 subclasses of (class) Delegate but subclasses of MulticastDelegate are created as MethodSigs so that 1546 type inference and sig matching can be done if such a MethodSig is used as a type.. 1540 1547 1541 1548 Note that MethodSig is a subclass of Class and therefore both a Box and an IType. Also, it will 1542 1549 return true for .isDescendantOf(.compiler.delegateType). … … 1554 1561 _params = params 1555 1562 _returnTypeProxy = returnTypeProxy 1556 1563 1564 cue init(nativeType as NativeType) 1565 base.init(TokenFix.empty, TokenFix.empty, ClrTypeProxy.cobraNameForSharpBoxName(nativeType.name), 1566 List<of IType>(), List<of String>(), AttributeList(), 1567 LibraryTypeProxy('System.MulticastDelegate'), List<of ITypeProxy>(), 1568 List<of ITypeProxy>(), nil) 1569 _initNativeType(nativeType) 1570 # below are temp placeholders until _scanNativeType runs (no params, void returned) 1571 _params = List<of Param>() 1572 _returnTypeProxy = TypeProxy(.compiler.voidType) 1573 1557 1574 get params from var 1558 1575 1559 1576 get returnTypeProxy from var … … 1563 1580 get resultType as IType? is override 1564 1581 return .returnType 1565 1582 1583 def addRefFields 1584 base.addRefFields 1585 .addField('params', _params) 1586 .addField('returnType', _returnType) 1587 1566 1588 def _bindInh 1567 1589 base._bindInh 1568 1590 assert _baseClass 1569 1591 assert _baseClass.qualifiedName == 'System.MulticastDelegate' 1570 1592 assert .parentBox or .parentNameSpace 1571 1593 assert not _needScanNativeType 1594 1572 1595 def _bindInt 1573 returnType as ITypeProxy = .returnType ? .returnTypeProxy 1574 .addDecl(_makeMethod('invoke', .params.clone, returnType)) 1575 # dynamic type vari length param in list as placeholder for multiple params 1576 params = [Param('vParam', VariTypeIdentifier(.token, TypeIdentifier(.token, DynamicType())))] 1577 .addDecl(_makeMethod('beginInvoke', params, TypeIdentifier(.token.copy('ID', 'IAsyncResult')) to ITypeProxy)) 1578 .addDecl(_makeMethod('endInvoke', params, returnType )) 1596 if not .isFromBinaryLibrary # If From Assembly/Library these methods have already been inserted 1597 # TODO: push these down to _ScanClrType, platform specific. 1598 returnType as ITypeProxy = .returnType ? .returnTypeProxy 1599 .addDecl(_makeMethod('invoke', .params.clone, returnType)) 1600 # dynamic type vari length param in list as placeholder for multiple params 1601 params = [Param('vParam', VariTypeIdentifier(.token, TypeIdentifier(.token, DynamicType())))] 1602 .addDecl(_makeMethod('beginInvoke', params, TypeIdentifier(.token.copy('ID', 'IAsyncResult')) to ITypeProxy)) 1603 .addDecl(_makeMethod('endInvoke', params, returnType )) 1579 1604 base._bindInt 1580 1605 for param in .params 1581 1606 param.bindInt … … 1590 1615 # method body just to avoid a Cobra warning during .bindImp 1591 1616 m.statements.add(ThrowStmt(.token, PostCallExpr(.token, IdentifierExpr(.token, 'Exception'), List<of Expr>()))) 1592 1617 return m 1618 1619 def isAssignableTo(type as IType) as bool is override 1620 r = base.isAssignableTo(type) 1621 if not r 1622 if (nnt = type.nonNil) inherits MethodSig 1623 r = .isAnonymousMatch(nnt) 1624 return r 1625 1626 def isAnonymousMatch(aSig as MethodSig) as bool 1627 """ 1628 Indicate whether this methodSig is an anonymous match for the provided one. 1629 An anonymous match is one that ignores the name but succeeds if the sig returnType and 1630 the count, type and ordering of the parameters is the same. 1631 """ 1632 if .isFromBinaryLibrary 1633 # if from platform Assembly/Library do (minimal) bindings on-demand 1634 if not .didBindInh, .bindInh # TODO: optimise this more 1635 if not .didBindInt, .bindInt 1636 assert aSig.returnType 1637 assert .returnType 1638 #print ' [aSig.name] [.name] ReturnType', aSig.returnType.name, .returnType.name 1639 if not _matchesType(aSig.returnType to !, .returnType to !) 1640 return false 1641 params = .params 1642 otherParams = aSig.params 1643 #print ' ParamCount', otherParams.count, params.count 1644 if otherParams.count <> params.count 1645 return false 1646 for i in params.count 1647 #print ' param([i])', otherParams[i].type.name, params[i].type.name, otherParams[i].type, params[i].type 1648 if not _matchesType(otherParams[i].type, params[i].type) 1649 return false 1650 if otherParams[i].direction <> params[i].direction 1651 return false 1652 return true 1653 1654 def _matchesType(a as IType, b as IType) as bool 1655 if a.nonNil inherits GenericParam or b.nonNil inherits GenericParam 1656 return true 1657 # The above provides a mixed blessing of matches to generic delegates (delegates with generic params) 1658 # of which in 'use'ed assemblies (System specifically) there are a bunch that match common cases. 1659 # Good for Comparable implementations, erroneous hits for pretty much every other simple signature 1660 # See ScanClrType for how this is addressed. 1661 return a.isAssignableTo(b) # is this sufficient? 1662 1663 def toCobraSource as String 1664 s = StringBuilder() 1665 s.append('sig ' + .name ) 1666 if .params.count 1667 s.append('(') 1668 sep = '' 1669 for p in .params 1670 s.append(sep) 1671 sep = ', ' 1672 s.append(p.name) 1673 s.append(' as ') 1674 s.append(p.type.name) 1675 s.append(')') 1676 if .returnType <> .compiler.voidType 1677 s.append(' as ') 1678 s.append(.returnType.name) 1679 return s.toString 1593 1680 1594 1681 class GenericParam inherits CobraType is partial 1595 1682 """ -
Source/Container.cobra
25 25 May return nil if no such member exists. 26 26 Case-sensitive. 27 27 """ 28 29 def sigForMethodSig(msig as MethodSig, searchHier as bool) as MethodSig? 30 """ 31 Returns the first method signature of this container matching the provided signature, if searchHier is true includes 32 any inherited methodSignatures ( i.e follows inheritance chain). 33 A 'matching' signature has the same returnType, paramList size and paramList types in the same order. 34 May return nil if no such sig exists. 35 """ 28 36 # TODO: 29 37 # require 30 38 # # TODO: not .compiler.isParsing … … 83 91 var _declsInOrder as List<of TMember> 84 92 var _declsByName as Dictionary<of String, TMember> 85 93 var _declsByNameCI as Dictionary<of String, TMember> 94 var _sigsInOrder as List<of MethodSig> 86 95 var _docString as String 87 96 var _isNames as IList<of String> 88 97 … … 93 102 base.init(token, name) 94 103 _initParent(parent) 95 104 _declsInOrder = List<of TMember>() 105 _sigsInOrder = List<of MethodSig>() 96 106 _declsByName = Dictionary<of String, TMember>() 97 107 _declsByNameCI = Dictionary<of String, TMember>() 98 108 _isNames = isNames.toList … … 161 171 else 162 172 _declsByNameCI.add(decl.name.toLower, decl) 163 173 174 def addSig(signat as MethodSig) 175 _sigsInOrder.add(signat) 176 164 177 def declForName(name as String) as TMember? 165 178 require 166 179 name.length … … 345 358 346 359 def cloneCollections 347 360 _declsInOrder = List<of TMember>(_declsInOrder) 361 _sigsInOrder = List<of MethodSig>(_sigsInOrder) 348 362 _declsByName = Dictionary<of String, TMember>(_declsByName) 349 363 _declsByNameCI = Dictionary<of String, TMember>(_declsByNameCI) 350 351 364 365 def sigForMethodSig(ms as MethodSig, searchHier as bool) as MethodSig? 366 """ 367 Search inheritance tree for a MethodSig matching the given parameter. 368 Look in this containers siglist for a matching sig, If none recursively look in parent. 369 Return first matching sig or nil if none found 370 """ 371 aSig = _haveSigForMethodSig(ms) 372 if aSig 373 return aSig 374 375 if .parent and searchHier 376 return .parent.sigForMethodSig(ms, searchHier) 377 return nil 378 379 def _haveSigForMethodSig(ms as MethodSig) as MethodSig? 380 """Return first matching sig in this container matching the MethodSig parameter or nil if none.""" 381 for aSig in _sigsInOrder 382 #print ms.name, aSig.name 383 if aSig.isAnonymousMatch(ms) 384 return aSig 385 return nil 386 352 387 interface IMember 353 388 is partial 354 389 inherits INamedNode -
Source/BinaryOpExpr.cobra
295 295 rightName = _right.definition.name 296 296 .compiler.warning(this, 'Setting a parameter ("[leftName]") to a class variable ("[rightName]") is often a mistake. You may want to reverse the assignment.') 297 297 298 # method type inference for assignment from a ref where sig is buried in target class 299 # Needs doing after both _left and _right have been through bindImp 300 if not .hasError and _right inherits RefExpr and _right.type inherits PassThroughType # _type not already set 301 refExp as RefExpr = _right to RefExpr 302 # form: id = ref expr - already checked in RefExpr but deferred 303 #if _left inherits IdentifierExpr 304 # refExp.missingSig(.compiler.curCodeMember.parentBox) 305 # form: {a.}*member = ref expr - Sig is allowed to be buried in {a.}* 306 if _left inherits DotExpr 307 if _left.left.type inherits Box 308 container = _left.left.type to Box 309 refExp.tryForLocalSig(container) 298 310 311 299 312 class NumericPromoExpr inherits BinaryOpExpr is partial 300 313 301 314 cue init(opToken as IToken, op as String, left as Expr, right as Expr) … … 367 380 _type = leftType 368 381 else if cannotMix 369 382 .throwError('Cannot mix types [_left.type.name] and [_right.type.name] for arithmetic.') 383 else if _left.isKindOf(.compiler.delegateType) 384 _type = tpassthrough # Not really but allows catching += -= below 385 370 386 if _type is nil 371 387 sugg = 'Try finding a method that performs this function.' 372 388 if leftType == rightType … … 413 429 base._bindImp 414 430 # TODO: does NumericPromoExpr cover everything we need? 415 431 # C# and other languages use += and -= on delegates and events, but Cobra does not. 416 if .left.type inherits MethodSig 417 # TODO: error 418 pass 419 else if .left.type.nonNil.isDescendantOf(.compiler.delegateType) 432 if .left.type inherits MethodSig or .left.type.nonNil.isDescendantOf(.compiler.delegateType) 420 433 leftSource = .left.toCobraSource 421 434 rightSource = .right.toCobraSource 422 435 if not .right inherits RefExpr, rightSource = 'ref ' + rightSource -
Source/NameSpace.cobra
264 264 for ud in _useDirectives 265 265 m = ud.extensionMemberFor(box, name) 266 266 if m, return m 267 return if(_superNameSpace, _superNameSpace._extensionMemberFromUseDirectives(box, name), nil) 267 if _superNameSpace 268 m = _superNameSpace._extensionMemberFromUseDirectives(box, name) 269 if m, return m 270 return nil 271 272 def sigForMethodSig(ms as MethodSig, searchHier as bool) as MethodSig? is override 273 """ 274 Search namespace and UseDirectives for a MethodSig matching the given parameter. 275 Return first matching sig or nil if none found. 276 """ 277 if not .isUnified 278 m = _unifiedNameSpace.sigForMethodSig(ms, searchHier) 279 if m 280 #print 'MATCH (u-ns [.name])', m.name 281 return m 282 return _sigMethodFromUseDirectives(ms) 283 else 284 asig = _haveSigForMethodSig(ms) # from Container baseclass 285 if asig 286 #print 'MATCH (ns)', asig.name 287 return asig 288 if _superNameSpace and searchHier 289 s = _superNameSpace._sigMethodFromUseDirectives(ms) 290 if s 291 #print 'MATCH (super-ns)', s.name 292 return s 293 #print 'NO-MATCH (ns [.name])', ms.name 294 return nil 268 295 296 297 def _sigMethodFromUseDirectives(ms as MethodSig) as MethodSig? 298 """ Look for MethodSig in namespaces referenced by the useDirectives""" 299 for ud in _useDirectives 300 #print 'USEDIR', ud.fullName 301 s = ud.sigMethodFor(ms) 302 if s 303 #print 'MATCH (usedir [ud.fullName])', s.name 304 return s 305 if _superNameSpace 306 s = _superNameSpace._sigMethodFromUseDirectives(ms) 307 if s 308 #print 'MATCH (ud super-ns)', s.name 309 return s 310 #print 'NO-MATCH (usedirs)', ms.name 311 return nil 312 313 269 314 def symbolForName(name as String) as IMember? 270 315 if not .isUnified 271 316 x = _unifiedNameSpace.symbolForName(name) … … 276 321 if members.count == 1 277 322 return List<of IMember>(members)[0] # TODO: feels silly. maybe Set should have a .only method with require .count==1 278 323 else if members.count > 1 279 membersList = List<of IMember>(members) 280 membersList.sort(do(a as IMember, b as IMember)) 281 return a.parentNameSpace.fullName.compareTo(b.parentNameSpace.fullName) 282 spaces = (for m in membersList get '"[m.parentNameSpace.fullName]"').join(', ', ' and ') 283 if .compiler and .compiler.nodeStack.peek inherits ISyntaxNode 284 node = .compiler.nodeStack.peek 285 else 286 node = this 287 node.throwError('Ambiguous reference "[name]" found in namespaces [spaces].') 324 _throwAmbiguousRefError(name, members) 288 325 else 289 326 # our decl? 290 327 # TODO: should this come before checking our name? what does C# do? … … 298 335 if x, return x 299 336 #/ 300 337 return nil 301 338 339 def _throwAmbiguousRefError(name as String, members as Set<of IMember>) 340 membersList = List<of IMember>(members) 341 membersList.sort(do(a as IMember, b as IMember)) 342 return a.parentNameSpace.fullName.compareTo(b.parentNameSpace.fullName) 343 spaces = (for m in membersList get '"[m.parentNameSpace.fullName]"').join(', ', ' and ') 344 if .compiler and .compiler.nodeStack.peek inherits ISyntaxNode 345 node = .compiler.nodeStack.peek 346 else 347 node = this 348 node.throwError('Ambiguous reference "[name]" found in namespaces [spaces].') 349 302 350 def _symbolsForNameFromUseDirectives(name as String, members as Set<of IMember>) 303 351 """ 304 352 Populates `members` with all symbols from `use` directives that match `name`. … … 308 356 if x, members.add(x) 309 357 if _superNameSpace 310 358 _superNameSpace._symbolsForNameFromUseDirectives(name, members) 311 359 312 360 def addDecl(decl as INameSpaceMember) is override 313 361 base.addDecl(decl) 314 362 if decl inherits NameSpace … … 332 380 pass 333 381 else 334 382 _unifiedNameSpace.addDecl(decl) 383 if decl inherits MethodSig 384 base.addSig(decl) 335 385 336 386 def addUseDirective(ud as UseDirective) 337 387 _useDirectives.add(ud) … … 403 453 .addField('boundNameSpace', _boundNameSpace) 404 454 405 455 get boundNameSpace from var 456 get fullName from var 406 457 407 458 def extensionMemberFor(box as Box, name as String) as IMember? 408 459 require .didBindUse … … 411 462 def findSymbol(name as String) as IMember? 412 463 require .didBindUse 413 464 return _boundNameSpace.symbolForName(name) 465 466 def sigMethodFor(ms as MethodSig) as MethodSig? 467 require .didBindUse 468 return _boundNameSpace.sigForMethodSig(ms, true) -
Tests/120-classes/320-construct-prop-set.cobra
67 67 pro style from var 68 68 69 69 70 # This sig needs to be accessible to both Stuff and X but C# evidently 71 # leaks this local type on assignment and evidently cobra must also. 70 72 sig DoSomethingSig 71 73 72 74 pro doSomething from var as DoSomethingSig? -
Tests/320-misc-two/820-anonymous-methods-aka-closures/210-anonymous-method-assign.cobra
1 class TestAnonMethodAssign 2 3 sig RetInt(a as int, b as int) as int 4 sig RetStr(a as int, b as int) as String 5 6 def main is shared 7 t = [4, 7, 1, 2, 3] 8 t1=t 9 10 # embedded closure 11 t.sort(do(a as int, b as int)) 12 return a.compareTo(b) 13 assert t == [1,2,3,4,7] 14 15 # store closure in local var 16 c as Comparison<of int> = do(a as int, b as int) 17 return a.compareTo(b) 18 t1.sort(c) 19 assert t1 == [1,2,3,4,7] 20 21 # this should work shouldnt it ? 22 /#c0 = do(a as int, b as int) as int 23 return a - b 24 t1.sort(c0) 25 print t1 26 print .x(c0) 27 #/ 28 29 # now try with various combinations of typing and inference 30 c1 as RetStr = do(a as int, b as int) as String 31 return '[a] - [b]' 32 assert .xs(c1) == '10 - 5' 33 34 # infer (and match to existing sig) variable type 35 c2 = do(a as int, b as int) as String 36 return '[a]xx - [b]xx' 37 assert c2.typeOf == RetStr 38 assert .xs(c2) == '10xx - 5xx' 39 40 c3 = do(a as int, b as int) #infer returnType 41 return '[a]xy - [b]xy' 42 assert c3.typeOf == RetStr 43 assert .xs(c3) == '10xy - 5xy' 44 45 def x( m as RetInt) as int is shared 46 return m(10, 5) 47 48 def xs( m as RetStr) as String is shared 49 return m(10, 5) 50 -
Tests/320-misc-two/800-attributes/130-attributes-tricky-names.cobra
8 8 with no warnings or errors. 9 9 """ 10 10 use System.Xml 11 use System.Xml.Linq12 11 use System.Xml.Serialization 13 12 14 13 class Season has Serializable -
Tests/320-misc-two/830-lambdas/310-lambda-assign.cobra
1 class LambdaAssign 2 3 sig RetInt(a as int, b as int) as int 4 sig RetStr(a as int, b as int) as String 5 6 def main is shared 7 t = [4, 7, 1, 2, 3] 8 t1=t 9 10 # embedded closure 11 t.sort(do(a as int, b as int) = a.compareTo(b)) 12 assert t == [1,2,3,4,7] 13 14 # store closure in local var 15 c as Comparison<of int> = do(a as int, b as int) = a.compareTo(b) 16 t1.sort(c) 17 assert t1 == [1,2,3,4,7] 18 19 # this should work shouldnt it ? 20 # evidently not 21 /#c0 = do(a as int, b as int) = a - b 22 t1.sort(c0) 23 print t1 24 print .x(c0) 25 #/ 26 27 # now try with various combinations of typing and inference 28 c1 as RetStr = do(a as int, b as int) = '[a] - [b]' 29 assert .xs(c1) == '10 - 5' 30 31 c2 = do(a as int, b as int) = '[a]xx - [b]xx' 32 assert c2.typeOf == RetStr 33 assert .xs(c2) == '10xx - 5xx' 34 35 #infer returnType 36 c3 = do(a as int, b as int) = 10*a -b 37 assert c3.typeOf == RetInt 38 assert .x(c3) == 95 39 40 def x( m as RetInt) as int is shared 41 return m(10, 5) 42 43 def xs( m as RetStr) as String is shared 44 return m(10, 5) 45 -
Tests/220-delegates-etc/100-delegates/176-sig-infer-local-common.cobra
1 # Support weird C# non inheritance-scope Sig type inference 2 # Forward reference to sig in Target class 3 # passing ref typed for Sig dcl in target class 4 # passing init code to run in context of other class 5 # setting property with Sig type declared in other class 6 7 class X 8 9 shared 10 11 var _counter = 0 12 13 get counter from var 14 15 def incCounter 16 _counter += 1 17 18 def main 19 s = Stuff(ref .incCounter) # pass a method reference to ctor 20 assert .counter == 0 21 ds = s.doSomething 22 ds() 23 assert .counter == 1 24 25 s1 = Stuff(doSomething = ref .incCounter) # pass nowt, init prop to a method reference 26 _counter = 10 27 assert .counter == 10 28 ds = s1.doSomething 29 ds() 30 assert .counter == 11 31 32 33 34 s2 = Stuff() # pass nowt 35 s2.doSomething = ref .incCounter #init prop to a method reference 36 # This is OK - and a damn sight clearer 37 #s2.doSomething = Stuff.DoSomethingSig(ref .incCounter) 38 _counter = 20 39 assert .counter == 20 40 ds = s2.doSomething 41 ds() 42 assert .counter == 21 43 44 45 class Stuff 46 47 sig DoSomethingSig 48 49 pro doSomething from var as DoSomethingSig? 50 51 cue init 52 base.init 53 54 cue init(ds as DoSomethingSig) 55 base.init 56 .doSomething = ds -
Tests/220-delegates-etc/100-delegates/172-infer-ref-type-no-sig.cobra
1 # Ref type inference and methodSig auto generation and injection 2 class MyType 3 pass 4 5 class AutoGenMethodSig 6 #sig MethNoArg 7 8 # non simple signature that doesnt collide with any generic System delegates 9 # e.g System.Action (one arg, no return), 10 # System.EventHandler(2 args, no return), 11 # System.Comparison(2 args, int return) 12 def methUnknown(r as MyType, r1 as MyType) as MyType 13 return r 14 15 def methUnknown2(r as MyType, r1 as MyType) as MyType 16 return r1 17 18 def methAction0 19 pass 20 21 def methAction(r as MyType) 22 pass 23 24 def main is shared 25 c = AutoGenMethodSig() 26 27 meUnk = ref c.methUnknown # .warning. No signature matching 28 assert meUnk.typeOf == SigFor_methUnknown # autogen Sig and inserted 29 30 meUnk2 = ref c.methUnknown2 31 assert meUnk2.typeOf == SigFor_methUnknown # found autogen Sig 32 33 # was matchiung to CrossAppDomainDelegate 34 meAct0 = ref c.methAction0 # .warning. No signature matching 35 assert meAct0.typeOf == SigFor_methAction0 36 #assert meAct0.typeOf == MethNoArg 37 38 # was matching to Converter<to,> 39 meAct1 = ref c.methAction # .warning. No signature matching 40 print meAct1 41 -
Tests/220-delegates-etc/100-delegates/178-sig-infer-local-err.cobra
1 # Local variable using target local Sig - if not explicitly typed and 2 # no matching Sig in scope cobra creates default one 3 # BUT C# cannot/willnot then implicitly (or explicitly) convert fm 4 # compatible Sig to target local Sig 5 class X 6 7 shared 8 9 var _counter = 0 10 11 get counter from var 12 13 def incCounter 14 _counter += 1 15 16 def main 17 18 s3 = Stuff() # pass nowt 19 x = ref .incCounter # .warning. no signature matching 20 s3.doSomething = x # .error. cannot implicitly convert 21 _counter = 22 22 assert .counter == 22 23 ds = s3.doSomething 24 ds() 25 assert .counter == 23 26 27 class Stuff 28 29 sig DoSomethingSig 30 31 pro doSomething from var as DoSomethingSig? 32 33 cue init 34 base.init 35 36 cue init(ds as DoSomethingSig) 37 base.init 38 .doSomething = ds -
Tests/220-delegates-etc/100-delegates/170-infer-ref-type.cobra
1 # Test Ref type inference and matching autogenerated ref sig 2 # to App or system MethodSigs 3 4 sig SigForMethOuter(s as String) 5 6 class RefType 7 8 sig SigForMethInner(a as int) 9 sig SigForDynamic(a as dynamic?) as bool 10 11 def meth(a as int) 12 print a 13 14 def methOuter(s as String) 15 print s 16 17 def methUnknown(r) 18 pass 19 20 def methConcDy(a as Object?) as bool 21 return false 22 23 # EventHandler 24 def handleEvent( src as Object, args as EventArgs) 25 pass 26 27 # ResolveEventHandler 28 def handleResolveEvent(sender as Object, args as ResolveEventArgs) as System.Reflection.Assembly? 29 return System.Reflection.Assembly.getExecutingAssembly 30 31 def chkMySig 32 me = ref .meth 33 assert me.typeOf == SigForMethInner 34 35 def main is shared 36 c = RefType() 37 c.chkMySig 38 39 me = ref c.meth # auto type me 40 assert me.typeOf == SigForMethInner 41 42 me1 = ref c.methOuter 43 assert me1.typeOf == SigForMethOuter 44 45 46 # equivalence Object? and dynamic arg 47 mdy = ref c.methConcDy 48 assert mdy.typeOf == SigForDynamic 49 50 # match to System MethodSigs (from use assembly/dll) 51 meh = ref c.handleEvent 52 assert meh.typeOf == System.EventHandler 53 54 meres = ref c.handleResolveEvent 55 assert meres.typeOf == System.ResolveEventHandler 56 57 # ticket 140 58 for x in [ref c.meth, ref c.meth] 59 assert x.typeOf == SigForMethInner 60 61 for y in [ref c.methOuter, ref c.methOuter] 62 assert y.typeOf == SigForMethOuter 63 64 #meUnk = ref c.methUnknown 65 #print 'me2', meUnk 66 67 -
Tests/220-delegates-etc/100-delegates/177-sig-infer-local.cobra
1 # local var using target local Sig - needs to be explicitly types 2 class X 3 4 shared 5 6 var _counter = 0 7 8 get counter from var 9 10 def incCounter 11 _counter += 1 12 13 def main 14 15 s3 = Stuff() # pass nowt 16 x as Stuff.DoSomethingSig = ref .incCounter #init local to a non scoped Sig method reference 17 #x = Stuff.DoSomethingSig(ref .incCounter) #init local to a non scoped Sig method reference 18 s3.doSomething = x 19 _counter = 22 20 assert .counter == 22 21 ds = s3.doSomething 22 ds() 23 assert .counter == 23 24 25 26 27 class Stuff 28 29 sig DoSomethingSig 30 31 pro doSomething from var as DoSomethingSig? 32 33 cue init 34 base.init 35 36 cue init(ds as DoSomethingSig) 37 base.init 38 .doSomething = ds