Skip to content

Commit 58db000

Browse files
committed
Improve nullable analysis of local functions
This design tries to meld better analysis of nullable reference types in local functions with performance. To keep the common case one pass, local functions are analyzed using the starting state that is an intersection of all the states before its usages (calls, delegate conversions, etc), but the results of variables made nullable or non-nullable inside the local function do not propagate to the callers.
1 parent 0b8a8c0 commit 58db000

File tree

6 files changed

+281
-76
lines changed

6 files changed

+281
-76
lines changed

src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ protected AbstractFlowPass(
200200
this.Diagnostics = DiagnosticBag.GetInstance();
201201
this.compilation = compilation;
202202
_symbol = symbol;
203+
CurrentSymbol = symbol;
203204
this.methodMainNode = node;
204205
this.firstInRegion = firstInRegion;
205206
this.lastInRegion = lastInRegion;
@@ -1167,11 +1168,10 @@ public override BoundNode VisitCall(BoundCall node)
11671168
return null;
11681169
}
11691170

1170-
private void VisitLocalFunctionUse(LocalFunctionSymbol symbol, SyntaxNode syntax, bool isCall)
1171+
protected void VisitLocalFunctionUse(LocalFunctionSymbol symbol, SyntaxNode syntax, bool isCall)
11711172
{
11721173
var localFuncState = GetOrCreateLocalFuncUsages(symbol);
11731174
VisitLocalFunctionUse(symbol, localFuncState, syntax, isCall);
1174-
localFuncState.Visited = true;
11751175
}
11761176

11771177
protected virtual void VisitLocalFunctionUse(
@@ -1185,6 +1185,7 @@ protected virtual void VisitLocalFunctionUse(
11851185
Join(ref State, ref localFunctionState.StateFromBottom);
11861186
Meet(ref State, ref localFunctionState.StateFromTop);
11871187
}
1188+
localFunctionState.Visited = true;
11881189
}
11891190

11901191
private void VisitReceiverBeforeCall(BoundExpression receiverOpt, MethodSymbol method)

src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.LocalFunctions.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,6 @@ private void CheckIfAssignedDuringLocalFunctionReplay(Symbol symbol, SyntaxNode
7777
}
7878
}
7979

80-
private int RootSlot(int slot)
81-
{
82-
while (true)
83-
{
84-
var varInfo = variableBySlot[slot];
85-
if (varInfo.ContainingSlot == 0)
86-
{
87-
return slot;
88-
}
89-
else
90-
{
91-
slot = varInfo.ContainingSlot;
92-
}
93-
}
94-
}
95-
9680
private void RecordReadInLocalFunction(int slot)
9781
{
9882
var localFunc = GetNearestLocalFunctionOpt(CurrentSymbol);

src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ internal DefiniteAssignmentPass(
132132
{
133133
this.initiallyAssignedVariables = null;
134134
_sourceAssembly = ((object)member == null) ? null : (SourceAssemblySymbol)member.ContainingAssembly;
135-
this.CurrentSymbol = member;
136135
_unassignedVariableAddressOfSyntaxes = unassignedVariableAddressOfSyntaxes;
137136
_requireOutParamsAssigned = requireOutParamsAssigned;
138137
_trackClassFields = trackClassFields;

src/Compilers/CSharp/Portable/FlowAnalysis/LocalDataFlowPass.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,5 +286,21 @@ protected int MakeMemberSlot(BoundExpression receiverOpt, Symbol member)
286286
}
287287
return GetOrCreateSlot(member, containingSlot);
288288
}
289+
290+
protected int RootSlot(int slot)
291+
{
292+
while (true)
293+
{
294+
ref var varInfo = ref variableBySlot[slot];
295+
if (varInfo.ContainingSlot == 0)
296+
{
297+
return slot;
298+
}
299+
else
300+
{
301+
slot = varInfo.ContainingSlot;
302+
}
303+
}
304+
}
289305
}
290306
}

0 commit comments

Comments
 (0)