diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs index 6e2280f48fead..f510c75ec2861 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs @@ -213,6 +213,10 @@ internal static SyntaxToken ExtractAnonymousTypeMemberName(this ExpressionSyntax continue; + case SyntaxKind.SuppressNullableWarningExpression: + input = ((PostfixUnaryExpressionSyntax)input).Operand; + continue; + default: return default(SyntaxToken); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index d8874eb23e32b..f72d843bae8c8 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -80646,9 +80646,9 @@ void M(C c) Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t4.Item1").WithLocation(25, 9), // line 6 - // (34,52): warning CS8619: Nullability of reference types in value of type '(C, string)' doesn't match target type '(C, string)'. + // (34,52): warning CS8619: Nullability of reference types in value of type '(C c, string)' doesn't match target type '(C, string)'. // (string, (C, string)) t6 = (null!, (c!, null!)); // warn - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "(c!, null!)").WithArguments("(C, string)", "(C, string)").WithLocation(34, 52), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "(c!, null!)").WithArguments("(C c, string)", "(C, string)").WithLocation(34, 52), // line 8 // (44,51): warning CS8619: Nullability of reference types in value of type '(C c, string?)' doesn't match target type '(C, string)'. @@ -85853,7 +85853,7 @@ static void F(string? x, string? y) { (object a, long b) t = (x, 0)/*T:(string? x, int)*/; // 1 (object a, (long b, object c)) t2 = (x, (0, y)/*T:(int, string? y)*/)/*T:(string? x, (int, string? y))*/; // 2, 3 - (object a, (long b, object c)) t3 = (x!, (0, y!)/*T:(int, string!)*/)/*T:(string!, (int, string!))*/; + (object a, (long b, object c)) t3 = (x!, (0, y!)/*T:(int, string! y)*/)/*T:(string! x, (int, string! y))*/; (int b, string? c)? t4 = null; (object? a, (long b, object? c)?) t5 = (x, t4)/*T:(string? x, (int b, string? c)? t4)*/; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ValueTupleTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ValueTupleTests.cs index 71f9cde3274ee..3be694cb565d3 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ValueTupleTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ValueTupleTests.cs @@ -843,5 +843,67 @@ void M() Assert.Equal("C", secondTupleArgInfo.Type.ToTestDisplayString()); Assert.Equal("C", secondTupleArgInfo.ConvertedType.ToTestDisplayString()); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80752")] + public void ElementNameInference_FromLocal_NullSuppression() + { + var source = """ + #nullable enable + + class C + { + string M() + { + string? str = null; + C? c = null; + var t = (str!, c!); + return t.str ?? ""; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var tupleExpression = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single(); + var tupleTypeInfo = model.GetTypeInfo(tupleExpression); + Assert.Equal("(System.String str, C c)", tupleTypeInfo.Type.ToTestDisplayString()); + Assert.Equal("(System.String str, C c)", tupleTypeInfo.ConvertedType.ToTestDisplayString()); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80752")] + public void ElementNameInference_FromPropertyName_NullSuppression() + { + var source = """ + #nullable enable + + class C + { + public string? Prop1 { get; set; } + + public string? Prop2 { get; set; } + + string M(C c) + { + var t = (c.Prop1!, c.Prop2!); + return t.Prop1 ?? ""; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var tupleExpression = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single(); + var tupleTypeInfo = model.GetTypeInfo(tupleExpression); + Assert.Equal("(System.String Prop1, System.String Prop2)", tupleTypeInfo.Type.ToTestDisplayString()); + Assert.Equal("(System.String Prop1, System.String Prop2)", tupleTypeInfo.ConvertedType.ToTestDisplayString()); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/AnonymousTypesSymbolTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/AnonymousTypesSymbolTests.cs index 3f21385a75283..e0afae33794fb 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/AnonymousTypesSymbolTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/AnonymousTypesSymbolTests.cs @@ -1927,5 +1927,79 @@ .maxstack 2 this.CompileAndVerify(compilation).VerifyIL("C.Main", expectedIL); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80752")] + public void ElementNameInference_FromLocal_NullSuppression() + { + var source = """ + #nullable enable + + class C + { + string M() + { + string? str = null; + C? c = null; + var a = new { str!, c! }; + return a.str ?? ""; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (9,23): error CS0746: Invalid anonymous type member declarator. Anonymous type members must be declared with a member assignment, simple name or member access. + // var a = new { str!, c! }; + Diagnostic(ErrorCode.ERR_InvalidAnonymousTypeMemberDeclarator, "str!").WithLocation(9, 23), + // (9,29): error CS0746: Invalid anonymous type member declarator. Anonymous type members must be declared with a member assignment, simple name or member access. + // var a = new { str!, c! }; + Diagnostic(ErrorCode.ERR_InvalidAnonymousTypeMemberDeclarator, "c!").WithLocation(9, 29)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var tupleExpression = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single(); + var tupleTypeInfo = model.GetTypeInfo(tupleExpression); + Assert.Equal("", tupleTypeInfo.Type.ToTestDisplayString()); + Assert.Equal("", tupleTypeInfo.ConvertedType.ToTestDisplayString()); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80752")] + public void ElementNameInference_FromPropertyName_NullSuppression() + { + var source = """ + #nullable enable + + class C + { + public string? Prop1 { get; set; } + + public string? Prop2 { get; set; } + + string M(C c) + { + var a = new { c.Prop1!, c.Prop2! }; + return a.Prop1 ?? ""; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (11,23): error CS0746: Invalid anonymous type member declarator. Anonymous type members must be declared with a member assignment, simple name or member access. + // var a = new { c.Prop1!, c.Prop2! }; + Diagnostic(ErrorCode.ERR_InvalidAnonymousTypeMemberDeclarator, "c.Prop1!").WithLocation(11, 23), + // (11,33): error CS0746: Invalid anonymous type member declarator. Anonymous type members must be declared with a member assignment, simple name or member access. + // var a = new { c.Prop1!, c.Prop2! }; + Diagnostic(ErrorCode.ERR_InvalidAnonymousTypeMemberDeclarator, "c.Prop2!").WithLocation(11, 33)); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var tupleExpression = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single(); + var tupleTypeInfo = model.GetTypeInfo(tupleExpression); + Assert.Equal("", tupleTypeInfo.Type.ToTestDisplayString()); + Assert.Equal("", tupleTypeInfo.ConvertedType.ToTestDisplayString()); + } } }