Skip to content

Commit

Permalink
Merge pull request #31149 from dotnet/merges/dev16.0-preview2-to-dev1…
Browse files Browse the repository at this point in the history
…6.0-preview2-vs-deps

Merge dev16.0-preview2 to dev16.0-preview2-vs-deps
  • Loading branch information
dotnet-automerge-bot authored Nov 13, 2018
2 parents 712f3bf + 69e0571 commit cb7682d
Show file tree
Hide file tree
Showing 11 changed files with 2,228 additions and 397 deletions.
20 changes: 15 additions & 5 deletions src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,27 +176,37 @@ internal override TypeSymbol GetIteratorElementType(YieldStatementSyntax node, D
}

private TypeSymbol GetIteratorElementTypeFromReturnType(RefKind refKind, TypeSymbol returnType, CSharpSyntaxNode errorLocationNode, DiagnosticBag diagnostics)
{
return GetIteratorElementTypeFromReturnType(Compilation, refKind, returnType, errorLocationNode, diagnostics).TypeSymbol;
}

internal static TypeSymbolWithAnnotations GetIteratorElementTypeFromReturnType(CSharpCompilation compilation, RefKind refKind, TypeSymbol returnType, CSharpSyntaxNode errorLocationNode, DiagnosticBag diagnostics)
{
if (refKind == RefKind.None && returnType.Kind == SymbolKind.NamedType)
{
switch (returnType.OriginalDefinition.SpecialType)
{
case SpecialType.System_Collections_IEnumerable:
case SpecialType.System_Collections_IEnumerator:
return GetSpecialType(SpecialType.System_Object, diagnostics, errorLocationNode);
var objectType = compilation.GetSpecialType(SpecialType.System_Object);
if (diagnostics != null)
{
ReportUseSiteDiagnostics(objectType, diagnostics, errorLocationNode);
}
return TypeSymbolWithAnnotations.Create(objectType);

case SpecialType.System_Collections_Generic_IEnumerable_T:
case SpecialType.System_Collections_Generic_IEnumerator_T:
return ((NamedTypeSymbol)returnType).TypeArgumentsNoUseSiteDiagnostics[0].TypeSymbol;
return ((NamedTypeSymbol)returnType).TypeArgumentsNoUseSiteDiagnostics[0];
}

if (returnType.OriginalDefinition == Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T))
if (returnType.OriginalDefinition == compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T))
{
return ((NamedTypeSymbol)returnType).TypeArgumentsNoUseSiteDiagnostics[0].TypeSymbol;
return ((NamedTypeSymbol)returnType).TypeArgumentsNoUseSiteDiagnostics[0];
}
}

return null;
return default;
}

internal override void LookupSymbolsInSingleBinder(
Expand Down
106 changes: 98 additions & 8 deletions src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.CSharp
internal abstract partial class AbstractFlowPass<TLocalState> : PreciseAbstractFlowPass<TLocalState>
where TLocalState : PreciseAbstractFlowPass<TLocalState>.AbstractLocalState
{
protected readonly bool trackUnassignments; // for the data flows out walker, we track unassignments as well as assignments
private readonly bool _trackUnassignments; // for the data flows out walker, we track unassignments as well as assignments

protected AbstractFlowPass(
CSharpCompilation compilation,
Expand All @@ -26,7 +26,7 @@ protected AbstractFlowPass(
bool trackUnassignments = false)
: base(compilation, member, node)
{
this.trackUnassignments = trackUnassignments;
this._trackUnassignments = trackUnassignments;
}

protected AbstractFlowPass(
Expand All @@ -39,11 +39,25 @@ protected AbstractFlowPass(
bool trackUnassignments = false)
: base(compilation, member, node, firstInRegion, lastInRegion, trackRegions)
{
this.trackUnassignments = trackUnassignments;
this._trackUnassignments = trackUnassignments;
}

protected abstract void UnionWith(ref TLocalState self, ref TLocalState other);

/// <summary>
/// Nontrivial implementation is required for DataFlowsOutWalker or any flow analysis pass that "tracks
/// unassignments" like the nullable walker. The result should be a state, for each variable, that is
/// the strongest result possible (i.e. definitely assigned for the data flow passes, or not null for
/// the nullable analysis). Slightly more formally, this should be a reachable state that won't affect
/// another reachable state when this is intersected with the other state.
/// </summary>
protected virtual TLocalState AllBitsSet()
{
return default(TLocalState);
}

#region TryStatements

public override BoundNode VisitTryStatement(BoundTryStatement node)
{
var oldPending = SavePending(); // we do not allow branches into a try statement
Expand All @@ -52,13 +66,13 @@ public override BoundNode VisitTryStatement(BoundTryStatement node)
// use this state to resolve all the branches introduced and internal to try/catch
var pendingBeforeTry = SavePending();

VisitTryBlock(node.TryBlock, node, ref initialState);
VisitTryBlockWithUnassignments(node.TryBlock, node, ref initialState);
var finallyState = initialState.Clone();
var endState = this.State;
foreach (var catchBlock in node.CatchBlocks)
{
SetState(initialState.Clone());
VisitCatchBlock(catchBlock, ref finallyState);
VisitCatchBlockWithUnassignments(catchBlock, ref finallyState);
IntersectWith(ref endState, ref this.State);
}

Expand All @@ -84,27 +98,101 @@ public override BoundNode VisitTryStatement(BoundTryStatement node)
// we will need pending branches as they were before finally later
var tryAndCatchPending = SavePending();
var unsetInFinally = AllBitsSet();
VisitFinallyBlock(node.FinallyBlockOpt, ref unsetInFinally);
VisitFinallyBlockWithUnassignments(node.FinallyBlockOpt, ref unsetInFinally);
foreach (var pend in tryAndCatchPending.PendingBranches)
{
if (pend.Branch == null) continue; // a tracked exception
if (pend.Branch.Kind != BoundKind.YieldReturnStatement)
{
UnionWith(ref pend.State, ref this.State);
if (trackUnassignments) IntersectWith(ref pend.State, ref unsetInFinally);
if (_trackUnassignments) IntersectWith(ref pend.State, ref unsetInFinally);
}
}

RestorePending(tryAndCatchPending);
UnionWith(ref endState, ref this.State);
if (trackUnassignments) IntersectWith(ref endState, ref unsetInFinally);
if (_trackUnassignments) IntersectWith(ref endState, ref unsetInFinally);
}

SetState(endState);
RestorePending(oldPending);
return null;
}

protected Optional<TLocalState> _tryState;

private void VisitTryBlockWithUnassignments(BoundStatement tryBlock, BoundTryStatement node, ref TLocalState tryState)
{
if (_trackUnassignments)
{
Optional<TLocalState> oldTryState = _tryState;
_tryState = AllBitsSet();
VisitTryBlock(tryBlock, node, ref tryState);
var tempTryStateValue = _tryState.Value;
IntersectWith(ref tryState, ref tempTryStateValue);
if (oldTryState.HasValue)
{
var oldTryStateValue = oldTryState.Value;
IntersectWith(ref oldTryStateValue, ref tempTryStateValue);
oldTryState = oldTryStateValue;
}

_tryState = oldTryState;
}
else
{
VisitTryBlock(tryBlock, node, ref tryState);
}
}

private void VisitCatchBlockWithUnassignments(BoundCatchBlock catchBlock, ref TLocalState finallyState)
{
if (_trackUnassignments)
{
Optional<TLocalState> oldTryState = _tryState;
_tryState = AllBitsSet();
VisitCatchBlock(catchBlock, ref finallyState);
var tempTryStateValue = _tryState.Value;
IntersectWith(ref finallyState, ref tempTryStateValue);
if (oldTryState.HasValue)
{
var oldTryStateValue = oldTryState.Value;
IntersectWith(ref oldTryStateValue, ref tempTryStateValue);
oldTryState = oldTryStateValue;
}

_tryState = oldTryState;
}
else
{
VisitCatchBlock(catchBlock, ref finallyState);
}
}

private void VisitFinallyBlockWithUnassignments(BoundStatement finallyBlock, ref TLocalState unsetInFinally)
{
if (_trackUnassignments)
{
Optional<TLocalState> oldTryState = _tryState;
_tryState = AllBitsSet();
VisitFinallyBlock(finallyBlock, ref unsetInFinally);
var tempTryStateValue = _tryState.Value;
IntersectWith(ref unsetInFinally, ref tempTryStateValue);
if (oldTryState.HasValue)
{
var oldTryStateValue = oldTryState.Value;
IntersectWith(ref oldTryStateValue, ref tempTryStateValue);
oldTryState = oldTryStateValue;
}

_tryState = oldTryState;
}
else
{
VisitFinallyBlock(finallyBlock, ref unsetInFinally);
}
}

protected virtual void VisitTryBlock(BoundStatement tryBlock, BoundTryStatement node, ref TLocalState tryState)
{
VisitStatement(tryBlock);
Expand All @@ -130,5 +218,7 @@ protected virtual void VisitFinallyBlock(BoundStatement finallyBlock, ref TLocal
{
VisitStatement(finallyBlock); // this should generate no pending branches
}

#endregion TryStatements
}
}
83 changes: 1 addition & 82 deletions src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,6 @@

namespace Microsoft.CodeAnalysis.CSharp
{
#if REFERENCE_STATE
using OptionalState = Optional<DataFlowPass.LocalState>;
#else
using OptionalState = Nullable<DataFlowPass.LocalState>;
#endif

/// <summary>
/// Implement C# data flow analysis (definite assignment).
/// </summary>
Expand Down Expand Up @@ -1332,7 +1326,7 @@ protected override LocalState ReachableState()
protected override LocalState AllBitsSet()
{
var result = new LocalState(BitVector.AllSet(nextVariableSlot));
result.Assigned[0] = false;
result.Assigned[0] = false; // make the state reachable
return result;
}

Expand Down Expand Up @@ -1952,56 +1946,7 @@ public override BoundNode VisitBaseReference(BoundBaseReference node)
return null;
}

#region TryStatements
private OptionalState _tryState;

protected override void VisitTryBlock(BoundStatement tryBlock, BoundTryStatement node, ref LocalState tryState)
{
if (trackUnassignments)
{
OptionalState oldTryState = _tryState;
_tryState = AllBitsSet();
base.VisitTryBlock(tryBlock, node, ref tryState);
var tts = _tryState.Value;
IntersectWith(ref tryState, ref tts);
if (oldTryState.HasValue)
{
var ots = oldTryState.Value;
IntersectWith(ref ots, ref tts);
oldTryState = ots;
}
_tryState = oldTryState;
}
else
{
base.VisitTryBlock(tryBlock, node, ref tryState);
}
}

protected override void VisitCatchBlock(BoundCatchBlock catchBlock, ref LocalState finallyState)
{
if (trackUnassignments)
{
OptionalState oldTryState = _tryState;
_tryState = AllBitsSet();
VisitCatchBlockInternal(catchBlock, ref finallyState);
var tts = _tryState.Value;
IntersectWith(ref finallyState, ref tts);
if (oldTryState.HasValue)
{
var ots = oldTryState.Value;
IntersectWith(ref ots, ref tts);
oldTryState = ots;
}
_tryState = oldTryState;
}
else
{
VisitCatchBlockInternal(catchBlock, ref finallyState);
}
}

private void VisitCatchBlockInternal(BoundCatchBlock catchBlock, ref LocalState finallyState)
{
DeclareVariables(catchBlock.Locals);

Expand All @@ -2019,32 +1964,6 @@ private void VisitCatchBlockInternal(BoundCatchBlock catchBlock, ref LocalState
}
}

protected override void VisitFinallyBlock(BoundStatement finallyBlock, ref LocalState unsetInFinally)
{
if (trackUnassignments)
{
OptionalState oldTryState = _tryState;
_tryState = AllBitsSet();
base.VisitFinallyBlock(finallyBlock, ref unsetInFinally);
var tts = _tryState.Value;
IntersectWith(ref unsetInFinally, ref tts);
if (oldTryState.HasValue)
{
var ots = oldTryState.Value;
IntersectWith(ref ots, ref tts);
oldTryState = ots;
}

_tryState = oldTryState;
}
else
{
base.VisitFinallyBlock(finallyBlock, ref unsetInFinally);
}
}

#endregion TryStatements

public override BoundNode VisitFieldAccess(BoundFieldAccess node)
{
var result = base.VisitFieldAccess(node);
Expand Down
29 changes: 26 additions & 3 deletions src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ private NullableWalker(
ArrayBuilder<(RefKind, TypeSymbolWithAnnotations)> returnTypes,
VariableState initialState,
Action<BoundExpression, TypeSymbolWithAnnotations> callbackOpt)
: base(compilation, method, node, new EmptyStructTypeCache(compilation, dev12CompilerCompatibility: false), trackUnassignments: false)
: base(compilation, method, node, new EmptyStructTypeCache(compilation, dev12CompilerCompatibility: false), trackUnassignments: true)
{
_sourceAssembly = (method is null) ? null : (SourceAssemblySymbol)method.ContainingAssembly;
_callbackOpt = callbackOpt;
Expand Down Expand Up @@ -629,11 +629,18 @@ private void TrackNullableStateForAssignment(BoundExpression value, TypeSymbolWi
if (targetSlot >= this.State.Capacity) Normalize(ref this.State);

// https://github.com/dotnet/roslyn/issues/29968 Remove isByRefTarget check?
this.State[targetSlot] = isByRefTarget ?
var newState = isByRefTarget ?
// Since reference can point to the heap, we cannot assume the value is not null after this assignment,
// regardless of what value is being assigned.
(targetType.IsNullable == true) ? targetType.NullableAnnotation : NullableAnnotation.Unknown :
valueType.NullableAnnotation;
this.State[targetSlot] = newState;
if (newState.IsAnyNullable() && _tryState.HasValue)
{
var state = _tryState.Value;
state[targetSlot] = NullableAnnotation.NullableBasedOnAnalysis;
_tryState = state;
}

// https://github.com/dotnet/roslyn/issues/29968 Might this clear state that
// should be copied in InheritNullableStateOfTrackableType?
Expand Down Expand Up @@ -826,7 +833,10 @@ protected override LocalState UnreachableState()

protected override LocalState AllBitsSet()
{
return new LocalState(reachable: true, new ArrayBuilder<NullableAnnotation>(nextVariableSlot));
// Create a reachable state in which all variables are known to be non-null.
var builder = new ArrayBuilder<NullableAnnotation>(nextVariableSlot);
builder.AddMany(NullableAnnotation.NotNullableBasedOnAnalysis, nextVariableSlot);
return new LocalState(reachable: true, builder);
}

private void EnterParameters()
Expand Down Expand Up @@ -4592,6 +4602,19 @@ public override BoundNode VisitThrowExpression(BoundThrowExpression node)
return result;
}

public override BoundNode VisitYieldReturnStatement(BoundYieldReturnStatement node)
{
BoundExpression expr = node.Expression;
if (expr == null)
{
return null;
}
var method = (MethodSymbol)_member;
TypeSymbolWithAnnotations elementType = InMethodBinder.GetIteratorElementTypeFromReturnType(compilation, RefKind.None, method.ReturnType.TypeSymbol, errorLocationNode: null, diagnostics: null);
VisitOptionalImplicitConversion(expr, elementType, useLegacyWarnings: false, AssignmentKind.Return);
return null;
}

#endregion Visitors

protected override string Dump(LocalState state)
Expand Down
Loading

0 comments on commit cb7682d

Please sign in to comment.