示例#1
0
        private UnboundLambda BindAnonymousFunction(CSharpSyntaxNode syntax, DiagnosticBag diagnostics)
        {
            Debug.Assert(syntax != null);
            Debug.Assert(syntax.IsAnonymousFunction());

            var results = AnalyzeAnonymousFunction(syntax, diagnostics);

            var refKinds = results.Item1;
            var types    = results.Item2;
            var names    = results.Item3;
            var isAsync  = results.Item4;

            if (!types.IsDefault)
            {
                foreach (var type in types)
                {
                    // UNDONE: Where do we report improper use of pointer types?
                    if (!type.IsNull && type.IsStatic)
                    {
                        Error(diagnostics, ErrorCode.ERR_ParameterIsStaticClass, syntax, type.TypeSymbol);
                    }
                }
            }

            var lambda = new UnboundLambda(syntax, this, refKinds, types, names, isAsync);

            if (!names.IsDefault)
            {
                var  binder = new LocalScopeBinder(this);
                bool allowShadowingNames = binder.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureNameShadowingInNestedFunctions);
                var  pNames = PooledHashSet <string> .GetInstance();

                for (int i = 0; i < lambda.ParameterCount; i++)
                {
                    var name = lambda.ParameterName(i);

                    if (string.IsNullOrEmpty(name))
                    {
                        continue;
                    }

                    if (!pNames.Add(name))
                    {
                        // The parameter name '{0}' is a duplicate
                        diagnostics.Add(ErrorCode.ERR_DuplicateParamName, lambda.ParameterLocation(i), name);
                    }
                    else if (!allowShadowingNames)
                    {
                        binder.ValidateLambdaParameterNameConflictsInScope(lambda.ParameterLocation(i), name, diagnostics);
                    }
                }
                pNames.Free();
            }

            return(lambda);
        }
示例#2
0
        // An anonymous function can be of the form:
        //
        // delegate { }              (missing parameter list)
        // delegate (int x) { }      (typed parameter list)
        // x => ...                  (type-inferred parameter list)
        // (x) => ...                (type-inferred parameter list)
        // (x, y) => ...             (type-inferred parameter list)
        // ( ) => ...                (typed parameter list)
        // (ref int x) => ...        (typed parameter list)
        // (int x, out int y) => ... (typed parameter list)
        //
        // and so on. We want to canonicalize these various ways of writing the signatures.
        //
        // If we are in the first case then the name, modifier and type arrays are all null.
        // If we have a parameter list then the names array is non-null, but possibly empty.
        // If we have types then the types array is non-null, but possibly empty.
        // If we have no modifiers then the modifiers array is null; if we have any modifiers
        // then the modifiers array is non-null and not empty.

        private Tuple <ImmutableArray <RefKind>, ImmutableArray <TypeSymbolWithAnnotations>, ImmutableArray <string>, bool> AnalyzeAnonymousFunction(
            CSharpSyntaxNode syntax, DiagnosticBag diagnostics)
        {
            Debug.Assert(syntax != null);
            Debug.Assert(syntax.IsAnonymousFunction());

            var  names    = default(ImmutableArray <string>);
            var  refKinds = default(ImmutableArray <RefKind>);
            var  types    = default(ImmutableArray <TypeSymbolWithAnnotations>);
            bool isAsync  = false;

            var namesBuilder = ArrayBuilder <string> .GetInstance();

            SeparatedSyntaxList <ParameterSyntax>?parameterSyntaxList = null;
            bool hasSignature;

            switch (syntax.Kind())
            {
            default:
            case SyntaxKind.SimpleLambdaExpression:
                // x => ...
                hasSignature = true;
                var simple = (SimpleLambdaExpressionSyntax)syntax;
                namesBuilder.Add(simple.Parameter.Identifier.ValueText);
                isAsync = (simple.AsyncKeyword.Kind() == SyntaxKind.AsyncKeyword);
                break;

            case SyntaxKind.ParenthesizedLambdaExpression:
                // (T x, U y) => ...
                // (x, y) => ...
                hasSignature = true;
                var paren = (ParenthesizedLambdaExpressionSyntax)syntax;
                parameterSyntaxList = paren.ParameterList.Parameters;
                CheckParenthesizedLambdaParameters(parameterSyntaxList.Value, diagnostics);
                isAsync = (paren.AsyncKeyword.Kind() == SyntaxKind.AsyncKeyword);
                break;

            case SyntaxKind.AnonymousMethodExpression:
                // delegate (int x) { }
                // delegate { }
                var anon = (AnonymousMethodExpressionSyntax)syntax;
                hasSignature = anon.ParameterList != null;
                if (hasSignature)
                {
                    parameterSyntaxList = anon.ParameterList.Parameters;
                }
                isAsync = (anon.AsyncKeyword.Kind() == SyntaxKind.AsyncKeyword);
                break;
            }

            if (parameterSyntaxList != null)
            {
                var hasExplicitlyTypedParameterList = true;
                var allValue = true;

                var typesBuilder = ArrayBuilder <TypeSymbolWithAnnotations> .GetInstance();

                var refKindsBuilder = ArrayBuilder <RefKind> .GetInstance();

                // In the batch compiler case we probably should have given a syntax error if the
                // user did something like (int x, y)=>x+y -- but in the IDE scenario we might be in
                // this case. If we are, then rather than try to make partial deductions from the
                // typed formal parameters, simply bail out and treat it as an untyped lambda.
                //
                // However, we still want to give errors on every bad type in the list, even if one
                // is missing.

                foreach (var p in parameterSyntaxList.Value)
                {
                    foreach (var attributeList in p.AttributeLists)
                    {
                        Error(diagnostics, ErrorCode.ERR_AttributesNotAllowed, attributeList);
                    }

                    if (p.Default != null)
                    {
                        Error(diagnostics, ErrorCode.ERR_DefaultValueNotAllowed, p.Default.EqualsToken);
                    }

                    if (p.IsArgList)
                    {
                        Error(diagnostics, ErrorCode.ERR_IllegalVarArgs, p);
                        continue;
                    }

                    var typeSyntax = p.Type;
                    TypeSymbolWithAnnotations type = default;
                    var refKind = RefKind.None;

                    if (typeSyntax == null)
                    {
                        hasExplicitlyTypedParameterList = false;
                    }
                    else
                    {
                        var extendedSyntax = typeSyntax as ExtendedTypeSyntax;
                        type = BindType(typeSyntax, diagnostics);
                        if (extendedSyntax != null)
                        {
                            foreach (var modifier in extendedSyntax.Modifiers)
                            {
                                switch (modifier.Kind())
                                {
                                case SyntaxKind.RefKeyword:
                                    refKind  = RefKind.Ref;
                                    allValue = false;
                                    break;

                                case SyntaxKind.OutKeyword:
                                    refKind  = RefKind.Out;
                                    allValue = false;
                                    break;

                                case SyntaxKind.InKeyword:
                                    refKind  = RefKind.In;
                                    allValue = false;
                                    break;

                                case SyntaxKind.ParamsKeyword:
                                    // This was a parse error in the native compiler;
                                    // it is a semantic analysis error in Roslyn. See comments to
                                    // changeset 1674 for details.
                                    Error(diagnostics, ErrorCode.ERR_IllegalParams, p);
                                    break;

                                case SyntaxKind.ThisKeyword:
                                    Error(diagnostics, ErrorCode.ERR_ThisInBadContext, modifier);
                                    break;
                                }
                            }
                        }
                    }

                    namesBuilder.Add(p.Identifier.ValueText);
                    typesBuilder.Add(type);
                    refKindsBuilder.Add(refKind);
                }

                if (hasExplicitlyTypedParameterList)
                {
                    types = typesBuilder.ToImmutable();
                }

                if (!allValue)
                {
                    refKinds = refKindsBuilder.ToImmutable();
                }

                typesBuilder.Free();
                refKindsBuilder.Free();
            }

            if (hasSignature)
            {
                names = namesBuilder.ToImmutable();
            }

            namesBuilder.Free();

            return(Tuple.Create(refKinds, types, names, isAsync));
        }