Пример #1
0
        public static DecisionTree Create(BoundExpression expression, TypeSymbol type, Symbol enclosingSymbol)
        {
            Debug.Assert(expression.Type == type);
            LocalSymbol temp = null;
            if (expression.ConstantValue == null)
            {
                // Unless it is a constant, the decision tree acts on a copy of the input expression.
                // We create a temp to represent that copy. Lowering will assign into this temp.
                temp = new SynthesizedLocal(enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatchingTemp, expression.Syntax, false, RefKind.None);
                expression = new BoundLocal(expression.Syntax, temp, null, type);
            }

            if (expression.Type.CanBeAssignedNull())
            {
                // We need the ByType decision tree to separate null from non-null values.
                // Note that, for the purpose of the decision tree (and subsumption), we
                // ignore the fact that the input may be a constant, and therefore always
                // or never null.
                return new ByType(expression, type, temp);
            }
            else
            {
                // If it is a (e.g. builtin) value type, we can switch on its (constant) values.
                // If it isn't a builtin, in practice we will only use the Default part of the
                // ByValue.
                return new ByValue(expression, type, temp);
            }
        }
        /// <summary>
        /// Applies the conversions.
        /// Adds any new locals to the temps and any new expressions to be evaluated to the stores.
        /// </summary>
        private void ApplyConversions(BoundDeconstructionAssignmentOperator node, ArrayBuilder<LocalSymbol> temps, ArrayBuilder<BoundExpression> stores, ArrayBuilder<BoundValuePlaceholderBase> placeholders)
        {
            int numConversions = node.ConversionSteps.Length;
            var conversionLocals = ArrayBuilder<BoundExpression>.GetInstance();

            foreach (var conversionInfo in node.ConversionSteps)
            {
                // lower the conversions and assignments to locals
                var localSymbol = new SynthesizedLocal(_factory.CurrentMethod, conversionInfo.OutputPlaceholder.Type, SynthesizedLocalKind.LoweringTemp);
                var localBound = new BoundLocal(node.Syntax,
                                               localSymbol,
                                               null,
                                               conversionInfo.OutputPlaceholder.Type)
                { WasCompilerGenerated = true };

                temps.Add(localSymbol);
                conversionLocals.Add(localBound);

                AddPlaceholderReplacement(conversionInfo.OutputPlaceholder, localBound);
                placeholders.Add(conversionInfo.OutputPlaceholder);

                var conversion = VisitExpression(conversionInfo.Assignment);

                stores.Add(conversion);
            }
        }
        /// <summary>
        /// Prepares local variables to be used in Deconstruct call
        /// Adds a invocation of Deconstruct with those as out parameters onto the 'stores' sequence
        /// Returns the expressions for those out parameters
        /// </summary>
        private void CallDeconstruct(BoundDeconstructionAssignmentOperator node, BoundDeconstructionDeconstructStep deconstruction, ArrayBuilder<LocalSymbol> temps, ArrayBuilder<BoundExpression> stores, ArrayBuilder<BoundValuePlaceholderBase> placeholders)
        {
            Debug.Assert((object)deconstruction.DeconstructInvocationOpt != null);

            CSharpSyntaxNode syntax = node.Syntax;

            // prepare out parameters for Deconstruct
            var deconstructParameters = deconstruction.OutputPlaceholders;
            var outParametersBuilder = ArrayBuilder<BoundExpression>.GetInstance(deconstructParameters.Length);

            for (var i = 0; i < deconstructParameters.Length; i++)
            {
                var deconstructParameter = deconstructParameters[i];
                var localSymbol = new SynthesizedLocal(_factory.CurrentMethod, deconstructParameter.Type, SynthesizedLocalKind.LoweringTemp);

                var localBound = new BoundLocal(syntax,
                                                localSymbol,
                                                null,
                                                deconstructParameter.Type
                                                )
                { WasCompilerGenerated = true };

                temps.Add(localSymbol);
                outParametersBuilder.Add(localBound);

                AddPlaceholderReplacement(deconstruction.OutputPlaceholders[i], localBound);
                placeholders.Add(deconstruction.OutputPlaceholders[i]);
            }

            var outParameters = outParametersBuilder.ToImmutableAndFree();

            // invoke Deconstruct with placeholders replaced by locals
            stores.Add(VisitExpression(deconstruction.DeconstructInvocationOpt));
        }
            public LabelSymbol ProxyReturnIfNeeded(
                MethodSymbol containingMethod,
                BoundExpression valueOpt,
                out SynthesizedLocal returnValue)
            {
                returnValue = null;

                // no need to proxy returns  at the root
                if (this.IsRoot())
                {
                    return null;
                }

                var returnProxy = this.returnProxyLabel;
                if (returnProxy == null)
                {
                    this.returnProxyLabel = returnProxy = new GeneratedLabelSymbol("returnProxy");
                }

                if (valueOpt != null)
                {
                    returnValue = this.returnValue;
                    if (returnValue == null)
                    {
                        Debug.Assert(_tryStatementSyntaxOpt != null);
                        this.returnValue = returnValue = new SynthesizedLocal(containingMethod, valueOpt.Type, SynthesizedLocalKind.AsyncMethodReturnValue, _tryStatementSyntaxOpt);
                    }
                }

                return returnProxy;
            }
        private BoundStatement UnpendBranches(
            AwaitFinallyFrame frame,
            SynthesizedLocal pendingBranchVar,
            SynthesizedLocal pendingException)
        {
            var parent = frame.ParentOpt;

            // handle proxy labels if have any
            var proxiedLabels = frame.proxiedLabels;
            var proxyLabels = frame.proxyLabels;

            // skip 0 - it means we took no explicit branches
            int i = 1;
            var cases = ArrayBuilder<BoundSwitchSection>.GetInstance();

            if (proxiedLabels != null)
            {
                for (int cnt = proxiedLabels.Count; i <= cnt; i++)
                {
                    var target = proxiedLabels[i - 1];
                    var parentProxy = parent.ProxyLabelIfNeeded(target);
                    var caseStatement = _F.SwitchSection(i, _F.Goto(parentProxy));
                    cases.Add(caseStatement);
                }
            }

            if (frame.returnProxyLabel != null)
            {
                BoundLocal pendingValue = null;
                if (frame.returnValue != null)
                {
                    pendingValue = _F.Local(frame.returnValue);
                }

                SynthesizedLocal returnValue;
                BoundStatement unpendReturn;

                var returnLabel = parent.ProxyReturnIfNeeded(_F.CurrentMethod, pendingValue, out returnValue);

                if (returnLabel == null)
                {
                    unpendReturn = new BoundReturnStatement(_F.Syntax, pendingValue);
                }
                else
                {
                    if (pendingValue == null)
                    {
                        unpendReturn = _F.Goto(returnLabel);
                    }
                    else
                    {
                        unpendReturn = _F.Block(
                            _F.Assignment(
                                _F.Local(returnValue),
                                pendingValue),
                            _F.Goto(returnLabel));
                    }
                }

                var caseStatement = _F.SwitchSection(i, unpendReturn);
                cases.Add(caseStatement);
            }

            return _F.Switch(_F.Local(pendingBranchVar), cases.ToImmutableAndFree());
        }
        public override BoundNode VisitTryStatement(BoundTryStatement node)
        {
            var tryStatementSyntax = node.Syntax;
            // If you add a syntax kind to the assertion below, please also ensure
            // that the scenario has been tested with Edit-and-Continue.
            Debug.Assert(
                tryStatementSyntax.IsKind(SyntaxKind.TryStatement) ||
                tryStatementSyntax.IsKind(SyntaxKind.UsingStatement) ||
                tryStatementSyntax.IsKind(SyntaxKind.ForEachStatement));

            BoundStatement finalizedRegion;
            BoundBlock rewrittenFinally;

            var finallyContainsAwaits = _analysis.FinallyContainsAwaits(node);
            if (!finallyContainsAwaits)
            {
                finalizedRegion = RewriteFinalizedRegion(node);
                rewrittenFinally = (BoundBlock)this.Visit(node.FinallyBlockOpt);

                if (rewrittenFinally == null)
                {
                    return finalizedRegion;
                }

                var asTry = finalizedRegion as BoundTryStatement;
                if (asTry != null)
                {
                    // since finalized region is a try we can just attach finally to it
                    Debug.Assert(asTry.FinallyBlockOpt == null);
                    return asTry.Update(asTry.TryBlock, asTry.CatchBlocks, rewrittenFinally, asTry.PreferFaultHandler);
                }
                else
                {
                    // wrap finalizedRegion into a Try with a finally.
                    return _F.Try((BoundBlock)finalizedRegion, ImmutableArray<BoundCatchBlock>.Empty, rewrittenFinally);
                }
            }

            // rewrite finalized region (try and catches) in the current frame
            var frame = PushFrame(node);
            finalizedRegion = RewriteFinalizedRegion(node);
            rewrittenFinally = (BoundBlock)this.VisitBlock(node.FinallyBlockOpt);
            PopFrame();

            var exceptionType = _F.SpecialType(SpecialType.System_Object);
            var pendingExceptionLocal = new SynthesizedLocal(_F.CurrentMethod, exceptionType, SynthesizedLocalKind.TryAwaitPendingException, tryStatementSyntax);
            var finallyLabel = _F.GenerateLabel("finallyLabel");
            var pendingBranchVar = new SynthesizedLocal(_F.CurrentMethod, _F.SpecialType(SpecialType.System_Int32), SynthesizedLocalKind.TryAwaitPendingBranch, tryStatementSyntax);

            var catchAll = _F.Catch(_F.Local(pendingExceptionLocal), _F.Block());

            var catchAndPendException = _F.Try(
                _F.Block(
                    finalizedRegion,
                    _F.HiddenSequencePoint(),
                    _F.Goto(finallyLabel),
                    PendBranches(frame, pendingBranchVar, finallyLabel)),
                ImmutableArray.Create(catchAll));

            var syntheticFinally = _F.Block(
                _F.HiddenSequencePoint(),
                _F.Label(finallyLabel),
                rewrittenFinally,
                _F.HiddenSequencePoint(),
                UnpendException(pendingExceptionLocal),
                UnpendBranches(
                    frame,
                    pendingBranchVar,
                    pendingExceptionLocal));


            var locals = ArrayBuilder<LocalSymbol>.GetInstance();
            var statements = ArrayBuilder<BoundStatement>.GetInstance();

            statements.Add(_F.HiddenSequencePoint());

            locals.Add(pendingExceptionLocal);
            statements.Add(_F.Assignment(_F.Local(pendingExceptionLocal), _F.Default(pendingExceptionLocal.Type)));
            locals.Add(pendingBranchVar);
            statements.Add(_F.Assignment(_F.Local(pendingBranchVar), _F.Default(pendingBranchVar.Type)));

            LocalSymbol returnLocal = frame.returnValue;
            if (returnLocal != null)
            {
                locals.Add(returnLocal);
            }

            statements.Add(catchAndPendException);
            statements.Add(syntheticFinally);

            var completeTry = _F.Block(
                locals.ToImmutableAndFree(),
                ImmutableArray<LocalFunctionSymbol>.Empty,
                statements.ToImmutableAndFree());

            return completeTry;
        }
            public AwaitCatchFrame(SyntheticBoundNodeFactory F, TryStatementSyntax tryStatementSyntax)
            {
                this.pendingCaughtException = new SynthesizedLocal(F.CurrentMethod, F.SpecialType(SpecialType.System_Object), SynthesizedLocalKind.TryAwaitPendingCaughtException, tryStatementSyntax);
                this.pendingCatch = new SynthesizedLocal(F.CurrentMethod, F.SpecialType(SpecialType.System_Int32), SynthesizedLocalKind.TryAwaitPendingCatch, tryStatementSyntax);

                this.handlers = new List<BoundBlock>();
                _hoistedLocals = new Dictionary<LocalSymbol, LocalSymbol>();
                _orderedHoistedLocals = new List<LocalSymbol>();
            }
        /// <summary>
        /// Generate a thread-safe accessor for a regular field-like event.
        /// 
        /// DelegateType tmp0 = _event; //backing field
        /// DelegateType tmp1;
        /// DelegateType tmp2;
        /// do {
        ///     tmp1 = tmp0;
        ///     tmp2 = (DelegateType)Delegate.Combine(tmp1, value); //Remove for -=
        ///     tmp0 = Interlocked.CompareExchange&lt;DelegateType&gt;(ref _event, tmp2, tmp1);
        /// } while ((object)tmp0 != (object)tmp1);
        /// </summary>
        internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode;

            TypeSymbol delegateType = eventSymbol.Type;
            MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;
            ParameterSymbol thisParameter = accessor.ThisParameter;

            TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean);
            MethodSymbol updateMethod = (MethodSymbol)compilation.GetSpecialTypeMember(isAddMethod ? SpecialMember.System_Delegate__Combine : SpecialMember.System_Delegate__Remove);
            MethodSymbol compareExchangeMethod = GetConstructedCompareExchangeMethod(delegateType, compilation, accessor.Locations[0], diagnostics);

            if ((object)compareExchangeMethod == null)
            {
                return new BoundBlock(syntax,
                    locals: ImmutableArray<LocalSymbol>.Empty,
                    statements: ImmutableArray.Create<BoundStatement>(
                        new BoundReturnStatement(syntax,
                            expressionOpt: null)
                { WasCompilerGenerated = true }))
                { WasCompilerGenerated = true };
            }

            GeneratedLabelSymbol loopLabel = new GeneratedLabelSymbol("loop");

            const int numTemps = 3;

            LocalSymbol[] tmps = new LocalSymbol[numTemps];
            BoundLocal[] boundTmps = new BoundLocal[numTemps];

            for (int i = 0; i < numTemps; i++)
            {
                tmps[i] = new SynthesizedLocal(accessor, delegateType, SynthesizedLocalKind.LoweringTemp);
                boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType);
            }

            BoundThisReference fieldReceiver = eventSymbol.IsStatic ?
                null :
                new BoundThisReference(syntax, thisParameter.Type) { WasCompilerGenerated = true };

            BoundFieldAccess boundBackingField = new BoundFieldAccess(syntax,
                receiver: fieldReceiver,
                fieldSymbol: eventSymbol.AssociatedField,
                constantValueOpt: null)
            { WasCompilerGenerated = true };

            BoundParameter boundParameter = new BoundParameter(syntax,
                parameterSymbol: accessor.Parameters[0])
            { WasCompilerGenerated = true };

            // tmp0 = _event;
            BoundStatement tmp0Init = new BoundExpressionStatement(syntax,
                expression: new BoundAssignmentOperator(syntax,
                    left: boundTmps[0],
                    right: boundBackingField,
                    type: delegateType)
            { WasCompilerGenerated = true })
            { WasCompilerGenerated = true };

            // LOOP:
            BoundStatement loopStart = new BoundLabelStatement(syntax,
                label: loopLabel)
            { WasCompilerGenerated = true };

            // tmp1 = tmp0;
            BoundStatement tmp1Update = new BoundExpressionStatement(syntax,
                expression: new BoundAssignmentOperator(syntax,
                    left: boundTmps[1],
                    right: boundTmps[0],
                    type: delegateType)
            { WasCompilerGenerated = true })
            { WasCompilerGenerated = true };

            // (DelegateType)Delegate.Combine(tmp1, value)
            BoundExpression delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax,
                operand: BoundCall.Synthesized(syntax,
                    receiverOpt: null,
                    method: updateMethod,
                    arguments: ImmutableArray.Create<BoundExpression>(boundTmps[1], boundParameter)),
                kind: ConversionKind.ExplicitReference,
                type: delegateType);

            // tmp2 = (DelegateType)Delegate.Combine(tmp1, value);
            BoundStatement tmp2Update = new BoundExpressionStatement(syntax,
                expression: new BoundAssignmentOperator(syntax,
                    left: boundTmps[2],
                    right: delegateUpdate,
                    type: delegateType)
            { WasCompilerGenerated = true })
            { WasCompilerGenerated = true };

            // Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1)
            BoundExpression compareExchange = BoundCall.Synthesized(syntax,
                receiverOpt: null,
                method: compareExchangeMethod,
                arguments: ImmutableArray.Create<BoundExpression>(boundBackingField, boundTmps[2], boundTmps[1]));

            // tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1);
            BoundStatement tmp0Update = new BoundExpressionStatement(syntax,
                expression: new BoundAssignmentOperator(syntax,
                    left: boundTmps[0],
                    right: compareExchange,
                    type: delegateType)
            { WasCompilerGenerated = true })
            { WasCompilerGenerated = true };

            // tmp0 == tmp1 // i.e. exit when they are equal, jump to start otherwise
            BoundExpression loopExitCondition = new BoundBinaryOperator(syntax,
                operatorKind: BinaryOperatorKind.ObjectEqual,
                left: boundTmps[0],
                right: boundTmps[1],
                constantValueOpt: null,
                methodOpt: null,
                resultKind: LookupResultKind.Viable,
                type: boolType)
            { WasCompilerGenerated = true };
            
            // branchfalse (tmp0 == tmp1) LOOP
            BoundStatement loopEnd = new BoundConditionalGoto(syntax,
                condition: loopExitCondition,
                jumpIfTrue: false,
                label: loopLabel)
            { WasCompilerGenerated = true };

            BoundStatement @return = new BoundReturnStatement(syntax,
                expressionOpt: null)
            { WasCompilerGenerated = true };

            return new BoundBlock(syntax,
                locals: tmps.AsImmutable(),
                statements: ImmutableArray.Create<BoundStatement>(
                    tmp0Init,
                    loopStart,
                    tmp1Update,
                    tmp2Update,
                    tmp0Update,
                    loopEnd,
                    @return))
            { WasCompilerGenerated = true };

        }
Пример #9
0
        private BoundExpression HoistRefInitialization(SynthesizedLocal local, BoundAssignmentOperator node)
        {
            Debug.Assert(local.SynthesizedKind == SynthesizedLocalKind.AwaitSpill);
            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();

            AwaitExpressionSyntax awaitSyntaxOpt;
            int syntaxOffset;
            if (F.Compilation.Options.OptimizationLevel == OptimizationLevel.Debug)
            {
                awaitSyntaxOpt = (AwaitExpressionSyntax)local.GetDeclaratorSyntax();
                syntaxOffset = this.OriginalMethod.CalculateLocalSyntaxOffset(awaitSyntaxOpt.SpanStart, 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, true, 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(type == replacement.Type);
                return F.Sequence(ImmutableArray.Create(sacrificialTemp), sideEffects.ToImmutableAndFree(), F.AssignmentExpression(F.Local(sacrificialTemp), replacement, refKind: RefKind.Ref));
            }

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

            var last = sideEffects.Last();
            sideEffects.RemoveLast();
            return F.Sequence(ImmutableArray<LocalSymbol>.Empty, sideEffects.ToImmutableAndFree(), last);
        }
Пример #10
0
        private bool TryRewriteLocal(LocalSymbol local, out LocalSymbol newLocal)
        {
            if (VariablesCaptured.Contains(local))
            {
                // no longer a local symbol
                newLocal = null;
                return false;
            }

            if (localMap.TryGetValue(local, out newLocal))
            {
                return true;
            }

            var newType = VisitType(local.Type);
            if (newType == local.Type)
            {
                newLocal = local;
            }
            else
            {
                newLocal = new SynthesizedLocal(CurrentMethod, newType, local.Name);
                localMap.Add(local, newLocal);
            }

            return true;
        }
Пример #11
0
        private DecisionTree AddByType(DecisionTree.ByType byType, TypeSymbol type, DecisionMaker makeDecision)
        {
            if (byType.Default != null)
            {
                try
                {
                    return AddByType(byType.Default, type, makeDecision);
                }
                finally
                {
                    if (byType.Default.MatchIsComplete)
                    {
                        byType.MatchIsComplete = true;
                    }
                }
            }
            foreach (var kvp in byType.TypeAndDecision)
            {
                var MatchedType = kvp.Key;
                var Decision = kvp.Value;
                // See if matching Type matches this value
                switch (ExpressionOfTypeMatchesPatternType(type, MatchedType, ref _useSiteDiagnostics))
                {
                    case true:
                        if (Decision.MatchIsComplete)
                        {
                            return null;
                        }

                        continue;
                    case false:
                        continue;
                    case null:
                        continue;
                }
            }

            var localSymbol = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatchingTemp, Syntax, false, RefKind.None);
            var expression = new BoundLocal(Syntax, localSymbol, null, type);
            var result = makeDecision(expression, type);
            Debug.Assert(result.Temp == null);
            result.Temp = localSymbol;
            byType.TypeAndDecision.Add(new KeyValuePair<TypeSymbol, DecisionTree>(type, result));
            if (ExpressionOfTypeMatchesPatternType(byType.Type, type, ref _useSiteDiagnostics) == true &&
                result.MatchIsComplete &&
                byType.WhenNull?.MatchIsComplete == true)
            {
                byType.MatchIsComplete = true;
            }

            return result;
        }
Пример #12
0
        private DecisionTree AddByValue(DecisionTree.ByType byType, BoundConstantPattern value, DecisionMaker makeDecision)
        {
            if (byType.Default != null)
            {
                try
                {
                    return AddByValue(byType.Default, value, makeDecision);
                }
                finally
                {
                    if (byType.Default.MatchIsComplete)
                    {
                        byType.MatchIsComplete = true;
                    }
                }
            }

            if (value.ConstantValue == ConstantValue.Null)
            {
                return byType.Expression.ConstantValue?.IsNull == false
                    ? null : AddByNull((DecisionTree)byType, makeDecision);
            }

            foreach (var kvp in byType.TypeAndDecision)
            {
                var matchedType = kvp.Key;
                var decision = kvp.Value;

                // See if the test is already subsumed
                switch (ExpressionOfTypeMatchesPatternType(value.Value.Type, matchedType, ref _useSiteDiagnostics))
                {
                    case true:
                        if (decision.MatchIsComplete)
                        {
                            return null;
                        }

                        continue;
                    case false:
                    case null:
                        continue;
                }
            }

            DecisionTree forType = null;

            // Find an existing decision tree for the expression's type. Since this new test
            // should logically be last, we look for the last one we can piggy-back it onto.
            for (int i = byType.TypeAndDecision.Count - 1; i >= 0 && forType == null; i--)
            {
                var kvp = byType.TypeAndDecision[i];
                var matchedType = kvp.Key;
                var decision = kvp.Value;
                if (matchedType.TupleUnderlyingTypeOrSelf() == value.Value.Type.TupleUnderlyingTypeOrSelf())
                {
                    forType = decision;
                    break;
                }
                else if (ExpressionOfTypeMatchesPatternType(value.Value.Type, matchedType, ref _useSiteDiagnostics) != false)
                {
                    break;
                }
            }

            if (forType == null)
            {
                var type = value.Value.Type;
                var localSymbol = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatchingTemp, Syntax, false, RefKind.None);
                var narrowedExpression = new BoundLocal(Syntax, localSymbol, null, type);
                forType = new DecisionTree.ByValue(narrowedExpression, value.Value.Type.TupleUnderlyingTypeOrSelf(), localSymbol);
                byType.TypeAndDecision.Add(new KeyValuePair<TypeSymbol, DecisionTree>(value.Value.Type, forType));
            }

            return AddByValue(forType, value, makeDecision);
        }
Пример #13
0
        internal BoundLocal MakeTempForDiscard(BoundDiscardedExpression node, out LocalSymbol temp)
        {
            temp = new SynthesizedLocal(this.CurrentMethod, node.Type, SynthesizedLocalKind.LoweringTemp);

            return new BoundLocal(node.Syntax, temp, constantValueOpt: null, type: node.Type) { WasCompilerGenerated = true };
        }
        // Generates:
        // 
        // private static T {Factory}(InteractiveSession session) 
        // {
        //    T submissionResult;
        //    new {ThisScriptClass}(session, out submissionResult);
        //    return submissionResult;
        // }
        private BoundBlock CreateSubmissionFactoryBody()
        {
            Debug.Assert(_containingType.TypeKind == TypeKind.Submission);

            SyntaxTree syntaxTree = CSharpSyntaxTree.Dummy;
            CSharpSyntaxNode syntax = (CSharpSyntaxNode)syntaxTree.GetRoot();

            var interactiveSessionParam = new BoundParameter(syntax, _parameters[0]) { WasCompilerGenerated = true };

            var ctor = _containingType.InstanceConstructors.Single();
            Debug.Assert(ctor is SynthesizedInstanceConstructor);
            Debug.Assert(ctor.ParameterCount == 2);

            var submissionResultType = ctor.Parameters[1].Type;

            var resultLocal = new SynthesizedLocal(ctor, submissionResultType, SynthesizedLocalKind.LoweringTemp);
            var localReference = new BoundLocal(syntax, resultLocal, null, submissionResultType) { WasCompilerGenerated = true };

            BoundExpression submissionResult = localReference;
            if (submissionResultType.IsStructType() && _returnType.SpecialType == SpecialType.System_Object)
            {
                submissionResult = new BoundConversion(syntax, submissionResult, Conversion.Boxing, false, true, ConstantValue.NotAvailable, _returnType)
                { WasCompilerGenerated = true };
            }

            return new BoundBlock(syntax,
                // T submissionResult;
                ImmutableArray.Create<LocalSymbol>(resultLocal),
                ImmutableArray.Create<BoundStatement>(
                    // new Submission(interactiveSession, out submissionResult);
                    new BoundExpressionStatement(syntax,
                        new BoundObjectCreationExpression(
                            syntax,
                            ctor,
                            ImmutableArray.Create<BoundExpression>(interactiveSessionParam, localReference),
                            ImmutableArray<string>.Empty,
                            ImmutableArray.Create<RefKind>(RefKind.None, RefKind.Ref),
                            false,
                            default(ImmutableArray<int>),
                            null,
                            null,
                            _containingType
                        )
                        { WasCompilerGenerated = true })
                    { WasCompilerGenerated = true },
                    // return submissionResult;
                    new BoundReturnStatement(syntax, submissionResult) { WasCompilerGenerated = true }))
            { WasCompilerGenerated = true };
        }
Пример #15
0
        internal DecisionTree ComputeDecisionTree()
        {
            Debug.Assert(_section == null);
            var expression = _switchStatement.Expression;
            if (expression.ConstantValue == null && expression.Kind != BoundKind.Local)
            {
                // unless the expression is simple enough, copy it into a local
                var localSymbol = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, expression.Type, SynthesizedLocalKind.PatternMatchingTemp, _switchStatement.Syntax, false, RefKind.None);
                expression = new BoundLocal(expression.Syntax, localSymbol, null, expression.Type);
            }

            var result = DecisionTree.Create(_switchStatement.Expression, _switchStatement.Expression.Type, _enclosingSymbol);
            BoundPatternSwitchLabel defaultLabel = null;
            BoundPatternSwitchSection defaultSection = null;
            foreach (var section in _switchStatement.SwitchSections)
            {
                this._section = section;
                foreach (var label in section.SwitchLabels)
                {
                    if (label.Syntax.Kind() == SyntaxKind.DefaultSwitchLabel)
                    {
                        if (defaultLabel != null)
                        {
                            // duplicate switch label will have been reported during initial binding.
                        }
                        else
                        {
                            defaultLabel = label;
                            defaultSection = section;
                        }
                    }
                    else
                    {
                        this._syntax = label.Syntax;
                        // For purposes of subsumption, we do not take into consideration the value
                        // of the input expression. Therefore we consider null possible if the type permits.
                        var subsumedErrorCode = CheckSubsumed(label.Pattern, result, inputCouldBeNull: true);
                        if (subsumedErrorCode != 0 && subsumedErrorCode != ErrorCode.ERR_NoImplicitConvCast)
                        {
                            if (!label.HasErrors)
                            {
                                _diagnostics.Add(subsumedErrorCode, label.Pattern.Syntax.Location);
                            }
                        }
                        else
                        {
                            AddToDecisionTree(result, label);
                        }
                    }
                }
            }

            if (defaultLabel != null)
            {
                Add(result, (e, t) => new DecisionTree.Guarded(_switchStatement.Expression, _switchStatement.Expression.Type, default(ImmutableArray<KeyValuePair<BoundExpression, LocalSymbol>>), defaultSection, null, defaultLabel));
            }

            return result;
        }
        // Generates:
        //
        // private static T {Factory}(InteractiveSession session)
        // {
        //    T submissionResult;
        //    new {ThisScriptClass}(session, out submissionResult);
        //    return submissionResult;
        // }
        private BoundBlock CreateSubmissionFactoryBody()
        {
            Debug.Assert(_containingType.TypeKind == TypeKind.Submission);

            SyntaxTree       syntaxTree = CSharpSyntaxTree.Dummy;
            CSharpSyntaxNode syntax     = (CSharpSyntaxNode)syntaxTree.GetRoot();

            var interactiveSessionParam = new BoundParameter(syntax, _parameters[0])
            {
                WasCompilerGenerated = true
            };

            var ctor = _containingType.InstanceConstructors.Single();

            Debug.Assert(ctor is SynthesizedInstanceConstructor);
            Debug.Assert(ctor.ParameterCount == 2);

            var submissionResultType = ctor.Parameters[1].Type;

            var resultLocal    = new SynthesizedLocal(ctor, submissionResultType, SynthesizedLocalKind.LoweringTemp);
            var localReference = new BoundLocal(syntax, resultLocal, null, submissionResultType)
            {
                WasCompilerGenerated = true
            };

            BoundExpression submissionResult = localReference;

            if (submissionResultType.IsStructType() && _returnType.SpecialType == SpecialType.System_Object)
            {
                submissionResult = new BoundConversion(syntax, submissionResult, Conversion.Boxing, false, true, ConstantValue.NotAvailable, _returnType)
                {
                    WasCompilerGenerated = true
                };
            }

            return(new BoundBlock(syntax,
                                  // T submissionResult;
                                  ImmutableArray.Create <LocalSymbol>(resultLocal),
                                  ImmutableArray.Create <BoundStatement>(
                                      // new Submission(interactiveSession, out submissionResult);
                                      new BoundExpressionStatement(syntax,
                                                                   new BoundObjectCreationExpression(
                                                                       syntax,
                                                                       ctor,
                                                                       ImmutableArray.Create <BoundExpression>(interactiveSessionParam, localReference),
                                                                       ImmutableArray <string> .Empty,
                                                                       ImmutableArray.Create <RefKind>(RefKind.None, RefKind.Ref),
                                                                       false,
                                                                       default(ImmutableArray <int>),
                                                                       null,
                                                                       null,
                                                                       _containingType
                                                                       )
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            },
                                      // return submissionResult;
                                      new BoundReturnStatement(syntax, submissionResult)
            {
                WasCompilerGenerated = true
            }))
            {
                WasCompilerGenerated = true
            });
        }