Exemplo n.º 1
0
        /// <summary>
        /// Construct context
        /// </summary>
        public RegionAnalysisContext(CSharpCompilation compilation, Symbol member, BoundNode boundNode, BoundNode firstInRegion, BoundNode lastInRegion)
        {
            this.Compilation = compilation;
            this.Member = member;
            this.BoundNode = boundNode;
            this.FirstInRegion = firstInRegion;
            this.LastInRegion = lastInRegion;
            this.Failed =
                boundNode == null ||
                firstInRegion == null ||
                lastInRegion == null ||
                firstInRegion.Syntax.SpanStart > lastInRegion.Syntax.Span.End;

            if (!this.Failed && ReferenceEquals(firstInRegion, lastInRegion))
            {
                switch (firstInRegion.Kind)
                {
                    case BoundKind.NamespaceExpression:
                    case BoundKind.TypeExpression:

                        // Some bound nodes are still considered to be invalid for flow analysis
                        this.Failed = true;
                        break;
                }
            }
        }
Exemplo n.º 2
0
 public override BoundNode Visit(BoundNode node)
 {
     IOperation operation = node as IOperation;
     if (operation != null)
     {
         this.nodes.Add(operation);
         // Following operations are not bound node, therefore have to be added explicitly:
         //  1. IArgument
         //  2. IMemberInitializer
         //  3. ICase
         switch (operation.Kind)
         {
             case OperationKind.InvocationExpression:
                 nodes.AddRange(((IInvocationExpression)operation).ArgumentsInSourceOrder);
                 break;
             case OperationKind.ObjectCreationExpression:
                 var objCreationExp = (IObjectCreationExpression)operation;
                 nodes.AddRange(objCreationExp.ConstructorArguments);
                 nodes.AddRange(objCreationExp.MemberInitializers);
                 break;
             case OperationKind.SwitchStatement:
                 nodes.AddRange(((ISwitchStatement)operation).Cases);
                 break;
         }
     }
     return base.Visit(node);
 }
        public static MultiDictionary<Symbol, CSharpSyntaxNode> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node)
        {
            var emptyStructs = new CaptureWalkerEmptyStructTypeCache();
            var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, emptyStructs);

            var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, emptyStructs, initiallyAssignedVariables);

            bool badRegion = false;
            walker.Analyze(ref badRegion);
            Debug.Assert(!badRegion);

            var result = walker.variablesCaptured;


            if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct)
            {
                // It is possible that the enclosing method only *writes* to the enclosing struct, but in that
                // case it should be considered captured anyway so that we have a proxy for it to write to.
                result.Add(method.ThisParameter, node.Syntax);
            }

            foreach (var variable in result.Keys.ToArray()) // take a snapshot, as we are modifying the underlying multidictionary
            {
                var local = variable as LocalSymbol;
                if ((object)local != null && local.RefKind != RefKind.None)
                {
                    walker.AddSpillsForRef(walker.refLocalInitializers[local], result[local]);
                }
            }

            walker.Free();
            return result;
        }
Exemplo n.º 4
0
        internal static void Analyze(
            CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet<PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes,
            out IEnumerable<Symbol> readInside,
            out IEnumerable<Symbol> writtenInside,
            out IEnumerable<Symbol> readOutside,
            out IEnumerable<Symbol> writtenOutside,
            out IEnumerable<Symbol> captured,
            out IEnumerable<Symbol> unsafeAddressTaken)
        {
            var walker = new ReadWriteWalker(compilation, member, node, firstInRegion, lastInRegion, unassignedVariableAddressOfSyntaxes);
            try
            {
                bool badRegion = false;
                walker.Analyze(ref badRegion);
                if (badRegion)
                {
                    readInside = writtenInside = readOutside = writtenOutside = captured = unsafeAddressTaken = Enumerable.Empty<Symbol>();
                }
                else
                {
                    readInside = walker._readInside;
                    writtenInside = walker._writtenInside;
                    readOutside = walker._readOutside;
                    writtenOutside = walker._writtenOutside;

                    captured = walker.GetCaptured();
                    unsafeAddressTaken = walker.GetUnsafeAddressTaken();
                }
            }
            finally
            {
                walker.Free();
            }
        }
        public static void IssueDiagnostics(CSharpCompilation compilation, BoundNode node, DiagnosticBag diagnostics, MethodSymbol containingSymbol)
        {
            Debug.Assert(node != null);
            Debug.Assert((object)containingSymbol != null);

            var diagnosticPass = new DiagnosticsPass(compilation, diagnostics, containingSymbol);
            diagnosticPass.Visit(node);
        }
 private void NoteUnsafe(BoundNode node)
 {
     if (_inExpressionLambda && !_reportedUnsafe)
     {
         Error(ErrorCode.ERR_ExpressionTreeContainsPointerOp, node);
         _reportedUnsafe = true;
     }
 }
 private IteratorAndAsyncCaptureWalker(CSharpCompilation compilation, MethodSymbol method, BoundNode node, CaptureWalkerEmptyStructTypeCache emptyStructCache, HashSet<Symbol> initiallyAssignedVariables)
     : base(compilation, 
           method, 
           node, 
           emptyStructCache, 
           trackUnassignments: true, 
           initiallyAssignedVariables: initiallyAssignedVariables)
 {
 }
 internal AbstractRegionControlFlowPass(
     CSharpCompilation compilation,
     Symbol member,
     BoundNode node,
     BoundNode firstInRegion,
     BoundNode lastInRegion)
     : base(compilation, member, node, firstInRegion, lastInRegion)
 {
 }
Exemplo n.º 9
0
            public override BoundNode Visit(BoundNode node)
            {
                IOperation operation = node as IOperation;
                if (operation != null)
                {
                    this.nodes.Add(operation);
                }

                return base.Visit(node);
            }
Exemplo n.º 10
0
 internal AbstractRegionDataFlowPass(
     CSharpCompilation compilation,
     Symbol member,
     BoundNode node,
     BoundNode firstInRegion,
     BoundNode lastInRegion,
     HashSet<Symbol> initiallyAssignedVariables = null,
     HashSet<PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes = null,
     bool trackUnassignments = false)
     : base(compilation, member, node, firstInRegion, lastInRegion, initiallyAssignedVariables, unassignedVariableAddressOfSyntaxes, trackUnassignments)
 {
 }
Exemplo n.º 11
0
 public static HashSet<LabelSymbol> Find(BoundNode node, Dictionary<BoundNode, HashSet<LabelSymbol>> unmatchedLabelsCache)
 {
     UnmatchedGotoFinder finder = new UnmatchedGotoFinder(unmatchedLabelsCache);
     finder.Visit(node);
     HashSet<LabelSymbol> gotos = finder._gotos;
     HashSet<LabelSymbol> targets = finder._targets;
     if (gotos != null && targets != null)
     {
         gotos.RemoveAll(targets);
     }
     return gotos;
 }
Exemplo n.º 12
0
        protected override void NoteBranch(
            PendingBranch pending,
            BoundNode gotoStmt,
            BoundStatement targetStmt)
        {
            targetStmt.AssertIsLabeledStatement();
            if (!gotoStmt.WasCompilerGenerated && !targetStmt.WasCompilerGenerated && !RegionContains(gotoStmt.Syntax.Span) && RegionContains(targetStmt.Syntax.Span))
            {
                pending.State = ResetState(pending.State);
            }

            base.NoteBranch(pending, gotoStmt, targetStmt);
        }
        // Returns deterministically ordered list of variables that ought to be hoisted.
        public static OrderedSet<Symbol> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node, DiagnosticBag diagnostics)
        {
            var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, convertInsufficientExecutionStackExceptionToCancelledByStackGuardException: true);
            var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, new NeverEmptyStructTypeCache(), initiallyAssignedVariables);

            walker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true;

            bool badRegion = false;
            walker.Analyze(ref badRegion);
            Debug.Assert(!badRegion);

            if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct)
            {
                // It is possible that the enclosing method only *writes* to the enclosing struct, but in that
                // case it should be considered captured anyway so that we have a proxy for it to write to.
                walker.CaptureVariable(method.ThisParameter, node.Syntax);
            }

            var variablesToHoist = walker._variablesToHoist;
            var lazyDisallowedCaptures = walker._lazyDisallowedCaptures;
            var allVariables = walker.variableBySlot;

            walker.Free();

            if (lazyDisallowedCaptures != null)
            {
                foreach (var kvp in lazyDisallowedCaptures)
                {
                    var variable = kvp.Key;
                    var type = (variable.Kind == SymbolKind.Local) ? ((LocalSymbol)variable).Type : ((ParameterSymbol)variable).Type;

                    foreach (CSharpSyntaxNode syntax in kvp.Value)
                    {
                        // CS4013: Instance of type '{0}' cannot be used inside an anonymous function, query expression, iterator block or async method
                        diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, type);
                    }
                }
            }

            if (compilation.Options.OptimizationLevel != OptimizationLevel.Release)
            {
                Debug.Assert(variablesToHoist.Count == 0);

                // In debug build we hoist all locals and parameters:
                variablesToHoist.AddRange(from v in allVariables
                                          where v.Symbol != null && HoistInDebugBuild(v.Symbol)
                                          select v.Symbol);
            }

            return variablesToHoist;
        }
Exemplo n.º 14
0
 internal static IEnumerable<Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion)
 {
     var walker = new VariablesDeclaredWalker(compilation, member, node, firstInRegion, lastInRegion);
     try
     {
         bool badRegion = false;
         walker.Analyze(ref badRegion);
         return badRegion ? SpecializedCollections.EmptyEnumerable<Symbol>() : walker._variablesDeclared;
     }
     finally
     {
         walker.Free();
     }
 }
Exemplo n.º 15
0
 internal static IEnumerable<Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion)
 {
     var walker = new AlwaysAssignedWalker(compilation, member, node, firstInRegion, lastInRegion);
     bool badRegion = false;
     try
     {
         var result = walker.Analyze(ref badRegion);
         return badRegion ? SpecializedCollections.EmptyEnumerable<Symbol>() : result;
     }
     finally
     {
         walker.Free();
     }
 }
 internal static HashSet<Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, EmptyStructTypeCache emptyStructCache = null)
 {
     var walker = new UnassignedVariablesWalker(compilation, member, node, emptyStructCache);
     try
     {
         bool badRegion = false;
         var result = walker.Analyze(ref badRegion);
         return badRegion ? new HashSet<Symbol>() : result;
     }
     finally
     {
         walker.Free();
     }
 }
 internal static HashSet<PrefixUnaryExpressionSyntax> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node)
 {
     var walker = new UnassignedAddressTakenVariablesWalker(compilation, member, node);
     try
     {
         bool badRegion = false;
         var result = walker.Analyze(ref badRegion);
         Debug.Assert(!badRegion);
         return result;
     }
     finally
     {
         walker.Free();
     }
 }
Exemplo n.º 18
0
        public static void IssueDiagnostics(CSharpCompilation compilation, BoundNode node, DiagnosticBag diagnostics, MethodSymbol containingSymbol)
        {
            Debug.Assert(node != null);
            Debug.Assert((object)containingSymbol != null);

            try
            {
                var diagnosticPass = new DiagnosticsPass(compilation, diagnostics, containingSymbol);
                diagnosticPass.Visit(node);
            }
            catch (CancelledByStackGuardException ex)
            {
                ex.AddAnError(diagnostics);
            }
        }
Exemplo n.º 19
0
 internal static IEnumerable<StatementSyntax> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion)
 {
     var walker = new ExitPointsWalker(compilation, member, node, firstInRegion, lastInRegion);
     try
     {
         bool badRegion = false;
         walker.Analyze(ref badRegion);
         var result = walker._branchesOutOf.ToImmutableAndFree();
         walker._branchesOutOf = null;
         return badRegion ? SpecializedCollections.EmptyEnumerable<StatementSyntax>() : result;
     }
     finally
     {
         walker.Free();
     }
 }
 internal static IEnumerable<LabeledStatementSyntax> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, out bool? succeeded)
 {
     var walker = new EntryPointsWalker(compilation, member, node, firstInRegion, lastInRegion);
     bool badRegion = false;
     try
     {
         walker.Analyze(ref badRegion);
         var result = walker.entryPoints;
         succeeded = !badRegion;
         return badRegion ? SpecializedCollections.EmptyEnumerable<LabeledStatementSyntax>() : result;
     }
     finally
     {
         walker.Free();
     }
 }
Exemplo n.º 21
0
 internal static HashSet<Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion,
     HashSet<Symbol> unassignedVariables, HashSet<PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes, out bool? succeeded)
 {
     var walker = new DataFlowsInWalker(compilation, member, node, firstInRegion, lastInRegion, unassignedVariables, unassignedVariableAddressOfSyntaxes);
     try
     {
         bool badRegion = false;
         var result = walker.Analyze(ref badRegion);
         succeeded = !badRegion;
         return badRegion ? new HashSet<Symbol>() : result;
     }
     finally
     {
         walker.Free();
     }
 }
Exemplo n.º 22
0
        internal static HashSet<Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet<Symbol> unassignedVariables, ImmutableArray<ISymbol> dataFlowsIn)
        {
            var walker = new DataFlowsOutWalker(compilation, member, node, firstInRegion, lastInRegion, unassignedVariables, dataFlowsIn);
            try
            {
                bool badRegion = false;
                var result = walker.Analyze(ref badRegion);
#if DEBUG
                // Assert that DataFlowsOut only contains variables that were assigned to inside the region
                Debug.Assert(badRegion || !result.Any((variable) => !walker.assignedInside.Contains(variable)));
#endif
                return badRegion ? new HashSet<Symbol>() : result;
            }
            finally
            {
                walker.Free();
            }
        }
Exemplo n.º 23
0
        public override BoundNode Visit(BoundNode node)
        {
            HashSet<LabelSymbol> unmatched;
            if (node != null && _unmatchedLabelsCache.TryGetValue(node, out unmatched))
            {
                if (unmatched != null)
                {
                    foreach (LabelSymbol label in unmatched)
                    {
                        AddGoto(label);
                    }
                }

                return null; // Don't visit children.
            }

            return base.Visit(node);
        }
Exemplo n.º 24
0
 internal static void Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion,
     out bool startPointIsReachable, out bool endPointIsReachable)
 {
     var walker = new RegionReachableWalker(compilation, member, node, firstInRegion, lastInRegion);
     var diagnostics = DiagnosticBag.GetInstance();
     bool badRegion = false;
     try
     {
         walker.Analyze(ref badRegion, diagnostics);
         startPointIsReachable = badRegion || walker._reginStartPointIsReachable.GetValueOrDefault(true);
         endPointIsReachable = badRegion || walker._reginEndPointIsReachable.GetValueOrDefault(walker.State.Alive);
     }
     finally
     {
         diagnostics.Free();
         walker.Free();
     }
 }
            public override BoundNode Visit(BoundNode node)
            {
                var partiallyLowered = node as PartiallyLoweredLocalFunctionReference;
                if (partiallyLowered != null)
                {
                    var underlying = partiallyLowered.UnderlyingNode;
                    Debug.Assert(underlying.Kind == BoundKind.Call ||
                                 underlying.Kind == BoundKind.DelegateCreationExpression ||
                                 underlying.Kind == BoundKind.Conversion);
                    var oldProxies = _lambdaRewriter.proxies;
                    _lambdaRewriter.proxies = partiallyLowered.Proxies;

                    var result = base.Visit(underlying);

                    _lambdaRewriter.proxies = oldProxies;

                    return result;
                }
                return base.Visit(node);
            }
Exemplo n.º 26
0
 public override BoundNode Visit(BoundNode node)
 {
     IOperation operation = node as IOperation;
     if (operation != null)
     {
         this.nodes.Add(operation);
         switch (operation.Kind)
         {
             case OperationKind.InvocationExpression:
                 nodes.AddRange(((IInvocationExpression)operation).ArgumentsInSourceOrder);
                 break;
             case OperationKind.ObjectCreationExpression:
                 var objCreationExp = (IObjectCreationExpression)operation;
                 nodes.AddRange(objCreationExp.ConstructorArguments);
                 nodes.AddRange(objCreationExp.MemberInitializers);
                 break;
         }
     }
     return base.Visit(node);
 }
Exemplo n.º 27
0
        internal static HashSet<Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node,
                                                bool convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = false)
        {
            var walker = new UnassignedVariablesWalker(compilation, member, node);

            if (convertInsufficientExecutionStackExceptionToCancelledByStackGuardException)
            {
                walker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true;
            }

            try
            {
                bool badRegion = false;
                var result = walker.Analyze(ref badRegion);
                return badRegion ? new HashSet<Symbol>() : result;
            }
            finally
            {
                walker.Free();
            }
        }
        public static MultiDictionary<Symbol, CSharpSyntaxNode> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node)
        {
            var emptyStructs = new CaptureWalkerEmptyStructTypeCache();
            var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, emptyStructs);

            var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, emptyStructs, initiallyAssignedVariables);

            bool badRegion = false;
            walker.Analyze(ref badRegion);
            Debug.Assert(!badRegion);

            var result = walker.variablesCaptured;

            if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct)
            {
                // It is possible that the enclosing method only *writes* to the enclosing struct, but in that
                // case it should be considered captured anyway so that we have a proxy for it to write to.
                result.Add(method.ThisParameter, node.Syntax);
            }

            walker.Free();
            return result;
        }
Exemplo n.º 29
0
        internal static IEnumerable <Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion)
        {
            var  walker    = new AlwaysAssignedWalker(compilation, member, node, firstInRegion, lastInRegion);
            bool badRegion = false;

            try
            {
                var result = walker.Analyze(ref badRegion);
                return(badRegion ? SpecializedCollections.EmptyEnumerable <Symbol>() : result);
            }
            finally
            {
                walker.Free();
            }
        }
Exemplo n.º 30
0
        public override BoundNode?VisitLocalFunctionStatement(BoundLocalFunctionStatement localFunc)
        {
            var oldSymbol       = this.CurrentSymbol;
            var localFuncSymbol = localFunc.Symbol;

            this.CurrentSymbol = localFuncSymbol;

            var oldPending = SavePending(); // we do not support branches into a lambda

            // SPEC: The entry point to a local function is always reachable.
            // Captured variables are definitely assigned if they are definitely assigned on
            // all branches into the local function.

            var savedState = this.State;

            this.State = this.TopState();

            Optional <TLocalState> savedNonMonotonicState = NonMonotonicState;

            if (_nonMonotonicTransfer)
            {
                NonMonotonicState = ReachableBottomState();
            }

            if (!localFunc.WasCompilerGenerated)
            {
                EnterParameters(localFuncSymbol.Parameters);
            }

            // State changes to captured variables are recorded, as calls to local functions
            // transition the state of captured variables if the variables have state changes
            // across all branches leaving the local function

            var localFunctionState      = GetOrCreateLocalFuncUsages(localFuncSymbol);
            var savedLocalFunctionState = LocalFunctionStart(localFunctionState);

            var oldPending2 = SavePending();

            // If this is an iterator, there's an implicit branch before the first statement
            // of the function where the enumerable is returned.
            if (localFuncSymbol.IsIterator)
            {
                PendingBranches.Add(new PendingBranch(null, this.State, null));
            }

            VisitAlways(localFunc.Body);
            RestorePending(oldPending2); // process any forward branches within the lambda body
            ImmutableArray <PendingBranch> pendingReturns = RemoveReturns();

            RestorePending(oldPending);

            Location?location = null;

            if (!localFuncSymbol.Locations.IsDefaultOrEmpty)
            {
                location = localFuncSymbol.Locations[0];
            }

            LeaveParameters(localFuncSymbol.Parameters, localFunc.Syntax, location);

            // Intersect the state of all branches out of the local function
            var stateAtReturn = this.State;

            foreach (PendingBranch pending in pendingReturns)
            {
                this.State = pending.State;
                BoundNode branch = pending.Branch;

                // Pass the local function identifier as a location if the branch
                // is null or compiler generated.
                LeaveParameters(localFuncSymbol.Parameters,
                                branch?.Syntax,
                                branch?.WasCompilerGenerated == false ? null : location);

                Join(ref stateAtReturn, ref this.State);
            }

            // Record any changes to the state of captured variables
            if (RecordStateChange(
                    savedLocalFunctionState,
                    localFunctionState,
                    ref stateAtReturn) &&
                localFunctionState.Visited)
            {
                // If the sets have changed and we already used the results
                // of this local function in another computation, the previous
                // calculations may be invalid. We need to analyze until we
                // reach a fixed-point.
                stateChangedAfterUse       = true;
                localFunctionState.Visited = false;
            }

            this.State         = savedState;
            NonMonotonicState  = savedNonMonotonicState;
            this.CurrentSymbol = oldSymbol;

            return(null);
        }
Exemplo n.º 31
0
        private void CheckVacuousComparisons(BoundBinaryOperator tree, ConstantValue constantValue, BoundNode operand)
        {
            Debug.Assert(tree != null);
            Debug.Assert(constantValue != null);
            Debug.Assert(operand != null);

            // We wish to detect comparisons between integers and constants which are likely to be wrong
            // because we know at compile time whether they will be true or false. For example:
            //
            // const short s = 1000;
            // byte b = whatever;
            // if (b < s)
            //
            // We know that this will always be true because when b and s are both converted to int for
            // the comparison, the left side will always be less than the right side.
            //
            // We only give the warning if there is no explicit conversion involved on the operand.
            // For example, if we had:
            //
            // const uint s = 1000;
            // sbyte b = whatever;
            // if ((byte)b < s)
            //
            // Then we do not give a warning.
            //
            // Note that the native compiler has what looks to be some dead code. It checks to see
            // if the conversion on the operand is from an enum type. But this is unnecessary if
            // we are rejecting cases with explicit conversions. The only possible cases are:
            //
            // enum == enumConstant           -- enum types must be the same, so it must be in range.
            // enum == integralConstant       -- not legal unless the constant is zero, which is in range.
            // enum == (ENUM)anyConstant      -- if the constant is out of range then this is not legal in the first place
            //                                   unless we're in an unchecked context, in which case, the user probably does
            //                                   not want the warning.
            // integral == enumConstant       -- never legal in the first place
            //
            // Since it seems pointless to try to check enums, we simply look for vacuous comparisons of
            // integral types here.

            for (BoundConversion conversion = operand as BoundConversion;
                 conversion != null;
                 conversion = conversion.Operand as BoundConversion)
            {
                if (conversion.ConversionKind != ConversionKind.ImplicitNumeric &&
                    conversion.ConversionKind != ConversionKind.ImplicitConstant)
                {
                    return;
                }

                // As in dev11, we don't dig through explicit casts (see ExpressionBinder::WarnAboutBadRelationals).
                if (conversion.ExplicitCastInCode)
                {
                    return;
                }

                if (!conversion.Operand.Type.SpecialType.IsIntegralType() || !conversion.Type.SpecialType.IsIntegralType())
                {
                    return;
                }

                if (!Binder.CheckConstantBounds(conversion.Operand.Type.SpecialType, constantValue))
                {
                    Error(ErrorCode.WRN_VacuousIntegralComp, tree, conversion.Operand.Type);
                    return;
                }
            }
        }
Exemplo n.º 32
0
        private Symbol GetNodeSymbol(BoundNode node)
        {
            while (node != null)
            {
                switch (node.Kind)
                {
                case BoundKind.DeclarationPattern:
                {
                    return(((BoundDeclarationPattern)node).LocalSymbol);
                }

                case BoundKind.FieldAccess:
                {
                    var fieldAccess = (BoundFieldAccess)node;
                    if (MayRequireTracking(fieldAccess.ReceiverOpt, fieldAccess.FieldSymbol))
                    {
                        node = fieldAccess.ReceiverOpt;
                        continue;
                    }

                    return(null);
                }

                case BoundKind.LocalDeclaration:
                {
                    return(((BoundLocalDeclaration)node).LocalSymbol);
                }

                case BoundKind.ThisReference:
                {
                    return(MethodThisParameter);
                }

                case BoundKind.Local:
                {
                    return(((BoundLocal)node).LocalSymbol);
                }

                case BoundKind.Parameter:
                {
                    return(((BoundParameter)node).ParameterSymbol);
                }

                case BoundKind.CatchBlock:
                {
                    var local = ((BoundCatchBlock)node).Locals.FirstOrDefault();
                    return(local?.DeclarationKind == LocalDeclarationKind.CatchVariable ? local : null);
                }

                case BoundKind.ForEachStatement:
                {
                    return(((BoundForEachStatement)node).IterationVariableOpt);
                }

                case BoundKind.RangeVariable:
                {
                    return(((BoundRangeVariable)node).RangeVariableSymbol);
                }

                case BoundKind.EventAccess:
                {
                    var         eventAccess     = (BoundEventAccess)node;
                    FieldSymbol associatedField = eventAccess.EventSymbol.AssociatedField;
                    if ((object)associatedField != null)
                    {
                        if (MayRequireTracking(eventAccess.ReceiverOpt, associatedField))
                        {
                            node = eventAccess.ReceiverOpt;
                            continue;
                        }
                    }
                    return(null);
                }

                case BoundKind.LocalFunctionStatement:
                {
                    return(((BoundLocalFunctionStatement)node).Symbol);
                }

                default:
                {
                    return(null);
                }
                }
            }

            return(null);
        }
Exemplo n.º 33
0
        public static void GetExpressionSymbols(this BoundExpression node, ArrayBuilder <Symbol> symbols, BoundNode parent, Binder binder)
        {
            switch (node.Kind)
            {
            case BoundKind.MethodGroup:
                // Special case: if we are looking for info on "M" in "new Action(M)" in the context of a parent
                // then we want to get the symbol that overload resolution chose for M, not on the whole method group M.
                var delegateCreation = parent as BoundDelegateCreationExpression;
                if (delegateCreation != null && (object)delegateCreation.MethodOpt != null)
                {
                    symbols.Add(delegateCreation.MethodOpt);
                }
                else
                {
                    symbols.AddRange(CSharpSemanticModel.GetReducedAndFilteredMethodGroupSymbols(binder, (BoundMethodGroup)node));
                }
                break;

            case BoundKind.BadExpression:
                symbols.AddRange(((BoundBadExpression)node).Symbols);
                break;

            case BoundKind.DelegateCreationExpression:
                var expr = (BoundDelegateCreationExpression)node;
                var ctor = expr.Type.GetMembers(WellKnownMemberNames.InstanceConstructorName).FirstOrDefault();
                if ((object)ctor != null)
                {
                    symbols.Add(ctor);
                }
                break;

            case BoundKind.Call:
                // Either overload resolution succeeded for this call or it did not. If it did not
                // succeed then we've stashed the original method symbols from the method group,
                // and we should use those as the symbols displayed for the call. If it did succeed
                // then we did not stash any symbols; just fall through to the default case.

                var originalMethods = ((BoundCall)node).OriginalMethodsOpt;
                if (originalMethods.IsDefault)
                {
                    goto default;
                }
                symbols.AddRange(originalMethods);
                break;

            case BoundKind.IndexerAccess:
                // Same behavior as for a BoundCall: if overload resolution failed, pull out stashed candidates;
                // otherwise use the default behavior.

                var originalIndexers = ((BoundIndexerAccess)node).OriginalIndexersOpt;
                if (originalIndexers.IsDefault)
                {
                    goto default;
                }
                symbols.AddRange(originalIndexers);
                break;

            default:
                var symbol = node.ExpressionSymbol;
                if ((object)symbol != null)
                {
                    symbols.Add(symbol);
                }
                break;
            }
        }
Exemplo n.º 34
0
            public static BoundNode Rewrite(PooledDictionary <LocalSymbol, LocalSymbol> tempSubstitution, BoundNode node)
            {
                if (tempSubstitution.Count == 0)
                {
                    return(node);
                }

                var substituter = new LocalSubstituter(tempSubstitution);

                return(substituter.Visit(node));
            }
Exemplo n.º 35
0
 private ReadWriteWalker(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion,
                         HashSet <PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes)
     : base(compilation, member, node, firstInRegion, lastInRegion, unassignedVariableAddressOfSyntaxes: unassignedVariableAddressOfSyntaxes)
 {
 }
Exemplo n.º 36
0
        internal static void Analyze(
            CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet <PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes,
            out IEnumerable <Symbol> readInside,
            out IEnumerable <Symbol> writtenInside,
            out IEnumerable <Symbol> readOutside,
            out IEnumerable <Symbol> writtenOutside,
            out IEnumerable <Symbol> captured,
            out IEnumerable <Symbol> unsafeAddressTaken,
            out IEnumerable <Symbol> capturedInside,
            out IEnumerable <Symbol> capturedOutside)
        {
            var walker = new ReadWriteWalker(compilation, member, node, firstInRegion, lastInRegion, unassignedVariableAddressOfSyntaxes);

            try
            {
                bool badRegion = false;
                walker.Analyze(ref badRegion);
                if (badRegion)
                {
                    readInside = writtenInside = readOutside = writtenOutside = captured = unsafeAddressTaken = capturedInside = capturedOutside = Enumerable.Empty <Symbol>();
                }
                else
                {
                    readInside     = walker._readInside;
                    writtenInside  = walker._writtenInside;
                    readOutside    = walker._readOutside;
                    writtenOutside = walker._writtenOutside;

                    captured        = walker.GetCaptured();
                    capturedInside  = walker.GetCapturedInside();
                    capturedOutside = walker.GetCapturedOutside();

                    unsafeAddressTaken = walker.GetUnsafeAddressTaken();
                }
            }
            finally
            {
                walker.Free();
            }
        }
Exemplo n.º 37
0
 public override BoundNode DefaultVisit(BoundNode node)
 {
     Debug.Assert(!(node is BoundStatement));
     return(base.DefaultVisit(node));
 }
Exemplo n.º 38
0
 private void Error(ErrorCode code, BoundNode node, params object[] args)
 {
     _diagnostics.Add(code, node.Syntax.Location, args);
 }
Exemplo n.º 39
0
 private T GetUpdatedSymbol <T>(BoundNode expr, T sym) where T : Symbol?
 {
     if (sym is null)
Exemplo n.º 40
0
 private UnassignedVariablesWalker(CSharpCompilation compilation, Symbol member, BoundNode node)
     : base(compilation, member, node, new NeverEmptyStructTypeCache())
 {
 }
Exemplo n.º 41
0
 public override BoundNode Visit(BoundNode node)
 {
     VisitAlways(node);
     return(null);
 }
Exemplo n.º 42
0
 DataFlowsOutWalker(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet<Symbol> unassignedVariables, ImmutableArray<ISymbol> dataFlowsIn)
     : base(compilation, member, node, firstInRegion, lastInRegion, unassignedVariables, trackUnassignments: true)
 {
     this.dataFlowsIn = dataFlowsIn;
 }
Exemplo n.º 43
0
 protected override void AnalyzeBoundNodeNullability(BoundNode boundRoot, Binder binder, DiagnosticBag diagnostics, bool createSnapshots)
 {
     NullableWalker.AnalyzeWithoutRewrite(Compilation, symbol: null, boundRoot, binder, diagnostics, createSnapshots);
 }
Exemplo n.º 44
0
 private void EnterStatement(BoundNode boundStatement)
 {
     _tempSubstitution.Clear();
 }
        public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatement localFunc)
        {
            var oldSymbol       = this.currentSymbol;
            var localFuncSymbol = localFunc.Symbol;

            this.currentSymbol = localFuncSymbol;

            var oldPending = SavePending(); // we do not support branches into a lambda

            // SPEC: The entry point to a local function is always reachable.
            // Captured variables are definitely assigned if they are definitely assigned on
            // all branches into the local function.

            var savedState = this.State;

            this.State = this.TopState();

            if (!localFunc.WasCompilerGenerated)
            {
                EnterParameters(localFuncSymbol.Parameters);
            }

            // Captured variables are definitely assigned if they are assigned on
            // all branches into the local function, so we store all reads from
            // possibly unassigned captured variables and later report definite
            // assignment errors if any of the captured variables is not assigned
            // on a particular branch.
            //
            // Assignments to captured variables are also recorded, as calls to local functions
            // definitely assign captured variables if the variables are definitely assigned at
            // all branches out of the local function.

            var usages   = GetOrCreateLocalFuncUsages(localFuncSymbol);
            var oldReads = usages.ReadVars.Clone();

            usages.ReadVars.Clear();

            var oldPending2 = SavePending();

            // If this is an iterator, there's an implicit branch before the first statement
            // of the function where the enumerable is returned.
            if (localFuncSymbol.IsIterator)
            {
                PendingBranches.Add(new PendingBranch(null, this.State, null));
            }

            VisitAlways(localFunc.Body);
            RestorePending(oldPending2); // process any forward branches within the lambda body
            ImmutableArray <PendingBranch> pendingReturns = RemoveReturns();

            RestorePending(oldPending);

            Location location = null;

            if (!localFuncSymbol.Locations.IsDefaultOrEmpty)
            {
                location = localFuncSymbol.Locations[0];
            }

            LeaveParameters(localFuncSymbol.Parameters, localFunc.Syntax, location);

            // Intersect the state of all branches out of the local function
            LocalState stateAtReturn = this.State;

            foreach (PendingBranch pending in pendingReturns)
            {
                this.State = pending.State;
                BoundNode branch = pending.Branch;

                // Pass the local function identifier as a location if the branch
                // is null or compiler generated.
                LeaveParameters(localFuncSymbol.Parameters,
                                branch?.Syntax,
                                branch?.WasCompilerGenerated == false ? null : location);

                Join(ref stateAtReturn, ref this.State);
            }

            // Check for changes to the possibly unassigned and assigned sets
            // of captured variables
            if (RecordChangedVars(ref usages.WrittenVars,
                                  ref stateAtReturn,
                                  ref oldReads,
                                  ref usages.ReadVars) &&
                usages.LocalFuncVisited)
            {
                // If the sets have changed and we already used the results
                // of this local function in another computation, the previous
                // calculations may be invalid. We need to analyze until we
                // reach a fixed-point. The previous writes are always valid,
                // so they are stored in usages.WrittenVars, while the reads
                // may be invalidated by new writes, so we throw the results out.
                stateChangedAfterUse    = true;
                usages.LocalFuncVisited = false;
            }

            this.State         = savedState;
            this.currentSymbol = oldSymbol;

            return(null);
        }
Exemplo n.º 46
0
 private void PopBlock(BoundNode previousBlock)
 {
     _currentScope = previousBlock;
 }
Exemplo n.º 47
0
        internal static HashSet <Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet <Symbol> unassignedVariables, ImmutableArray <ISymbol> dataFlowsIn)
        {
            var walker = new DataFlowsOutWalker(compilation, member, node, firstInRegion, lastInRegion, unassignedVariables, dataFlowsIn);

            try
            {
                bool badRegion = false;
                var  result    = walker.Analyze(ref badRegion);
#if DEBUG
                // Assert that DataFlowsOut only contains variables that were assigned to inside the region
                Debug.Assert(badRegion || !result.Any((variable) => !walker._assignedInside.Contains(variable)));
#endif
                return(badRegion ? new HashSet <Symbol>() : result);
            }
            finally
            {
                walker.Free();
            }
        }
Exemplo n.º 48
0
            /// <summary>
            /// Create the optimized plan for the location of lambda methods and whether scopes need access to parent scopes
            ///  </summary>
            internal void ComputeLambdaScopesAndFrameCaptures()
            {
                LambdaScopes     = new Dictionary <MethodSymbol, BoundNode>(ReferenceEqualityComparer.Instance);
                NeedsParentFrame = new HashSet <BoundNode>();

                RemoveUnneededReferences();

                foreach (var kvp in CapturedVariablesByLambda)
                {
                    var lambda       = kvp.Key;
                    var capturedVars = kvp.Value;

                    var allCapturedVars = ArrayBuilder <Symbol> .GetInstance(capturedVars.Count);

                    allCapturedVars.AddRange(capturedVars);

                    // If any of the captured variables are local functions we'll need
                    // to add the captured variables of that local function to the current
                    // set. This has the effect of ensuring that if the local function
                    // captures anything "above" the current scope then parent frame
                    // is itself captured (so that the current lambda can call that
                    // local function).
                    foreach (var captured in capturedVars)
                    {
                        var capturedLocalFunction = captured as LocalFunctionSymbol;
                        if (capturedLocalFunction != null)
                        {
                            allCapturedVars.AddRange(
                                CapturedVariablesByLambda[capturedLocalFunction]);
                        }
                    }

                    // get innermost and outermost scopes from which a lambda captures
                    int       innermostScopeDepth = -1;
                    BoundNode innermostScope      = null;

                    int       outermostScopeDepth = int.MaxValue;
                    BoundNode outermostScope      = null;

                    foreach (var captured in allCapturedVars)
                    {
                        BoundNode curBlock = null;
                        int       curBlockDepth;

                        if (!VariableScope.TryGetValue(captured, out curBlock))
                        {
                            // this is something that is not defined in a block, like "this"
                            // Since it is defined outside of the method, the depth is -1
                            curBlockDepth = -1;
                        }
                        else
                        {
                            curBlockDepth = BlockDepth(curBlock);
                        }

                        if (curBlockDepth > innermostScopeDepth)
                        {
                            innermostScopeDepth = curBlockDepth;
                            innermostScope      = curBlock;
                        }

                        if (curBlockDepth < outermostScopeDepth)
                        {
                            outermostScopeDepth = curBlockDepth;
                            outermostScope      = curBlock;
                        }
                    }

                    allCapturedVars.Free();

                    // 1) if there is innermost scope, lambda goes there as we cannot go any higher.
                    // 2) scopes in [innermostScope, outermostScope) chain need to have access to the parent scope.
                    //
                    // Example:
                    //   if a lambda captures a method's parameter and `this`,
                    //   its innermost scope depth is 0 (method locals and parameters)
                    //   and outermost scope is -1
                    //   Such lambda will be placed in a closure frame that corresponds to the method's outer block
                    //   and this frame will also lift original `this` as a field when created by its parent.
                    //   Note that it is completely irrelevant how deeply the lexical scope of the lambda was originally nested.
                    if (innermostScope != null)
                    {
                        LambdaScopes.Add(lambda, innermostScope);

                        // Disable struct closures on methods converted to delegates, as well as on async and iterator methods.
                        var markAsNoStruct = MethodsConvertedToDelegates.Contains(lambda) || lambda.IsAsync || lambda.IsIterator;
                        if (markAsNoStruct)
                        {
                            ScopesThatCantBeStructs.Add(innermostScope);
                        }

                        while (innermostScope != outermostScope)
                        {
                            NeedsParentFrame.Add(innermostScope);
                            ScopeParent.TryGetValue(innermostScope, out innermostScope);
                            if (markAsNoStruct)
                            {
                                ScopesThatCantBeStructs.Add(innermostScope);
                            }
                        }
                    }
                }
            }
Exemplo n.º 49
0
 private DataFlowsOutWalker(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet <Symbol> unassignedVariables, ImmutableArray <ISymbol> dataFlowsIn)
     : base(compilation, member, node, firstInRegion, lastInRegion, unassignedVariables, trackUnassignments: true)
 {
     _dataFlowsIn = dataFlowsIn;
 }
Exemplo n.º 50
0
 internal VariablesDeclaredWalker(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion)
     : base(compilation, member, node, firstInRegion, lastInRegion)
 {
 }
Exemplo n.º 51
0
        public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatement localFunc)
        {
            var oldMethodOrLambda = this.currentMethodOrLambda;

            this.currentMethodOrLambda = localFunc.Symbol;

            var oldPending = SavePending(); // we do not support branches into a lambda

            // Local functions don't affect outer state and are analyzed
            // with everything unassigned and reachable
            var savedState = this.State;

            this.State = this.ReachableState();

            var usages   = GetOrCreateLocalFuncUsages(localFunc.Symbol);
            var oldReads = usages.ReadVars;

            usages.ReadVars = BitVector.Empty;

            if (!localFunc.WasCompilerGenerated)
            {
                EnterParameters(localFunc.Symbol.Parameters);
            }

            var oldPending2 = SavePending();

            VisitAlways(localFunc.Body);
            RestorePending(oldPending2); // process any forward branches within the lambda body
            ImmutableArray <PendingBranch> pendingReturns = RemoveReturns();

            RestorePending(oldPending);

            Location location = null;

            if (!localFunc.Symbol.Locations.IsDefaultOrEmpty)
            {
                location = localFunc.Symbol.Locations[0];
            }

            LeaveParameters(localFunc.Symbol.Parameters, localFunc.Syntax, location);

            LocalState stateAtReturn = this.State;

            foreach (PendingBranch pending in pendingReturns)
            {
                this.State = pending.State;
                BoundNode branch = pending.Branch;
                if (branch.Kind == BoundKind.ReturnStatement)
                {
                    // ensure out parameters are definitely assigned at each return
                    LeaveParameters(localFunc.Symbol.Parameters, branch.Syntax,
                                    branch.WasCompilerGenerated ? location : null);
                    IntersectWith(ref stateAtReturn, ref this.State);
                }
                else
                {
                    // other ways of branching out of a lambda are errors, previously reported in control-flow analysis
                }
            }

            // Check for changes to the read and write sets
            if (RecordChangedVars(ref usages.WrittenVars,
                                  ref stateAtReturn.Assigned,
                                  ref oldReads,
                                  ref usages.ReadVars) &&
                usages.LocalFuncVisited)
            {
                stateChangedAfterUse    = true;
                usages.LocalFuncVisited = false;
            }

            this.State = savedState;
            this.currentMethodOrLambda = oldMethodOrLambda;

            return(null);
        }
Exemplo n.º 52
0
        internal static IEnumerable <Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion)
        {
            var walker = new VariablesDeclaredWalker(compilation, member, node, firstInRegion, lastInRegion);

            try
            {
                bool badRegion = false;
                walker.Analyze(ref badRegion);
                return(badRegion ? SpecializedCollections.EmptyEnumerable <Symbol>() : walker._variablesDeclared);
            }
            finally
            {
                walker.Free();
            }
        }
Exemplo n.º 53
0
        internal static (HashSet <Symbol> entry, HashSet <Symbol> exit) Analyze(
            CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion)
        {
            var walker = new DefinitelyAssignedWalker(compilation, member, node, firstInRegion, lastInRegion);

            try
            {
                bool badRegion = false;
                walker.Analyze(ref badRegion, diagnostics: null);
                return(badRegion
                    ? (new HashSet <Symbol>(), new HashSet <Symbol>())
                    : (walker._definitelyAssignedOnEntry, walker._definitelyAssignedOnExit));
            }
            finally
            {
                walker.Free();
            }
        }
Exemplo n.º 54
0
        private BoundNode RewriteLambdaConversion(BoundLambda node)
        {
            var wasInExpressionLambda = inExpressionLambda;

            inExpressionLambda = inExpressionLambda || node.Type.IsExpressionTree();

            if (inExpressionLambda)
            {
                var newType = VisitType(node.Type);
                var newBody = (BoundBlock)Visit(node.Body);
                node = node.Update(node.Symbol, newBody, node.Diagnostics, node.Binder, newType);
                var result0 = wasInExpressionLambda ? node : ExpressionLambdaRewriter.RewriteLambda(node, CompilationState, Diagnostics);
                inExpressionLambda = wasInExpressionLambda;
                return(result0);
            }

            NamedTypeSymbol translatedLambdaContainer;
            BoundNode       lambdaScope = null;

            if (analysis.lambdaScopes.TryGetValue(node.Symbol, out lambdaScope))
            {
                translatedLambdaContainer = frames[lambdaScope];
            }
            else
            {
                translatedLambdaContainer = topLevelMethod.ContainingType;
            }

            // Move the body of the lambda to a freshly generated synthetic method on its frame.
            bool lambdaIsStatic = analysis.captures[node.Symbol].IsEmpty();
            SynthesizedLambdaMethod generatedMethod = new SynthesizedLambdaMethod(translatedLambdaContainer, topLevelMethod, node, lambdaIsStatic, CompilationState);

            if (CompilationState.Emitting)
            {
                CompilationState.ModuleBuilder.AddCompilerGeneratedDefinition(translatedLambdaContainer, generatedMethod);
            }

            for (int i = 0; i < node.Symbol.ParameterCount; i++)
            {
                parameterMap.Add(node.Symbol.Parameters[i], generatedMethod.Parameters[i]);
            }

            // rewrite the lambda body as the generated method's body
            var oldMethod                = currentMethod;
            var oldFrameThis             = currentFrameThis;
            var oldTypeParameters        = currentTypeParameters;
            var oldInnermostFramePointer = innermostFramePointer;
            var oldTypeMap               = currentLambdaBodyTypeMap;
            var oldAddedStatements       = addedStatements;
            var oldAddedLocals           = addedLocals;

            addedStatements = null;
            addedLocals     = null;

            // switch to the generated method

            currentMethod = generatedMethod;
            if (lambdaIsStatic)
            {
                // no link from a static lambda to its container
                innermostFramePointer = currentFrameThis = null;
            }
            else
            {
                currentFrameThis      = generatedMethod.ThisParameter;
                innermostFramePointer = null;
                framePointers.TryGetValue(translatedLambdaContainer, out innermostFramePointer);
            }

            if (translatedLambdaContainer.OriginalDefinition is LambdaFrame)
            {
                currentTypeParameters    = translatedLambdaContainer.TypeParameters;
                currentLambdaBodyTypeMap = (translatedLambdaContainer as LambdaFrame).TypeMap;
            }
            else
            {
                currentTypeParameters    = generatedMethod.TypeParameters;
                currentLambdaBodyTypeMap = new TypeMap(topLevelMethod.TypeParameters, currentTypeParameters);
            }

            var body = AddStatementsIfNeeded((BoundStatement)VisitBlock(node.Body));

            CheckLocalsDefined(body);
            CompilationState.AddGeneratedMethod(generatedMethod, body);

            // return to the old method

            currentMethod            = oldMethod;
            currentFrameThis         = oldFrameThis;
            currentTypeParameters    = oldTypeParameters;
            innermostFramePointer    = oldInnermostFramePointer;
            currentLambdaBodyTypeMap = oldTypeMap;
            addedLocals     = oldAddedLocals;
            addedStatements = oldAddedStatements;

            // Rewrite the lambda expression (and the enclosing anonymous method conversion) as a delegate creation expression
            NamedTypeSymbol constructedFrame = (translatedLambdaContainer is LambdaFrame) ? translatedLambdaContainer.ConstructIfGeneric(StaticCast <TypeSymbol> .From(currentTypeParameters)) : translatedLambdaContainer;
            BoundExpression receiver         = lambdaIsStatic ? new BoundTypeExpression(node.Syntax, null, constructedFrame) : FrameOfType(node.Syntax, constructedFrame);
            MethodSymbol    referencedMethod = generatedMethod.AsMember(constructedFrame);

            if (referencedMethod.IsGenericMethod)
            {
                referencedMethod = referencedMethod.Construct(StaticCast <TypeSymbol> .From(currentTypeParameters));
            }
            TypeSymbol      type   = this.VisitType(node.Type);
            BoundExpression result = new BoundDelegateCreationExpression(
                node.Syntax,
                receiver,
                referencedMethod,
                isExtensionMethod: false,
                type: type);

            // if the block containing the lambda is not the innermost block,
            // or the lambda is static, then the lambda object should be cached in its frame.
            // NOTE: we are not caching static lambdas in static ctors - cannot reuse such cache.
            var shouldCacheForStaticMethod = lambdaIsStatic &&
                                             currentMethod.MethodKind != MethodKind.StaticConstructor &&
                                             !referencedMethod.IsGenericMethod;

            // NOTE: We require "lambdaScope != null".
            //       We do not want to introduce a field into an actual user's class (not a synthetic frame).
            var shouldCacheInLoop = lambdaScope != null &&
                                    lambdaScope != analysis.blockParent[node.Body] &&
                                    InLoopOrLambda(node.Syntax, lambdaScope.Syntax);

            if (shouldCacheForStaticMethod || shouldCacheInLoop)
            {
                // replace the expression "new Delegate(frame.M)" with "(frame.cache == null) ? (frame.cache = new Delegate(frame.M)) : frame.cache"
                var F = new SyntheticBoundNodeFactory(currentMethod, node.Syntax, CompilationState, Diagnostics);
                try
                {
                    var             cacheVariableName = GeneratedNames.MakeLambdaCacheName(CompilationState.GenerateTempNumber());
                    BoundExpression cacheVariable;
                    if (shouldCacheForStaticMethod || shouldCacheInLoop && translatedLambdaContainer is LambdaFrame)
                    {
                        var cacheVariableType = lambdaIsStatic ? type : (translatedLambdaContainer as LambdaFrame).TypeMap.SubstituteType(type);
                        var cacheField        = new SynthesizedFieldSymbol(translatedLambdaContainer, cacheVariableType, cacheVariableName, isPublic: !lambdaIsStatic, isStatic: lambdaIsStatic);
                        CompilationState.ModuleBuilder.AddCompilerGeneratedDefinition(translatedLambdaContainer, cacheField);
                        cacheVariable = F.Field(receiver, cacheField.AsMember(constructedFrame)); //NOTE: the field was added to the unconstructed frame type.
                    }
                    else
                    {
                        // the lambda captures at most the "this" of the enclosing method.  We cache its delegate in a local variable.
                        var cacheLocal = F.SynthesizedLocal(type, cacheVariableName);
                        if (addedLocals == null)
                        {
                            addedLocals = ArrayBuilder <LocalSymbol> .GetInstance();
                        }
                        addedLocals.Add(cacheLocal);
                        if (addedStatements == null)
                        {
                            addedStatements = ArrayBuilder <BoundStatement> .GetInstance();
                        }
                        cacheVariable = F.Local(cacheLocal);
                        addedStatements.Add(F.Assignment(cacheVariable, F.Null(type)));
                    }

                    result = F.Coalesce(cacheVariable, F.AssignmentExpression(cacheVariable, result));
                }
                catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex)
                {
                    Diagnostics.Add(ex.Diagnostic);
                    return(new BoundBadExpression(F.Syntax, LookupResultKind.Empty, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundNode>(node), node.Type));
                }
            }

            return(result);
        }
Exemplo n.º 55
0
        /// <summary>
        /// Introduce a frame around the translation of the given node.
        /// </summary>
        /// <param name="node">The node whose translation should be translated to contain a frame</param>
        /// <param name="frame">The frame for the translated node</param>
        /// <param name="F">A function that computes the translation of the node.  It receives lists of added statements and added symbols</param>
        /// <returns>The translated statement, as returned from F</returns>
        private T IntroduceFrame <T>(BoundNode node, LambdaFrame frame, Func <ArrayBuilder <BoundExpression>, ArrayBuilder <LocalSymbol>, T> F)
        {
            NamedTypeSymbol frameType    = frame.ConstructIfGeneric(StaticCast <TypeSymbol> .From(currentTypeParameters));
            LocalSymbol     framePointer = new LambdaFrameLocalSymbol(this.topLevelMethod, frameType, CompilationState);

            CSharpSyntaxNode syntax = node.Syntax;

            // assign new frame to the frame variable
            CompilationState.AddGeneratedMethod(frame.Constructor, FlowAnalysisPass.AppendImplicitReturn(Compiler.BindMethodBody(frame.Constructor, null), frame.Constructor));

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

            MethodSymbol constructor = frame.Constructor.AsMember(frameType);

            Debug.Assert(frameType == constructor.ContainingType);
            var newFrame = new BoundObjectCreationExpression(
                syntax: syntax,
                constructor: constructor);

            prologue.Add(new BoundAssignmentOperator(syntax,
                                                     new BoundLocal(syntax, framePointer, null, frameType),
                                                     newFrame,
                                                     frameType));

            CapturedSymbolReplacement oldInnermostFrameProxy = null;

            if ((object)innermostFramePointer != null)
            {
                proxies.TryGetValue(innermostFramePointer, out oldInnermostFrameProxy);
                if (analysis.needsParentFrame.Contains(node))
                {
                    var             capturedFrame = new LambdaCapturedVariable(frame, innermostFramePointer);
                    FieldSymbol     frameParent   = capturedFrame.AsMember(frameType);
                    BoundExpression left          = new BoundFieldAccess(syntax, new BoundLocal(syntax, framePointer, null, frameType), frameParent, null);
                    BoundExpression right         = FrameOfType(syntax, frameParent.Type as NamedTypeSymbol);
                    BoundExpression assignment    = new BoundAssignmentOperator(syntax, left, right, left.Type);

                    if (this.currentMethod.MethodKind == MethodKind.Constructor && capturedFrame.Type == this.currentMethod.ContainingType && !this.seenBaseCall)
                    {
                        // Containing method is a constructor
                        // Initialization statement for the "this" proxy must be inserted
                        // after the constructor initializer statement block
                        // This insertion will be done by the delegate F
                        Debug.Assert(thisProxyInitDeferred == null);
                        thisProxyInitDeferred = assignment;
                    }
                    else
                    {
                        prologue.Add(assignment);
                    }

                    if (CompilationState.Emitting)
                    {
                        CompilationState.ModuleBuilder.AddCompilerGeneratedDefinition(frame, capturedFrame);
                    }

                    proxies[innermostFramePointer] = new CapturedToFrameSymbolReplacement(capturedFrame);
                }
            }

            // Capture any parameters of this block.  This would typically occur
            // at the top level of a method or lambda with captured parameters, or in a catch block.
            // TODO: speed up the following by computing it in analysis.
            foreach (var p in analysis.variablesCaptured)
            {
                BoundNode varNode;
                if (!analysis.variableBlock.TryGetValue(p, out varNode) ||
                    varNode != node ||
                    analysis.declaredInsideExpressionLambda.Contains(p))
                {
                    continue;
                }

                if (p is ParameterSymbol)
                {
                    InitParameterProxy(syntax, p, framePointer, prologue);
                    continue;
                }
            }

            Symbol oldInnermostFramePointer = innermostFramePointer;

            innermostFramePointer = framePointer;
            var addedLocals = ArrayBuilder <LocalSymbol> .GetInstance();

            addedLocals.Add(framePointer);
            framePointers.Add(frame, framePointer);

            var result = F(prologue, addedLocals);

            framePointers.Remove(frame);
            innermostFramePointer = oldInnermostFramePointer;

            if ((object)innermostFramePointer != null)
            {
                if (oldInnermostFrameProxy != null)
                {
                    proxies[innermostFramePointer] = oldInnermostFrameProxy;
                }
                else
                {
                    proxies.Remove(innermostFramePointer);
                }
            }

            return(result);
        }
Exemplo n.º 56
0
 /// <summary>
 /// Check that the top-level node is well-defined, in the sense that all
 /// locals that are used are defined in some enclosing scope.
 /// </summary>
 /// <param name="node"></param>
 static partial void CheckLocalsDefined(BoundNode node);
Exemplo n.º 57
0
 private ParameterSymbol Param(BoundNode node)
 {
     switch (node.Kind)
     {
         case BoundKind.Parameter: return ((BoundParameter)node).ParameterSymbol;
         case BoundKind.ThisReference: return this.MethodThisParameter;
         default: return null;
     }
 }
Exemplo n.º 58
0
 /// <summary>
 /// Ensure that local variables are always in scope where used in bound trees
 /// </summary>
 /// <param name="node"></param>
 static partial void CheckLocalsDefined(BoundNode node)
 {
     LocalsDefinedScanner.INSTANCE.Visit(node);
 }
Exemplo n.º 59
0
        internal static HashSet <Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node,
                                                 bool convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = false)
        {
            var walker = new UnassignedVariablesWalker(compilation, member, node);

            if (convertInsufficientExecutionStackExceptionToCancelledByStackGuardException)
            {
                walker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true;
            }

            try
            {
                bool badRegion = false;
                var  result    = walker.Analyze(ref badRegion);
                return(badRegion ? new HashSet <Symbol>() : result);
            }
            finally
            {
                walker.Free();
            }
        }
Exemplo n.º 60
0
        internal static HashSet <Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion,
                                                 HashSet <Symbol> unassignedVariables, HashSet <PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes, out bool?succeeded)
        {
            var walker = new DataFlowsInWalker(compilation, member, node, firstInRegion, lastInRegion, unassignedVariables, unassignedVariableAddressOfSyntaxes);

            try
            {
                bool badRegion = false;
                var  result    = walker.Analyze(ref badRegion);
                succeeded = !badRegion;
                return(badRegion ? new HashSet <Symbol>() : result);
            }
            finally
            {
                walker.Free();
            }
        }