Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support SetsRequiredMembersAttribute #60392

Merged
merged 14 commits into from
Apr 15, 2022
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ internal struct ProcessedFieldInitializers
{
internal ImmutableArray<BoundInitializer> BoundInitializers { get; set; }
internal BoundStatement? LoweredInitializers { get; set; }
internal NullableWalker.VariableState AfterInitializersState;
internal bool HasErrors { get; set; }
internal ImportChain? FirstImportChain { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ protected override BoundNode RewriteNullableBoundNodesWithSnapshots(
out NullableWalker.SnapshotManager snapshotManager,
ref ImmutableDictionary<Symbol, Symbol> remappedSymbols)
{
var afterInitializersState = NullableWalker.GetAfterInitializersState(Compilation, MemberSymbol);
var afterInitializersState = NullableWalker.GetAfterInitializersState(Compilation, MemberSymbol, boundRoot);
return NullableWalker.AnalyzeAndRewrite(Compilation, MemberSymbol, boundRoot, binder, afterInitializersState, diagnostics, createSnapshots, out snapshotManager, ref remappedSymbols);
}

Expand Down
84 changes: 53 additions & 31 deletions src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ private void CompileNamedType(NamedTypeSymbol containingType)
useConstructorExitWarnings: true,
initialNullableState: null,
getFinalNullableState: false,
baseOrThisInitializer: null,
finalNullableState: out _);
}
}
Expand Down Expand Up @@ -1011,7 +1012,8 @@ private void CompileMethod(
useConstructorExitWarnings: false,
initialNullableState: null,
getFinalNullableState: true,
out processedInitializers.AfterInitializersState);
baseOrThisInitializer: null,
out _);
}

var unusedDiagnostics = DiagnosticBag.GetInstance();
Expand All @@ -1031,28 +1033,12 @@ private void CompileMethod(
processedInitializers.HasErrors = processedInitializers.HasErrors || analyzedInitializers.HasAnyErrors;
}

if (includeInitializersInBody &&
processedInitializers.AfterInitializersState is null &&
ReportNullableDiagnostics)
{
NullableWalker.AnalyzeIfNeeded(
_compilation,
methodSymbol,
// we analyze to produce an AfterInitializersState even if there are no initializers
// because it conveniently allows us to capture all the 'default' states for applicable members
analyzedInitializers ?? GetSynthesizedEmptyBody(methodSymbol),
diagsForCurrentMethod.DiagnosticBag,
useConstructorExitWarnings: false,
initialNullableState: null,
getFinalNullableState: true,
out processedInitializers.AfterInitializersState);
}

body = BindMethodBody(
methodSymbol,
compilationState,
diagsForCurrentMethod,
processedInitializers.AfterInitializersState,
includeInitializersInBody,
analyzedInitializers,
ReportNullableDiagnostics,
includesFieldInitializers: includeInitializersInBody && !processedInitializers.BoundInitializers.IsEmpty,
out importChain,
Expand Down Expand Up @@ -1702,32 +1688,48 @@ private static void GetStateMachineSlotDebugInfo(
}

// NOTE: can return null if the method has no body.
internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics)
#nullable enable
internal static BoundBlock? BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics)
{
return BindMethodBody(method, compilationState, diagnostics, nullableInitialState: null, reportNullableDiagnostics: true, includesFieldInitializers: false, out _, out _, out _);
return BindMethodBody(
method,
compilationState,
diagnostics,
includeInitializersInBody: false,
initializersBody: null,
reportNullableDiagnostics: true,
includesFieldInitializers: false,
importChain: out _,
originalBodyNested: out _,
forSemanticModel: out _);
}

// NOTE: can return null if the method has no body.
private static BoundBlock BindMethodBody(
private static BoundBlock? BindMethodBody(
MethodSymbol method,
TypeCompilationState compilationState,
BindingDiagnosticBag diagnostics,
NullableWalker.VariableState nullableInitialState,
bool includeInitializersInBody,
BoundNode? initializersBody,
bool reportNullableDiagnostics,
bool includesFieldInitializers,
out ImportChain importChain,
out ImportChain? importChain,
out bool originalBodyNested,
out MethodBodySemanticModel.InitialState forSemanticModel)
{
originalBodyNested = false;
importChain = null;
forSemanticModel = default;

BoundBlock body;
BoundBlock? body;
NullableWalker.VariableState? nullableInitialState = null;

initializersBody ??= GetSynthesizedEmptyBody(method);

if (method is SynthesizedRecordConstructor recordStructPrimaryCtor && method.ContainingType.IsRecordStruct)
{
body = BoundBlock.SynthesizedNoLocals(recordStructPrimaryCtor.GetSyntax());
nullableInitialState = getInitializerState(body);
}
else if (method is SourceMemberMethodSymbol sourceMethod)
{
Expand Down Expand Up @@ -1756,12 +1758,15 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax &&
importChain = bodyBinder.ImportChain;
BoundNode methodBody = bodyBinder.BindMethodBody(syntaxNode, diagnostics, includesFieldInitializers);
BoundNode methodBodyForSemanticModel = methodBody;
NullableWalker.SnapshotManager snapshotManager = null;
ImmutableDictionary<Symbol, Symbol> remappedSymbols = null;
NullableWalker.SnapshotManager? snapshotManager = null;
ImmutableDictionary<Symbol, Symbol>? remappedSymbols = null;
var compilation = bodyBinder.Compilation;

nullableInitialState = getInitializerState(methodBody);

if (reportNullableDiagnostics)
{
Debug.Assert(diagnostics.DiagnosticBag != null);
if (compilation.IsNullableAnalysisEnabledIn(method))
{
var isSufficientLangVersion = compilation.LanguageVersion >= MessageID.IDS_FeatureNullableReferenceTypes.RequiredVersion();
Expand Down Expand Up @@ -1789,17 +1794,18 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax &&
useConstructorExitWarnings: true,
nullableInitialState,
getFinalNullableState: false,
baseOrThisInitializer: null,
finalNullableState: out _);
}
}

forSemanticModel = new MethodBodySemanticModel.InitialState(syntaxNode, methodBodyForSemanticModel, bodyBinder, snapshotManager, remappedSymbols);

switch (methodBody.Kind)
{
case BoundKind.ConstructorMethodBody:
var constructor = (BoundConstructorMethodBody)methodBody;
body = constructor.BlockBody ?? constructor.ExpressionBody;
body = constructor.BlockBody ?? constructor.ExpressionBody!;
Debug.Assert(body != null);

if (constructor.Initializer is BoundNoOpStatement)
{
Expand Down Expand Up @@ -1832,7 +1838,8 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax &&

case BoundKind.NonConstructorMethodBody:
var nonConstructor = (BoundNonConstructorMethodBody)methodBody;
body = nonConstructor.BlockBody ?? nonConstructor.ExpressionBody;
body = nonConstructor.BlockBody ?? nonConstructor.ExpressionBody!;
Debug.Assert(body != null);
break;

case BoundKind.Block:
Expand All @@ -1845,7 +1852,7 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax &&
else
{
var property = sourceMethod.AssociatedSymbol as SourcePropertySymbolBase;
if ((object)property != null && property.IsAutoPropertyWithGetAccessor)
if (property is not null && property.IsAutoPropertyWithGetAccessor)
{
return MethodBodySynthesizer.ConstructAutoPropertyAccessorBody(sourceMethod);
}
Expand All @@ -1862,15 +1869,18 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax &&
var stmts = ArrayBuilder<BoundStatement>.GetInstance();
ctor.GenerateMethodBodyStatements(factory, stmts, diagnostics);
body = BoundBlock.SynthesizedNoLocals(node, stmts.ToImmutableAndFree());
nullableInitialState = getInitializerState(body);
}
else
{
// synthesized methods should return their bound bodies
body = null;
nullableInitialState = getInitializerState(null);
}

if (reportNullableDiagnostics && method.IsConstructor() && method.IsImplicitlyDeclared && nullableInitialState is object)
{
Debug.Assert(diagnostics.AccumulatesDiagnostics);
NullableWalker.AnalyzeIfNeeded(
compilationState.Compilation,
method,
Expand All @@ -1879,6 +1889,7 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax &&
useConstructorExitWarnings: true,
nullableInitialState,
getFinalNullableState: false,
baseOrThisInitializer: null,
finalNullableState: out _);
}

Expand Down Expand Up @@ -1910,7 +1921,18 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax &&
}

return BoundBlock.SynthesizedNoLocals(method.GetNonNullSyntaxNode(), statements);

NullableWalker.VariableState? getInitializerState(BoundNode? body)
{
if (reportNullableDiagnostics && includeInitializersInBody)
{
return NullableWalker.GetAfterInitializersState(compilationState.Compilation, method, initializersBody, body, diagnostics);
}

return null;
}
}
#nullable disable

private static BoundBlock GetSynthesizedEmptyBody(Symbol symbol)
{
Expand Down
Loading