diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 7187b4a5e3f30..1d8009c2ceff2 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -1563,6 +1563,10 @@ private BoundExpression BindIdentifier( if (GetSymbolForPossibleFieldKeyword() is { } backingField) { expression = BindNonMethod(node, backingField, diagnostics, LookupResultKind.Viable, indexed: false, isError: false); + if (IsInsideNameof) + { + Error(diagnostics, ErrorCode.ERR_FieldKeywordInsideNameOf, node); + } } } } diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 3abfac0e83f71..7eb0b8a3802b3 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7001,4 +7001,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Unexpected keyword 'record'. Did you mean 'record struct' or 'record class'? + + Cannot use 'field' keyword inside 'nameof' expressions. + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 4b07492640e46..cafbaa6e06359 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2050,6 +2050,8 @@ internal enum ErrorCode ERR_NoDelegateConstraint = 9011, ERR_MisplacedRecord = 9012, + ERR_FieldKeywordInsideNameOf = 9013, + #endregion // Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd) diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index f68dcd3be5136..37119e712aa13 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -532,6 +532,11 @@ Funkce {0} není v C# 9.0 dostupná. Použijte prosím jazykovou verzi {1} nebo větší. + + Cannot use 'field' keyword inside 'nameof' expressions. + Cannot use 'field' keyword inside 'nameof' expressions. + + Field-like event '{0}' cannot be 'readonly'. Událost podobná poli {0} nemůže mít modifikátor readonly. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 508a996c17c0b..cb70dcf30c5cb 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -532,6 +532,11 @@ Die Funktion "{0}" ist in C# 9.0 nicht verfügbar. Verwenden Sie Sprachversion {1} oder höher. + + Cannot use 'field' keyword inside 'nameof' expressions. + Cannot use 'field' keyword inside 'nameof' expressions. + + Field-like event '{0}' cannot be 'readonly'. Ein feldähnliches Ereignis "{0}" darf nicht "readonly" sein. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 2908ff4afb81a..bd64294278d02 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -532,6 +532,11 @@ La característica "{0}" no está disponible en C# 9.0. Use la versión {1} del lenguaje o una posterior. + + Cannot use 'field' keyword inside 'nameof' expressions. + Cannot use 'field' keyword inside 'nameof' expressions. + + Field-like event '{0}' cannot be 'readonly'. El evento de tipo campo "{0}" no puede ser "readonly". diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index bbca3ed9d5fdd..768d4eb2c1d3f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -532,6 +532,11 @@ La fonctionnalité '{0}' n'est pas disponible en C# 9.0. Utilisez la version de langage {1} ou une version ultérieure. + + Cannot use 'field' keyword inside 'nameof' expressions. + Cannot use 'field' keyword inside 'nameof' expressions. + + Field-like event '{0}' cannot be 'readonly'. L'événement de type champ '{0}' ne peut pas être 'readonly'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index cbab7dce34dbc..f579173609b8d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -532,6 +532,11 @@ La funzionalità '{0}' non è disponibile in C# 9.0. Usare la versione {1} o versioni successive del linguaggio. + + Cannot use 'field' keyword inside 'nameof' expressions. + Cannot use 'field' keyword inside 'nameof' expressions. + + Field-like event '{0}' cannot be 'readonly'. L'evento simile a campo '{0}' non può essere 'readonly'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 794537811a0e8..98ef7d7367289 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -532,6 +532,11 @@ 機能 '{0}' は C# 9.0 では使用できません。言語バージョン {1} 以上を使用してください。 + + Cannot use 'field' keyword inside 'nameof' expressions. + Cannot use 'field' keyword inside 'nameof' expressions. + + Field-like event '{0}' cannot be 'readonly'. フィールドに類似したイベント '{0}' を 'readonly' にすることはできません。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 6e2f95eade78b..4baf018b78d8c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -532,6 +532,11 @@ '{0}' 기능은 C# 9.0에서 사용할 수 없습니다. {1} 이상의 언어 버전을 사용하세요. + + Cannot use 'field' keyword inside 'nameof' expressions. + Cannot use 'field' keyword inside 'nameof' expressions. + + Field-like event '{0}' cannot be 'readonly'. 필드와 유사한 이벤트 '{0}'이(가) 'readonly'일 수 없습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index c18e47055be97..b89134579c9a9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -532,6 +532,11 @@ Funkcja „{0}” nie jest dostępna w języku C# 9.0. Użyj języka w wersji {1} lub nowszej. + + Cannot use 'field' keyword inside 'nameof' expressions. + Cannot use 'field' keyword inside 'nameof' expressions. + + Field-like event '{0}' cannot be 'readonly'. Zdarzenie-pole „{0}” nie może być zadeklarowane jako „readonly”. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index fd93d2f204ded..81fd4a3b46f66 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -532,6 +532,11 @@ O recurso '{0}' não está disponível no C# 9.0. Use a versão da linguagem {1} ou superior. + + Cannot use 'field' keyword inside 'nameof' expressions. + Cannot use 'field' keyword inside 'nameof' expressions. + + Field-like event '{0}' cannot be 'readonly'. O evento '{0}' semelhante ao de campo não pode ser 'readonly'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 1a91c5e5625ec..fb2cc16e03c03 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -532,6 +532,11 @@ Функция "{0}" недоступна в C# 9.0. Используйте как минимум версию языка {1}. + + Cannot use 'field' keyword inside 'nameof' expressions. + Cannot use 'field' keyword inside 'nameof' expressions. + + Field-like event '{0}' cannot be 'readonly'. Подобное полю событие "{0}" не может быть readonly. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 9f7b4fb609c52..5dc93241e253a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -532,6 +532,11 @@ '{0}' özelliği C# 9.0'da kullanılamıyor. Lütfen {1} veya daha yüksek dil sürümünü kullanın. + + Cannot use 'field' keyword inside 'nameof' expressions. + Cannot use 'field' keyword inside 'nameof' expressions. + + Field-like event '{0}' cannot be 'readonly'. Alan benzeri '{0}' olayı 'readonly' olamaz. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 01d54adcd19b0..99a8d4a41389f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -532,6 +532,11 @@ 功能“{0}”在 C# 9.0 中不可用。请使用语言版本 {1} 或更高版本。 + + Cannot use 'field' keyword inside 'nameof' expressions. + Cannot use 'field' keyword inside 'nameof' expressions. + + Field-like event '{0}' cannot be 'readonly'. 类似字段的事件 "{0}" 不能为 "readonly"。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 85cdecf84ae38..eb9751002831f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -532,6 +532,11 @@ 在 C# 9.0 中無法使用 '{0}' 功能。請使用語言版本 {1} 或更高的版本。 + + Cannot use 'field' keyword inside 'nameof' expressions. + Cannot use 'field' keyword inside 'nameof' expressions. + + Field-like event '{0}' cannot be 'readonly'. 類似欄位的事件 '{0}' 不能是 'readonly'。 diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PropertyFieldKeywordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PropertyFieldKeywordTests.cs index 4712070312528..8ddc442a28ce1 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PropertyFieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PropertyFieldKeywordTests.cs @@ -104,6 +104,61 @@ public class MyAttribute : System.Attribute { public MyAttribute(string s) { } } +"); + var accessorBindingData = new SourcePropertySymbolBase.AccessorBindingData(); + comp.TestOnlyCompilationData = accessorBindingData; + comp.VerifyDiagnostics( + // (10,24): error CS9013: Cannot use 'field' keyword inside 'nameof' expressions. + // [My(nameof(field))] + Diagnostic(ErrorCode.ERR_FieldKeywordInsideNameOf, "field").WithLocation(10, 24) + ); + Assert.Equal(0, accessorBindingData.NumberOfPerformedAccessorBinding); + } + + [Fact] + public void TestNameOfField() + { + var comp = CreateCompilation(@" +public class C +{ + public int P + { + get + { + return nameof(field); + } + } +} +"); + var accessorBindingData = new SourcePropertySymbolBase.AccessorBindingData(); + comp.TestOnlyCompilationData = accessorBindingData; + comp.VerifyDiagnostics( + // (8,20): error CS0029: Cannot implicitly convert type 'string' to 'int' + // return nameof(field); + Diagnostic(ErrorCode.ERR_NoImplicitConv, "nameof(field)").WithArguments("string", "int").WithLocation(8, 20), + // (8,27): error CS9013: Cannot use 'field' keyword inside 'nameof' expressions. + // return nameof(field); + Diagnostic(ErrorCode.ERR_FieldKeywordInsideNameOf, "field").WithLocation(8, 27) + ); + Assert.Equal(0, accessorBindingData.NumberOfPerformedAccessorBinding); + } + + [Fact] + public void TestNameOfField_NameofIsMethodInvocation() + { + var comp = CreateCompilation(@" +public class C +{ + public int P + { + get + { + return nameof(field); + } + } + + public int nameof(int x) => 0; +} "); var accessorBindingData = new SourcePropertySymbolBase.AccessorBindingData(); comp.TestOnlyCompilationData = accessorBindingData; @@ -123,36 +178,35 @@ .method public hidebysig specialname instance int32 get_P () cil managed { // Method begins at RVA 0x2050 - // Code size 6 (0x6) + // Code size 13 (0xd) .maxstack 8 - IL_0000: call int32 C::'g__local|1_0'() - IL_0005: ret + IL_0000: ldarg.0 + IL_0001: ldarg.0 + IL_0002: ldfld int32 C::'

k__BackingField' + IL_0007: call instance int32 C::nameof(int32) + IL_000c: ret } // end of method C::get_P + .method public hidebysig + instance int32 nameof ( + int32 x + ) cil managed + { + // Method begins at RVA 0x205e + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldc.i4.0 + IL_0001: ret + } // end of method C::nameof .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { - // Method begins at RVA 0x2057 + // Method begins at RVA 0x2061 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method C::.ctor - .method assembly hidebysig static - int32 'g__local|1_0' () cil managed - { - .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( - 01 00 00 00 - ) - .custom instance void MyAttribute::.ctor(string) = ( - 01 00 05 66 69 65 6c 64 00 00 - ) - // Method begins at RVA 0x205f - // Code size 2 (0x2) - .maxstack 8 - IL_0000: ldc.i4.0 - IL_0001: ret - } // end of method C::'g__local|1_0' // Properties .property instance int32 P() { @@ -765,6 +819,81 @@ .property instance int32 P() Assert.Equal(0, accessorBindingData.NumberOfPerformedAccessorBinding); } + [Fact] + public void TestNameOfField_NameofIsLocalFunctionInvocation() + { + var comp = CreateCompilation(@" +public class C +{ + public int P + { + get + { + return nameof(field); + + int nameof(int x) => 0; + } + } +} +"); + var accessorBindingData = new SourcePropertySymbolBase.AccessorBindingData(); + comp.TestOnlyCompilationData = accessorBindingData; + comp.VerifyDiagnostics(); + VerifyTypeIL(comp, "C", @" +.class public auto ansi beforefieldinit C + extends [mscorlib]System.Object +{ + // Fields + .field private initonly int32 '

k__BackingField' + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname + instance int32 get_P () cil managed + { + // Method begins at RVA 0x2050 + // Code size 12 (0xc) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld int32 C::'

k__BackingField' + IL_0006: call int32 C::'g__nameof|1_0'(int32) + IL_000b: ret + } // end of method C::get_P + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x205d + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method C::.ctor + .method assembly hidebysig static + int32 'g__nameof|1_0' ( + int32 x + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2065 + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldc.i4.0 + IL_0001: ret + } // end of method C::'g__nameof|1_0' + // Properties + .property instance int32 P() + { + .get instance int32 C::get_P() + } +} // end of class C +"); + Assert.Equal(0, accessorBindingData.NumberOfPerformedAccessorBinding); + } + [Fact] public void TestFieldIsShadowedByField_ReferencedFromRegularLambda() { @@ -844,6 +973,34 @@ .property instance int32 P() Assert.Equal(0, accessorBindingData.NumberOfPerformedAccessorBinding); } + [Theory] + [InlineData("private void field() { }")] + [InlineData("private int field { get => 0; }")] + [InlineData("private int field;")] + public void TestNameOfField_FieldIsMember(string member) + { + var comp = CreateCompilation($@" +System.Console.WriteLine(new C().P); + +public class C +{{ + {member} + + public string P + {{ + get + {{ + return nameof(field); + }} + }} +}} +"); + var accessorBindingData = new SourcePropertySymbolBase.AccessorBindingData(); + comp.TestOnlyCompilationData = accessorBindingData; + CompileAndVerify(comp, expectedOutput: "field"); + Assert.Equal(0, accessorBindingData.NumberOfPerformedAccessorBinding); + } + [Fact(Skip = "PROTOTYPE(semi-auto-props): Assigning in constructor is not yet supported.")] public void TestFieldOnlyGetter() { @@ -4535,6 +4692,8 @@ public MyAttribute(string s) { } var fieldKeywordSymbolInfo = speculativeModel.GetSymbolInfo(fieldNode); var fieldKeywordSymbolInfo2 = model.GetSpeculativeSymbolInfo(attributeSyntax.SpanStart, fieldNode, bindingOption); + Assert.Equal(comp.GetTypeByMetadataName("C").GetFieldsToEmit().Single(), fieldKeywordSymbolInfo.Symbol.GetSymbol()); + if (bindingOption == SpeculativeBindingOption.BindAsTypeOrNamespace) { Assert.True(fieldKeywordSymbolInfo2.IsEmpty); @@ -4542,8 +4701,7 @@ public MyAttribute(string s) { } } else { - Assert.Equal(fieldKeywordSymbolInfo, fieldKeywordSymbolInfo2); - Assert.Equal(comp.GetTypeByMetadataName("C").GetFieldsToEmit().Single(), fieldKeywordSymbolInfo.Symbol.GetSymbol()); + Assert.Equal(fieldKeywordSymbolInfo2, fieldKeywordSymbolInfo); } var typeInfo = model.GetSpeculativeTypeInfo(attributeSyntax.SpanStart, fieldNode, bindingOption); @@ -4597,14 +4755,16 @@ public MyAttribute(string s) { } var fieldKeywordSymbolInfo = speculativeModel.GetSymbolInfo(fieldNode); var fieldKeywordSymbolInfo2 = model.GetSpeculativeSymbolInfo(attributeSyntax.SpanStart, fieldNode, bindingOption); - if (bindingOption == SpeculativeBindingOption.BindAsExpression) + Assert.Equal(comp.GetTypeByMetadataName("C").GetFieldsToEmit().Single(), fieldKeywordSymbolInfo.Symbol.GetSymbol()); + + if (bindingOption == SpeculativeBindingOption.BindAsTypeOrNamespace) { - Assert.Equal(fieldKeywordSymbolInfo, fieldKeywordSymbolInfo2); + Assert.True(fieldKeywordSymbolInfo2.IsEmpty); + Assert.Null(fieldKeywordSymbolInfo2.Symbol); } else { - Assert.True(fieldKeywordSymbolInfo2.IsEmpty); - Assert.Null(fieldKeywordSymbolInfo2.Symbol); + Assert.Equal(fieldKeywordSymbolInfo2, fieldKeywordSymbolInfo); } var typeInfo = model.GetSpeculativeTypeInfo(attributeSyntax.SpanStart, fieldNode, bindingOption); @@ -4616,7 +4776,6 @@ public MyAttribute(string s) { } Assert.Null(aliasInfo); Assert.Equal("System.Int32 C.

k__BackingField", comp.GetTypeByMetadataName("C").GetFieldsToEmit().Single().ToTestDisplayString()); - Assert.Equal(comp.GetTypeByMetadataName("C").GetFieldsToEmit().Single(), fieldKeywordSymbolInfo.Symbol.GetSymbol()); Assert.Equal(runNullableAnalysis == "always" ? 0 : 1, accessorBindingData.NumberOfPerformedAccessorBinding); }