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<DelegateType>(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 }; }
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); }
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; }
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; }
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); }
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 }; }
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 }); }