private static BoundExpression ConvertToLocalTypeHelper(CSharpCompilation compilation, BoundExpression expr, TypeSymbol type, BindingDiagnosticBag diagnostics) { Debug.Assert(diagnostics.DiagnosticBag != null); // NOTE: This conversion can fail if some of the types involved are from not-yet-loaded modules. // For example, if System.Exception hasn't been loaded, then this call will fail for $stowedexception. var useSiteInfo = new CompoundUseSiteInfo <AssemblySymbol>(diagnostics, compilation.Assembly); var conversion = compilation.Conversions.ClassifyConversionFromExpression(expr, type, isChecked: false, ref useSiteInfo); diagnostics.Add(expr.Syntax, useSiteInfo); Debug.Assert(conversion.IsValid || diagnostics.HasAnyErrors()); return(BoundConversion.Synthesized( expr.Syntax, expr, conversion, @checked: false, explicitCastInCode: false, conversionGroupOpt: null, constantValueOpt: null, type: type, hasErrors: !conversion.IsValid)); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { ImmutableArray <LocalSymbol> declaredLocalsArray; var body = _generateMethodBody(this, diagnostics.DiagnosticBag, out declaredLocalsArray, out _lazyResultProperties); var compilation = compilationState.Compilation; _lazyReturnType = TypeWithAnnotations.Create(CalculateReturnType(compilation, body)); // Can't do this until the return type has been computed. TypeParameterChecker.Check(this, _allTypeParameters); if (diagnostics.HasAnyErrors()) { return; } DiagnosticsPass.IssueDiagnostics(compilation, body, diagnostics, this); if (diagnostics.HasAnyErrors()) { return; } // Check for use-site diagnostics (e.g. missing types in the signature). UseSiteInfo <AssemblySymbol> useSiteInfo = default; this.CalculateUseSiteDiagnostic(ref useSiteInfo); if (useSiteInfo.DiagnosticInfo != null && useSiteInfo.DiagnosticInfo.Severity == DiagnosticSeverity.Error) { diagnostics.Add(useSiteInfo.DiagnosticInfo, this.Locations[0]); return; } try { var declaredLocals = PooledHashSet <LocalSymbol> .GetInstance(); try { // Rewrite local declaration statement. body = (BoundStatement)LocalDeclarationRewriter.Rewrite( compilation, _container, declaredLocals, body, declaredLocalsArray, diagnostics.DiagnosticBag); // Verify local declaration names. foreach (var local in declaredLocals) { Debug.Assert(local.Locations.Length > 0); var name = local.Name; if (name.StartsWith("$", StringComparison.Ordinal)) { diagnostics.Add(ErrorCode.ERR_UnexpectedCharacter, local.Locations[0], name[0]); return; } } // Rewrite references to placeholder "locals". body = (BoundStatement)PlaceholderLocalRewriter.Rewrite(compilation, _container, declaredLocals, body, diagnostics.DiagnosticBag); if (diagnostics.HasAnyErrors()) { return; } } finally { declaredLocals.Free(); } var syntax = body.Syntax; var statementsBuilder = ArrayBuilder <BoundStatement> .GetInstance(); statementsBuilder.Add(body); // Insert an implicit return statement if necessary. if (body.Kind != BoundKind.ReturnStatement) { statementsBuilder.Add(new BoundReturnStatement(syntax, RefKind.None, expressionOpt: null, @checked: false)); } var localsSet = PooledHashSet <LocalSymbol> .GetInstance(); try { var localsBuilder = ArrayBuilder <LocalSymbol> .GetInstance(); foreach (var local in this.LocalsForBinding) { Debug.Assert(!localsSet.Contains(local)); localsBuilder.Add(local); localsSet.Add(local); } foreach (var local in this.Locals) { if (localsSet.Add(local)) { localsBuilder.Add(local); } } body = new BoundBlock(syntax, localsBuilder.ToImmutableAndFree(), statementsBuilder.ToImmutableAndFree()) { WasCompilerGenerated = true }; Debug.Assert(!diagnostics.HasAnyErrors()); Debug.Assert(!body.HasErrors); bool sawLambdas; bool sawLocalFunctions; bool sawAwaitInExceptionHandler; ImmutableArray <SourceSpan> dynamicAnalysisSpans = ImmutableArray <SourceSpan> .Empty; body = LocalRewriter.Rewrite( compilation: this.DeclaringCompilation, method: this, methodOrdinal: _methodOrdinal, containingType: _container, statement: body, compilationState: compilationState, previousSubmissionFields: null, allowOmissionOfConditionalCalls: false, instrumentForDynamicAnalysis: false, debugDocumentProvider: null, dynamicAnalysisSpans: ref dynamicAnalysisSpans, diagnostics: diagnostics, sawLambdas: out sawLambdas, sawLocalFunctions: out sawLocalFunctions, sawAwaitInExceptionHandler: out sawAwaitInExceptionHandler); Debug.Assert(!sawAwaitInExceptionHandler); Debug.Assert(dynamicAnalysisSpans.Length == 0); if (body.HasErrors) { return; } // Variables may have been captured by lambdas in the original method // or in the expression, and we need to preserve the existing values of // those variables in the expression. This requires rewriting the variables // in the expression based on the closure classes from both the original // method and the expression, and generating a preamble that copies // values into the expression closure classes. // // Consider the original method: // static void M() // { // int x, y, z; // ... // F(() => x + y); // } // and the expression in the EE: "F(() => x + z)". // // The expression is first rewritten using the closure class and local <1> // from the original method: F(() => <1>.x + z) // Then lambda rewriting introduces a new closure class that includes // the locals <1> and z, and a corresponding local <2>: F(() => <2>.<1>.x + <2>.z) // And a preamble is added to initialize the fields of <2>: // <2> = new <>c__DisplayClass0(); // <2>.<1> = <1>; // <2>.z = z; // Rewrite "this" and "base" references to parameter in this method. // Rewrite variables within body to reference existing display classes. body = (BoundStatement)CapturedVariableRewriter.Rewrite( this.GenerateThisReference, compilation.Conversions, _displayClassVariables, body, diagnostics.DiagnosticBag); if (body.HasErrors) { Debug.Assert(false, "Please add a test case capturing whatever caused this assert."); return; } if (diagnostics.HasAnyErrors()) { return; } if (sawLambdas || sawLocalFunctions) { var closureDebugInfoBuilder = ArrayBuilder <ClosureDebugInfo> .GetInstance(); var lambdaDebugInfoBuilder = ArrayBuilder <LambdaDebugInfo> .GetInstance(); body = ClosureConversion.Rewrite( loweredBody: body, thisType: this.SubstitutedSourceMethod.ContainingType, thisParameter: _thisParameter, method: this, methodOrdinal: _methodOrdinal, substitutedSourceMethod: this.SubstitutedSourceMethod.OriginalDefinition, closureDebugInfoBuilder: closureDebugInfoBuilder, lambdaDebugInfoBuilder: lambdaDebugInfoBuilder, slotAllocatorOpt: null, compilationState: compilationState, diagnostics: diagnostics, assignLocals: localsSet); // we don't need this information: closureDebugInfoBuilder.Free(); lambdaDebugInfoBuilder.Free(); } } finally { localsSet.Free(); } // Insert locals from the original method, // followed by any new locals. var block = (BoundBlock)body; var localBuilder = ArrayBuilder <LocalSymbol> .GetInstance(); foreach (var local in this.Locals) { Debug.Assert(!(local is EELocalSymbol) || (((EELocalSymbol)local).Ordinal == localBuilder.Count)); localBuilder.Add(local); } foreach (var local in block.Locals) { if (local is EELocalSymbol oldLocal) { Debug.Assert(localBuilder[oldLocal.Ordinal] == oldLocal); continue; } localBuilder.Add(local); } body = block.Update(localBuilder.ToImmutableAndFree(), block.LocalFunctions, block.Statements); TypeParameterChecker.Check(body, _allTypeParameters); compilationState.AddSynthesizedMethod(this, body); } catch (BoundTreeVisitor.CancelledByStackGuardException ex) { ex.AddAnError(diagnostics); } }