Example #1
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 UnboundLambda AnalyzeAnonymousFunction(
            AnonymousFunctionExpressionSyntax syntax, BindingDiagnosticBag diagnostics)
        {
            Debug.Assert(syntax != null);
            Debug.Assert(syntax.IsAnonymousFunction());

            ImmutableArray <string>              names    = default;
            ImmutableArray <RefKind>             refKinds = default;
            ImmutableArray <DeclarationScope>    scopes   = default;
            ImmutableArray <TypeWithAnnotations> types    = default;
            RefKind             returnRefKind             = RefKind.None;
            TypeWithAnnotations returnType = default;
            ImmutableArray <SyntaxList <AttributeListSyntax> > parameterAttributes = default;

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

            ImmutableArray <bool> discardsOpt = default;
            SeparatedSyntaxList <ParameterSyntax>?parameterSyntaxList = null;
            bool hasSignature;

            if (syntax is LambdaExpressionSyntax lambdaSyntax)
            {
                checkAttributes(syntax, lambdaSyntax.AttributeLists, diagnostics);
            }

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

            case SyntaxKind.ParenthesizedLambdaExpression:
                // (T x, U y) => ...
                // (x, y) => ...
                hasSignature = true;
                var paren = (ParenthesizedLambdaExpressionSyntax)syntax;
                if (paren.ReturnType is { } returnTypeSyntax)
                {
                    (returnRefKind, returnType) = BindExplicitLambdaReturnType(returnTypeSyntax, diagnostics);
                }
                parameterSyntaxList = paren.ParameterList.Parameters;
                CheckParenthesizedLambdaParameters(parameterSyntaxList.Value, diagnostics);
                break;

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

            var isAsync  = syntax.Modifiers.Any(SyntaxKind.AsyncKeyword);
            var isStatic = syntax.Modifiers.Any(SyntaxKind.StaticKeyword);

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

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

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

                var scopesBuilder = ArrayBuilder <DeclarationScope> .GetInstance();

                var attributesBuilder = ArrayBuilder <SyntaxList <AttributeListSyntax> > .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.

                int underscoresCount = 0;
                foreach (var p in parameterSyntaxList.Value)
                {
                    if (p.Identifier.IsUnderscoreToken())
                    {
                        underscoresCount++;
                    }

                    checkAttributes(syntax, p.AttributeLists, diagnostics);

                    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;
                    TypeWithAnnotations type = default;
                    var refKind = RefKind.None;
                    var scope   = DeclarationScope.Unscoped;

                    if (typeSyntax == null)
                    {
                        hasExplicitlyTypedParameterList = false;
                    }
                    else
                    {
                        type = BindType(typeSyntax, diagnostics);
                        ParameterHelpers.CheckParameterModifiers(p, diagnostics, parsingFunctionPointerParams: false, parsingLambdaParams: true);
                        refKind = ParameterHelpers.GetModifiers(p.Modifiers, out _, out _, out _, out scope);
                    }

                    namesBuilder.Add(p.Identifier.ValueText);
                    typesBuilder.Add(type);
                    refKindsBuilder.Add(refKind);
                    scopesBuilder.Add(scope);
                    attributesBuilder.Add(syntax.Kind() == SyntaxKind.ParenthesizedLambdaExpression ? p.AttributeLists : default);
Example #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 UnboundLambda AnalyzeAnonymousFunction(
            AnonymousFunctionExpressionSyntax syntax, BindingDiagnosticBag diagnostics)
        {
            Debug.Assert(syntax != null);
            Debug.Assert(syntax.IsAnonymousFunction());

            var names    = default(ImmutableArray <string>);
            var refKinds = default(ImmutableArray <RefKind>);
            var types    = default(ImmutableArray <TypeWithAnnotations>);

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

            ImmutableArray <bool> discardsOpt = default;
            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);
                break;

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

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

            var isAsync  = syntax.Modifiers.Any(SyntaxKind.AsyncKeyword);
            var isStatic = syntax.Modifiers.Any(SyntaxKind.StaticKeyword);

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

                var typesBuilder = ArrayBuilder <TypeWithAnnotations> .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.

                int underscoresCount = 0;
                foreach (var p in parameterSyntaxList.Value)
                {
                    if (p.Identifier.IsUnderscoreToken())
                    {
                        underscoresCount++;
                    }

                    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;
                    TypeWithAnnotations type = default;
                    var refKind = RefKind.None;

                    if (typeSyntax == null)
                    {
                        hasExplicitlyTypedParameterList = false;
                    }
                    else
                    {
                        type = BindType(typeSyntax, diagnostics);
                        foreach (var modifier in p.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);
                }

                discardsOpt = computeDiscards(parameterSyntaxList.Value, underscoresCount);

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

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

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

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

            namesBuilder.Free();

            return(new UnboundLambda(syntax, this, diagnostics.AccumulatesDependencies, refKinds, types, names, discardsOpt, isAsync, isStatic));