Esempio n. 1
0
        private ExpressionNode BindStaticMemberOfType(SyntaxNode node, ExpressionNode left, SimpleNameSyntax right, LookupResult lookupResult)
        {
            Debug.Assert(node != null);
            Debug.Assert(left != null);
            Debug.Assert(right != null);
            Debug.Assert(lookupResult.IsViable);
            Debug.Assert(lookupResult.Symbols.Any());

            SymbolOrMethodGroup symbolOrMethods = GetSymbolOrMethodGroup(lookupResult);

            if (symbolOrMethods.IsMethodGroup)
            {
                // If I identifies one or more methods, then the result is a method group with no
                // associated instance expression. If a type argument list was specified, it is used
                // in calling a generic method.
                // UNDONE: Construct the type argument list if there is one.
                return(new MethodGroup(right, null, left, symbolOrMethods.MethodGroup));
            }
            else
            {
                Symbol symbol = symbolOrMethods.NonMethod;

                switch (symbol.Kind)
                {
                case SymbolKind.NamedType:
                case SymbolKind.ErrorType:
                    // If I identifies a type, then the result is that type constructed with the given type arguments.
                    // UNDONE: Construct the child type if it is generic!
                    return(new TypeExpression(node, (TypeSymbol)symbol));

                case SymbolKind.Property:
                    // If I identifies a static property, then the result is a property access with no
                    // associated instance expression.
                    // UNDONE: give error if not static.
                    return(null);

                case SymbolKind.Field:
                    // If I identifies a static field:
                    // UNDONE: If the field is readonly and the reference occurs outside the static constructor of
                    // UNDONE: the class or struct in which the field is declared, then the result is a value, namely
                    // UNDONE: the value of the static field I in E.
                    // UNDONE: Otherwise, the result is a variable, namely the static field I in E.

                    // UNDONE: Need a way to mark an expression node as "I am a variable, not a value".

                    // UNDONE: Give error for non-static.
                    return(null);

                default:
                    Debug.Fail("Unexpected symbol kind");
                    return(null);
                }
            }
        }
Esempio n. 2
0
        private ExpressionNode BindInstanceMemberOfType(SyntaxNode node, TypeSymbol type,
                                                        ExpressionNode left, SimpleNameSyntax right, LookupResult lookupResult)
        {
            Debug.Assert(left != null);
            Debug.Assert(right != null);
            Debug.Assert(node != null);
            Debug.Assert(lookupResult.IsViable);
            Debug.Assert(lookupResult.Symbols.Any());

            // UNDONE: First, if E is a property or indexer access, then the value of the property or indexer access is obtained (§7.1.1) and E is reclassified as a value.

            SymbolOrMethodGroup symbolOrMethods = GetSymbolOrMethodGroup(lookupResult);

            if (symbolOrMethods.IsMethodGroup)
            {
                // If I identifies one or more methods, then the result is a method group with an associated
                // instance expression of E. If a type argument list was specified, it is used in calling
                // a generic method.

                // UNDONE: Construct the type argument list if there is one.
                return(new MethodGroup(right, null, left, symbolOrMethods.MethodGroup));
            }

            // UNDONE: If I identifies an instance property, then the result is a property access with an associated instance expression of E.
            // UNDONE: If T is a class-type and I identifies an instance field of that class-type:
            // UNDONE:   If the value of E is null, then a System.NullReferenceException is thrown.
            // UNDONE:   Otherwise, if the field is readonly and the reference occurs outside an instance constructor of the class in which the field is declared, then the result is a value, namely the value of the field I in the object referenced by E.
            // UNDONE:   Otherwise, the result is a variable, namely the field I in the object referenced by E.
            // UNDONE: If T is a struct-type and I identifies an instance field of that struct-type:
            // UNDONE:   If E is a value, or if the field is readonly and the reference occurs outside an instance constructor of the struct in which the field is declared, then the result is a value, namely the value of the field I in the struct instance given by E.
            // UNDONE:   Otherwise, the result is a variable, namely the field I in the struct instance given by E.
            // UNDONE: If I identifies an instance event:
            // UNDONE:   If the reference occurs within the class or struct in which the event is declared, and the event was declared without event-accessor-declarations (§10.8), then E.I is processed exactly as if I was an instance field.
            // UNDONE:   Otherwise, the result is an event access with an associated instance expression of E.

            return(null);
        }
Esempio n. 3
0
        // A simple-name is either of the form I or of the form I<A1, ..., AK>, where I is a single
        // identifier and <A1, ..., AK> is an optional type-argument-list. When no type-argument-list
        // is specified, consider K to be zero. The simple-name is evaluated and classified as follows:

        private BoundExpression BindIdentifier(IdentifierNameSyntax node)
        {
            Debug.Assert(node != null);

            // If K is zero and the simple-name appears within a block and if the block’s
            // (or an enclosing block’s) local variable declaration space contains a local variable, parameter
            // or constant with name I, then the simple-name refers to that local variable, parameter
            // or constant and is classified as a variable or value.

            // If K is zero and the simple-name appears within the body of a generic method declaration
            // and if that declaration includes a type parameter with name I, then the simple-name refers
            // to that type parameter.


            // UNDONE: I think we need to use a form of Lookup that takes an arity, and explicity pass 0. Otherwise
            // UNDONE: we will find generic
            var result = context.Lookup(node.PlainName, null, null);

            if (result.IsViable)
            {
                SymbolOrMethodGroup symbolOrMethods = GetSymbolOrMethodGroup(result);

                if (symbolOrMethods.IsMethodGroup)
                {
                    // If T is the instance type of the immediately enclosing class or struct type and the lookup identifies
                    // one or more methods, the result is a method group with an associated instance expression of this.

                    // The semantics of lookup mean that we'll only find members associated with one containing
                    // class or struct, or bases thereof.

                    // UNDONE: Construct the type argument list if there is one.
                    if (IsMemberOfType(symbolOrMethods.MethodGroup[0], this.containingMethod.ContainingType))
                    {
                        return(new BoundMethodGroup(node, null, new BoundThisReference(null, this.containingMethod.ContainingType), symbolOrMethods.MethodGroup));
                    }
                    else
                    {
                        // UNDONE: diagnose error, it was a method in an enclosing type that wasn't immediately enclosing.
                        return(null);
                    }
                }
                else
                {
                    Symbol symbol = symbolOrMethods.NonMethod;

                    switch (symbol.Kind)
                    {
                    case SymbolKind.Local:
                        // UNDONE: Better ctor for local that doesn't take a type.
                        return(new BoundLocal(node, (LocalSymbol)symbol, ((LocalSymbol)symbol).Type));

                    case SymbolKind.Parameter:
                        // UNDONE: Formal parameter
                        Debug.Fail("Undone: formal parameters");
                        return(null);

                    case SymbolKind.NamedType:
                    case SymbolKind.ErrorType:
                        // If I identifies a type, then the result is that type constructed with the given type arguments.
                        // UNDONE: Construct the child type if it is generic!
                        return(new BoundTypeExpression(node, (TypeSymbol)symbol));

                    case SymbolKind.Property:
                    case SymbolKind.Field:
                        // UNDONE: Otherwise, if T is the instance type of the immediately enclosing class or struct type,
                        // UNDONE: if the lookup identifies an instance member, and if the reference occurs within the
                        // UNDONE: block of an instance constructor, an instance method, or an instance accessor, the
                        // UNDONE: result is the same as a member access of the form this.I. This can only happen when K is zero.

                        // UNDONE: Otherwise, the result is the same as a member access of the form T.I or T.I<A1, ..., AK>. In this case, it is a
                        // UNDONE: compile-time error for the simple-name to refer to an instance member.

                        bool inImmediateEnclosing = IsMemberOfType(symbol, this.containingMethod.ContainingType);
                        bool isStatic             = symbol.IsStatic;

                        return(null);

                    case SymbolKind.Namespace:
                        return(new BoundNamespaceExpression(node, (NamespaceSymbol)symbol));

                    default:
                        Debug.Fail("Unexpected symbol kind");
                        return(null);
                    }
                }
            }

#if SLOW        // A lookup in the containing types is already done by context.Lookup.
                // So no need to do it again.


            // Otherwise, for each instance type T, starting with the instance type of the immediately enclosing
            // type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):

            foreach (NamedTypeSymbol t in this.containingMethod.ContainingType.TypeAndOuterTypes())
            {
                // If K is zero and the declaration of T includes a type parameter with name I,
                // then the simple-name refers to that type parameter.
                var typeParameter = t.TypeParameters.FirstOrDefault(p => p.Name == node.PlainName);
                if (typeParameter != null)
                {
                    Debug.Fail("Undone: type parameters");
                    return(null);
                    // UNDONE: Type parameter
                }

                // Otherwise, if a member lookup of I in T with K type arguments produces a match:

                var lookupResult = MemberLookup(t, node.PlainName, 0, false);
                if (lookupResult.IsViable)
                {
                    Debug.Assert(lookupResult.Symbols.Any());
                    // If T is the instance type of the immediately enclosing class or struct type and the lookup identifies
                    // one or more methods, the result is a method group with an associated instance expression of this.

                    if (t == this.containingMethod.ContainingType)
                    {
                        if (lookupResult.Symbols.OfType <MethodSymbol>().Any())
                        {
                            return(new BoundMethodGroup(node, null,
                                                        new BoundThisReference(null, t),
                                                        lookupResult.Symbols.OfType <MethodSymbol>().ToList()));
                        }

                        // UNDONE: Otherwise, if T is the instance type of the immediately enclosing class or struct type,
                        // UNDONE: if the lookup identifies an instance member, and if the reference occurs within the
                        // UNDONE: block of an instance constructor, an instance method, or an instance accessor, the
                        // UNDONE: result is the same as a member access of the form this.I. This can only happen when K is zero.

                        // UNDONE: Field, event, property...
                    }

                    // UNDONE: Otherwise, the result is the same as a member access of the form T.I or T.I<A1, ..., AK>. In this case, it is a
                    // UNDONE: compile-time error for the simple-name to refer to an instance member.
                }
            }
#endif
#if false
            // Otherwise, for each namespace N, starting with the namespace in which the simple-name occurs,
            // continuing with each enclosing namespace (if any), and ending with the global namespace,
            // the following steps are evaluated until an entity is located:

            foreach (var ns in containingMethod.ContainingNamespaces())
            {
                // If K is zero and I is the name of a namespace in N, then:
                var childNamespace = ns.GetMembers(node.PlainName).OfType <NamespaceSymbol>().FirstOrDefault();
                if (childNamespace != null)
                {
                    // UNDONE: If the location where the simple-name occurs is enclosed by a
                    // UNDONE: namespace declaration for N and the namespace declaration contains
                    // UNDONE: an extern-alias-directive or using-alias-directive that associates the
                    // UNDONE: name I with a namespace or type, then the simple-name is ambiguous and
                    // UNDONE: a compile-time error occurs.

                    // Otherwise, the simple-name refers to the namespace named I in N.
                    return(new NamespaceExpression(node, childNamespace));
                }
                // Otherwise, if N contains an accessible type having name I and K type parameters, then:
                var childType = ns.GetMembers(node.PlainName).OfType <TypeSymbol>().FirstOrDefault();
                // UNDONE: Check accessibility
                if (childType != null)
                {
                    // UNDONE: If K is zero and the location where the simple-name occurs
                    // UNDONE: is enclosed by a namespace declaration for N and the namespace
                    // UNDONE: declaration contains an extern-alias-directive or using-alias-directive
                    // UNDONE: that associates the name I with a namespace or type, then the simple-name
                    // UNDONE: is ambiguous and a compile-time error occurs.

                    // Otherwise, the namespace-or-type-name refers to the type constructed with the given type arguments.
                    return(new TypeExpression(node, childType));
                }
                // UNDONE: Otherwise, if the location where the simple-name occurs is enclosed by a namespace declaration for N:

                // UNDONE: If K is zero and the namespace declaration contains an extern-alias-directive or using-alias-directive
                // UNDONE: that associates the name I with an imported namespace or type, then the simple-name refers to that namespace or type.
                // UNDONE: Otherwise, if the namespaces imported by the using-namespace-directives of the namespace declaration
                // UNDONE: contain exactly one type having name I and K type parameters, then the simple-name refers to that type
                // UNDONE: constructed with the given type arguments.
                // UNDONE: Otherwise, if the namespaces imported by the using-namespace-directives of the namespace declaration contain more than one type having name I and K type parameters, then the simple-name is ambiguous and an error occurs.
            }
#endif
            // UNDONE: Otherwise, the simple-name is undefined and a compile-time error occurs.
            return(null);
        }