Wiki

Ticket #39: ref-lambda-type-inference.patch

File ref-lambda-type-inference.patch, 35.8 KB (added by hopscc, 15 years ago)
  • Source/Members.cobra

     
    596596    get shouldBeVirtual as bool is override 
    597597        return false 
    598598 
    599     def lambdaReturnType as IType 
     599    def inferLambdaReturnType # as IType 
    600600        """ This is a service method for LambdaExpr. """ 
    601601        require .didBindInt and .didBindImp 
    602602        stmt = _stmts[0] 
    603603        if stmt inherits ReturnStmt 
    604             return stmt.expr.type to ! 
     604            if stmt.expr.type 
     605                _returnType =  stmt.expr.type to ! 
    605606        else 
    606607            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         
    608622    def _bindInt is override 
    609623        base._bindInt 
    610624        if _returnTypeNode is nil 
    611             _returnType = .compiler.passThroughType  # TODO: infer return type from return statement like C# does 
     625            _returnType = .compiler.passThroughType  
    612626 
    613627    def _bindImp is override 
    614628        base._bindImp 
     
    623637                break 
    624638        if hasYield, .throwError('Cannot yield inside an anonymous method.') 
    625639 
    626  
    627640class AbstractMethod 
    628641    is abstract, partial 
    629642    inherits BoxMember 
  • Source/Expr.cobra

     
    202202        body 
    203203            base._bindImp 
    204204 
     205    def _matchingOrNewSig(aSig as MethodSig, container as Box, tag as String) as MethodSig 
     206        """ 
     207        Return a compatible matching Sig for asig in container or containers ancestor inheritance hierarchy  
     208        otherwise warn and insert (instantiate) aSig into container. 
     209         
     210        Support method for RefExpr and AnonymousMethod and lambdaExpr 
     211        """ 
     212        compatSig = container.sigForMethodSig(aSig) 
     213        if not compatSig 
     214            msg = 'No signature matching the signature of the [tag] ([aSig.toCobraSource]) in the inheritance tree or used namespaces.' 
     215            sugg = 'Did you leave out a sig statement in scope for this method reference?' 
     216            action = 'Adding generated sig "[aSig.toCobraSource]" to [container.name]' 
     217            .compiler.warning(this, '[msg]\n[sugg]\n[action]') 
     218            container.addDecl(aSig) 
     219        else 
     220            aSig = compatSig to ! 
     221        return aSig  
     222                 
    205223    def _suggestionsMessage(suggs as List<of String>) as String 
    206224        """ 
    207225        Shared by MemberExpr, CallExpr and IdentifierExpr to give suggestions in an error message about an unknown member. 
     
    320338        base.addSubFields 
    321339        .addField('params', .params) 
    322340 
     341    def _makeAnonSig(tag as String, resultType as IType, isNames as String*) as MethodSig 
     342        """ 
     343        Make an anonymous methodSig for this anonymous expr (lambda or anonMethod) 
     344        and return  a declared match for it or instantiate it into its containing box.  
     345        """ 
     346        sigToken  = .token.copy('ID', 'sigFor[tag]')  
     347        nameToken = .token.copy('ID', 'SigFor[tag]_[.token.lineNum]_[.serialNum]') 
     348        docString = '' to ? 
     349        aSig = MethodSig(sigToken, nameToken, .curCodeMember.parentBox, nameToken.text, .params,  
     350            resultType, isNames, AttributeList(), docString) 
     351        aSig.bindInh 
     352        aSig.bindInt 
     353        aSig.bindImp 
     354        #print aSig 
     355        return _matchingOrNewSig(aSig, .curCodeMember.parentBox, tag) # in Expr 
     356             
    323357    def toCobraSource as String is override 
    324358        sb = StringBuilder('do(') 
    325359        sep = '' 
     
    335369class AnonymousMethodExpr inherits AnonymousExpr is partial 
    336370    implements HasAddStmt 
    337371    """ 
     372    do(a as int, b as int) as int 
     373        ... 
     374        return a.compareTo(b) 
     375 
    338376    Also called "closures". 
    339377    """ 
    340378     
     
    354392 
    355393    def _bindImp is override 
    356394        base._bindImp 
    357         _method = AnonymousMethod(.token, .curCodeMember, .params, _returnTypeProxy, if(.curCodeMember.isShared, ['shared'], List<of String>())) 
     395        isNames = if(.curCodeMember.isShared, ['shared'], List<of String>()) 
     396        _method = AnonymousMethod(.token, .curCodeMember, .params, _returnTypeProxy, isNames) 
    358397        for stmt in .stmts, _method.addStmt(stmt) 
    359398        _method.bindInt 
    360399        _method.bindImp 
    361         _type = _method.resultType 
     400        _method.inferReturnType  
     401        #print .token.lineNum, _method.resultType 
     402        _type = _makeAnonSig('AnonMthd', _method.resultType, List<of String>()) 
     403     
    362404 
    363  
    364405class LambdaExpr inherits AnonymousExpr is partial 
    365406    """ 
    366407    ... do(a as int, b as int)=a.compareTo(b) ... 
     
    392433 
    393434    def _bindImp is override 
    394435        base._bindImp 
    395         _method = AnonymousMethod(.token, .curCodeMember, .params, .compiler.dynamicType, if(.curCodeMember.isShared, ['shared'], List<of String>())) 
     436        isNames = if(.curCodeMember.isShared, ['shared'], List<of String>()) 
     437        _method = AnonymousMethod(.token, .curCodeMember, .params,  .compiler.dynamicType, isNames) 
    396438        ret = ReturnStmt(.token.copy('RETURN', 'return'), .expr) 
    397439        _method.addStmt(ret) 
    398440        _method.bindInt 
    399441        _method.bindImp 
    400442        # the expression may have been transformed, but if so, only the containing ReturnStmt got the notice 
    401443        _expr = ret.expr to ! 
    402         _type = .compiler.passThroughType # TODO: Set a real type such as .compiler.delegateType 
    403         # method.lambdaReturnType 
     444        _type = .compiler.passThroughType 
     445        _method.inferLambdaReturnType 
     446        _type = _makeAnonSig('Lambda', _method.resultType, isNames) 
    404447 
    405448 
    406449class AsExpr 
     
    18211864        ref obj.foo 
    18221865        ref _foo 
    18231866    """ 
    1824  
     1867     
    18251868    cue init(token as IToken, expr as Expr) 
    18261869        base.init(token) 
    18271870        # TODO: can the types of expressions be limited? 
     
    18551898            throw 
    18561899        finally 
    18571900            .compiler.refExprLevel -= 1 
     1901        _checkRefExpr    
     1902        _type = .compiler.passThroughType # something if refSig make signature fails 
     1903        refSig = _makeSignatureOfExpr 
     1904        if refSig 
     1905            refSig.bindInh 
     1906            refSig.bindInt 
     1907            refSig.bindImp 
     1908            _type = _matchingOrNewSig(refSig, .compiler.curCodeMember.parentBox, _expr.definition.name) # in Expr 
     1909                 
     1910    def _checkRefExpr    
    18581911        if _expr inherits DotExpr 
    18591912            right = _expr.right 
    18601913            if right inherits MemberExpr 
     
    18701923            else 
    18711924                throw FallThroughException([this, _expr, right]) 
    18721925        else if _expr inherits IdentifierExpr 
    1873             if _expr.definition inherits AbstractMethod 
    1874                 pass 
    1875             else 
     1926            if not ( _expr.definition inherits AbstractMethod ) 
    18761927                .throwError('Only methods can be referenced, not [Utils.pluralize(_expr.definition.englishName)].') 
    18771928        else 
    18781929            .throwError('Unexpected reference. Refer to methods after `ref` or remove `ref`.') 
    1879         _type = .compiler.passThroughType # TODO: Set a real type such as .compiler.delegateType 
    1880         # TODO: need to do something more sophisticated like overriding:    def canBeAssignedTo(type as IType) as bool 
    1881  
     1930             
     1931    def _makeSignatureOfExpr as MethodSig? 
     1932        """Auto generate a signature for type of expression being 'ref'd"""  
     1933        if _expr inherits DotExpr 
     1934            right = _expr.right 
     1935            if right inherits MemberExpr 
     1936                if right.definition inherits AbstractMethod  
     1937                    am = right.definition to AbstractMethod 
     1938                    signature = _makeSig(am, _expr.right.token) 
     1939                else if right.definition inherits MemberOverload 
     1940                    mo = right.definition to MemberOverload 
     1941                    if mo.members[0] inherits AbstractMethod 
     1942                        am = mo.members[0] to AbstractMethod  
     1943                        signature = _makeSig(am, _expr.right.token) 
     1944        else if _expr inherits IdentifierExpr 
     1945            if _expr.definition inherits AbstractMethod 
     1946                am = _expr.definition to AbstractMethod 
     1947                signature = _makeSig(am, _expr.token) 
     1948        return signature 
     1949             
     1950    def _makeSig(am as AbstractMethod, token as IToken) as MethodSig 
     1951        """Make an (anonymously named) signature corresponding to the provided method""" 
     1952        sigToken= token.copy('ID', 'sigForRef')  
     1953        nameToken = token.copy  
     1954        container = .compiler.curCodeMember.parentBox 
     1955        name = 'SigFor_'+nameToken.value to String 
     1956        isNames = List<of String>() 
     1957        attribs = AttributeList() 
     1958        docString = '' to ? 
     1959        returnType = am.resultType 
     1960        params     = List<of Param>(am.params) 
     1961        return MethodSig(sigToken, nameToken, container, name, params, returnType, isNames, attribs, docString) 
     1962         
    18821963    def toCobraSource as String is override 
    18831964        return 'ref ' + _expr.toCobraSource 
    18841965 
  • Source/BackEndClr/ScanClrType.cobra

     
    5555                    if type.isClass 
    5656                        if type.name.startsWith('Extend_') and type.name.count(c'_') >= 2 
    5757                            curNameSpace.addDecl(Extension(clrType)) 
     58                        else if _shouldBeMethodSig(type) 
     59                            #print curNameSpace.name, type.name  
     60                            curNameSpace.addDecl(MethodSig(clrType)) 
    5861                        else 
    5962                            curNameSpace.addDecl(Class(clrType)) 
    6063                    else if type.isInterface 
     
    7073                        throw FallThroughException(type) 
    7174        finally 
    7275            _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  
    7382 
     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             
    7491    def fixNilableMemberSigs 
    7592        # TODO: this really needs to go in a separate file that the compiler reads each time 
    7693 
     
    465482 
    466483    def _memberTypeProxy(clrType as Type?, notNullAttr as bool) as ITypeProxy 
    467484        """ 
    468         Returns a type proxy for a member type such as a parameter type or method return type. 
     485        Returns a type proxy for a member type such as a parameter type or member type. 
    469486        In CLR, reference types are nilable by default, but you can pass `true` for `notNullAttr` to indicate there was a NotNullAttribute in the DLL. 
    470487        """ 
    471488        if clrType is nil 
     
    481498 
    482499    def _memberTypeResultProxy(member as MemberInfo, clrType as Type?) as ITypeProxy 
    483500        """ 
    484         Returns a type proxy for a member type such as a parameter type or method return type. 
     501        Returns a type proxy for a member result type such as a property or field type or method return type. 
    485502        In CLR, reference types are nilable by default. 
    486503        """ 
    487         if clrType is nil 
     504        if clrType is nil or clrType is sharp'typeof(void)' # C# null data vs null code return 
    488505            return .compiler.voidType 
    489506        else if clrType.isValueType 
    490507            return ClrTypeProxy(clrType) 
     
    571588        # the first argument is implicit in an Extension 
    572589        results = base._scanParams(paramInfos) 
    573590        return results[1:] 
     591         
     592class MethodSig  
     593    is partial 
     594     
     595    def _scanNativeType 
     596        base._scanNativeType 
     597        _scanIsNames 
     598        #_scanImplements 
     599        #_scanNestedTypes 
     600        #_scanFields 
     601        _scanInitializers 
     602        #_scanProperties 
     603        _scanMethods 
     604        #_scanEvents 
     605         
     606        # reflect on  invoke method to find signature 
     607        methInfo = .clrType.getMethod('Invoke', BindingFlags(Instance, Static, DeclaredOnly, Public, NonPublic)) 
     608        if methInfo and _methOK(methInfo to !) 
     609            _params = _scanParams(methInfo.getParameters) 
     610            _returnTypeProxy = _memberTypeResultProxy(methInfo to !, methInfo.returnType)  
     611        #if .clrType.isGenericType 
     612        #   print .name, methInfo.returnType, _params 
     613                 
     614    def _methOK( methInfo as System.Reflection.MethodInfo)  as bool 
     615        if methInfo.isSpecialName or methInfo.isAssembly or methInfo.isPrivate 
     616            return false 
     617        if methInfo.declaringType is not .clrType, return false 
     618        if  _badRelatedType(methInfo.returnType) 
     619            return false 
     620        for paramInfo in methInfo.getParameters 
     621            if _badRelatedType(paramInfo.parameterType) 
     622                return false 
     623        return true      
  • Source/Boxes.cobra

     
    417417            _declsByName[ol.name] = ol 
    418418            _declsByNameCI[ol.name.toLower] = ol 
    419419 
     420    def addDecl(decl as IBoxMember) is override 
     421        base.addDecl(decl) 
     422        # overridden to explicitly store methodSigs separately 
     423        if decl inherits MethodSig 
     424            base.addSig(decl) 
     425 
    420426    def addDeclFromOverload(decl as IBoxMember, ol as MemberOverload) 
    421427        require 
    422428            ol in .overloads 
     
    15011507    The "sig" keyword fits nicely with other declaration keywords like "var" "def" and "get". 
    15021508    And "sig" is a more platform neutral term should we have other non-CLI backends. 
    15031509     
    1504     MethodSigs are only created when parsing. When reading from a DLL, delegates are merely 
    1505     subclasses of Delegate or MulticastDelegate. 
     1510    MethodSigs are created when parsing. When reading from a DLL, delegates are merely 
     1511    subclasses of (class) Delegate but subclasses of MulticastDelegate are created as MethodSigs so that 
     1512    type inference and sig matching can be done if such a MethodSig is used as a type.. 
    15061513     
    15071514    Note that MethodSig is a subclass of Class and therefore both a Box and an IType. Also, it will 
    15081515    return true for .isDescendantOf(.compiler.delegateType). 
     
    15201527        _params = params 
    15211528        _returnTypeProxy = returnTypeProxy 
    15221529  
     1530    cue init(nativeType as NativeType) 
     1531        base.init(TokenFix.empty, TokenFix.empty, ClrTypeProxy.cobraNameForSharpBoxName(nativeType.name), 
     1532            List<of IType>(), List<of String>(), AttributeList(),  
     1533            LibraryTypeProxy('System.MulticastDelegate'), List<of ITypeProxy>(),  
     1534            List<of ITypeProxy>(), nil) 
     1535        _initNativeType(nativeType) 
     1536        # below are temp placeholders until _scanNativeType runs (no params, void returned) 
     1537        _params = List<of Param>() 
     1538        _returnTypeProxy = TypeProxy(.compiler.voidType) 
     1539 
    15231540    get params from var 
    15241541     
    15251542    get returnTypeProxy from var 
     
    15291546    get resultType as IType? is override 
    15301547        return .returnType 
    15311548 
     1549    def addRefFields 
     1550        base.addRefFields 
     1551        .addField('params', _params) 
     1552        .addField('returnType', _returnType) 
     1553         
    15321554    def _bindInh 
    15331555        base._bindInh 
    15341556        assert _baseClass 
    15351557        assert _baseClass.qualifiedName == 'System.MulticastDelegate' 
    15361558        assert .parentBox or .parentNameSpace 
    1537  
     1559        assert not _needScanNativeType 
     1560         
    15381561    def _bindInt 
    1539         returnType as ITypeProxy = .returnType ? .returnTypeProxy 
    1540         .addDecl(_makeMethod('invoke', .params.clone, returnType)) 
    1541         # dynamic type vari length param in list as placeholder for multiple params  
    1542         params = [Param('vParam', VariTypeIdentifier(.token, TypeIdentifier(.token, DynamicType())))] 
    1543         .addDecl(_makeMethod('beginInvoke', params, TypeIdentifier(.token.copy('ID', 'IAsyncResult')) to ITypeProxy)) 
    1544         .addDecl(_makeMethod('endInvoke',   params, returnType )) 
     1562        if not .isFromBinaryLibrary # If From Assembly/Library these methods have already been inserted  
     1563            # TODO: push these down to _ScanClrType, platform specific. 
     1564            returnType as ITypeProxy = .returnType ? .returnTypeProxy 
     1565            .addDecl(_makeMethod('invoke', .params.clone, returnType)) 
     1566            # dynamic type vari length param in list as placeholder for multiple params  
     1567            params = [Param('vParam', VariTypeIdentifier(.token, TypeIdentifier(.token, DynamicType())))] 
     1568            .addDecl(_makeMethod('beginInvoke', params, TypeIdentifier(.token.copy('ID', 'IAsyncResult')) to ITypeProxy)) 
     1569            .addDecl(_makeMethod('endInvoke',   params, returnType )) 
    15451570        base._bindInt 
    15461571        for param in .params 
    15471572            param.bindInt 
     
    15561581        # method body just to avoid a Cobra warning during .bindImp 
    15571582        m.statements.add(ThrowStmt(.token, PostCallExpr(.token, IdentifierExpr(.token, 'Exception'), List<of Expr>())))  
    15581583        return m 
     1584     
     1585    def isAssignableTo(type as IType) as bool is override 
     1586        r = base.isAssignableTo(type) 
     1587        if not r 
     1588            if (nnt = type.nonNil) inherits MethodSig 
     1589                r = .isAnonymousMatch(nnt) 
     1590        return r 
     1591             
     1592    def isAnonymousMatch(aSig as MethodSig) as bool 
     1593        """ 
     1594        Indicate whether this methodSig is an anonymous match for the provided one. 
     1595        An anonymous match is one that ignores the name but succeeds if the sig returnType and 
     1596        the count, type and ordering of the parameters is the same. 
     1597        """ 
     1598        if .isFromBinaryLibrary  
     1599            # if from platform Assembly/Library do (minimal) bindings on-demand   
     1600            if not .didBindInh, .bindInh # TODO: optimise this more 
     1601            if not .didBindInt, .bindInt     
     1602        assert aSig.returnType 
     1603        assert .returnType 
     1604        #print '    [aSig.name] [.name] ReturnType', aSig.returnType.name, .returnType.name 
     1605        if not _matchesType(aSig.returnType to !, .returnType to !) 
     1606            return false 
     1607        params = .params 
     1608        otherParams = aSig.params 
     1609        #print '    ParamCount',  otherParams.count, params.count 
     1610        if otherParams.count <> params.count 
     1611            return false 
     1612        for i in params.count 
     1613            #print '    param([i])',  otherParams[i].type.name, params[i].type.name, otherParams[i].type, params[i].type 
     1614            if not _matchesType(otherParams[i].type, params[i].type) 
     1615                return false 
     1616            if otherParams[i].direction <> params[i].direction 
     1617                return false 
     1618        return true 
     1619 
     1620    def _matchesType(a as IType, b as IType) as bool 
     1621        if a.nonNil inherits GenericParam or b.nonNil inherits GenericParam 
     1622            return true 
     1623        # The above provides a mixed blessing of matches to generic delegates (delegates with generic params)  
     1624        # of which in 'use'ed assemblies (System specifically) there are a bunch that match common cases.  
     1625        # Good for Comparable implementations, erroneous hits for pretty much every other simple signature 
     1626        # See ScanClrType for how this is addressed. 
     1627        return a.isAssignableTo(b) # is this sufficient? 
     1628     
     1629    def toCobraSource as String 
     1630        s = StringBuilder() 
     1631        s.append('sig ' + .name ) 
     1632        if .params.count 
     1633            s.append('(') 
     1634            sep = '' 
     1635            for p in .params 
     1636                s.append(sep) 
     1637                sep = ', ' 
     1638                s.append(p.name) 
     1639                s.append(' as ') 
     1640                s.append(p.type.name) 
     1641            s.append(')') 
     1642        if .returnType <> .compiler.voidType 
     1643            s.append(' as ') 
     1644            s.append(.returnType.name) 
     1645        return s.toString 
    15591646         
    15601647class GenericParam inherits CobraType is partial 
    15611648    """ 
  • Source/Container.cobra

     
    2525        May return nil if no such member exists. 
    2626        Case-sensitive. 
    2727        """ 
     28         
     29    def sigForMethodSig(msig as MethodSig) as MethodSig? 
     30        """ 
     31        Returns the first method signature of this container matching the provided signature, including  
     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        """ 
    2836# TODO: 
    2937#       require 
    3038#           # TODO: not .compiler.isParsing 
     
    8391    var _declsInOrder as List<of TMember> 
    8492    var _declsByName as Dictionary<of String, TMember> 
    8593    var _declsByNameCI as Dictionary<of String, TMember> 
     94    var _sigsInOrder as List<of MethodSig> 
    8695    var _docString as String 
    8796    var _isNames as IList<of String> 
    8897 
     
    93102        base.init(token, name) 
    94103        _initParent(parent) 
    95104        _declsInOrder = List<of TMember>() 
     105        _sigsInOrder = List<of MethodSig>() 
    96106        _declsByName = Dictionary<of String, TMember>() 
    97107        _declsByNameCI = Dictionary<of String, TMember>() 
    98108        _isNames = isNames.toList 
     
    161171            else 
    162172                _declsByNameCI.add(decl.name.toLower, decl) 
    163173 
     174    def addSig(signat as MethodSig)          
     175        _sigsInOrder.add(signat) 
     176 
    164177    def declForName(name as String) as TMember? 
    165178        require 
    166179            name.length 
     
    345358 
    346359    def cloneCollections 
    347360        _declsInOrder = List<of TMember>(_declsInOrder) 
     361        _sigsInOrder  = List<of MethodSig>(_sigsInOrder) 
    348362        _declsByName = Dictionary<of String, TMember>(_declsByName) 
    349363        _declsByNameCI = Dictionary<of String, TMember>(_declsByNameCI) 
    350  
    351  
     364         
     365    def sigForMethodSig(ms as MethodSig) 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 
     376            return .parent.sigForMethodSig(ms) 
     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             
    352387interface IMember 
    353388    is partial 
    354389    inherits INamedNode 
  • Source/BinaryOpExpr.cobra

     
    373373                _type = leftType 
    374374            else if cannotMix 
    375375                .throwError('Cannot mix types [_left.type.name] and [_right.type.name] for arithmetic.') 
     376            else if _left.isKindOf(.compiler.delegateType) 
     377                _type = tpassthrough # Not really but allows catching += -= below 
     378     
    376379            if _type is nil 
    377380                sugg = 'Try finding a method that performs this function.' 
    378381                if leftType == rightType 
     
    404407        base._bindImp 
    405408        # TODO: does NumericPromoExpr cover everything we need? 
    406409        # C# and other languages use += and -= on delegates and events, but Cobra does not. 
    407         if .left.type inherits MethodSig 
    408             # TODO: error 
    409             pass 
    410         else if .left.type.nonNil.isDescendantOf(.compiler.delegateType) 
     410        if .left.type inherits MethodSig or .left.type.nonNil.isDescendantOf(.compiler.delegateType) 
    411411            leftSource = .left.toCobraSource 
    412412            rightSource = .right.toCobraSource 
    413413            if not .right inherits RefExpr, rightSource = 'ref ' + rightSource 
  • Source/NameSpace.cobra

     
    264264        for ud in _useDirectives 
    265265            m = ud.extensionMemberFor(box, name) 
    266266            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) 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) 
     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 
     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 
    268295 
     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 
    269314    def symbolForName(name as String) as IMember? 
    270315        if not .isUnified 
    271316            x = _unifiedNameSpace.symbolForName(name) 
     
    276321            if members.count == 1 
    277322                return List<of IMember>(members)[0]  # TODO: feels silly. maybe Set should have a .only method with require .count==1 
    278323            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) 
    288325        else 
    289326            # our decl? 
    290327            # TODO: should this come before checking our name? what does C# do? 
     
    298335                if x, return x 
    299336#/ 
    300337        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         
    302350    def _symbolsForNameFromUseDirectives(name as String, members as Set<of IMember>) 
    303351        """ 
    304352        Populates `members` with all symbols from `use` directives that match `name`. 
     
    308356            if x, members.add(x) 
    309357        if _superNameSpace 
    310358            _superNameSpace._symbolsForNameFromUseDirectives(name, members) 
    311  
     359             
    312360    def addDecl(decl as INameSpaceMember) is override 
    313361        base.addDecl(decl) 
    314362        if decl inherits NameSpace 
     
    332380                pass 
    333381            else 
    334382                _unifiedNameSpace.addDecl(decl) 
     383        if decl inherits MethodSig 
     384            base.addSig(decl) 
    335385 
    336386    def addUseDirective(ud as UseDirective) 
    337387        _useDirectives.add(ud) 
     
    403453        .addField('boundNameSpace', _boundNameSpace) 
    404454 
    405455    get boundNameSpace from var 
     456    get fullName from var 
    406457 
    407458    def extensionMemberFor(box as Box, name as String) as IMember? 
    408459        require .didBindUse 
     
    411462    def findSymbol(name as String) as IMember? 
    412463        require .didBindUse 
    413464        return _boundNameSpace.symbolForName(name) 
     465 
     466    def sigMethodFor(ms as MethodSig) as MethodSig?  
     467        require .didBindUse 
     468        return _boundNameSpace.sigForMethodSig(ms) 
  • Source/CobraParser.cobra

     
    16711671        possibleVarDef = .curBox.declForName(varName) 
    16721672        if not possibleVarDef 
    16731673            if not initExpr and not declVarType 
     1674                #TODO: hops support __varname as target  
    16741675                .throwError('There is no variable named "[varName]" to match the property "[name]".') 
    16751676            varDef = BoxVar(token, token, .curBox, varName, declVarType, List<of String>(_isNamesStack), initExpr, nil, 'Automatic backing var for property "[name]".') 
    16761677            .curBox.addDecl(varDef) 
  • Tests/120-classes/320-construct-prop-set.cobra

     
     1sig DoSomethingSig 
     2# Signature hoisted for ref inference Jun-2010.  
     3#Needs to be accessible to both class X and class Stuff  
     4# (or add a Sig to class X compatible with one in class Stuff) 
     5 
    16class X 
    27 
    38    shared 
     
    6772    pro style from var 
    6873 
    6974 
    70     sig DoSomethingSig 
     75    # this sig needs to be accessible to both Stuff and X 
     76    #sig DoSomethingSig 
    7177 
    7278    pro doSomething from var as DoSomethingSig? 
    7379 
  • Tests/320-misc-two/820-anonymous-methods-aka-closures/210-anonymous-method-assign.cobra

     
     1class 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/830-lambdas/310-lambda-assign.cobra

     
     1class 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/112-declare-sig-inside-class.cobra

     
    3232 
    3333class Program 
    3434 
     35    # need this additional sig type now ref type inference is implemented  
     36    # and searching for compat sig  only up inheritance tree and  
     37    # 'use'ed namespaces. 
     38    # Test is now that the sig types in each class are assignment compatible 
     39    sig BinaryOpP(a as int, b as int) as int 
     40 
    3541    def main is shared 
    3642        Program().run 
    3743     
  • Tests/220-delegates-etc/100-delegates/172-infer-ref-type-no-sig.cobra

     
     1# Ref type inference and methodSig auto generation and injection 
     2class MyType 
     3    pass 
     4 
     5class 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/170-infer-ref-type.cobra

     
     1# Test Ref type inference and matching autogenerated ref sig 
     2# to App or system MethodSigs 
     3 
     4sig SigForMethOuter(s as String) 
     5 
     6class 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/100-basics.cobra

     
     1sig SigCompareInt(a as int, b as int) as int  
     2# Above Add for ref inference  Jun-2010. Not find/match generic delegate 
     3 
    14class X 
    25 
    36    def main is shared 
  • Developer/IntermediateReleaseNotes.text

     
    6060 
    6161* Enumeration members can now be placed on the same line separated by commas. 
    6262 
     63* Provide type inference on ref expressions (find matching Sigs for ref to method) : tickets:39,40,138 
     64  similarly also provide correct type inference (to a method sig) on lambdas and anon methods. tickets:204 
    6365 
    6466================================================================================ 
    6567Library