Esempio n. 1
0
        public BoundLambda(SyntaxNode syntax, BoundBlock body, ImmutableArray <Diagnostic> diagnostics, Binder binder, TypeSymbol delegateType, bool inferReturnType)
            : this(syntax, (LambdaSymbol)binder.ContainingMemberOrLambda, body, diagnostics, binder, delegateType)
        {
            if (inferReturnType)
            {
                this._inferredReturnType = InferReturnType(
                    this.Body,
                    this.Binder,
                    delegateType,
                    this.Symbol.IsAsync,
                    ref this._inferredReturnTypeUseSiteDiagnostics,
                    out this._refKind,
                    out this._inferredFromSingleType);

#if DEBUG
                _hasInferredReturnType = true;
#endif
            }

            Debug.Assert(
                syntax.IsAnonymousFunction() ||                                                                  // lambda expressions
                syntax is ExpressionSyntax && LambdaUtilities.IsLambdaBody(syntax, allowReducedLambdas: true) || // query lambdas
                LambdaUtilities.IsQueryPairLambda(syntax)                                                        // "pair" lambdas in queries
                );
        }
Esempio n. 2
0
        private UnboundLambda MakePairLambda(CSharpSyntaxNode node, QueryTranslationState state, RangeVariableSymbol x1, RangeVariableSymbol x2)
        {
            Debug.Assert(LambdaUtilities.IsQueryPairLambda(node));

            LambdaBodyFactory bodyFactory = (LambdaSymbol lambdaSymbol, Binder lambdaBodyBinder, DiagnosticBag d) =>
            {
                var x1Expression = new BoundParameter(node, lambdaSymbol.Parameters[0])
                {
                    WasCompilerGenerated = true
                };
                var x2Expression = new BoundParameter(node, lambdaSymbol.Parameters[1])
                {
                    WasCompilerGenerated = true
                };
                var construction = MakePair(node, x1.Name, x1Expression, x2.Name, x2Expression, state, d);
                return(lambdaBodyBinder.CreateBlockFromExpression(node, ImmutableArray <LocalSymbol> .Empty, RefKind.None, construction, null, d));
            };

            var result = MakeQueryUnboundLambda(state.RangeVariableMap(), ImmutableArray.Create(x1, x2), node, bodyFactory);

            state.rangeVariable = state.TransparentRangeVariable(this);
            state.AddTransparentIdentifier(x1.Name);
            var x2m = state.allRangeVariables[x2];

            x2m[x2m.Count - 1] = x2.Name;
            return(result);
        }
Esempio n. 3
0
        private UnboundLambda MakeQueryUnboundLambda(CSharpSyntaxNode node, QueryUnboundLambdaState state)
        {
            Debug.Assert(node is ExpressionSyntax || LambdaUtilities.IsQueryPairLambda(node));
            var lambda = new UnboundLambda(node, state, hasErrors: false)
            {
                WasCompilerGenerated = true
            };

            state.SetUnboundLambda(lambda);
            return(lambda);
        }
Esempio n. 4
0
        private BoundExpression HoistRefInitialization(SynthesizedLocal local, BoundAssignmentOperator node)
        {
            Debug.Assert(local.SynthesizedKind == SynthesizedLocalKind.Spill);
            Debug.Assert(local.SyntaxOpt != null);
            Debug.Assert(this.OriginalMethod.IsAsync);

            var right = (BoundExpression)Visit(node.Right);

            var sideEffects = ArrayBuilder <BoundExpression> .GetInstance();

            bool needsSacrificialEvaluation = false;
            var  hoistedFields = ArrayBuilder <StateMachineFieldSymbol> .GetInstance();

            SyntaxNode awaitSyntaxOpt;
            int        syntaxOffset;

            if (F.Compilation.Options.OptimizationLevel == OptimizationLevel.Debug)
            {
                awaitSyntaxOpt = local.GetDeclaratorSyntax();
                Debug.Assert(awaitSyntaxOpt.IsKind(SyntaxKind.AwaitExpression) || awaitSyntaxOpt.IsKind(SyntaxKind.SwitchExpression));
                syntaxOffset = OriginalMethod.CalculateLocalSyntaxOffset(LambdaUtilities.GetDeclaratorPosition(awaitSyntaxOpt), awaitSyntaxOpt.SyntaxTree);
            }
            else
            {
                // These are only used to calculate debug id for ref-spilled variables,
                // no need to do so in release build.
                awaitSyntaxOpt = null;
                syntaxOffset   = -1;
            }

            var replacement = HoistExpression(right, awaitSyntaxOpt, syntaxOffset, local.RefKind, sideEffects, hoistedFields, ref needsSacrificialEvaluation);

            proxies.Add(local, new CapturedToExpressionSymbolReplacement(replacement, hoistedFields.ToImmutableAndFree(), isReusable: true));

            if (needsSacrificialEvaluation)
            {
                var type            = TypeMap.SubstituteType(local.Type).Type;
                var sacrificialTemp = F.SynthesizedLocal(type, refKind: RefKind.Ref);
                Debug.Assert(TypeSymbol.Equals(type, replacement.Type, TypeCompareKind.ConsiderEverything2));
                return(F.Sequence(ImmutableArray.Create(sacrificialTemp), sideEffects.ToImmutableAndFree(), F.AssignmentExpression(F.Local(sacrificialTemp), replacement, isRef: true)));
            }

            if (sideEffects.Count == 0)
            {
                sideEffects.Free();
                return(null);
            }

            var last = sideEffects.Last();

            sideEffects.RemoveLast();
            return(F.Sequence(ImmutableArray <LocalSymbol> .Empty, sideEffects.ToImmutableAndFree(), last));
        }
        private static void AssertIsClosureScopeSyntax(SyntaxNode syntaxOpt)
        {
            // See C# specification, chapter 3.7 Scopes.

            // static lambdas technically have the class scope so the scope syntax is null
            if (syntaxOpt == null)
            {
                return;
            }

            if (LambdaUtilities.IsClosureScope(syntaxOpt))
            {
                return;
            }

            throw ExceptionUtilities.UnexpectedValue(syntaxOpt.Kind());
        }
            internal DebugId GetClosureId(SyntaxNode syntax, ArrayBuilder <ClosureDebugInfo> closureDebugInfo)
            {
                Debug.Assert(syntax != null);

                DebugId closureId;
                DebugId previousClosureId;

                if (_slotAllocatorOpt != null && _slotAllocatorOpt.TryGetPreviousClosure(syntax, out previousClosureId))
                {
                    closureId = previousClosureId;
                }
                else
                {
                    closureId = new DebugId(closureDebugInfo.Count, _compilationState.ModuleBuilderOpt.CurrentGenerationOrdinal);
                }

                int syntaxOffset = _topLevelMethod.CalculateLocalSyntaxOffset(LambdaUtilities.GetDeclaratorPosition(syntax), syntax.SyntaxTree);

                closureDebugInfo.Add(new ClosureDebugInfo(syntaxOffset, closureId));

                return(closureId);
            }
Esempio n. 7
0
 public static bool IsLambdaBody(SyntaxNode node)
 {
     return(LambdaUtilities.IsLambdaBody(node));
 }
Esempio n. 8
0
        private void CreateNonReusableLocalProxies(
            IEnumerable <Symbol> variablesToHoist,
            out IReadOnlyDictionary <Symbol, CapturedSymbolReplacement> proxies,
            out int nextFreeHoistedLocalSlot)
        {
            var proxiesBuilder = new Dictionary <Symbol, CapturedSymbolReplacement>();

            var  typeMap             = stateMachineType.TypeMap;
            bool isDebugBuild        = F.Compilation.Options.OptimizationLevel == OptimizationLevel.Debug;
            bool mapToPreviousFields = isDebugBuild && slotAllocatorOpt != null;

            nextFreeHoistedLocalSlot = mapToPreviousFields ? slotAllocatorOpt.PreviousHoistedLocalSlotCount : 0;

            foreach (var variable in variablesToHoist)
            {
                Debug.Assert(variable.Kind == SymbolKind.Local || variable.Kind == SymbolKind.Parameter);

                if (variable.Kind == SymbolKind.Local)
                {
                    var local           = (LocalSymbol)variable;
                    var synthesizedKind = local.SynthesizedKind;

                    if (!synthesizedKind.MustSurviveStateMachineSuspension())
                    {
                        continue;
                    }

                    // no need to hoist constants
                    if (local.IsConst)
                    {
                        continue;
                    }

                    if (local.RefKind != RefKind.None)
                    {
                        // we'll create proxies for these variables later:
                        Debug.Assert(synthesizedKind == SynthesizedLocalKind.Spill);
                        continue;
                    }

                    Debug.Assert(local.RefKind == RefKind.None);
                    StateMachineFieldSymbol field = null;

                    if (ShouldPreallocateNonReusableProxy(local))
                    {
                        // variable needs to be hoisted
                        var fieldType = typeMap.SubstituteType(local.Type).Type;

                        LocalDebugId id;
                        int          slotIndex = -1;

                        if (isDebugBuild)
                        {
                            // Calculate local debug id.
                            //
                            // EnC: When emitting the baseline (gen 0) the id is stored in a custom debug information attached to the kickoff method.
                            //      When emitting a delta the id is only used to map to the existing field in the previous generation.
                            SyntaxNode declaratorSyntax = local.GetDeclaratorSyntax();
                            int        syntaxOffset     = method.CalculateLocalSyntaxOffset(LambdaUtilities.GetDeclaratorPosition(declaratorSyntax), declaratorSyntax.SyntaxTree);
                            int        ordinal          = synthesizedLocalOrdinals.AssignLocalOrdinal(synthesizedKind, syntaxOffset);
                            id = new LocalDebugId(syntaxOffset, ordinal);

                            // map local id to the previous id, if available:
                            int previousSlotIndex;
                            if (mapToPreviousFields && slotAllocatorOpt.TryGetPreviousHoistedLocalSlotIndex(
                                    declaratorSyntax,
                                    F.ModuleBuilderOpt.Translate(fieldType, declaratorSyntax, diagnostics),
                                    synthesizedKind,
                                    id,
                                    diagnostics,
                                    out previousSlotIndex))
                            {
                                slotIndex = previousSlotIndex;
                            }
                        }
                        else
                        {
                            id = LocalDebugId.None;
                        }

                        if (slotIndex == -1)
                        {
                            slotIndex = nextFreeHoistedLocalSlot++;
                        }

                        string fieldName = GeneratedNames.MakeHoistedLocalFieldName(synthesizedKind, slotIndex, local.Name);
                        field = F.StateMachineField(fieldType, fieldName, new LocalSlotDebugInfo(synthesizedKind, id), slotIndex);
                    }

                    if (field != null)
                    {
                        proxiesBuilder.Add(local, new CapturedToStateMachineFieldReplacement(field, isReusable: false));
                    }
                }
                else
                {
                    var parameter = (ParameterSymbol)variable;
                    if (parameter.IsThis)
                    {
                        var containingType = method.ContainingType;
                        var proxyField     = F.StateMachineField(containingType, GeneratedNames.ThisProxyFieldName(), isPublic: true, isThis: true);
                        proxiesBuilder.Add(parameter, new CapturedToStateMachineFieldReplacement(proxyField, isReusable: false));

                        if (PreserveInitialParameterValuesAndThreadId)
                        {
                            var initialThis = containingType.IsStructType() ?
                                              F.StateMachineField(containingType, GeneratedNames.StateMachineThisParameterProxyName(), isPublic: true, isThis: true) : proxyField;

                            initialParameters.Add(parameter, new CapturedToStateMachineFieldReplacement(initialThis, isReusable: false));
                        }
                    }
                    else
                    {
                        // The field needs to be public iff it is initialized directly from the kickoff method
                        // (i.e. not for IEnumerable which loads the values from parameter proxies).
                        var proxyField = F.StateMachineField(typeMap.SubstituteType(parameter.Type).Type, parameter.Name, isPublic: !PreserveInitialParameterValuesAndThreadId);
                        proxiesBuilder.Add(parameter, new CapturedToStateMachineFieldReplacement(proxyField, isReusable: false));

                        if (PreserveInitialParameterValuesAndThreadId)
                        {
                            var field = F.StateMachineField(typeMap.SubstituteType(parameter.Type).Type, GeneratedNames.StateMachineParameterProxyFieldName(parameter.Name), isPublic: true);
                            initialParameters.Add(parameter, new CapturedToStateMachineFieldReplacement(field, isReusable: false));
                        }
                    }
                }
            }

            proxies = proxiesBuilder;
        }
Esempio n. 9
0
 internal override SyntaxNode GetLambda()
 {
     return(LambdaUtilities.GetLambda(this));
 }
Esempio n. 10
0
 internal sealed override SyntaxNode GetCorrespondingLambdaBody(SyntaxNode body)
 {
     return(LambdaUtilities.GetCorrespondingLambdaBody(body, this));
 }