Wiki

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

File ref-lambda-type-inference-target-local.patch, 41.2 KB (added by hopscc, 7 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# uu 
    614628    def _bindImp is override 
     
    628642                break 
    629643        if hasYield, .throwError('Cannot yield inside an anonymous method.') 
    630644 
    631  
    632645class AbstractMethod 
    633646    is abstract, partial 
    634647    inherits BoxMember 
  • Source/Expr.cobra

     
    210210        body 
    211211            base._bindImp 
    212212 
     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                 
    213234    def _suggestionsMessage(suggs as List<of String>) as String 
    214235        """ 
    215236        Shared by MemberExpr, CallExpr and IdentifierExpr to give suggestions in an error message about an unknown member. 
     
    328349        base.addSubFields 
    329350        .addField('params', .params) 
    330351 
     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         
    331383    def toCobraSource as String is override 
    332384        sb = StringBuilder('do(') 
    333385        sep = '' 
     
    343395class AnonymousMethodExpr inherits AnonymousExpr is partial 
    344396    implements HasAddStmt 
    345397    """ 
     398    do(a as int, b as int) as int 
     399        ... 
     400        return a.compareTo(b) 
     401 
    346402    Also called "closures". 
    347403    """ 
    348404     
     
    362418 
    363419    def _bindImp is override 
    364420        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) 
    366423        for stmt in .stmts, _method.addStmt(stmt) 
    367424        _method.bindInt 
    368425        _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     
    370430 
    371  
    372431class LambdaExpr inherits AnonymousExpr is partial 
    373432    """ 
    374433    ... do(a as int, b as int)=a.compareTo(b) ... 
     
    400459 
    401460    def _bindImp is override 
    402461        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) 
    404464        ret = ReturnStmt(.token.copy('RETURN', 'return'), .expr) 
    405465        _method.addStmt(ret) 
    406466        _method.bindInt 
    407467        _method.bindImp 
    408468        # the expression may have been transformed, but if so, only the containing ReturnStmt got the notice 
    409469        _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) 
    412473 
    413474 
    414475class AsExpr 
     
    19131974        ref obj.foo 
    19141975        ref _foo 
    19151976    """ 
    1916  
     1977     
     1978    var _refSig as MethodSig?        
     1979     
    19171980    cue init(token as IToken, expr as Expr) 
    19181981        base.init(token) 
    19191982        # TODO: can the types of expressions be limited? 
     
    19472010            throw 
    19482011        finally 
    19492012            .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    
    19502043        if _expr inherits DotExpr 
    19512044            right = _expr.right 
    19522045            if right inherits MemberExpr 
     
    19622055            else 
    19632056                throw FallThroughException([this, _expr, right]) 
    19642057        else if _expr inherits IdentifierExpr 
    1965             if _expr.definition inherits AbstractMethod 
    1966                 pass 
    1967             else 
     2058            if not ( _expr.definition inherits AbstractMethod ) 
    19682059                .throwError('Only methods can be referenced, not [Utils.pluralize(_expr.definition.englishName)].') 
    19692060        else 
    19702061            .throwError('Unexpected reference. Refer to methods after `ref` or remove `ref`.') 
    1971         _type = .compiler.passThroughType # TODO: Set a real type such as .compiler.delegateType 
    1972         # TODO: need to do something more sophisticated like overriding:    def canBeAssignedTo(type as IType) as bool 
    19732062 
     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         
    19742118    def toCobraSource as String is override 
    19752119        return 'ref ' + _expr.toCobraSource 
    19762120 
  • 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 
     
    479496 
    480497    def _memberTypeProxy(clrType as Type?, notNullAttr as bool) as ITypeProxy 
    481498        """ 
    482         Returns a type proxy for a member type such as a parameter type or method return type. 
     499        Returns a type proxy for a member type such as a parameter type or member type. 
    483500        In CLR, reference types are nilable by default, but you can pass `true` for `notNullAttr` to indicate there was a NotNullAttribute in the DLL. 
    484501        """ 
    485502        if clrType is nil 
     
    495512 
    496513    def _memberTypeResultProxy(member as MemberInfo, clrType as Type?) as ITypeProxy 
    497514        """ 
    498         Returns a type proxy for a member type such as a parameter type 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. 
    499516        In CLR, reference types are nilable by default. 
    500517        """ 
    501         if clrType is nil 
     518        if clrType is nil or clrType is sharp'typeof(void)' # C# null data vs null code return 
    502519            return .compiler.voidType 
    503520        else if clrType.isValueType 
    504521            return ClrTypeProxy(clrType) 
     
    585602        # the first argument is implicit in an Extension 
    586603        results = base._scanParams(paramInfos) 
    587604        return results[1:] 
     605         
     606class 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

     
    430430            _declsByName[ol.name] = ol 
    431431            _declsByNameCI[ol.name.toLower] = ol 
    432432 
     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 
    433439    def addDeclFromOverload(decl as IBoxMember, ol as MemberOverload) 
    434440        require 
    435441            ol in .overloads 
     
    15351541    The "sig" keyword fits nicely with other declaration keywords like "var" "def" and "get". 
    15361542    And "sig" is a more platform neutral term should we have other non-CLI backends. 
    15371543     
    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.. 
    15401547     
    15411548    Note that MethodSig is a subclass of Class and therefore both a Box and an IType. Also, it will 
    15421549    return true for .isDescendantOf(.compiler.delegateType). 
     
    15541561        _params = params 
    15551562        _returnTypeProxy = returnTypeProxy 
    15561563  
     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 
    15571574    get params from var 
    15581575     
    15591576    get returnTypeProxy from var 
     
    15631580    get resultType as IType? is override 
    15641581        return .returnType 
    15651582 
     1583    def addRefFields 
     1584        base.addRefFields 
     1585        .addField('params', _params) 
     1586        .addField('returnType', _returnType) 
     1587         
    15661588    def _bindInh 
    15671589        base._bindInh 
    15681590        assert _baseClass 
    15691591        assert _baseClass.qualifiedName == 'System.MulticastDelegate' 
    15701592        assert .parentBox or .parentNameSpace 
    1571  
     1593        assert not _needScanNativeType 
     1594         
    15721595    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 )) 
    15791604        base._bindInt 
    15801605        for param in .params 
    15811606            param.bindInt 
     
    15901615        # method body just to avoid a Cobra warning during .bindImp 
    15911616        m.statements.add(ThrowStmt(.token, PostCallExpr(.token, IdentifierExpr(.token, 'Exception'), List<of Expr>())))  
    15921617        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 
    15931680         
    15941681class GenericParam inherits CobraType is partial 
    15951682    """ 
  • Source/Container.cobra

     
    2525        May return nil if no such member exists. 
    2626        Case-sensitive. 
    2727        """ 
     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        """ 
    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, 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             
    352387interface IMember 
    353388    is partial 
    354389    inherits INamedNode 
  • Source/BinaryOpExpr.cobra

     
    295295                    rightName = _right.definition.name 
    296296                    .compiler.warning(this, 'Setting a parameter ("[leftName]") to a class variable ("[rightName]") is often a mistake. You may want to reverse the assignment.') 
    297297 
     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) 
    298310 
     311 
    299312class NumericPromoExpr inherits BinaryOpExpr is partial 
    300313 
    301314    cue init(opToken as IToken, op as String, left as Expr, right as Expr) 
     
    367380                _type = leftType 
    368381            else if cannotMix 
    369382                .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     
    370386            if _type is nil 
    371387                sugg = 'Try finding a method that performs this function.' 
    372388                if leftType == rightType 
     
    413429        base._bindImp 
    414430        # TODO: does NumericPromoExpr cover everything we need? 
    415431        # 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) 
    420433            leftSource = .left.toCobraSource 
    421434            rightSource = .right.toCobraSource 
    422435            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, 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 
    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, true) 
  • Tests/120-classes/320-construct-prop-set.cobra

     
    6767    pro style from var 
    6868 
    6969 
     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. 
    7072    sig DoSomethingSig 
    7173 
    7274    pro doSomething from var as DoSomethingSig? 
  • 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/800-attributes/130-attributes-tricky-names.cobra

     
    88with no warnings or errors. 
    99""" 
    1010use System.Xml 
    11 use System.Xml.Linq 
    1211use System.Xml.Serialization 
    1312 
    1413class Season has Serializable 
  • 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/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 
     7class 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 
     45class 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 
     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/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 
     5class 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 
     27class 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 
     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/177-sig-infer-local.cobra

     
     1# local var using target local Sig - needs to be explicitly types 
     2class 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 
     27class 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