diff --git a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs index fee66db548649..6a76ef8c943d8 100644 --- a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs @@ -176,6 +176,11 @@ 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) { @@ -183,20 +188,25 @@ private TypeSymbol GetIteratorElementTypeFromReturnType(RefKind refKind, TypeSym { 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( diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index ca1d5883039a1..a61011ee3209e 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.CSharp internal abstract partial class AbstractFlowPass : PreciseAbstractFlowPass where TLocalState : PreciseAbstractFlowPass.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, @@ -26,7 +26,7 @@ protected AbstractFlowPass( bool trackUnassignments = false) : base(compilation, member, node) { - this.trackUnassignments = trackUnassignments; + this._trackUnassignments = trackUnassignments; } protected AbstractFlowPass( @@ -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); + /// + /// 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. + /// + 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 @@ -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); } @@ -84,20 +98,20 @@ 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); @@ -105,6 +119,80 @@ public override BoundNode VisitTryStatement(BoundTryStatement node) return null; } + protected Optional _tryState; + + private void VisitTryBlockWithUnassignments(BoundStatement tryBlock, BoundTryStatement node, ref TLocalState tryState) + { + if (_trackUnassignments) + { + Optional 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 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 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); @@ -130,5 +218,7 @@ protected virtual void VisitFinallyBlock(BoundStatement finallyBlock, ref TLocal { VisitStatement(finallyBlock); // this should generate no pending branches } + + #endregion TryStatements } } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs index bca81cb3ac975..411e0eaa11690 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs @@ -28,12 +28,6 @@ namespace Microsoft.CodeAnalysis.CSharp { -#if REFERENCE_STATE - using OptionalState = Optional; -#else - using OptionalState = Nullable; -#endif - /// /// Implement C# data flow analysis (definite assignment). /// @@ -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; } @@ -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); @@ -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); diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 59270a46b3e20..02288a4eb4fb9 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -136,7 +136,7 @@ private NullableWalker( ArrayBuilder<(RefKind, TypeSymbolWithAnnotations)> returnTypes, VariableState initialState, Action 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; @@ -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? @@ -826,7 +833,10 @@ protected override LocalState UnreachableState() protected override LocalState AllBitsSet() { - return new LocalState(reachable: true, new ArrayBuilder(nextVariableSlot)); + // Create a reachable state in which all variables are known to be non-null. + var builder = new ArrayBuilder(nextVariableSlot); + builder.AddMany(NullableAnnotation.NotNullableBasedOnAnalysis, nextVariableSlot); + return new LocalState(reachable: true, builder); } private void EnterParameters() @@ -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) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs index bed20ffa04b78..69b31aa6760c6 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs @@ -1572,11 +1572,6 @@ public override BoundNode VisitTryStatement(BoundTryStatement node) return null; } - protected virtual LocalState AllBitsSet() // required for DataFlowsOutWalker - { - return default(LocalState); - } - public sealed override BoundNode VisitReturnStatement(BoundReturnStatement node) { var result = VisitReturnStatementNoAdjust(node); diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 3c44fd3ac5fd9..9d452b4a57fe5 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -4524,7 +4524,7 @@ private VariableDeclaratorSyntax ParseVariableDeclarator( case SyntaxKind.OpenBracketToken: bool sawNonOmittedSize; _termState |= TerminatorState.IsPossibleEndOfVariableDeclaration; - var specifier = this.ParseArrayRankSpecifier(isArrayCreation: false, expectSizes: flags == VariableFlags.Fixed, allowQuestionToken: false, sawNonOmittedSize: out sawNonOmittedSize); + var specifier = this.ParseArrayRankSpecifier(isArrayCreation: false, expectSizes: flags == VariableFlags.Fixed, questionTokenModeOpt: null, sawNonOmittedSize: out sawNonOmittedSize); _termState = saveTerm; var open = specifier.OpenBracketToken; var sizes = specifier.Sizes; @@ -6214,7 +6214,6 @@ private TypeSyntax ParseTypeCore( ParseTypeMode mode, bool expectSizes) { - var isOrAs = mode == ParseTypeMode.AsExpression || mode == ParseTypeMode.AfterIs; NameOptions nameOptions; switch (mode) { @@ -6244,31 +6243,15 @@ private TypeSyntax ParseTypeCore( } var type = this.ParseUnderlyingType(parentIsParameter: mode == ParseTypeMode.Parameter, options: nameOptions); + Debug.Assert(type != null); - if (this.CurrentToken.Kind == SyntaxKind.QuestionToken && - // we do not permit nullable types in a declaration pattern - (mode != ParseTypeMode.AfterIs && mode != ParseTypeMode.AfterCase || !IsTrueIdentifier(this.PeekToken(1)))) + if (this.CurrentToken.Kind == SyntaxKind.QuestionToken) { - var resetPoint = this.GetResetPoint(); - try + var question = EatNullableQualifierIfApplicable(mode); + if (question != null) { - var question = this.EatToken(); - - if (isOrAs && (IsTerm() || IsPredefinedType(this.CurrentToken.Kind) || SyntaxFacts.IsAnyUnaryExpression(this.CurrentToken.Kind))) - { - this.Reset(ref resetPoint); - - Debug.Assert(type != null); - return type; - } - - question = CheckFeatureAvailability(question, MessageID.IDS_FeatureNullable); type = _syntaxFactory.NullableType(type, question); } - finally - { - this.Release(ref resetPoint); - } } switch (mode) @@ -6301,7 +6284,7 @@ private TypeSyntax ParseTypeCore( while (this.IsPossibleRankAndDimensionSpecifier()) { bool unused; - var rank = this.ParseArrayRankSpecifier(mode == ParseTypeMode.ArrayCreation, expectSizes, allowQuestionToken: true, out unused); + var rank = this.ParseArrayRankSpecifier(mode == ParseTypeMode.ArrayCreation, expectSizes, questionTokenModeOpt: mode, out unused); ranks.Add(rank); expectSizes = false; } @@ -6318,6 +6301,36 @@ private TypeSyntax ParseTypeCore( return type; } + private SyntaxToken EatNullableQualifierIfApplicable(ParseTypeMode mode) + { + Debug.Assert(this.CurrentToken.Kind == SyntaxKind.QuestionToken); + + // we do not permit nullable types in a declaration pattern + if (mode != ParseTypeMode.AfterIs && mode != ParseTypeMode.AfterCase || !IsTrueIdentifier(this.PeekToken(1))) + { + var resetPoint = this.GetResetPoint(); + try + { + var question = this.EatToken(); + + var isOrAs = mode == ParseTypeMode.AsExpression || mode == ParseTypeMode.AfterIs; + if (isOrAs && (IsTerm() || IsPredefinedType(this.CurrentToken.Kind) || SyntaxFacts.IsAnyUnaryExpression(this.CurrentToken.Kind))) + { + this.Reset(ref resetPoint); + return null; + } + + return CheckFeatureAvailability(question, MessageID.IDS_FeatureNullable); + } + finally + { + this.Release(ref resetPoint); + } + } + + return null; + } + private bool PointerTypeModsFollowedByRankAndDimensionSpecifier() { // Are pointer specifiers (if any) followed by an array specifier? @@ -6340,7 +6353,7 @@ private bool IsPossibleRankAndDimensionSpecifier() return this.CurrentToken.Kind == SyntaxKind.OpenBracketToken; } - private ArrayRankSpecifierSyntax ParseArrayRankSpecifier(bool isArrayCreation, bool expectSizes, bool allowQuestionToken, out bool sawNonOmittedSize) + private ArrayRankSpecifierSyntax ParseArrayRankSpecifier(bool isArrayCreation, bool expectSizes, ParseTypeMode? questionTokenModeOpt, out bool sawNonOmittedSize) { sawNonOmittedSize = false; bool sawOmittedSize = false; @@ -6407,9 +6420,9 @@ private ArrayRankSpecifierSyntax ParseArrayRankSpecifier(bool isArrayCreation, b var close = this.EatToken(SyntaxKind.CloseBracketToken); SyntaxToken questionToken = null; - if (allowQuestionToken && this.CurrentToken.Kind == SyntaxKind.QuestionToken) + if (questionTokenModeOpt != null && this.CurrentToken.Kind == SyntaxKind.QuestionToken) { - questionToken = this.EatToken(); + questionToken = EatNullableQualifierIfApplicable(questionTokenModeOpt.GetValueOrDefault()); } return _syntaxFactory.ArrayRankSpecifier(open, list, close, questionToken); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs index 93b7a68dbfc4e..59ea97bc82d6c 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs @@ -24,7 +24,7 @@ public class CodeGenAsyncIteratorTests : EmitMetadataTestBase { private void VerifyMissingMember(WellKnownMember member, params DiagnosticDescription[] expected) { - var lib = CreateCompilationWithTasksExtensions(s_common); + var lib = CreateCompilationWithAsyncIterator(""); var lib_ref = lib.EmitToImageReference(); string source = @" @@ -41,7 +41,7 @@ class C private void VerifyMissingType(WellKnownType type, params DiagnosticDescription[] expected) { - var lib = CreateCompilationWithTasksExtensions(s_common); + var lib = CreateCompilationWithAsyncIterator(""); var lib_ref = lib.EmitToImageReference(); string source = @" @@ -57,7 +57,7 @@ class C } private CSharpCompilation CreateCompilationWithAsyncIterator(string source, CSharpCompilationOptions options = null) - => CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: options); + => CreateCompilationWithTasksExtensions(new[] { source, AsyncStreamsTypes }, options: options); [Fact] [WorkItem(30566, "https://github.com/dotnet/roslyn/issues/30566")] @@ -315,8 +315,14 @@ static async System.Collections.Generic.IAsyncEnumerable M() yield break; } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, parseOptions: TestOptions.Regular7_3); + var comp = CreateCompilationWithTasksExtensions(new[] { source }, parseOptions: TestOptions.Regular7_3); comp.VerifyDiagnostics( + // (4,45): error CS0234: The type or namespace name 'IAsyncEnumerable<>' does not exist in the namespace 'System.Collections.Generic' (are you missing an assembly reference?) + // static async System.Collections.Generic.IAsyncEnumerable M() + Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "IAsyncEnumerable").WithArguments("IAsyncEnumerable<>", "System.Collections.Generic").WithLocation(4, 45), + // (4,67): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, or IAsyncEnumerable + // static async System.Collections.Generic.IAsyncEnumerable M() + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M").WithLocation(4, 67), // (4,67): error CS8370: Feature 'async streams' is not available in C# 7.3. Please use language version 8.0 or greater. // static async System.Collections.Generic.IAsyncEnumerable M() Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "M").WithArguments("async streams", "8.0").WithLocation(4, 67), @@ -347,7 +353,7 @@ static async System.Threading.Tasks.Task Main() ref struct S { }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (4,65): error CS0306: The type 'S' may not be used as a type argument // static async System.Collections.Generic.IAsyncEnumerable M() @@ -371,7 +377,7 @@ static async System.Collections.Generic.IAsyncEnumerable M() yield return 42; } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }); + var comp = CreateCompilationWithAsyncIterator(source); comp.VerifyDiagnostics(); var m2 = comp.GlobalNamespace.GetMember("C.M2"); @@ -395,7 +401,7 @@ public static async System.Collections.Generic.IAsyncEnumerable M() yield return 4; } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugDll); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugDll); comp.VerifyDiagnostics(); CompileAndVerify(comp, symbolValidator: module => { @@ -417,7 +423,7 @@ public static async System.Collections.Generic.IAsyncEnumerator M() yield return 4; } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }); + var comp = CreateCompilationWithAsyncIterator(source); comp.VerifyDiagnostics( // (4,74): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, or IAsyncEnumerable // public static async System.Collections.Generic.IAsyncEnumerator M() @@ -775,7 +781,7 @@ async System.Collections.Generic.IAsyncEnumerable M() break; } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }); + var comp = CreateCompilationWithAsyncIterator(source); comp.VerifyDiagnostics( // (8,9): error CS0139: No enclosing loop out of which to break or continue // break; @@ -800,7 +806,7 @@ async System.Collections.Generic.IAsyncEnumerable M2() return 4; } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }); + var comp = CreateCompilationWithAsyncIterator(source); comp.VerifyDiagnostics( // (8,9): error CS1622: Cannot return a value from an iterator. Use the yield return statement to return a value, or yield break to end the iteration. // return 1; @@ -831,7 +837,7 @@ async System.Collections.Generic.IAsyncEnumerable M2() return null; } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }); + var comp = CreateCompilationWithAsyncIterator(source); comp.VerifyDiagnostics( // (8,9): error CS1622: Cannot return a value from an iterator. Use the yield return statement to return a value, or yield break to end the iteration. // return null; @@ -862,7 +868,7 @@ async System.Collections.Generic.IAsyncEnumerable M2(ref string s2) return ref s2; } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }); + var comp = CreateCompilationWithAsyncIterator(source); comp.VerifyDiagnostics( // (4,73): error CS1988: Async methods cannot have ref, in or out parameters // async System.Collections.Generic.IAsyncEnumerable M(ref string s) @@ -902,7 +908,7 @@ async System.Collections.Generic.IAsyncEnumerable M2() return default; } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }); + var comp = CreateCompilationWithAsyncIterator(source); comp.VerifyDiagnostics( // (8,9): error CS1622: Cannot return a value from an iterator. Use the yield return statement to return a value, or yield break to end the iteration. // return default; @@ -948,7 +954,7 @@ static async System.Threading.Tasks.Task Main() } } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0 1 2 3 4 5"); } @@ -980,7 +986,7 @@ static async System.Threading.Tasks.Task Main() }"; foreach (var options in new[] { TestOptions.DebugExe, TestOptions.ReleaseExe }) { - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: options); + var comp = CreateCompilationWithAsyncIterator(source, options: options); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: "0 1 2 3 4 5"); @@ -1377,7 +1383,7 @@ static async System.Threading.Tasks.Task Main() Write(""5""); } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0 1 2 3 4 5"); } @@ -1410,7 +1416,7 @@ static async System.Threading.Tasks.Task Main() Write(""5""); } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0 1 2 3 4 5"); } @@ -1442,7 +1448,7 @@ static async System.Threading.Tasks.Task Main() Write(""End""); } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "Start p:10 p:11 Value p:12 End"); } @@ -1475,7 +1481,7 @@ static async System.Threading.Tasks.Task Main() Write(""End""); } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); var v = CompileAndVerify(comp, expectedOutput: "Start f:10 f:11 Value f:12 End"); } @@ -1493,7 +1499,7 @@ public static async System.Collections.Generic.IAsyncEnumerable M() return null; } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }); + var comp = CreateCompilationWithAsyncIterator(source); comp.VerifyDiagnostics( // (8,9): error CS1622: Cannot return a value from an iterator. Use the yield return statement to return a value, or yield break to end the iteration. // return null; @@ -1526,7 +1532,7 @@ static async System.Threading.Tasks.Task Main() Write(""Done""); } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0 1 2 3 4 Done"); } @@ -1557,7 +1563,7 @@ static async System.Threading.Tasks.Task Main() Write(""Done""); } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0 1 2 3 4 5 Done"); } @@ -1586,7 +1592,7 @@ static async System.Threading.Tasks.Task Main() Write(""Done""); } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0 1 2 3 Done"); } @@ -1615,7 +1621,7 @@ static async System.Threading.Tasks.Task Main() Write(""Done""); } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0 1 2 Done"); } @@ -1649,7 +1655,7 @@ static async System.Threading.Tasks.Task Main() Write(""Done""); } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0 1 2 3 Done"); } @@ -1693,7 +1699,7 @@ static async System.Threading.Tasks.Task Main() Write(""Done""); }} }}"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: expectation); } @@ -1721,7 +1727,7 @@ async System.Collections.Generic.IAsyncEnumerable local() }} }} }}"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: expectation); } @@ -1794,7 +1800,7 @@ static async System.Threading.Tasks.Task Main() Write(""Done""); } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: "0 1 2 3 4 Done"); } @@ -1810,7 +1816,7 @@ async System.Collections.Generic.IAsyncEnumerable M() await System.Threading.Tasks.Task.CompletedTask; } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }); + var comp = CreateCompilationWithAsyncIterator(source); comp.VerifyDiagnostics( // (4,60): error CS0161: 'C.M()': not all code paths return a value // async System.Collections.Generic.IAsyncEnumerable M() @@ -1836,7 +1842,7 @@ public static async System.Threading.Tasks.Task Main() } } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (4,67): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. // static async System.Collections.Generic.IAsyncEnumerable M() @@ -1864,7 +1870,7 @@ public static async System.Threading.Tasks.Task Main() System.Console.Write(""none""); } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe); + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (4,67): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. // static async System.Collections.Generic.IAsyncEnumerable M() @@ -1883,7 +1889,7 @@ async System.Collections.Generic.IAsyncEnumerable M() { } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }); + var comp = CreateCompilationWithAsyncIterator(source); comp.VerifyDiagnostics( // (4,60): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. // async System.Collections.Generic.IAsyncEnumerable M() @@ -1906,7 +1912,7 @@ async System.Collections.Generic.IAsyncEnumerable M() yield return; } }"; - var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }); + var comp = CreateCompilationWithAsyncIterator(source); comp.VerifyDiagnostics( // (7,15): error CS1627: Expression expected after yield return // yield return; @@ -1920,243 +1926,10 @@ async System.Collections.Generic.IAsyncEnumerable M() ); } - private static readonly string s_common = @" -namespace System.Collections.Generic -{ - public interface IAsyncEnumerable - { - IAsyncEnumerator GetAsyncEnumerator(); - } - - public interface IAsyncEnumerator : System.IAsyncDisposable - { - System.Threading.Tasks.ValueTask MoveNextAsync(); - T Current { get; } - } -} -namespace System -{ - public interface IAsyncDisposable - { - System.Threading.Tasks.ValueTask DisposeAsync(); - } -} - -namespace System.Runtime.CompilerServices -{ - public interface IStrongBox - { - ref T Value { get; } - } -} - -namespace System.Threading.Tasks -{ - using System.Runtime.CompilerServices; - using System.Runtime.ExceptionServices; - using System.Threading.Tasks.Sources; - - public struct ManualResetValueTaskSourceLogic - { - private static readonly Action s_sentinel = new Action(s => throw new InvalidOperationException()); - - private readonly IStrongBox> _parent; - private Action _continuation; - private object _continuationState; - private object _capturedContext; - private ExecutionContext _executionContext; - private bool _completed; - private TResult _result; - private ExceptionDispatchInfo _error; - private short _version; - - public ManualResetValueTaskSourceLogic(IStrongBox> parent) - { - _parent = parent ?? throw new ArgumentNullException(nameof(parent)); - _continuation = null; - _continuationState = null; - _capturedContext = null; - _executionContext = null; - _completed = false; - _result = default; - _error = null; - _version = 0; - } - - public short Version => _version; - - private void ValidateToken(short token) - { - if (token != _version) - { - throw new InvalidOperationException(); - } - } - - public ValueTaskSourceStatus GetStatus(short token) - { - ValidateToken(token); - - return - !_completed ? ValueTaskSourceStatus.Pending : - _error == null ? ValueTaskSourceStatus.Succeeded : - _error.SourceException is OperationCanceledException ? ValueTaskSourceStatus.Canceled : - ValueTaskSourceStatus.Faulted; - } - - public TResult GetResult(short token) - { - ValidateToken(token); - - if (!_completed) - { - throw new InvalidOperationException(); - } - - _error?.Throw(); - return _result; - } - - public void Reset() - { - _version++; - - _completed = false; - _continuation = null; - _continuationState = null; - _result = default; - _error = null; - _executionContext = null; - _capturedContext = null; - } - - public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) - { - if (continuation == null) - { - throw new ArgumentNullException(nameof(continuation)); - } - ValidateToken(token); - - if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0) - { - _executionContext = ExecutionContext.Capture(); - } - - if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0) - { - SynchronizationContext sc = SynchronizationContext.Current; - if (sc != null && sc.GetType() != typeof(SynchronizationContext)) - { - _capturedContext = sc; - } - else - { - TaskScheduler ts = TaskScheduler.Current; - if (ts != TaskScheduler.Default) - { - _capturedContext = ts; - } - } - } - - _continuationState = state; - if (Interlocked.CompareExchange(ref _continuation, continuation, null) != null) - { - _executionContext = null; - - object cc = _capturedContext; - _capturedContext = null; - - switch (cc) - { - case null: - Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); - break; - - case SynchronizationContext sc: - sc.Post(s => - { - var tuple = (Tuple, object>)s; - tuple.Item1(tuple.Item2); - }, Tuple.Create(continuation, state)); - break; - - case TaskScheduler ts: - Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts); - break; - } - } - } - - public void SetResult(TResult result) - { - _result = result; - SignalCompletion(); - } - - public void SetException(Exception error) - { - _error = ExceptionDispatchInfo.Capture(error); - SignalCompletion(); - } - - private void SignalCompletion() - { - if (_completed) - { - throw new InvalidOperationException(); - } - _completed = true; - - if (Interlocked.CompareExchange(ref _continuation, s_sentinel, null) != null) - { - if (_executionContext != null) - { - ExecutionContext.Run( - _executionContext, - s => ((IStrongBox>)s).Value.InvokeContinuation(), - _parent ?? throw new InvalidOperationException()); - } - else - { - InvokeContinuation(); - } - } - } - - private void InvokeContinuation() - { - object cc = _capturedContext; - _capturedContext = null; - - switch (cc) - { - case null: - _continuation(_continuationState); - break; - - case SynchronizationContext sc: - sc.Post(s => - { - ref ManualResetValueTaskSourceLogic logicRef = ref ((IStrongBox>)s).Value; - logicRef._continuation(logicRef._continuationState); - }, _parent ?? throw new InvalidOperationException()); - break; - - case TaskScheduler ts: - Task.Factory.StartNew(_continuation, _continuationState, CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts); - break; - } - } - } -} -"; - [Fact] public void TestWellKnownMembers() { - var comp = CreateCompilation(s_common, references: new[] { TestReferences.NetStandard20.TasksExtensionsRef }, targetFramework: Roslyn.Test.Utilities.TargetFramework.NetStandard20); + var comp = CreateCompilation(AsyncStreamsTypes, references: new[] { TestReferences.NetStandard20.TasksExtensionsRef }, targetFramework: Roslyn.Test.Utilities.TargetFramework.NetStandard20); comp.VerifyDiagnostics(); verifyType(WellKnownType.System_Runtime_CompilerServices_IStrongBox_T, diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index 320612803cfa4..30c5ac490f3e8 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -14,6 +14,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics { + [CompilerTrait(CompilerFeature.NullableReferenceTypes)] public class NullableReferenceTypesTests : CSharpTestBase { [Fact] @@ -456,6 +457,72 @@ static void F2(object? w) Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(14, 26)); } + [Fact] + public void NullableAndConditionalOperators() + { + var source = +@"class Program +{ + static void F1(object x) + { + _ = x is string? 1 : 2; + _ = x is string? ? 1 : 2; + _ = x is string ? ? 1 : 2; + _ = x as string?? x; + _ = x as string ? ?? x; + } + static void F2(object y) + { + _ = y is object[]? 1 : 2; + _ = y is object[]? ? 1 : 2; + _ = y is object[] ? ? 1 : 2; + _ = y as object[]?? y; + _ = y as object[] ? ?? y; + } + static void F3(object z) + { + _ = z is T[][]? 1 : 2; + _ = z is T[]?[] ? 1 : 2; + _ = z is T[] ? [] ? 1 : 2; + _ = z as T[][]?? z; + _ = z as T[] ? [] ?? z; + } +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7); + comp.VerifyDiagnostics( + // (6,24): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater. + // _ = x is string? ? 1 : 2; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(6, 24), + // (7,25): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater. + // _ = x is string ? ? 1 : 2; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(7, 25), + // (9,25): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater. + // _ = x as string ? ?? x; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(9, 25), + // (14,26): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater. + // _ = y is object[]? ? 1 : 2; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(14, 26), + // (15,27): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater. + // _ = y is object[] ? ? 1 : 2; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(15, 27), + // (17,27): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater. + // _ = y as object[] ? ?? y; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(17, 27), + // (22,21): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater. + // _ = z is T[]?[] ? 1 : 2; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(22, 21), + // (23,22): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater. + // _ = z is T[] ? [] ? 1 : 2; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(23, 22), + // (25,22): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater. + // _ = z as T[] ? [] ?? z; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(25, 22)); + + comp = CreateCompilation(source, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics(); + } + [Fact, WorkItem(29318, "https://github.com/dotnet/roslyn/issues/29318")] public void IsOperatorOnNonNullExpression() { @@ -10234,6 +10301,29 @@ class CL1 ); } + [Fact] + public void ReturningValues_BadValue() + { + CSharpCompilation c = CreateCompilation(new[] { @" +class C +{ + string M() + { + return bad; + } +} +" }, options: WithNonNullTypesTrue()); + + c.VerifyDiagnostics( + // (6,16): error CS0103: The name 'bad' does not exist in the current context + // return bad; + Diagnostic(ErrorCode.ERR_NameNotInContext, "bad").WithArguments("bad").WithLocation(6, 16), + // (6,16): warning CS8619: Nullability of reference types in value of type '?' doesn't match target type 'string'. + // return bad; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "bad").WithArguments("?", "string").WithLocation(6, 16) + ); + } + [Fact] public void IdentityConversion_Return_01() { @@ -22568,6 +22658,8 @@ public void UnboundLambda_02() static void F(object? x) { var z = y => y ?? x.ToString(); + System.Func z2 = y => y ?? x.ToString(); + System.Func z3 = y => null; } }"; var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); @@ -22577,7 +22669,13 @@ static void F(object? x) Diagnostic(ErrorCode.ERR_ImplicitlyTypedVariableAssignedBadValue, "z = y => y ?? x.ToString()").WithArguments("lambda expression").WithLocation(5, 13), // (5,27): warning CS8602: Possible dereference of a null reference. // var z = y => y ?? x.ToString(); - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(5, 27)); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(5, 27), + // (6,53): warning CS8602: Possible dereference of a null reference. + // System.Func z2 = y => y ?? x.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(6, 53), + // (7,48): warning CS8603: Possible null reference return. + // System.Func z3 = y => null; + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(7, 48)); } /// @@ -28183,6 +28281,421 @@ class CL1 {} ); } + [Fact] + public void ReturningValues_IEnumerableT() + { + var source = @" +public class C +{ + System.Collections.Generic.IEnumerable M() + { + return null; // 1 + } + public System.Collections.Generic.IEnumerable? M2() + { + return null; + } + System.Collections.Generic.IEnumerable M3() => null; // 2 + System.Collections.Generic.IEnumerable? M4() => null; +}"; + + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (6,16): warning CS8603: Possible null reference return. + // return null; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(6, 16), + // (12,60): warning CS8603: Possible null reference return. + // System.Collections.Generic.IEnumerable M3() => null; // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(12, 60) + ); + + var source2 = @" +class D +{ + void M(C c) + { + c.M2() /*T:System.Collections.Generic.IEnumerable?*/ ; + } +} +"; + var comp2 = CreateCompilation(source2, references: new[] { comp.EmitToImageReference() }); + comp2.VerifyTypes(); + } + + [Fact] + public void Yield_IEnumerableT() + { + var source = @" +public class C +{ + public System.Collections.Generic.IEnumerable M() + { + yield return null; // 1 + yield return """"; + yield return null; // 2 + yield break; + } + public System.Collections.Generic.IEnumerable M2() + { + yield return null; + } +}"; + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (6,22): warning CS8603: Possible null reference return. + // yield return null; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(6, 22), + // (8,22): warning CS8603: Possible null reference return. + // yield return null; // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(8, 22) + ); + + var source2 = @" +class D +{ + void M(C c) + { + c.M() /*T:System.Collections.Generic.IEnumerable!*/ ; + c.M2() /*T:System.Collections.Generic.IEnumerable!*/ ; + } +} +"; + var comp2 = CreateCompilation(source2, references: new[] { comp.EmitToImageReference() }); + comp2.VerifyTypes(); + } + + [Fact] + public void Yield_IEnumerableT_LocalFunction() + { + var source = @" +class C +{ + void Method() + { + _ = M(); + _ = M2(); + + System.Collections.Generic.IEnumerable M() + { + yield return null; // 1 + yield return """"; + yield return null; // 2 + yield break; + } + System.Collections.Generic.IEnumerable M2() + { + yield return null; + } + } +}"; + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (11,26): warning CS8603: Possible null reference return. + // yield return null; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(11, 26), + // (13,26): warning CS8603: Possible null reference return. + // yield return null; // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(13, 26) + ); + } + + [Fact] + public void Yield_IEnumerableT_GenericT() + { + var source = @" +class C +{ + System.Collections.Generic.IEnumerable M() + { + yield return default; // 1 + } + System.Collections.Generic.IEnumerable M1() where T : class + { + yield return default; // 2 + } + System.Collections.Generic.IEnumerable M2() where T : class? + { + yield return default; // 3 + } + System.Collections.Generic.IEnumerable M3() where T : class + { + yield return default; + } +}"; + CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()).VerifyDiagnostics( + // (6,22): warning CS8603: Possible null reference return. + // yield return default; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "default").WithLocation(6, 22), + // (10,22): warning CS8603: Possible null reference return. + // yield return default; // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "default").WithLocation(10, 22), + // (14,22): warning CS8603: Possible null reference return. + // yield return default; // 3 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "default").WithLocation(14, 22) + ); + } + + [Fact] + public void Yield_IEnumerableT_ErrorValue() + { + var source = @" +class C +{ + System.Collections.Generic.IEnumerable M() + { + yield return bad; + } +}"; + CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()).VerifyDiagnostics( + // (6,22): error CS0103: The name 'bad' does not exist in the current context + // yield return bad; + Diagnostic(ErrorCode.ERR_NameNotInContext, "bad").WithArguments("bad").WithLocation(6, 22), + // (6,22): warning CS8619: Nullability of reference types in value of type '?' doesn't match target type 'string'. + // yield return bad; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "bad").WithArguments("?", "string").WithLocation(6, 22) + ); + } + + [Fact] + public void Yield_IEnumerableT_ErrorValue2() + { + var source = @" +static class C +{ + static System.Collections.Generic.IEnumerable M(object? x) + { + yield return (C)x; + } + static System.Collections.Generic.IEnumerable M(object? y) + { + yield return (C?)y; + } +}"; + CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()).VerifyDiagnostics( + // (6,22): error CS0716: Cannot convert to static type 'C' + // yield return (C)x; + Diagnostic(ErrorCode.ERR_ConvertToStaticClass, "(C)x").WithArguments("C").WithLocation(6, 22), + // (6,22): warning CS8600: Converting null literal or possible null value to non-nullable type. + // yield return (C)x; + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "(C)x").WithLocation(6, 22), + // (6,22): warning CS8603: Possible null reference return. + // yield return (C)x; + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "(C)x").WithLocation(6, 22), + // (8,60): error CS0111: Type 'C' already defines a member called 'M' with the same parameter types + // static System.Collections.Generic.IEnumerable M(object? y) + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "C").WithLocation(8, 60), + // (10,22): error CS0716: Cannot convert to static type 'C' + // yield return (C?)y; + Diagnostic(ErrorCode.ERR_ConvertToStaticClass, "(C?)y").WithArguments("C").WithLocation(10, 22) + ); + } + + [Fact] + public void Yield_IEnumerableT_NoValue() + { + var source = @" +class C +{ + System.Collections.Generic.IEnumerable M() + { + yield return; + } +}"; + CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()).VerifyDiagnostics( + // (6,9): warning CS8619: Nullability of reference types in value of type '?' doesn't match target type 'string'. + // yield return; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "yield return;").WithArguments("?", "string").WithLocation(6, 9), + // (6,15): error CS1627: Expression expected after yield return + // yield return; + Diagnostic(ErrorCode.ERR_EmptyYield, "return").WithLocation(6, 15) + ); + } + + [Fact] + public void Yield_IEnumeratorT() + { + var source = @" +class C +{ + System.Collections.Generic.IEnumerator M() + { + yield return null; // 1 + yield return """"; + } + System.Collections.Generic.IEnumerator M2() + { + yield return null; + } +}"; + CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()).VerifyDiagnostics( + // (6,22): warning CS8603: Possible null reference return. + // yield return null; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(6, 22) + ); + } + + [Fact] + public void Yield_IEnumeratorT_LocalFunction() + { + var source = @" +class C +{ + void Method() + { + _ = M(); + _ = M2(); + + System.Collections.Generic.IEnumerator M() + { + yield return null; // 1 + yield return """"; + } + System.Collections.Generic.IEnumerator M2() + { + yield return null; + } + } +}"; + CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()).VerifyDiagnostics( + // (11,26): warning CS8603: Possible null reference return. + // yield return null; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(11, 26) + ); + } + + [Fact] + public void Yield_IEnumerable() + { + var source = @" +class C +{ + System.Collections.IEnumerable M() + { + yield return null; + } +}"; + CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()).VerifyDiagnostics(); + } + + [Fact] + public void Yield_IEnumerator() + { + var source = @" +class C +{ + System.Collections.IEnumerator M() + { + yield return null; + yield return null; + } +}"; + CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()).VerifyDiagnostics(); + } + + [Fact, CompilerTrait(CompilerFeature.AsyncStreams)] + public void Yield_IAsyncEnumerable() + { + var source = @" +using System.Collections.Generic; +using System.Threading.Tasks; +class C +{ + public static async IAsyncEnumerable M() + { + yield return null; // 1 + yield return null; // 2 + await Task.Delay(1); + yield break; + } + public static async IAsyncEnumerable M2() + { + yield return null; + yield return null; + await Task.Delay(1); + } + void Method() + { + _ = local(); + _ = local2(); + + async IAsyncEnumerable local() + { + yield return null; // 3 + await Task.Delay(1); + yield break; + } + async IAsyncEnumerable local2() + { + yield return null; + await Task.Delay(1); + } + } +}"; + CreateCompilationWithTasksExtensions(new[] { source, AsyncStreamsTypes }, options: WithNonNullTypesTrue()).VerifyDiagnostics( + // (8,22): warning CS8603: Possible null reference return. + // yield return null; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(8, 22), + // (9,22): warning CS8603: Possible null reference return. + // yield return null; // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(9, 22), + // (26,26): warning CS8603: Possible null reference return. + // yield return null; // 3 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(26, 26) + ); + } + + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/31057"), CompilerTrait(CompilerFeature.AsyncStreams)] + public void Yield_IAsyncEnumerator() + { + var source = @" +using System.Collections.Generic; +using System.Threading.Tasks; +class C +{ + async IAsyncEnumerator M() + { + yield return null; // 1 + yield return null; // 2 + await Task.Delay(1); + yield break; + } + async IAsyncEnumerator M2() + { + yield return null; + yield return null; + await Task.Delay(1); + } + void Method() + { + _ = local(); + _ = local2(); + + async IAsyncEnumerator local() + { + yield return null; // 3 + await Task.Delay(1); + } + async IAsyncEnumerator local2() + { + yield return null; + await Task.Delay(1); + yield break; + } + } +}"; + CreateCompilationWithTasksExtensions(new[] { source, AsyncStreamsTypes }, options: WithNonNullTypesTrue()).VerifyDiagnostics( + // (8,22): warning CS8603: Possible null reference return. + // yield return null; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(8, 22), + // (9,22): warning CS8603: Possible null reference return. + // yield return null; // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(9, 22), + // (26,26): warning CS8603: Possible null reference return. + // yield return null; // 3 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(26, 26) + ); + } + [Fact] public void Await_01() { @@ -55966,5 +56479,669 @@ static void M(object x) // c2.F().ToString(); Diagnostic(ErrorCode.ERR_ObjectProhibited, "c2.F").WithArguments("C.F()").WithLocation(14, 9)); } + + [Fact, WorkItem(30561, "https://github.com/dotnet/roslyn/issues/30561")] + public void SetNullableStateInFinally_01() + { + var source = +@"public static class Program +{ + public static void Main() + { + string? s = string.Empty; + try + { + } + finally + { + s = null; + } + + _ = s.Length; // warning + } +} +"; + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (14,13): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(14, 13) + ); + } + + [Fact, WorkItem(30561, "https://github.com/dotnet/roslyn/issues/30561")] + public void SetNullableStateInTry_02() + { + var source = +@"public static class Program +{ + public static int Main() + { + string? s = string.Empty; + try + { + s = null; + MayThrow(); + s = string.Empty; + } + catch (System.Exception) + { + } + + return s.Length; // warning: possibly null + } + static void MayThrow() + { + throw null; + } +} +"; + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (16,16): warning CS8602: Possible dereference of a null reference. + // return s.Length; // warning: possibly null + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(16, 16) + ); + } + + [Fact, WorkItem(30561, "https://github.com/dotnet/roslyn/issues/30561")] + public void SetNullableStateInTry_03() + { + var source = +@"public static class Program +{ + public static int Main() + { + string? s = string.Empty; + try + { + s = null; + MayThrow(); + s = string.Empty; + } + catch (System.Exception) + { + return s.Length; // warning: possibly null + } + + return s.Length; + } + static void MayThrow() + { + throw null; + } +} +"; + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (14,20): warning CS8602: Possible dereference of a null reference. + // return s.Length; // warning: possibly null + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(14, 20) + ); + } + + [Fact, WorkItem(30561, "https://github.com/dotnet/roslyn/issues/30561")] + public void SetNullableStateInTry_04() + { + var source = +@"public static class Program +{ + public static int Main() + { + string? s = string.Empty; + try + { + s = null; + MayThrow(); + s = string.Empty; + } + catch (System.Exception) + { + _ = s.Length; // warning 1 + } + finally + { + _ = s.Length; // warning 2 + } + + return s.Length; // ok (previously dereferenced) + } + static void MayThrow() + { + throw null; + } +} +"; + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (14,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(14, 17), + // (18,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(18, 17) + ); + } + + [Fact, WorkItem(30561, "https://github.com/dotnet/roslyn/issues/30561")] + public void SetNullableStateInTry_05() + { + var source = +@"public static class Program +{ + public static int Main() + { + string? s = null; + try + { + MayThrow(); + s = string.Empty; + _ = s.Length; // ok + } + catch (System.Exception) + { + _ = s.Length; // warning 1 + } + finally + { + _ = s.Length; // warning 2 + } + + return s.Length; // ok (previously dereferenced) + } + static void MayThrow() + { + throw null; + } +} +"; + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (14,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(14, 17), + // (18,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(18, 17) + ); + } + + [Fact, WorkItem(30561, "https://github.com/dotnet/roslyn/issues/30561")] + public void SetNullableStateInTry_06() + { + var source = +@"public static class Program +{ + public static int Main() + { + string? s = null; + try + { + MayThrow(); + s = string.Empty; + _ = s.Length; // ok + } + catch (System.NullReferenceException) + { + _ = s.Length; // warning 1 + } + catch (System.Exception) + { + _ = s.Length; // warning 2 + } + finally + { + _ = s.Length; // warning 3 + } + + return s.Length; // ok (previously dereferenced) + } + static void MayThrow() + { + throw null; + } +} +"; + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (14,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(14, 17), + // (18,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(18, 17), + // (22,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 3 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(22, 17) + ); + } + + [Fact, WorkItem(30561, "https://github.com/dotnet/roslyn/issues/30561")] + public void SetNullableStateInTry_07() + { + var source = +@"public static class Program +{ + public static int Main() + { + string? s = null; + try + { + MayThrow(); + s = string.Empty; + _ = s.Length; // ok + } + catch (System.NullReferenceException) + { + _ = s.Length; // warning 1 + } + catch (System.Exception) + { + _ = s.Length; // warning 2 + } + + return s.Length; // ok + } + static void MayThrow() + { + throw null; + } +} +"; + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (14,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(14, 17), + // (18,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(18, 17) + ); + } + + [Fact, WorkItem(30561, "https://github.com/dotnet/roslyn/issues/30561")] + public void SetNullableStateBeforeTry_08() + { + var source = +@"public static class Program +{ + public static int Main() + { + string? s = null; + try + { + MayThrow(); + _ = s.Length; // warning 1 + } + catch (System.NullReferenceException) + { + _ = s.Length; // warning 2 + } + catch (System.Exception) + { + _ = s.Length; // warning 3 + } + + return s.Length; // ok (previously dereferenced) + } + static void MayThrow() + { + throw null; + } +} +"; + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (9,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(9, 17), + // (13,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(13, 17), + // (17,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 3 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(17, 17) + ); + } + + [Fact, WorkItem(30561, "https://github.com/dotnet/roslyn/issues/30561")] + public void SetNullableStateInTry_09() + { + var source = +@"public static class Program +{ + public static int Main() + { + string? s = string.Empty; + try + { + s = null; + MayThrow(); + s = string.Empty; + } + finally + { + _ = s.Length; // warning + } + + return s.Length; // ok + } + static void MayThrow() + { + throw null; + } +} +"; + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (14,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(14, 17) + ); + } + + [Fact, WorkItem(30561, "https://github.com/dotnet/roslyn/issues/30561")] + public void SetNullableStateInCatch_10() + { + var source = +@"public static class Program +{ + public static int Main() + { + string? s = string.Empty; + try + { + MayThrow(); + } + catch (System.Exception) + { + s = null; + MayThrow(); + s = string.Empty; + } + finally + { + _ = s.Length; // warning + } + + return s.Length; // ok + } + static void MayThrow() + { + throw null; + } +} +"; + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (18,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(18, 17) + ); + } + + [Fact, WorkItem(30561, "https://github.com/dotnet/roslyn/issues/30561")] + public void SetNullableStateInNestedTry_01() + { + var source = +@"public static class Program +{ + public static void Main() + { + { + string? s = string.Empty; + try + { + try + { + s = null; + } + catch (System.Exception) + { + } + finally + { + } + } + catch (System.Exception) + { + } + finally + { + } + + _ = s.Length; // warning 1a + } + + { + string? s = string.Empty; + try + { + try + { + } + catch (System.Exception) + { + s = null; + } + finally + { + } + } + catch (System.Exception) + { + } + finally + { + } + + _ = s.Length; // warning 1b + } + + { + string? s = string.Empty; + try + { + try + { + } + catch (System.Exception) + { + } + finally + { + s = null; + } + } + catch (System.Exception) + { + } + finally + { + } + + _ = s.Length; // warning 1c + } + + { + string? s = string.Empty; + try + { + } + catch (System.Exception) + { + try + { + s = null; + } + catch (System.Exception) + { + } + finally + { + } + } + finally + { + _ = s.Length; // warning 2a + } + } + + { + string? s = string.Empty; + try + { + } + catch (System.Exception) + { + try + { + } + catch (System.Exception) + { + s = null; + } + finally + { + } + } + finally + { + _ = s.Length; // warning 2b + } + } + + { + string? s = string.Empty; + try + { + } + catch (System.Exception) + { + try + { + } + catch (System.Exception) + { + } + finally + { + s = null; + } + } + finally + { + _ = s.Length; // warning 2c + } + } + + { + string? s = string.Empty; + try + { + } + catch (System.Exception) + { + } + finally + { + try + { + s = null; + } + catch (System.Exception) + { + } + finally + { + } + } + + _ = s.Length; // warning 3a + } + + { + string? s = string.Empty; + try + { + } + catch (System.Exception) + { + } + finally + { + try + { + } + catch (System.Exception) + { + s = null; + } + finally + { + } + } + + _ = s.Length; // warning 3b + } + + { + string? s = string.Empty; + try + { + } + catch (System.Exception) + { + } + finally + { + try + { + } + catch (System.Exception) + { + } + finally + { + s = null; + } + } + + _ = s.Length; // warning 3c + } + } +} +"; + var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (27,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 1a + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(27, 17), + // (52,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 1b + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(52, 17), + // (77,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 1c + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(77, 17), + // (100,21): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 2a + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(100, 21), + // (124,21): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 2b + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(124, 21), + // (148,21): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 2c + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(148, 21), + // (174,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 3a + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(174, 17), + // (199,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 3b + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(199, 17), + // (224,17): warning CS8602: Possible dereference of a null reference. + // _ = s.Length; // warning 3c + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(224, 17) + ); + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/NullableParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/NullableParsingTests.cs index e67f0dbcccd85..81f760b5fd19e 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/NullableParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/NullableParsingTests.cs @@ -291,6 +291,601 @@ public void NullableArray_Cast_05() EOF(); } + [Fact] + public void ConditionalOperator_NotNullableType() + { + UsingExpression("x is T ? y : z"); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "z"); + } + } + EOF(); + } + + [Fact] + public void ConditionalOperator_NullableType() + { + UsingExpression("x is T ? ? y : z"); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.NullableType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.QuestionToken); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "z"); + } + } + EOF(); + } + + [Fact] + public void ConditionalOperator_NotNullableArray() + { + UsingExpression("x is T[] ? y : z"); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "z"); + } + } + EOF(); + } + + [Fact] + public void ConditionalOperator_NullableArray() + { + UsingExpression("x is T[] ? ? y : z"); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + N(SyntaxKind.QuestionToken); + } + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "z"); + } + } + EOF(); + } + + [Fact] + public void NullCoalesingOperator_NotNullableType() + { + UsingExpression("x as T?? y"); + N(SyntaxKind.CoalesceExpression); + { + N(SyntaxKind.AsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.AsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + } + N(SyntaxKind.QuestionQuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + EOF(); + } + + [Fact] + public void NullCoalesingOperator_NullableType() + { + UsingExpression("x as T? ?? y"); + N(SyntaxKind.CoalesceExpression); + { + N(SyntaxKind.AsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.AsKeyword); + N(SyntaxKind.NullableType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.QuestionToken); + } + } + N(SyntaxKind.QuestionQuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + EOF(); + } + + [Fact] + public void NullCoalesingOperator_NullableType_Invalid() + { + UsingExpression("x as T??? y", + // (1,9): error CS1525: Invalid expression term '?' + // x as T??? y + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "?").WithArguments("?").WithLocation(1, 9), + // (1,12): error CS1003: Syntax error, ':' expected + // x as T??? y + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "").WithLocation(1, 12), + // (1,12): error CS1733: Expected expression + // x as T??? y + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 12)); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.CoalesceExpression); + { + N(SyntaxKind.AsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.AsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + } + N(SyntaxKind.QuestionQuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken); + } + } + EOF(); + } + + [Fact] + public void NullCoalesingOperator_NotNullableArray() + { + UsingExpression("x as T[] ?? y"); + N(SyntaxKind.CoalesceExpression); + { + N(SyntaxKind.AsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.AsKeyword); + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + } + } + N(SyntaxKind.QuestionQuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + EOF(); + } + + [Fact] + public void NullCoalesingOperator_NullableArray() + { + UsingExpression("x as T[] ? ?? y"); + N(SyntaxKind.CoalesceExpression); + { + N(SyntaxKind.AsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.AsKeyword); + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + N(SyntaxKind.QuestionToken); + } + } + } + N(SyntaxKind.QuestionQuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + EOF(); + } + + [Fact] + public void DeclarationPattern_NullableType() + { + UsingStatement("switch (e) { case T? t: break; }", + // (1,25): error CS1525: Invalid expression term 'break' + // switch (e) { case T? t: break; } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "break").WithArguments("break").WithLocation(1, 25), + // (1,25): error CS1003: Syntax error, ':' expected + // switch (e) { case T? t: break; } + Diagnostic(ErrorCode.ERR_SyntaxError, "break").WithArguments(":", "break").WithLocation(1, 25)); + N(SyntaxKind.SwitchStatement); + { + N(SyntaxKind.SwitchKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "e"); + } + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SwitchSection); + { + N(SyntaxKind.CaseSwitchLabel); + { + N(SyntaxKind.CaseKeyword); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "t"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.ColonToken); + } + N(SyntaxKind.BreakStatement); + { + N(SyntaxKind.BreakKeyword); + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + + [Fact] + public void DeclarationPattern_NullableArray() + { + UsingStatement("switch (e) { case T[]? t: break; }", + // (1,21): error CS0443: Syntax error; value expected + // switch (e) { case T[]? t: break; } + Diagnostic(ErrorCode.ERR_ValueExpected, "]").WithLocation(1, 21), + // (1,27): error CS1525: Invalid expression term 'break' + // switch (e) { case T[]? t: break; } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "break").WithArguments("break").WithLocation(1, 27), + // (1,27): error CS1003: Syntax error, ':' expected + // switch (e) { case T[]? t: break; } + Diagnostic(ErrorCode.ERR_SyntaxError, "break").WithArguments(":", "break").WithLocation(1, 27)); + N(SyntaxKind.SwitchStatement); + { + N(SyntaxKind.SwitchKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "e"); + } + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SwitchSection); + { + N(SyntaxKind.CaseSwitchLabel); + { + N(SyntaxKind.CaseKeyword); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.ElementAccessExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.BracketedArgumentList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.CloseBracketToken); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "t"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.ColonToken); + } + N(SyntaxKind.BreakStatement); + { + N(SyntaxKind.BreakKeyword); + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + + [Fact] + public void DeclarationPattern_ArrayOfNullableType() + { + UsingStatement("switch (e) { case T?[] t: break; }"); + N(SyntaxKind.SwitchStatement); + { + N(SyntaxKind.SwitchKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "e"); + } + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SwitchSection); + { + N(SyntaxKind.CasePatternSwitchLabel); + { + N(SyntaxKind.CaseKeyword); + N(SyntaxKind.DeclarationPattern); + { + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.NullableType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.QuestionToken); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + } + N(SyntaxKind.SingleVariableDesignation); + { + N(SyntaxKind.IdentifierToken, "t"); + } + } + N(SyntaxKind.ColonToken); + } + N(SyntaxKind.BreakStatement); + { + N(SyntaxKind.BreakKeyword); + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + + [Fact] + public void DeclarationPattern_NullableArrayOfArray() + { + UsingStatement("switch (e) { case T[]?[] t: break; }"); + N(SyntaxKind.SwitchStatement); + { + N(SyntaxKind.SwitchKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "e"); + } + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SwitchSection); + { + N(SyntaxKind.CasePatternSwitchLabel); + { + N(SyntaxKind.CaseKeyword); + N(SyntaxKind.DeclarationPattern); + { + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + N(SyntaxKind.QuestionToken); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + } + N(SyntaxKind.SingleVariableDesignation); + { + N(SyntaxKind.IdentifierToken, "t"); + } + } + N(SyntaxKind.ColonToken); + } + N(SyntaxKind.BreakStatement); + { + N(SyntaxKind.BreakKeyword); + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + [Fact] public void NullableArray_TypeArgument() { diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index 40958cc511e81..ceb31b6b644af 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -108,6 +108,241 @@ public class AssertsFalseAttribute : Attribute public AssertsFalseAttribute () { } } } +"; + + protected const string AsyncStreamsTypes = @" +namespace System.Collections.Generic +{ + public interface IAsyncEnumerable + { + IAsyncEnumerator GetAsyncEnumerator(); + } + + public interface IAsyncEnumerator : System.IAsyncDisposable + { + System.Threading.Tasks.ValueTask MoveNextAsync(); + T Current { get; } + } +} +namespace System +{ + public interface IAsyncDisposable + { + System.Threading.Tasks.ValueTask DisposeAsync(); + } +} + +#nullable disable + +namespace System.Runtime.CompilerServices +{ + public interface IStrongBox + { + ref T Value { get; } + } +} + +namespace System.Threading.Tasks +{ + using System.Runtime.CompilerServices; + using System.Runtime.ExceptionServices; + using System.Threading.Tasks.Sources; + + public struct ManualResetValueTaskSourceLogic + { + private static readonly Action s_sentinel = new Action(s => throw new InvalidOperationException()); + + private readonly IStrongBox> _parent; + private Action _continuation; + private object _continuationState; + private object _capturedContext; + private ExecutionContext _executionContext; + private bool _completed; + private TResult _result; + private ExceptionDispatchInfo _error; + private short _version; + + public ManualResetValueTaskSourceLogic(IStrongBox> parent) + { + _parent = parent ?? throw new ArgumentNullException(nameof(parent)); + _continuation = null; + _continuationState = null; + _capturedContext = null; + _executionContext = null; + _completed = false; + _result = default; + _error = null; + _version = 0; + } + + public short Version => _version; + + private void ValidateToken(short token) + { + if (token != _version) + { + throw new InvalidOperationException(); + } + } + + public ValueTaskSourceStatus GetStatus(short token) + { + ValidateToken(token); + + return + !_completed ? ValueTaskSourceStatus.Pending : + _error == null ? ValueTaskSourceStatus.Succeeded : + _error.SourceException is OperationCanceledException ? ValueTaskSourceStatus.Canceled : + ValueTaskSourceStatus.Faulted; + } + + public TResult GetResult(short token) + { + ValidateToken(token); + + if (!_completed) + { + throw new InvalidOperationException(); + } + + _error?.Throw(); + return _result; + } + + public void Reset() + { + _version++; + + _completed = false; + _continuation = null; + _continuationState = null; + _result = default; + _error = null; + _executionContext = null; + _capturedContext = null; + } + + public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) + { + if (continuation == null) + { + throw new ArgumentNullException(nameof(continuation)); + } + ValidateToken(token); + + if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0) + { + _executionContext = ExecutionContext.Capture(); + } + + if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0) + { + SynchronizationContext sc = SynchronizationContext.Current; + if (sc != null && sc.GetType() != typeof(SynchronizationContext)) + { + _capturedContext = sc; + } + else + { + TaskScheduler ts = TaskScheduler.Current; + if (ts != TaskScheduler.Default) + { + _capturedContext = ts; + } + } + } + + _continuationState = state; + if (Interlocked.CompareExchange(ref _continuation, continuation, null) != null) + { + _executionContext = null; + + object cc = _capturedContext; + _capturedContext = null; + + switch (cc) + { + case null: + Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + break; + + case SynchronizationContext sc: + sc.Post(s => + { + var tuple = (Tuple, object>)s; + tuple.Item1(tuple.Item2); + }, Tuple.Create(continuation, state)); + break; + + case TaskScheduler ts: + Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts); + break; + } + } + } + + public void SetResult(TResult result) + { + _result = result; + SignalCompletion(); + } + + public void SetException(Exception error) + { + _error = ExceptionDispatchInfo.Capture(error); + SignalCompletion(); + } + + private void SignalCompletion() + { + if (_completed) + { + throw new InvalidOperationException(); + } + _completed = true; + + if (Interlocked.CompareExchange(ref _continuation, s_sentinel, null) != null) + { + if (_executionContext != null) + { + ExecutionContext.Run( + _executionContext, + s => ((IStrongBox>)s).Value.InvokeContinuation(), + _parent ?? throw new InvalidOperationException()); + } + else + { + InvokeContinuation(); + } + } + } + + private void InvokeContinuation() + { + object cc = _capturedContext; + _capturedContext = null; + + switch (cc) + { + case null: + _continuation(_continuationState); + break; + + case SynchronizationContext sc: + sc.Post(s => + { + ref ManualResetValueTaskSourceLogic logicRef = ref ((IStrongBox>)s).Value; + logicRef._continuation(logicRef._continuationState); + }, _parent ?? throw new InvalidOperationException()); + break; + + case TaskScheduler ts: + Task.Factory.StartNew(_continuation, _continuationState, CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts); + break; + } + } + } +} "; protected static CSharpCompilationOptions WithNonNullTypesTrue(CSharpCompilationOptions options = null) diff --git a/src/Test/Utilities/Portable/Traits/CompilerFeature.cs b/src/Test/Utilities/Portable/Traits/CompilerFeature.cs index 25c13df1edac2..2615efc44acaf 100644 --- a/src/Test/Utilities/Portable/Traits/CompilerFeature.cs +++ b/src/Test/Utilities/Portable/Traits/CompilerFeature.cs @@ -33,5 +33,6 @@ public enum CompilerFeature StackAllocInitializer, NullCoalescingAssignment, AsyncStreams, + NullableReferenceTypes, } }