/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
52 926 строк
2 MB
Fred Silberberg
Add C# 15 language version (#84799)
11 авг 2026, 23:51
Не верифицирован
11 авг 2026, 23:51
1284a4a
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.VisualBasic; using Roslyn.Test.Utilities; using Xunit; using Xunit.Sdk; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics; [CompilerTrait(CompilerFeature.Extensions)] public partial class ExtensionTests : CompilingTestBase { private static string ExpectedOutput(string output) { return ExecutionConditionUtil.IsMonoOrCoreClr ? output : null; } private static void AssertExtensionDeclaration(INamedTypeSymbol symbol) { // Verify things that are common for all extension types Assert.Equal(TypeKind.Extension, symbol.TypeKind); Assert.True(symbol.IsExtension); Assert.False(string.IsNullOrEmpty(symbol.ExtensionGroupingName)); Assert.False(string.IsNullOrEmpty(symbol.ExtensionMarkerName)); Assert.Null(symbol.BaseType); Assert.Empty(symbol.Interfaces); Assert.Empty(symbol.AllInterfaces); Assert.True(symbol.IsReferenceType); Assert.False(symbol.IsValueType); Assert.False(symbol.IsAnonymousType); Assert.False(symbol.IsTupleType); Assert.False(symbol.IsNativeIntegerType); Assert.Equal(SpecialType.None, symbol.SpecialType); Assert.False(symbol.IsRefLikeType); Assert.False(symbol.IsUnmanagedType); Assert.False(symbol.IsReadOnly); Assert.False(symbol.IsRecord); Assert.Equal(CodeAnalysis.NullableAnnotation.None, symbol.NullableAnnotation); Assert.Throws<NotSupportedException>(() => { symbol.WithNullableAnnotation(CodeAnalysis.NullableAnnotation.Annotated); }); Assert.False(symbol.IsScriptClass); Assert.False(symbol.IsImplicitClass); Assert.False(symbol.IsComImport); Assert.False(symbol.IsFileLocal); Assert.Null(symbol.DelegateInvokeMethod); Assert.Null(symbol.EnumUnderlyingType); Assert.Null(symbol.AssociatedSymbol); Assert.False(symbol.MightContainExtensionMethods); Assert.Null(symbol.TupleUnderlyingType); Assert.True(symbol.TupleElements.IsDefault); Assert.False(symbol.IsSerializable); Assert.Null(symbol.NativeIntegerUnderlyingType); Assert.Equal(SymbolKind.NamedType, symbol.Kind); AssertEx.Equal("", symbol.Name); Assert.Equal(SpecialType.None, symbol.SpecialType); Assert.True(symbol.IsDefinition); Assert.False(symbol.IsStatic); Assert.False(symbol.IsVirtual); Assert.False(symbol.IsOverride); Assert.False(symbol.IsAbstract); Assert.True(symbol.IsSealed); Assert.False(symbol.IsExtern); Assert.False(symbol.IsImplicitlyDeclared); Assert.False(symbol.CanBeReferencedByName); Assert.Equal(Accessibility.Public, symbol.DeclaredAccessibility); var namedTypeSymbol = symbol.GetSymbol<NamedTypeSymbol>(); Assert.True(namedTypeSymbol.HasSpecialName); Assert.False(namedTypeSymbol.IsImplicitlyDeclared); } [Fact] public void EmptyExtension() { var src = """ public static class Extensions { extension(object) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( object '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2067 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$C43E2675C7BBF9284AF22FB8A9BF0280'::'<Extension>$' } // end of class <M>$C43E2675C7BBF9284AF22FB8A9BF0280 } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertExtensionDeclaration(symbol); Assert.Empty(symbol.MemberNames); Assert.Empty(symbol.InstanceConstructors); Assert.Empty(symbol.StaticConstructors); Assert.Empty(symbol.Constructors); Assert.Equal(0, symbol.Arity); Assert.False(symbol.IsGenericType); Assert.False(symbol.IsUnboundGenericType); Assert.Empty(symbol.TypeParameters); Assert.Empty(symbol.TypeArguments); Assert.Same(symbol, symbol.OriginalDefinition); Assert.Same(symbol, symbol.ConstructedFrom); AssertEx.Equal("Extensions", symbol.ContainingSymbol.Name); AssertEx.Equal("Extensions", symbol.ContainingType.Name); AssertEx.Equal("<M>$C43E2675C7BBF9284AF22FB8A9BF0280", symbol.MetadataName); var member = symbol.ContainingType.GetMembers().Single(); AssertEx.Equal("Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<M>$C43E2675C7BBF9284AF22FB8A9BF0280", member.ToTestDisplayString()); var underlying = (SourceNamedTypeSymbol)((Symbols.PublicModel.NamedTypeSymbol)member).UnderlyingNamedTypeSymbol; AssertEx.Equal("extension(System.Object)", underlying.ComputeExtensionGroupingRawName()); AssertEx.Equal("extension(System.Object)", underlying.ComputeExtensionMarkerRawName()); var format = new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces); AssertEx.Equal("Extensions.extension(System.Object)", symbol.ToDisplayString(format)); format = new SymbolDisplayFormat(kindOptions: SymbolDisplayKindOptions.IncludeTypeKeyword); AssertEx.Equal("Extensions.extension(Object)", symbol.ToDisplayString(format)); format = new SymbolDisplayFormat(); AssertEx.Equal("Extensions.extension(Object)", symbol.ToDisplayString(format)); format = new SymbolDisplayFormat(compilerInternalOptions: SymbolDisplayCompilerInternalOptions.UseMetadataMemberNames); AssertEx.Equal("Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<M>$C43E2675C7BBF9284AF22FB8A9BF0280", symbol.ToDisplayString(format)); var comp5 = CreateCompilation(src); comp5.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); comp5.VerifyEmitDiagnostics( // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // extension(object) { } Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5) ); } [Fact] public void TypeParameters_01() { // Unconstrained type parameter var src = """ public static class Extensions { extension<T>(T) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$8048A6C8BE30A622530249B904B537EB`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$01CE3801593377B4E240F33E20D30D50'<T> extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( !T '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2067 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$01CE3801593377B4E240F33E20D30D50'::'<Extension>$' } // end of class <M>$01CE3801593377B4E240F33E20D30D50 } // end of class <G>$8048A6C8BE30A622530249B904B537EB`1 } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertExtensionDeclaration(symbol); Assert.Equal(1, symbol.Arity); Assert.True(symbol.IsGenericType); Assert.False(symbol.IsUnboundGenericType); AssertEx.SequenceEqual(["T"], symbol.TypeParameters.ToTestDisplayStrings()); AssertEx.SequenceEqual(["T"], symbol.TypeArguments.ToTestDisplayStrings()); Assert.Same(symbol, symbol.OriginalDefinition); Assert.Same(symbol, symbol.ConstructedFrom); AssertEx.Equal("Extensions", symbol.ContainingSymbol.Name); AssertEx.Equal("Extensions", symbol.ContainingType.Name); AssertEx.Equal("<M>$01CE3801593377B4E240F33E20D30D50", symbol.MetadataName); var member = symbol.ContainingType.GetMembers().Single(); AssertEx.Equal("Extensions.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$01CE3801593377B4E240F33E20D30D50", member.ToTestDisplayString()); var constructed = symbol.Construct(comp.GetSpecialType(SpecialType.System_Int32)); Assert.True(constructed.IsExtension); AssertEx.Equal("Extensions.<G>$8048A6C8BE30A622530249B904B537EB<System.Int32>.<M>$01CE3801593377B4E240F33E20D30D50", constructed.ToTestDisplayString()); AssertEx.Equal("<M>$01CE3801593377B4E240F33E20D30D50", constructed.MetadataName); Assert.NotSame(symbol, constructed); Assert.Same(symbol, constructed.OriginalDefinition); Assert.Same(symbol, constructed.ConstructedFrom); var unbound = symbol.ConstructUnboundGenericType(); AssertEx.Equal("Extensions.<G>$8048A6C8BE30A622530249B904B537EB<>.<M>$01CE3801593377B4E240F33E20D30D50", unbound.ToTestDisplayString()); Assert.True(unbound.IsUnboundGenericType); Assert.NotSame(symbol, unbound); Assert.Same(symbol, unbound.OriginalDefinition); Assert.Same(symbol, unbound.ConstructedFrom); } [Fact] public void TypeParameters_02() { // Constrained type parameter var src = """ public static class Extensions { extension<T>(T) where T : struct { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$BCF902721DDD961E5243C324D8379E5C`1'<valuetype .ctor ([mscorlib]System.ValueType) $T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$B865B3ED3C68CE2EBBC104FFAF3CFF93'<valuetype .ctor ([mscorlib]System.ValueType) T> extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( !T '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2067 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$B865B3ED3C68CE2EBBC104FFAF3CFF93'::'<Extension>$' } // end of class <M>$B865B3ED3C68CE2EBBC104FFAF3CFF93 } // end of class <G>$BCF902721DDD961E5243C324D8379E5C`1 } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); Assert.Equal(1, symbol.Arity); Assert.True(symbol.IsGenericType); AssertEx.SequenceEqual(["T"], symbol.TypeParameters.ToTestDisplayStrings()); AssertEx.SequenceEqual(["T"], symbol.TypeArguments.ToTestDisplayStrings()); Assert.True(symbol.TypeParameters.Single().IsValueType); Assert.False(symbol.TypeParameters.Single().IsReferenceType); Assert.Empty(symbol.TypeParameters.Single().ConstraintTypes); var format = new SymbolDisplayFormat(genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints); AssertEx.Equal("Extensions.extension<T>(T) where T : struct", symbol.ToDisplayString(format)); } [Fact] public void TypeParameters_03() { // Constraint on undefined type parameter var src = """ public static class Extensions { extension(object) where T : struct { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,23): error CS0080: Constraints are not allowed on non-generic declarations // extension(object) where T : struct { } Diagnostic(ErrorCode.ERR_ConstraintOnlyAllowedOnGenericDecl, "where").WithLocation(3, 23)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); Assert.Equal(0, symbol.Arity); Assert.False(symbol.IsGenericType); Assert.Empty(symbol.TypeParameters.ToTestDisplayStrings()); Assert.Empty(symbol.TypeArguments.ToTestDisplayStrings()); } [Fact] public void TypeParameters_04() { // Type parameter variance var src = """ public static class Extensions { extension<out T>(T) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS1960: Invalid variance modifier. Only interface and delegate type parameters can be specified as variant. // extension<out T>(object) { } Diagnostic(ErrorCode.ERR_IllegalVarianceSyntax, "out").WithLocation(3, 15)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); Assert.Equal(1, symbol.Arity); Assert.True(symbol.IsGenericType); AssertEx.SequenceEqual(["out T"], symbol.TypeParameters.ToTestDisplayStrings()); AssertEx.SequenceEqual(["out T"], symbol.TypeArguments.ToTestDisplayStrings()); } [Fact] public void TypeParameters_05() { // Duplicate type parameter var src = """ public static class Extensions { extension<T, T>(T) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,18): error CS0692: Duplicate type parameter 'T' // extension<T, T>(T) { } Diagnostic(ErrorCode.ERR_DuplicateTypeParameter, "T").WithArguments("T").WithLocation(3, 18), // (3,21): error CS0229: Ambiguity between 'T' and 'T' // extension<T, T>(T) { } Diagnostic(ErrorCode.ERR_AmbigMember, "T").WithArguments("T", "T").WithLocation(3, 21)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); Assert.Equal(2, symbol.Arity); AssertEx.SequenceEqual(["T", "T"], symbol.TypeParameters.ToTestDisplayStrings()); AssertEx.SequenceEqual(["T", "T"], symbol.TypeArguments.ToTestDisplayStrings()); } [Fact] public void TypeParameters_05_Nested() { // Duplicate type parameter var src = """ public static class Extensions { extension<T, T>(C<T>) { } } class C<T> { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,18): error CS0692: Duplicate type parameter 'T' // extension<T, T>(C<T>) { } Diagnostic(ErrorCode.ERR_DuplicateTypeParameter, "T").WithArguments("T").WithLocation(3, 18), // (3,23): error CS0229: Ambiguity between 'T' and 'T' // extension<T, T>(C<T>) { } Diagnostic(ErrorCode.ERR_AmbigMember, "T").WithArguments("T", "T").WithLocation(3, 23)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); Assert.Equal(2, symbol.Arity); AssertEx.SequenceEqual(["T", "T"], symbol.TypeParameters.ToTestDisplayStrings()); AssertEx.SequenceEqual(["T", "T"], symbol.TypeArguments.ToTestDisplayStrings()); } [Fact] public void TypeParameters_06() { // Type parameter same as outer type parameter var src = """ public static class Extensions<T> { extension<T>(T) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension<T>(object) { } Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 5), // (3,15): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions<T>' // extension<T>(object) { } Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions<T>").WithLocation(3, 15)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); Assert.Equal(1, symbol.Arity); AssertEx.SequenceEqual(["T"], symbol.TypeParameters.ToTestDisplayStrings()); AssertEx.SequenceEqual(["T"], symbol.TypeArguments.ToTestDisplayStrings()); var container = symbol.ContainingType; var substitutedExtension = (INamedTypeSymbol)container.Construct(comp.GetSpecialType(SpecialType.System_Int32)).GetMembers().Single(); AssertEx.Equal("Extensions<System.Int32>.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$01CE3801593377B4E240F33E20D30D50", substitutedExtension.ToTestDisplayString()); Assert.True(substitutedExtension.IsExtension); } [Fact] public void TypeParameters_07() { // Reserved type name for type parameter var src = $$""" public static class Extensions { extension<record>(record) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): warning CS8860: Types and aliases should not be named 'record'. // extension<record>(object) { } Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(3, 15)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertEx.SequenceEqual(["record"], symbol.TypeParameters.ToTestDisplayStrings()); } [Fact] public void TypeParameters_08() { // Reserved type name for type parameter var src = $$""" public static class Extensions { extension<file>(file) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS9056: Types and aliases cannot be named 'file'. // extension<file>(object) { } Diagnostic(ErrorCode.ERR_FileTypeNameDisallowed, "file").WithLocation(3, 15)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertEx.SequenceEqual(["file"], symbol.TypeParameters.ToTestDisplayStrings()); } [Fact] public void TypeParameters_09() { // Member name same as type parameter var src = $$""" public static class Extensions { extension<T>(T t) { void T() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void TypeParameters_10() { var src = $$""" #nullable enable public static class Extensions { extension<T>(T) where T : notnull { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$8048A6C8BE30A622530249B904B537EB`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$C7A07C3975E80DE5DBC93B5392C6C922'<T> extends [mscorlib]System.Object { .param type T .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 01 00 00 ) // Methods .method private hidebysig specialname static void '<Extension>$' ( !T '' ) cil managed { .custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 01 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x209d // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$C7A07C3975E80DE5DBC93B5392C6C922'::'<Extension>$' } // end of class <M>$C7A07C3975E80DE5DBC93B5392C6C922 } // end of class <G>$8048A6C8BE30A622530249B904B537EB`1 } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } [Fact] public void BadContainer_Generic() { var src = """ object.M(); public static class Extensions<T> { extension(object) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,8): error CS0117: 'object' does not contain a definition for 'M' // object.M(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 8), // (5,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(object) { public static void M() { } } Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(5, 5)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertExtensionDeclaration(symbol); Assert.True(symbol.IsGenericType); var members = symbol.ContainingType.GetMembers(); AssertEx.SequenceEqual([ "Extensions<T>.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<M>$C43E2675C7BBF9284AF22FB8A9BF0280", "void Extensions<T>.M()" ], members.ToTestDisplayStrings()); } [Fact] public void BadContainer_TopLevel() { var src = """ object.M(); extension(object) { public static void M() { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,8): error CS0117: 'object' does not contain a definition for 'M' // object.M(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 8), // (3,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(object) { public static void M() { } } Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 1)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertExtensionDeclaration(symbol); Assert.Null(symbol.ContainingType); AssertEx.Equal("<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<M>$C43E2675C7BBF9284AF22FB8A9BF0280", symbol.ToTestDisplayString()); } [Fact] public void BadContainer_Nested() { var src = """ object.M(); public static class Extensions { static void Method() { object.M(); } public static class Extensions2 { extension(object) { public static void M() { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,8): error CS0117: 'object' does not contain a definition for 'M' // object.M(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 8), // (7,16): error CS0117: 'object' does not contain a definition for 'M' // object.M(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(7, 16), // (12,9): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(object) { public static void M() { } } Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(12, 9)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var nestedExtension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Last(); var nestedExtensionSymbol = model.GetDeclaredSymbol(nestedExtension); AssertExtensionDeclaration(nestedExtensionSymbol); AssertEx.Equal("Extensions.Extensions2", nestedExtensionSymbol.ContainingType.ToTestDisplayString()); var members = nestedExtensionSymbol.ContainingType.GetMembers(); AssertEx.SequenceEqual([ "Extensions.Extensions2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<M>$C43E2675C7BBF9284AF22FB8A9BF0280", "void Extensions.Extensions2.M()" ], members.ToTestDisplayStrings()); } [Fact] public void BadContainer_NestedInExtension() { var src = """ string.M(); public static class Extensions { static void Method2() { string.M(); } extension(object) { static void Method() { string.M(); } extension(string) { public static void M() { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,8): error CS0117: 'string' does not contain a definition for 'M' // string.M(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("string", "M").WithLocation(1, 8), // (7,16): error CS0117: 'string' does not contain a definition for 'M' // string.M(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("string", "M").WithLocation(7, 16), // (14,20): error CS0117: 'string' does not contain a definition for 'M' // string.M(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("string", "M").WithLocation(14, 20), // (17,9): error CS9282: This member is not allowed in an extension block // extension(string) { public static void M() { } } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "extension").WithLocation(17, 9)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var nestedExtension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Last(); var nestedExtensionSymbol = model.GetDeclaredSymbol(nestedExtension); AssertExtensionDeclaration(nestedExtensionSymbol); AssertEx.Equal("Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<M>$C43E2675C7BBF9284AF22FB8A9BF0280", nestedExtensionSymbol.ContainingType.ToTestDisplayString()); AssertEx.SequenceEqual([ "void Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method()", "Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<G>$34505F560D9EACF86A87F3ED1F85E448.<M>$34505F560D9EACF86A87F3ED1F85E448" ], nestedExtensionSymbol.ContainingType.GetMembers().ToTestDisplayStrings()); } [Fact] public void BadContainer_TypeKind() { var src = """ object.M(); public static struct Extensions { extension(object) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,8): error CS0117: 'object' does not contain a definition for 'M' // object.M(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 8), // (3,22): error CS0106: The modifier 'static' is not valid for this item // public static struct Extensions Diagnostic(ErrorCode.ERR_BadMemberFlag, "Extensions").WithArguments("static").WithLocation(3, 22), // (5,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(object) { public static void M() { } } Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(5, 5)); } [Fact] public void BadContainer_NotStatic() { var src = """ object.M(); public class Extensions { extension(object) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,8): error CS0117: 'object' does not contain a definition for 'M' // object.M(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 8), // (5,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(object) { public static void M() { } } Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(5, 5)); } [Theory, CombinatorialData] public void ExtensionIndex_InPartial(bool reverseOrder) { var src1 = """ public static partial class Extensions { extension(object) { } } """; var src2 = """ public static partial class Extensions { } """; var src = reverseOrder ? new[] { src2, src1 } : new[] { src1, src2 }; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( object '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2067 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$C43E2675C7BBF9284AF22FB8A9BF0280'::'<Extension>$' } // end of class <M>$C43E2675C7BBF9284AF22FB8A9BF0280 } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var tree = comp.SyntaxTrees[reverseOrder ? 1 : 0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertExtensionDeclaration(symbol); AssertEx.Equal("<M>$C43E2675C7BBF9284AF22FB8A9BF0280", symbol.MetadataName); } [Fact] public void ExtensionIndex_InPartial_TwoExtension() { var src1 = """ public static partial class Extensions { extension<T>(T t) { } } """; var src2 = """ public static partial class Extensions { extension<T1, T2>((T1, T2) t) { } } """; var comp = CreateCompilation([src1, src2]); comp.VerifyEmitDiagnostics(); var tree1 = comp.SyntaxTrees[0]; var model1 = comp.GetSemanticModel(tree1); var extension1 = tree1.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol1 = model1.GetDeclaredSymbol(extension1); var sourceExtension1 = symbol1.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$D1693D81A12E8DED4ED68FE22D9E856F", symbol1.MetadataName); AssertEx.Equal("Extensions.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$D1693D81A12E8DED4ED68FE22D9E856F", sourceExtension1.ToTestDisplayString()); var tree2 = comp.SyntaxTrees[1]; var extension2 = tree2.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var model2 = comp.GetSemanticModel(tree2); var symbol2 = model2.GetDeclaredSymbol(extension2); var sourceExtension2 = symbol2.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$38DD3033A2145E0D2274BCCB48D8434F", symbol2.MetadataName); AssertEx.Equal("Extensions.<G>$B6FEF98A1719AAFE96009C5CC65441CB<T1, T2>.<M>$38DD3033A2145E0D2274BCCB48D8434F", sourceExtension2.ToTestDisplayString()); } [Fact] public void ExtensionIndex_InPartial_TwoExtensions() { var src = """ public static partial class Extensions { extension<T>(T) { } } public static partial class Extensions { extension<T1, T2>((T1, T2)) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension1 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().First(); var symbol1 = model.GetDeclaredSymbol(extension1); AssertEx.Equal("<M>$01CE3801593377B4E240F33E20D30D50", symbol1.MetadataName); AssertEx.Equal("Extensions.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$01CE3801593377B4E240F33E20D30D50", symbol1.ToTestDisplayString()); var extension2 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Last(); var symbol2 = model.GetDeclaredSymbol(extension2); AssertEx.Equal("<M>$0A2F70F0BFFD1BC7F8C8E0A6CD0B0194", symbol2.MetadataName); AssertEx.Equal("Extensions.<G>$B6FEF98A1719AAFE96009C5CC65441CB<T1, T2>.<M>$0A2F70F0BFFD1BC7F8C8E0A6CD0B0194", symbol2.ToTestDisplayString()); } [Fact] public void ExtensionIndex_TwoExtensions_01() { var src = """ public static class Extensions { extension<T>(T) { } extension<T>(T) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension1 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().First(); var symbol1 = model.GetDeclaredSymbol(extension1); var sourceExtension1 = symbol1.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$01CE3801593377B4E240F33E20D30D50", symbol1.MetadataName); AssertEx.Equal("Extensions.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$01CE3801593377B4E240F33E20D30D50", symbol1.ToTestDisplayString()); var extension2 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Last(); var symbol2 = model.GetDeclaredSymbol(extension2); var sourceExtension2 = symbol2.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$01CE3801593377B4E240F33E20D30D50", symbol2.MetadataName); AssertEx.Equal("Extensions.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$01CE3801593377B4E240F33E20D30D50", symbol2.ToTestDisplayString()); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78222")] public void ExtensionInInterface() { var src = """ interface IInterface { extension(object) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(object) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 5) ); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78222")] public void ExtensionInClass() { var src = """ class SomeClass { extension(object) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(object) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 5) ); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78222")] public void ExtensionInStruct() { var src = """ struct SomeStruct { extension(object) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(object) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 5) ); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78222")] public void ExtensionInRecordClass() { var src = """ record class SomeRecord { extension(object) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(object) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 5) ); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78222")] public void ExtensionInRecordStruct() { var src = """ record struct SomeRecord { extension(object) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(object) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 5) ); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78222")] public void ExtensionInInterfaceWithVariance() { var src = """ interface IInterface<in T> { extension(object) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(object) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 5) ); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78135")] public void ExtensionWithCapturing() { var src = """ using System; using System.Text; var sb = new StringBuilder("Info: "); StringBuilder.Inspect(sb); public static class Extensions { extension(StringBuilder) { public static StringBuilder Inspect(StringBuilder sb) { var s = () => { foreach (char c in sb.ToString()) { Console.Write(c); } }; s(); return sb; } } } """; var comp = CreateCompilation(src); var verifier = CompileAndVerify(comp, expectedOutput: """ Info: """, expectedReturnCode: 0, trimOutput: false); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$CD29E70E0DCA5BBFCFAC7C2BEF3C5C99' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$CD29E70E0DCA5BBFCFAC7C2BEF3C5C99' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( class [mscorlib]System.Text.StringBuilder '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20fa // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$CD29E70E0DCA5BBFCFAC7C2BEF3C5C99'::'<Extension>$' } // end of class <M>$CD29E70E0DCA5BBFCFAC7C2BEF3C5C99 // Methods .method public hidebysig static class [mscorlib]System.Text.StringBuilder Inspect ( class [mscorlib]System.Text.StringBuilder sb ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 43 44 32 39 45 37 30 45 30 44 43 41 35 42 42 46 43 46 41 43 37 43 32 42 45 46 33 43 35 43 39 39 00 00 ) // Method begins at RVA 0x20bc // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$CD29E70E0DCA5BBFCFAC7C2BEF3C5C99'::Inspect } // end of class <G>$CD29E70E0DCA5BBFCFAC7C2BEF3C5C99 .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public class [mscorlib]System.Text.StringBuilder sb // Methods .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x2090 // 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__DisplayClass1_0'::.ctor .method assembly hidebysig instance void '<Inspect>b__0' () cil managed { // Method begins at RVA 0x20c4 // Code size 42 (0x2a) .maxstack 2 .locals init ( [0] string, [1] int32 ) IL_0000: ldarg.0 IL_0001: ldfld class [mscorlib]System.Text.StringBuilder Extensions/'<>c__DisplayClass1_0'::sb IL_0006: callvirt instance string [mscorlib]System.Object::ToString() IL_000b: stloc.0 IL_000c: ldc.i4.0 IL_000d: stloc.1 IL_000e: br.s IL_0020 // loop start (head: IL_0020) IL_0010: ldloc.0 IL_0011: ldloc.1 IL_0012: callvirt instance char [mscorlib]System.String::get_Chars(int32) IL_0017: call void [mscorlib]System.Console::Write(char) IL_001c: ldloc.1 IL_001d: ldc.i4.1 IL_001e: add IL_001f: stloc.1 IL_0020: ldloc.1 IL_0021: ldloc.0 IL_0022: callvirt instance int32 [mscorlib]System.String::get_Length() IL_0027: blt.s IL_0010 // end loop IL_0029: ret } // end of method '<>c__DisplayClass1_0'::'<Inspect>b__0' } // end of class <>c__DisplayClass1_0 // Methods .method public hidebysig static class [mscorlib]System.Text.StringBuilder Inspect ( class [mscorlib]System.Text.StringBuilder sb ) cil managed { // Method begins at RVA 0x2098 // Code size 35 (0x23) .maxstack 8 IL_0000: newobj instance void Extensions/'<>c__DisplayClass1_0'::.ctor() IL_0005: dup IL_0006: ldarg.0 IL_0007: stfld class [mscorlib]System.Text.StringBuilder Extensions/'<>c__DisplayClass1_0'::sb IL_000c: dup IL_000d: ldftn instance void Extensions/'<>c__DisplayClass1_0'::'<Inspect>b__0'() IL_0013: newobj instance void [mscorlib]System.Action::.ctor(object, native int) IL_0018: callvirt instance void [mscorlib]System.Action::Invoke() IL_001d: ldfld class [mscorlib]System.Text.StringBuilder Extensions/'<>c__DisplayClass1_0'::sb IL_0022: ret } // end of method Extensions::Inspect } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension1 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().First(); var symbol1 = model.GetDeclaredSymbol(extension1); var sourceExtension1 = symbol1.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$CD29E70E0DCA5BBFCFAC7C2BEF3C5C99", symbol1.MetadataName); AssertEx.Equal("Extensions.<G>$CD29E70E0DCA5BBFCFAC7C2BEF3C5C99.<M>$CD29E70E0DCA5BBFCFAC7C2BEF3C5C99", symbol1.ToTestDisplayString()); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78135")] [WorkItem("https://github.com/dotnet/roslyn/issues/78042")] public void ExtensionWithCapturing2() { var src = """ using System; var a = int.DoSomething(); a(); public static class IntExt { extension(int) { public static Action DoSomething() { var b = 7; Action a = () => { int a = 123; Console.WriteLine(a); b++; Console.WriteLine(b); }; Console.WriteLine("Some data"); ++b; return a; } } } """; var comp = CreateCompilation(src); var verifier = CompileAndVerify(comp, expectedOutput: """ Some data 123 9 """, expectedReturnCode: 0, trimOutput: false); verifier.VerifyTypeIL("IntExt", """ .class public auto ansi abstract sealed beforefieldinit IntExt extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x210b // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::'<Extension>$' } // end of class <M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69 // Methods .method public hidebysig static class [mscorlib]System.Action DoSomething () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 42 41 34 31 43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39 30 36 32 46 35 39 45 44 34 44 36 39 00 00 ) // Method begins at RVA 0x20d4 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::DoSomething } // end of class <G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69 .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public int32 b // Methods .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x208a // 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__DisplayClass1_0'::.ctor .method assembly hidebysig instance void '<DoSomething>b__0' () cil managed { // Method begins at RVA 0x20dc // Code size 35 (0x23) .maxstack 3 .locals init ( [0] int32 ) IL_0000: ldc.i4.s 123 IL_0002: call void [mscorlib]System.Console::WriteLine(int32) IL_0007: ldarg.0 IL_0008: ldfld int32 IntExt/'<>c__DisplayClass1_0'::b IL_000d: stloc.0 IL_000e: ldarg.0 IL_000f: ldloc.0 IL_0010: ldc.i4.1 IL_0011: add IL_0012: stfld int32 IntExt/'<>c__DisplayClass1_0'::b IL_0017: ldarg.0 IL_0018: ldfld int32 IntExt/'<>c__DisplayClass1_0'::b IL_001d: call void [mscorlib]System.Console::WriteLine(int32) IL_0022: ret } // end of method '<>c__DisplayClass1_0'::'<DoSomething>b__0' } // end of class <>c__DisplayClass1_0 // Methods .method public hidebysig static class [mscorlib]System.Action DoSomething () cil managed { // Method begins at RVA 0x2094 // Code size 52 (0x34) .maxstack 3 .locals init ( [0] class [mscorlib]System.Action, [1] int32 ) IL_0000: newobj instance void IntExt/'<>c__DisplayClass1_0'::.ctor() IL_0005: dup IL_0006: ldc.i4.7 IL_0007: stfld int32 IntExt/'<>c__DisplayClass1_0'::b IL_000c: dup IL_000d: ldftn instance void IntExt/'<>c__DisplayClass1_0'::'<DoSomething>b__0'() IL_0013: newobj instance void [mscorlib]System.Action::.ctor(object, native int) IL_0018: stloc.0 IL_0019: ldstr "Some data" IL_001e: call void [mscorlib]System.Console::WriteLine(string) IL_0023: dup IL_0024: ldfld int32 IntExt/'<>c__DisplayClass1_0'::b IL_0029: ldc.i4.1 IL_002a: add IL_002b: stloc.1 IL_002c: ldloc.1 IL_002d: stfld int32 IntExt/'<>c__DisplayClass1_0'::b IL_0032: ldloc.0 IL_0033: ret } // end of method IntExt::DoSomething } // end of class IntExt """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension1 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().First(); var symbol1 = model.GetDeclaredSymbol(extension1); var sourceExtension1 = symbol1.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69", symbol1.MetadataName); AssertEx.Equal("IntExt.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69", symbol1.ToTestDisplayString()); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78135")] [WorkItem("https://github.com/dotnet/roslyn/issues/78042")] public void ExtensionWithCapturing_LocalFunction() { var src = """ using System; var a = int.DoSomething(); a(); public static class IntExt { extension(int) { public static Action DoSomething() { var b = 7; Console.WriteLine("Some data"); ++b; return Do; void Do(){ int a = 123; Console.WriteLine(a); b++; Console.WriteLine(b); } } } } """; var comp = CreateCompilation(src); var verifier = CompileAndVerify(comp, expectedOutput: """ Some data 123 9 """, expectedReturnCode: 0, trimOutput: false); verifier.VerifyTypeIL("IntExt", """ .class public auto ansi abstract sealed beforefieldinit IntExt extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x210b // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::'<Extension>$' } // end of class <M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69 // Methods .method public hidebysig static class [mscorlib]System.Action DoSomething () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 42 41 34 31 43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39 30 36 32 46 35 39 45 44 34 44 36 39 00 00 ) // Method begins at RVA 0x20d2 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::DoSomething } // end of class <G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69 .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public int32 b // Methods .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x208a // 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__DisplayClass1_0'::.ctor .method assembly hidebysig instance void '<DoSomething>g__Do|0' () cil managed { // Method begins at RVA 0x20dc // Code size 35 (0x23) .maxstack 3 .locals init ( [0] int32 ) IL_0000: ldc.i4.s 123 IL_0002: call void [mscorlib]System.Console::WriteLine(int32) IL_0007: ldarg.0 IL_0008: ldfld int32 IntExt/'<>c__DisplayClass1_0'::b IL_000d: stloc.0 IL_000e: ldarg.0 IL_000f: ldloc.0 IL_0010: ldc.i4.1 IL_0011: add IL_0012: stfld int32 IntExt/'<>c__DisplayClass1_0'::b IL_0017: ldarg.0 IL_0018: ldfld int32 IntExt/'<>c__DisplayClass1_0'::b IL_001d: call void [mscorlib]System.Console::WriteLine(int32) IL_0022: ret } // end of method '<>c__DisplayClass1_0'::'<DoSomething>g__Do|0' } // end of class <>c__DisplayClass1_0 // Methods .method public hidebysig static class [mscorlib]System.Action DoSomething () cil managed { // Method begins at RVA 0x2094 // Code size 50 (0x32) .maxstack 3 .locals init ( [0] int32 ) IL_0000: newobj instance void IntExt/'<>c__DisplayClass1_0'::.ctor() IL_0005: dup IL_0006: ldc.i4.7 IL_0007: stfld int32 IntExt/'<>c__DisplayClass1_0'::b IL_000c: ldstr "Some data" IL_0011: call void [mscorlib]System.Console::WriteLine(string) IL_0016: dup IL_0017: ldfld int32 IntExt/'<>c__DisplayClass1_0'::b IL_001c: ldc.i4.1 IL_001d: add IL_001e: stloc.0 IL_001f: dup IL_0020: ldloc.0 IL_0021: stfld int32 IntExt/'<>c__DisplayClass1_0'::b IL_0026: ldftn instance void IntExt/'<>c__DisplayClass1_0'::'<DoSomething>g__Do|0'() IL_002c: newobj instance void [mscorlib]System.Action::.ctor(object, native int) IL_0031: ret } // end of method IntExt::DoSomething } // end of class IntExt """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension1 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().First(); var symbol1 = model.GetDeclaredSymbol(extension1); var sourceExtension1 = symbol1.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69", symbol1.MetadataName); AssertEx.Equal("IntExt.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69", symbol1.ToTestDisplayString()); } [Fact] public void ExtensionIndex_TwoExtensions_02() { var src = """ public static class Extensions { extension<T>(T) { } class C { } extension<T>(T) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension1 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().First(); var symbol1 = model.GetDeclaredSymbol(extension1); var sourceExtension1 = symbol1.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$01CE3801593377B4E240F33E20D30D50", symbol1.MetadataName); AssertEx.Equal("Extensions.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$01CE3801593377B4E240F33E20D30D50", symbol1.ToTestDisplayString()); var extension2 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Last(); var symbol2 = model.GetDeclaredSymbol(extension2); var sourceExtension2 = symbol2.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$01CE3801593377B4E240F33E20D30D50", symbol2.MetadataName); AssertEx.Equal("Extensions.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$01CE3801593377B4E240F33E20D30D50", symbol2.ToTestDisplayString()); } [Fact] public void ExtensionIndex_TwoExtensions_03() { var src = """ extension<T>(T) { } class C { } extension<T>(T) { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension<T>(object) { } Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(1, 1), // (3,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension<T>(object) { } Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 1)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension1 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().First(); var symbol1 = model.GetDeclaredSymbol(extension1); var sourceExtension1 = symbol1.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$01CE3801593377B4E240F33E20D30D50", symbol1.MetadataName); AssertEx.Equal("<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$01CE3801593377B4E240F33E20D30D50", symbol1.ToTestDisplayString()); var extension2 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Last(); var symbol2 = model.GetDeclaredSymbol(extension2); var sourceExtension2 = symbol2.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$01CE3801593377B4E240F33E20D30D50", symbol2.MetadataName); AssertEx.Equal("<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$01CE3801593377B4E240F33E20D30D50", symbol2.ToTestDisplayString()); } [Fact] public void ExtensionIndex_TwoExtensions_05() { var src = """ public static class Extensions { extension<T>(T) { } extension<T1, T2>((T1, T2) t) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension1 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().First(); var symbol1 = model.GetDeclaredSymbol(extension1); var sourceExtension1 = symbol1.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$01CE3801593377B4E240F33E20D30D50", symbol1.MetadataName); AssertEx.Equal("Extensions.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$01CE3801593377B4E240F33E20D30D50", symbol1.ToTestDisplayString()); var extension2 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Last(); var symbol2 = model.GetDeclaredSymbol(extension2); var sourceExtension2 = symbol2.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$38DD3033A2145E0D2274BCCB48D8434F", symbol2.MetadataName); AssertEx.Equal("Extensions.<G>$B6FEF98A1719AAFE96009C5CC65441CB<T1, T2>.<M>$38DD3033A2145E0D2274BCCB48D8434F", symbol2.ToTestDisplayString()); } [Fact] public void ExtensionIndex_TwoExtensions_06() { var src = """ public static class Extensions { extension<T>(T) { } extension<T1>(T1) where T1 : struct { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension1 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().First(); var symbol1 = model.GetDeclaredSymbol(extension1); var sourceExtension1 = symbol1.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$01CE3801593377B4E240F33E20D30D50", symbol1.MetadataName); AssertEx.Equal("Extensions.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$01CE3801593377B4E240F33E20D30D50", symbol1.ToTestDisplayString()); var extension2 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Last(); var symbol2 = model.GetDeclaredSymbol(extension2); var sourceExtension2 = symbol2.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$0F0A7F439039332917C923D7DF48FA4C", symbol2.MetadataName); AssertEx.Equal("Extensions.<G>$BCF902721DDD961E5243C324D8379E5C<T1>.<M>$0F0A7F439039332917C923D7DF48FA4C", symbol2.ToTestDisplayString()); } [Fact] public void ExtensionIndex_ElevenExtensions() { var src = """ public static class Extensions { extension<T1>(T1 o1) { } extension<T2>(T2 o2) { } extension<T3>(T3 o3) { } extension<T4>(T4 o4) { } extension<T5>(T5 o5) { } extension<T6>(T6 o6) { } extension<T7>(T7 o7) { } extension<T8>(T8 o8) { } extension<T9>(T9 o9) { } extension<T10>(T10 o10) { } class C { } extension<T11>(T11 o11) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Last(); var symbol = model.GetDeclaredSymbol(extension); var sourceExtension = symbol.GetSymbol<SourceNamedTypeSymbol>(); AssertEx.Equal("<M>$9B08A69343790083B512FC2D1C4929FC", symbol.MetadataName); AssertEx.Equal("Extensions.<G>$8048A6C8BE30A622530249B904B537EB<T11>.<M>$9B08A69343790083B512FC2D1C4929FC", symbol.ToTestDisplayString()); } [Fact] public void Member_InstanceMethod() { var src = """ public static class Extensions { extension(object o) { internal void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method assembly hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method assembly hidebysig instance void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x2080 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method assembly hidebysig static void M ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method Extensions::M } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertEx.SequenceEqual(["M"], symbol.MemberNames); AssertEx.SequenceEqual(["", "M"], symbol.ContainingType.MemberNames); AssertEx.Equal("void Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", symbol.GetMember("M").ToTestDisplayString()); } [Fact] public void Member_ExtensionMethod() { var src = """ public static class Extensions { extension(object o) { void M(this int i) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,16): error CS0027: Keyword 'this' is not available in the current context // void M(this int i) { } Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(5, 16)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var method = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(method); AssertEx.Equal("void Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M(System.Int32 i)", symbol.ToTestDisplayString()); Assert.False(symbol.IsExtensionMethod); } [Fact] public void Member_StaticMethod() { var src = """ public static class Extensions { extension(object) { static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( object '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$C43E2675C7BBF9284AF22FB8A9BF0280'::'<Extension>$' } // end of class <M>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method private hidebysig static void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 43 34 33 45 32 36 37 35 43 37 42 42 46 39 32 38 34 41 46 32 32 46 42 38 41 39 42 46 30 32 38 30 00 00 ) // Method begins at RVA 0x2080 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method private hidebysig static void M () cil managed { // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method Extensions::M } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertEx.SequenceEqual(["M"], symbol.MemberNames); AssertEx.Equal("void Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", symbol.GetMember("M").ToTestDisplayString()); } [Fact] public void Member_InstanceMethod_ExplicitInterfaceImplementation() { var src = """ public interface I { void M(); } public static class Extensions { extension(object o) { void I.M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (10,16): error CS0541: 'Extensions.extension(object).M()': explicit interface declaration can only be declared in a class, record, struct or interface // void I.M() { } Diagnostic(ErrorCode.ERR_ExplicitInterfaceImplementationInNonClassOrStruct, "M").WithArguments("Extensions.extension(object).M()").WithLocation(10, 16), // (10,16): error CS9282: This member is not allowed in an extension block // void I.M() { } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "M").WithLocation(10, 16)); } [Fact] public void Member_InstanceMethod_ShadowingTypeParameter() { var src = """ public static class Extensions { extension<T>(T o) { void M<T>() { } void M2(int T) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,16): error CS9289: Type parameter 'T' has the same name as an extension container type parameter // void M<T>() { } Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(5, 16), // (6,21): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter // void M2(int T) { } Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(6, 21) ); } [Fact] public void Member_InstanceProperty() { var src = """ public static class Extensions { extension(object o) { int Property { get => 42; set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2082 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method private hidebysig specialname instance int32 get_Property () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x2084 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::get_Property .method private hidebysig specialname instance void set_Property ( int32 'value' ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x2084 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::set_Property // Properties .property instance int32 Property() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) .get instance int32 Extensions/'<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::get_Property() .set instance void Extensions/'<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::set_Property(int32) } } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method private hidebysig static int32 get_Property ( object o ) cil managed { // Method begins at RVA 0x207e // Code size 3 (0x3) .maxstack 8 IL_0000: ldc.i4.s 42 IL_0002: ret } // end of method Extensions::get_Property .method private hidebysig static void set_Property ( object o, int32 'value' ) cil managed { // Method begins at RVA 0x2082 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method Extensions::set_Property } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertEx.SequenceEqual(["Property"], symbol.MemberNames); AssertEx.Equal("System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; set; }", symbol.GetMember("Property").ToTestDisplayString()); AssertEx.Equal([ "System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; set; }", "System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property.get", "void Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property.set"], symbol.GetMembers().ToTestDisplayStrings()); } [Fact] public void Member_InstanceProperty_Auto() { var src = """ public static class Extensions { extension(object o) { int Property { get; set; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,13): error CS9282: This member is not allowed in an extension block // int Property { get; set; } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Property").WithLocation(5, 13)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertEx.SequenceEqual(["Property"], symbol.MemberNames); AssertEx.Equal("System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; set; }", symbol.GetMember("Property").ToTestDisplayString()); AssertEx.Equal([ "System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<Property>k__BackingField", "System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; set; }", "System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property.get", "void Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property.set"], symbol.GetMembers().ToTestDisplayStrings()); } [Fact] public void Member_InstanceProperty_ExplicitInterfaceImplementation() { var src = """ public interface I { int Property { get; set; } } public static class Extensions { extension(object o) { int I.Property { get => 42; set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (9,15): error CS0541: 'Extensions.extension(object).Property': explicit interface declaration can only be declared in a class, record, struct or interface // int I.Property { get => 42; set { } } Diagnostic(ErrorCode.ERR_ExplicitInterfaceImplementationInNonClassOrStruct, "Property").WithArguments("Extensions.extension(object).Property").WithLocation(9, 15)); } [Fact] public void Member_StaticProperty() { var src = """ public static class Extensions { extension(object) { static int Property { get => 42; set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( object '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2082 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$C43E2675C7BBF9284AF22FB8A9BF0280'::'<Extension>$' } // end of class <M>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method private hidebysig specialname static int32 get_Property () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 43 34 33 45 32 36 37 35 43 37 42 42 46 39 32 38 34 41 46 32 32 46 42 38 41 39 42 46 30 32 38 30 00 00 ) // Method begins at RVA 0x2084 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::get_Property .method private hidebysig specialname static void set_Property ( int32 'value' ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 43 34 33 45 32 36 37 35 43 37 42 42 46 39 32 38 34 41 46 32 32 46 42 38 41 39 42 46 30 32 38 30 00 00 ) // Method begins at RVA 0x2084 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::set_Property // Properties .property int32 Property() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 43 34 33 45 32 36 37 35 43 37 42 42 46 39 32 38 34 41 46 32 32 46 42 38 41 39 42 46 30 32 38 30 00 00 ) .get int32 Extensions/'<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::get_Property() .set void Extensions/'<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::set_Property(int32) } } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method private hidebysig static int32 get_Property () cil managed { // Method begins at RVA 0x207e // Code size 3 (0x3) .maxstack 8 IL_0000: ldc.i4.s 42 IL_0002: ret } // end of method Extensions::get_Property .method private hidebysig static void set_Property ( int32 'value' ) cil managed { // Method begins at RVA 0x2082 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method Extensions::set_Property } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertEx.SequenceEqual(["Property"], symbol.MemberNames); AssertEx.Equal("System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; set; }", symbol.GetMember("Property").ToTestDisplayString()); } [Fact] public void Member_StaticProperty_Auto() { var src = """ public static class Extensions { extension(object) { static int Property { get; set; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,20): error CS9282: This member is not allowed in an extension block // static int Property { get; set; } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Property").WithLocation(5, 20)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertEx.SequenceEqual(["Property"], symbol.MemberNames); AssertEx.SequenceEqual([ "System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<Property>k__BackingField", "System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; set; }", "System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property.get", "void Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property.set"], symbol.GetMembers().ToTestDisplayStrings()); AssertEx.Equal("System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; set; }", symbol.GetMember("Property").ToTestDisplayString()); } [Fact] public void Member_InstanceIndexer() { var src = """ public static class Extensions { extension(object o) { int this[int i] { get => 42; set { } } } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics( // (5,13): error CS9327: Feature 'extension indexers' is not available in C# 14.0. Please use language version 15.0 or greater. // int this[int i] { get => 42; set { } } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "this").WithArguments("extension indexers", "15.0").WithLocation(5, 13)); comp = CreateCompilation(src, parseOptions: TestOptions.Regular15); comp.VerifyEmitDiagnostics(); comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertEx.SequenceEqual(["this[]"], symbol.MemberNames); AssertEx.Equal("System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.this[System.Int32 i] { get; set; }", symbol.GetMember("this[]").ToTestDisplayString()); AssertEx.Equal([ "System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.this[System.Int32 i] { get; set; }", "System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.this[System.Int32 i].get", "void Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.this[System.Int32 i].set"], symbol.GetMembers().ToTestDisplayStrings()); var comp5 = CreateCompilation(src); comp5.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); comp5.VerifyEmitDiagnostics( // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // extension(object o) Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5) ); } [Fact] public void Member_StaticIndexer() { var src = """ public static class Extensions { extension(object o) { static int this[int i] { get => 42; set { } } } } """; var comp = CreateCompilation(src); comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); comp.VerifyEmitDiagnostics( // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // extension(object o) Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5), // (5,20): error CS0106: The modifier 'static' is not valid for this item // static int this[int i] { get => 42; set { } } Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("static").WithLocation(5, 20) ); } [Fact] public void Member_Type_01() { var src = """ public static class Extensions { extension(object) { class Nested { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,15): error CS9282: This member is not allowed in an extension block // class Nested { } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Nested").WithLocation(5, 15)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); Assert.Empty(symbol.MemberNames); AssertEx.SequenceEqual(["Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Nested"], symbol.GetMembers().ToTestDisplayStrings()); AssertEx.SequenceEqual(["Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Nested"], symbol.GetTypeMembers().ToTestDisplayStrings()); AssertEx.Equal("Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Nested", symbol.GetTypeMember("Nested").ToTestDisplayString()); } [Fact] public void Member_Type_02() { var src = """ C.Nested x = null; public static class Extensions { extension(C) { public class Nested { } } } class C { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,3): error CS0426: The type name 'Nested' does not exist in the type 'C' // C.Nested x = null; Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInAgg, "Nested").WithArguments("Nested", "C").WithLocation(1, 3), // (7,22): error CS9282: This member is not allowed in an extension block // public class Nested { } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Nested").WithLocation(7, 22)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var syntax = GetSyntax<QualifiedNameSyntax>(tree, "C.Nested"); Assert.Null(model.GetSymbolInfo(syntax).Symbol); } [Fact] public void Member_Type_03() { var src = """ object.Nested x = null; public static class Extensions { extension(object) { class Nested { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,8): error CS0117: 'object' does not contain a definition for 'Nested' // object.Nested x = null; Diagnostic(ErrorCode.ERR_NoSuchMember, "Nested").WithArguments("object", "Nested").WithLocation(1, 8), // (1,15): error CS1002: ; expected // object.Nested x = null; Diagnostic(ErrorCode.ERR_SemicolonExpected, "x").WithLocation(1, 15), // (1,15): error CS0103: The name 'x' does not exist in the current context // object.Nested x = null; Diagnostic(ErrorCode.ERR_NameNotInContext, "x").WithArguments("x").WithLocation(1, 15), // (7,15): error CS9282: This member is not allowed in an extension block // class Nested { } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Nested").WithLocation(7, 15)); } [Fact] public void Member_Constructor() { var src = """ public static class Extensions { extension(object) { Extensions() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,25): error CS1520: Method must have a return type // extension(object) { Extensions() { } } Diagnostic(ErrorCode.ERR_MemberNeedsType, "Extensions").WithLocation(3, 25), // (3,25): error CS9282: This member is not allowed in an extension block // extension(object) { Extensions() { } } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Extensions").WithLocation(3, 25)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertExtensionDeclaration(symbol); AssertEx.SequenceEqual([".ctor"], symbol.MemberNames); AssertEx.SequenceEqual(["Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280..ctor()"], symbol.InstanceConstructors.ToTestDisplayStrings()); Assert.Empty(symbol.StaticConstructors); AssertEx.SequenceEqual(["Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280..ctor()"], symbol.Constructors.ToTestDisplayStrings()); } [Fact] public void Member_Finalizer() { var src = """ public static class Extensions { extension(object) { ~Extensions() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,26): error CS9282: This member is not allowed in an extension block // extension(object) { ~Extensions() { } } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Extensions").WithLocation(3, 26)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertExtensionDeclaration(symbol); AssertEx.SequenceEqual(["Finalize"], symbol.MemberNames); AssertEx.SequenceEqual(["void Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Finalize()"], symbol.GetMembers().ToTestDisplayStrings()); } [Fact] public void Member_Field() { var src = """ _ = new object().field; public static class Extensions { extension(object o) { int field = 0; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,18): error CS1061: 'object' does not contain a definition for 'field' and no accessible extension method 'field' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // _ = new object().field; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "field").WithArguments("object", "field").WithLocation(1, 18), // (5,31): error CS9282: This member is not allowed in an extension block // extension(object o) { int field = 0; } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "field").WithLocation(5, 31), // (5,31): warning CS0169: The field 'Extensions.extension(object).field' is never used // extension(object o) { int field = 0; } Diagnostic(ErrorCode.WRN_UnreferencedField, "field").WithArguments("Extensions.extension(object).field").WithLocation(5, 31)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertExtensionDeclaration(symbol); AssertEx.SequenceEqual(["field"], symbol.MemberNames); AssertEx.SequenceEqual(["System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.field"], symbol.GetMembers().ToTestDisplayStrings()); } [Fact] public void Member_Const() { var src = """ public static class Extensions { extension(object) { const int i = 0; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,35): error CS9282: This member is not allowed in an extension block // extension(object) { const int i = 0; } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "i").WithLocation(3, 35)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertExtensionDeclaration(symbol); AssertEx.SequenceEqual(["i"], symbol.MemberNames); AssertEx.SequenceEqual(["System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.i"], symbol.GetMembers().ToTestDisplayStrings()); } [Fact] public void Member_InstanceEvent_ExplicitInterfaceImplementation() { var src = """ public interface I { event System.Action E; } public static class Extensions { extension(object o) { event System.Action I.E { add { } remove { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (9,31): error CS0541: 'Extensions.extension(object).E': explicit interface declaration can only be declared in a class, record, struct or interface // event System.Action I.E { add { } remove { } } Diagnostic(ErrorCode.ERR_ExplicitInterfaceImplementationInNonClassOrStruct, "E").WithArguments("Extensions.extension(object).E").WithLocation(9, 31), // (9,31): error CS9282: This member is not allowed in an extension block // event System.Action I.E { add { } remove { } } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "E").WithLocation(9, 31), // (9,35): error CS9282: This member is not allowed in an extension block // event System.Action I.E { add { } remove { } } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "add").WithLocation(9, 35), // (9,43): error CS9282: This member is not allowed in an extension block // event System.Action I.E { add { } remove { } } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "remove").WithLocation(9, 43)); } [Theory] [InlineData("class")] [InlineData("struct")] [InlineData("interface")] [InlineData("record")] [InlineData("record struct")] public void IsExtension_MiscTypeKinds(string typeKind) { var src = $$""" {{typeKind}} C { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<TypeDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); Assert.False(symbol.IsExtension); } [Fact] public void IsExtension_Delegate() { var src = $$""" delegate void C(); """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<DelegateDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); Assert.False(symbol.IsExtension); } [Fact] public void IsExtension_Enum() { var src = $$""" enum E { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<EnumDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); Assert.False(symbol.IsExtension); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/82444")] public void Attributes_01() { var src = """ public static class Extensions { [System.Obsolete] extension(object) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS7014: Attributes are not valid in this context. // [System.Obsolete] Diagnostic(ErrorCode.ERR_AttributesNotAllowed, "[System.Obsolete]").WithLocation(3, 5)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); Assert.Empty(symbol.GetAttributes()); } [Fact] public void Attributes_02() { var src = """ public static class Extensions { [My(nameof(o)), My(nameof(Extensions))] extension(object o) { } } public class MyAttribute : System.Attribute { public MyAttribute(string s) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS7014: Attributes are not valid in this context. // [My(nameof(o)), My(nameof(Extensions))] Diagnostic(ErrorCode.ERR_AttributesNotAllowed, "[My(nameof(o)), My(nameof(Extensions))]").WithLocation(3, 5)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/82445")] public void Attributes_03() { var src = """ public static class E { [return: System.Obsolete] extension(object) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS7014: Attributes are not valid in this context. // [return: System.Obsolete] Diagnostic(ErrorCode.ERR_AttributesNotAllowed, "[return: System.Obsolete]").WithLocation(3, 5)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); Assert.Empty(symbol.GetAttributes()); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/82445")] [InlineData("return")] [InlineData("assembly")] [InlineData("module")] [InlineData("type")] [InlineData("method")] [InlineData("field")] [InlineData("property")] [InlineData("typevar")] public void Attributes_04(string target) { var src = $$""" public static class E { [{{target}}: My] extension(object o) { } } public class MyAttribute : System.Attribute { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS7014: Attributes are not valid in this context. // [assembly: My] Diagnostic(ErrorCode.ERR_AttributesNotAllowed, $"[{target}: My]").WithLocation(3, 5)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); Assert.Empty(symbol.GetAttributes()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/82445")] public void Attributes_05() { var src = """ public static class E { extension<[typevar: My] T>(object o) { } } public class MyAttribute : System.Attribute { } """; var comp = CreateCompilation(src); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); AssertEx.SetEqual(["MyAttribute"], symbol.TypeParameters[0].GetAttributes().Select(a => a.ToString())); verifier.VerifyTypeIL("E", """ .class public auto ansi abstract sealed beforefieldinit E extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$F3EC63F55CD2663D3F6B00F6D7E0AC7E`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$6BF82573E4B1538004B57C462825CE6A'<T> extends [mscorlib]System.Object { .param type T .custom instance void MyAttribute::.ctor() = ( 01 00 00 00 ) // Methods .method private hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2067 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$6BF82573E4B1538004B57C462825CE6A'::'<Extension>$' } // end of class <M>$6BF82573E4B1538004B57C462825CE6A } // end of class <G>$F3EC63F55CD2663D3F6B00F6D7E0AC7E`1 } // end of class E """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/82445")] public void Attributes_06() { var src = """ public static class Extensions { [typevar: My] extension<T>(object o) { } } public class MyAttribute : System.Attribute { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS7014: Attributes are not valid in this context. // [typevar: My] Diagnostic(ErrorCode.ERR_AttributesNotAllowed, "[typevar: My]").WithLocation(3, 5)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); Assert.Empty(symbol.GetAttributes()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/82445")] public void Attributes_07() { var src = """ public static class Extensions { extension([param: My] object o) { } } public class MyAttribute : System.Attribute { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); AssertEx.SetEqual(["MyAttribute"], symbol.ExtensionParameter.GetAttributes().Select(a => a.ToString())); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/82445")] public void Attributes_08() { var src = $$""" public static class E { [fake: My] extension(object o) { } } public class MyAttribute : System.Attribute { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS7014: Attributes are not valid in this context. // [fake: My] Diagnostic(ErrorCode.ERR_AttributesNotAllowed, "[fake: My]").WithLocation(3, 5)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); Assert.Empty(symbol.GetAttributes()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/82445")] public void Attributes_09() { var src = """ public static class E { extension<[typevar: A] T>(object o) { } extension<[typevar: B] U>(object o) { } } public class AAttribute : System.Attribute { } public class BAttribute : System.Attribute { } """; var comp = CreateCompilation(src); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyTypeIL("E", """ .class public auto ansi abstract sealed beforefieldinit E extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$F3EC63F55CD2663D3F6B00F6D7E0AC7E`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$79443493B28002B8C849C38A5107CBE5'<T> extends [mscorlib]System.Object { .param type T .custom instance void AAttribute::.ctor() = ( 01 00 00 00 ) // Methods .method private hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2067 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$79443493B28002B8C849C38A5107CBE5'::'<Extension>$' } // end of class <M>$79443493B28002B8C849C38A5107CBE5 .class nested public auto ansi abstract sealed specialname '<M>$892BEE6C9B63CFFC80DE2A9BC76F34AB'<U> extends [mscorlib]System.Object { .param type U .custom instance void BAttribute::.ctor() = ( 01 00 00 00 ) // Methods .method private hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2067 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$892BEE6C9B63CFFC80DE2A9BC76F34AB'::'<Extension>$' } // end of class <M>$892BEE6C9B63CFFC80DE2A9BC76F34AB } // end of class <G>$F3EC63F55CD2663D3F6B00F6D7E0AC7E`1 } // end of class E """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } [Fact] public void ReceiverParameter() { var src = """ public static class Extensions { extension(object) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); AssertEx.Equal("System.Object", symbol.ExtensionParameter.ToTestDisplayString()); } [Fact] public void ReceiverParameter_WithIdentifier() { var src = """ public static class Extensions { extension(object o) { public object M() { return o; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); AssertEx.Equal("System.Object o", symbol.ExtensionParameter.ToTestDisplayString()); var returnStatement = GetSyntax<ReturnStatementSyntax>(tree, "return o;"); AssertEx.Equal("System.Object o", model.GetSymbolInfo(returnStatement.Expression).Symbol.ToTestDisplayString()); } [Fact] public void ReceiverParameter_Multiple() { var src = """ public static class Extensions { extension(int i, int j, C c) { } } class C { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,22): error CS9285: An extension container can have only one receiver parameter // extension(int i, int j, C c) { } Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "int j").WithLocation(3, 22), // (3,29): error CS9285: An extension container can have only one receiver parameter // extension(int i, int j, C c) { } Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "C c").WithLocation(3, 29)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); var extensionParameter = symbol.ExtensionParameter; AssertEx.Equal("System.Int32 i", extensionParameter.ToTestDisplayString()); Assert.True(extensionParameter.Equals(extensionParameter)); var parameterSyntaxes = tree.GetRoot().DescendantNodes().OfType<ParameterSyntax>().ToArray(); AssertEx.Equal("System.Int32 i", model.GetDeclaredSymbol(parameterSyntaxes[0]).ToTestDisplayString()); Assert.Same(extensionParameter, model.GetDeclaredSymbol(parameterSyntaxes[0])); AssertEx.Equal("System.Int32", model.GetTypeInfo(parameterSyntaxes[1].Type).Type.ToTestDisplayString()); Assert.Null(model.GetDeclaredSymbol(parameterSyntaxes[1])); AssertEx.Equal("C", model.GetTypeInfo(parameterSyntaxes[2].Type).Type.ToTestDisplayString()); Assert.Null(model.GetDeclaredSymbol(parameterSyntaxes[2])); } [Fact] public void ReceiverParameter_Multiple_MissingType() { var src = """ public static class Extensions { extension(int i, Type) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,22): error CS9285: An extension container can have only one receiver parameter // extension(int i, Type) { } Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "Type").WithLocation(3, 22)); } [Fact] public void ReceiverParameter_TypeParameter_Found() { var src = """ public static class Extensions { extension<T>(T) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); var extensionParameter = symbol.ExtensionParameter; AssertEx.Equal("T", extensionParameter.ToTestDisplayString()); Assert.Same(extensionParameter.Type, symbol.TypeParameters[0]); } [Fact] public void ReceiverParameter_TypeParameter_Found_FromContainingType() { var src = """ public static class Extensions<T> { extension(T) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(T) { } Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 5)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); var extensionParameter = symbol.ExtensionParameter; AssertEx.Equal("T", extensionParameter.ToTestDisplayString()); Assert.Same(extensionParameter.Type, symbol.ContainingType.TypeParameters[0]); } [Fact] public void ReceiverParameter_TypeParameter_Missing() { var src = """ public static class Extensions { extension(T) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS0246: The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?) // extension(T) Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "T").WithArguments("T").WithLocation(3, 15)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); var parameter = symbol.ExtensionParameter; AssertEx.Equal("T", parameter.ToTestDisplayString()); Assert.True(parameter.Type.IsErrorType()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78472")] public void ReceiverParameter_TypeParameter_Unreferenced_01() { var src = """ int.M(); int.M<string>(); public static class Extensions { extension<T>(int) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,5): error CS0411: The type arguments for method 'Extensions.extension<T>(int).M()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // int.M(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("Extensions.extension<T>(int).M()").WithLocation(1, 5)); } [Fact] public void ReceiverParameter_TypeParameter_Unreferenced_02() { var src = """ int.M(); int.M<int, string>(); public static class Extensions { extension<T1, T2>(T1) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,5): error CS0411: The type arguments for method 'Extensions.extension<T1, T2>(T1).M()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // int.M(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("Extensions.extension<T1, T2>(T1).M()").WithLocation(1, 5)); } [Fact] public void ReceiverParameter_TypeParameter_Unreferenced_03() { var src = """ int.M(); public static class Extensions { extension<T1, T2>(T1) where T1 : class { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,5): error CS0411: The type arguments for method 'Extensions.extension<T1, T2>(T1).M()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // int.M(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("Extensions.extension<T1, T2>(T1).M()").WithLocation(1, 5)); } [Fact] public void ReceiverParameter_TypeParameter_Unreferenced_04() { var src = """ public static class E { extension<T>(int i) { public int P => 0; // 1 } extension<T>(C<T> c) { public int P => 0; } } public class C<T> { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,20): error CS9295: The type parameter `T` is not referenced by either the extension parameter or a parameter of this member // public int P => 0; // 1 Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "P").WithArguments("T").WithLocation(5, 20)); } [Fact] public void ReceiverParameter_TypeParameter_Unreferenced_05() { var src = """ public static class E { extension<T>(int) { public static int P => 0; // 1 } extension<T1, T2>(int) { public static int P => 0; // 2, 3 } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,27): error CS9295: The type parameter `T` is not referenced by either the extension parameter or a parameter of this member // public static int P => 0; // 1 Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "P").WithArguments("T").WithLocation(5, 27), // (9,27): error CS9295: The type parameter `T1` is not referenced by either the extension parameter or a parameter of this member // public static int P => 0; // 2, 3 Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "P").WithArguments("T1").WithLocation(9, 27), // (9,27): error CS9295: The type parameter `T2` is not referenced by either the extension parameter or a parameter of this member // public static int P => 0; // 2, 3 Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "P").WithArguments("T2").WithLocation(9, 27)); } [Fact] public void ReceiverParameter_TypeParameter_Unreferenced_06() { var src = """ public static class E { extension<T>(int i) { public int P => 0; public void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,20): error CS9295: The type parameter `T` is not referenced by either the extension parameter or a parameter of this member // public int P => 0; Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "P").WithArguments("T").WithLocation(5, 20)); } [Fact] public void ReceiverParameter_TypeParameter_Unreferenced_07() { var src = """ public static class E { extension<T>(int i) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void ReceiverParameter_TypeParameter_Unreferenced_08() { var src = """ public static class E { extension<T>(int) { public static int operator +(int i, T t) => 0; public static int operator -(int i, int j) => 0; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,36): error CS9295: The type parameter `T` is not referenced by either the extension parameter or a parameter of this member // public static int operator -(int i, int j) => 0; Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "-").WithArguments("T").WithLocation(6, 36)); } [Fact] public void ReceiverParameter_TypeParameter_Unreferenced_09() { var src = """ public static class E { extension<T>(int i) { public void operator +=(T t) { } public void operator -=(int j) { } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (5,30): error CS9322: Cannot declare instance operator for a struct unless containing extension block receiver parameter is a 'ref' parameter // public void operator +=(T t) { } Diagnostic(ErrorCode.ERR_InstanceOperatorStructExtensionWrongReceiverRefKind, "+=").WithLocation(5, 30), // (6,30): error CS9322: Cannot declare instance operator for a struct unless containing extension block receiver parameter is a 'ref' parameter // public void operator -=(int j) { } Diagnostic(ErrorCode.ERR_InstanceOperatorStructExtensionWrongReceiverRefKind, "-=").WithLocation(6, 30), // (6,30): error CS9295: The type parameter `T` is not referenced by either the extension parameter or a parameter of this member // public void operator -=(int j) { } Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "-=").WithArguments("T").WithLocation(6, 30)); } [Fact] public void ReceiverParameter_TypeParameter_Unreferenced_10() { var src = """ public static class E { extension<T>(int i) { public static implicit operator string() => ""; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (5,41): error CS9282: Extension declarations can include only methods or properties // public static implicit operator string() => ""; Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "string").WithLocation(5, 41), // (5,41): error CS9295: The type parameter `T` is not referenced by either the extension parameter or a parameter of this member // public static implicit operator string() => ""; Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "string").WithArguments("T").WithLocation(5, 41), // (5,47): error CS1019: Overloadable unary operator expected // public static implicit operator string() => ""; Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "()").WithLocation(5, 47)); } [Fact] public void ReceiverParameter_TypeParameter_Unreferenced_11() { var src = """ public static class E { extension<T>(int i) { public int this[int j] => 0; public int this[long l, T t] => 0; } extension<T>(T t) { public int this[string s] => 0; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (5,20): error CS9295: The type parameter `T` is not referenced by either the extension parameter or a parameter of this member // public int this[int j] => 0; Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "this").WithArguments("T").WithLocation(5, 20)); } [Fact] public void ReceiverParameter_TypeParameter_Unreferenced_12() { var src = """ public static class E<T> { extension<U>(T t) { public int P => 0; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (3,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension<U>(T t) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 5)); } [Fact] public void ReceiverParameter_TypeParameter_Unreferenced_13() { var src = """ #nullable enable public static class E { extension<T>(T? t) { public int P => 0; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); } [Fact] public void ReceiverParameter_TypeParameter_TopLevelExtension() { var src = """ extension<T>(int i) { public int P => 0; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension<T>(int) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(1, 1)); } [Fact] public void ReceiverParameter_TypeParameter_Missing_Local() { var src = """ public static class Extensions { extension(T t) { void T() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS0246: The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?) // extension(T t) Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "T").WithArguments("T").WithLocation(3, 15), // (5,14): error CS9326: 'T': extension member names cannot be the same as their extended type // void T() { } Diagnostic(ErrorCode.ERR_MemberNameSameAsExtendedType, "T").WithArguments("T").WithLocation(5, 14)); } [Fact] public void ReceiverParameter_Params() { var src = """ public static class Extensions { extension(params int[] i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS1670: params is not valid in this context // extension(params int[] i) { } Diagnostic(ErrorCode.ERR_IllegalParams, "params").WithLocation(3, 15)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type1 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().First(); var symbol1 = model.GetDeclaredSymbol(type1); var parameter = symbol1.ExtensionParameter; AssertEx.Equal("System.Int32[] i", parameter.ToTestDisplayString()); Assert.False(parameter.IsParams); } [Fact] public void ReceiverParameter_Params_BadType() { var src = """ public static class Extensions { extension(params int i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS1670: params is not valid in this context // extension(params int i) { } Diagnostic(ErrorCode.ERR_IllegalParams, "params").WithLocation(3, 15)); } [Fact] public void ReceiverParameter_Params_NotLast() { var src = """ public static class Extensions { extension(params int[] i, int j) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS1670: params is not valid in this context // extension(params int[] i, int j) { } Diagnostic(ErrorCode.ERR_IllegalParams, "params").WithLocation(3, 15), // (3,31): error CS9285: An extension container can have only one receiver parameter // extension(params int[] i, int j) { } Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "int j").WithLocation(3, 31)); } [Fact] public void ReceiverParameter_ParameterTypeViolatesConstraint() { var src = """ public static class Extensions { extension<T>(C<T>) { } extension<T2>(C<T2>) where T2 : struct { } } public class C<T> where T : struct { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,18): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'C<T>' // extension<T>(C<T>) { } Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "C<T>").WithArguments("C<T>", "T", "T").WithLocation(3, 18)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type1 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().First(); var symbol1 = model.GetDeclaredSymbol(type1); AssertEx.Equal("C<T>", symbol1.ExtensionParameter.ToTestDisplayString()); } [Fact] public void ReceiverParameter_DefaultValue() { var src = """ public static class Extensions { extension(int i = 0) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value // extension(int i = 0) { } Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "int i = 0").WithLocation(3, 15)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); Assert.True(symbol.ExtensionParameter.HasExplicitDefaultValue); } [Fact] public void ReceiverParameter_DefaultValue_BeforeAnotherParameter() { var src = """ public static class Extensions { extension(int i = 0, object) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value // extension(int i = 0, object) { } Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "int i = 0").WithLocation(3, 15), // (3,26): error CS9285: An extension container can have only one receiver parameter // extension(int i = 0, object) { } Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "object").WithLocation(3, 26)); } [Fact] public void ReceiverParameter_DefaultValue_BadValue() { var src = """ public static class Extensions { extension(int i = null) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value // extension(int i = null) { } Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "int i = null").WithLocation(3, 15)); } [Fact] public void ReceiverParameter_DefaultValue_RefReadonly() { var src = """ public static class Extensions { extension(ref readonly int x = 2) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value // extension(ref readonly int x = 2) { } Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "ref readonly int x = 2").WithLocation(3, 15)); } [Fact] public void ReceiverParameter_Attributes_01() { var src = """ public static class Extensions { extension([System.Runtime.InteropServices.DefaultParameterValue(1)] int o = 2) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value // extension([System.Runtime.InteropServices.DefaultParameterValue(1)] int o = 2) { } Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "[System.Runtime.InteropServices.DefaultParameterValue(1)] int o = 2").WithLocation(3, 15), // (3,16): error CS1745: Cannot specify default parameter value in conjunction with DefaultParameterAttribute or OptionalAttribute // extension([System.Runtime.InteropServices.DefaultParameterValue(1)] int o = 2) { } Diagnostic(ErrorCode.ERR_DefaultValueUsedWithAttributes, "System.Runtime.InteropServices.DefaultParameterValue").WithLocation(3, 16)); } [Fact] public void ReceiverParameter_Attributes_02() { var src = """ public static class Extensions { extension([System.Runtime.InteropServices.Optional, System.Runtime.InteropServices.DefaultParameterValue(1)] ref readonly int i) { } extension([System.Runtime.InteropServices.Optional, System.Runtime.InteropServices.DefaultParameterValue(2)] ref readonly int) { } } """; var comp = CreateCompilation(src); // Note: we use "" name in the diagnostic for the second parameter // Note: these attributes are allowed on the receiver parameter of an extension method comp.VerifyEmitDiagnostics( // (3,57): warning CS9200: A default value is specified for 'ref readonly' parameter 'i', but 'ref readonly' should be used only for references. Consider declaring the parameter as 'in'. // extension([System.Runtime.InteropServices.Optional, System.Runtime.InteropServices.DefaultParameterValue(1)] ref readonly int i) { } Diagnostic(ErrorCode.WRN_RefReadonlyParameterDefaultValue, "System.Runtime.InteropServices.DefaultParameterValue(1)").WithArguments("i").WithLocation(3, 57), // (4,57): warning CS9200: A default value is specified for 'ref readonly' parameter '', but 'ref readonly' should be used only for references. Consider declaring the parameter as 'in'. // extension([System.Runtime.InteropServices.Optional, System.Runtime.InteropServices.DefaultParameterValue(2)] ref readonly int) { } Diagnostic(ErrorCode.WRN_RefReadonlyParameterDefaultValue, "System.Runtime.InteropServices.DefaultParameterValue(2)").WithArguments("").WithLocation(4, 57), // (4,127): error CS9305: Cannot use modifiers on the unnamed receiver parameter of extension block // extension([System.Runtime.InteropServices.Optional, System.Runtime.InteropServices.DefaultParameterValue(2)] ref readonly int) { } Diagnostic(ErrorCode.ERR_ModifierOnUnnamedReceiverParameter, "int").WithLocation(4, 127)); } [Fact] public void ReceiverParameter_Attributes_03() { var src = """ public static class Extensions { extension([System.Runtime.CompilerServices.ParamCollectionAttribute] int[] xs) { } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (3,16): error CS0674: Do not use 'System.ParamArrayAttribute'/'System.Runtime.CompilerServices.ParamCollectionAttribute'. Use the 'params' keyword instead. // extension([System.Runtime.CompilerServices.ParamCollectionAttribute] int[] xs) { } Diagnostic(ErrorCode.ERR_ExplicitParamArrayOrCollection, "System.Runtime.CompilerServices.ParamCollectionAttribute").WithLocation(3, 16)); } [Fact] public void ReceiverParameter_Attributes_04() { var src = """ public static class Extensions { extension([System.Runtime.CompilerServices.CallerLineNumber] int x = 2) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value // extension([System.Runtime.CompilerServices.CallerLineNumber] int x = 2) { } Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "[System.Runtime.CompilerServices.CallerLineNumber] int x = 2").WithLocation(3, 15)); } [Fact] public void ReceiverParameter_Attributes_54() { var src = """ public static class Extensions { extension([System.Runtime.CompilerServices.CallerLineNumber] int x) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,16): error CS4020: The CallerLineNumberAttribute may only be applied to parameters with default values // extension([System.Runtime.CompilerServices.CallerLineNumber] int x) { } Diagnostic(ErrorCode.ERR_BadCallerLineNumberParamWithoutDefaultValue, "System.Runtime.CompilerServices.CallerLineNumber").WithLocation(3, 16)); } [Fact] public void ReceiverParameter_Attributes_06() { var src = """ public static class Extensions { extension([My] int x) { } } public class MyAttribute : System.Attribute { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var parameter = tree.GetRoot().DescendantNodes().OfType<ParameterSyntax>().Single(); var parameterSymbol = model.GetDeclaredSymbol(parameter); AssertEx.Equal("System.Int32 x", parameterSymbol.ToTestDisplayString()); AssertEx.SetEqual(["MyAttribute"], parameterSymbol.GetAttributes().Select(a => a.ToString())); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var extensionSymbol = model.GetDeclaredSymbol(type); AssertEx.SetEqual(["MyAttribute"], extensionSymbol.ExtensionParameter.GetAttributes().Select(a => a.ToString())); } [Fact] public void ReceiverParameter_This_01() { var src = """ public static class Extensions { extension(this int i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS0027: Keyword 'this' is not available in the current context // extension(this int i) { } Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(3, 15)); } [Fact] public void ReceiverParameter_This_02() { var src = """ public static class Extensions { extension(int i, this int j) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,22): error CS9285: An extension container can have only one receiver parameter // extension(int i, this int j) { } Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "this int j").WithLocation(3, 22)); } [Fact] public void ReceiverParameter_This_03() { var src = """ public static class Extensions { extension(this this int i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,20): error CS1107: A parameter can only have one 'this' modifier // extension(this this int i) { } Diagnostic(ErrorCode.ERR_DupParamMod, "this").WithArguments("this").WithLocation(3, 20), // (3,20): error CS0027: Keyword 'this' is not available in the current context // extension(this this int i) { } Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(3, 20)); } [Fact] public void ReceiverParameter_Ref_01() { var src = """ int i = 42; i.M(); System.Console.Write(i); public static class Extensions { extension(ref int i) { public void M() { System.Console.Write(i); i = 43; } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "4243").VerifyDiagnostics(); } [Fact] public void ReceiverParameter_Ref_02() { var src = """ public static class Extensions { extension(ref ref int i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,19): error CS1107: A parameter can only have one 'ref' modifier // extension(ref ref int i) { } Diagnostic(ErrorCode.ERR_DupParamMod, "ref").WithArguments("ref").WithLocation(3, 19)); } [Fact] public void ReceiverParameter_Out_01() { var src = """ public static class Extensions { extension(out int i) { void M2() { } static void M3() { } } static void M(this out int i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS8328: The parameter modifier 'out' cannot be used with 'extension' // extension(out int i) Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15), // (5,14): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method // void M2() { } Diagnostic(ErrorCode.ERR_ParamUnassigned, "M2").WithArguments("i").WithLocation(5, 14), // (8,17): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method // static void M(this out int i) { } Diagnostic(ErrorCode.ERR_ParamUnassigned, "M").WithArguments("i").WithLocation(8, 17), // (8,24): error CS8328: The parameter modifier 'out' cannot be used with 'this' // static void M(this out int i) { } Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "this").WithLocation(8, 24)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type1 = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().First(); var symbol1 = model.GetDeclaredSymbol(type1); var parameter = symbol1.ExtensionParameter; AssertEx.Equal("out System.Int32 i", parameter.ToTestDisplayString()); Assert.Equal(RefKind.Out, parameter.RefKind); } [Fact] public void ReceiverParameter_Out_02() { var src = """ public static class Extensions { extension(int i, out int j) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,22): error CS9285: An extension container can have only one receiver parameter // extension(int i, out int j) { } Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "out int j").WithLocation(3, 22)); } [Fact] public void ReceiverParameter_Out_03() { var src = """ public static class Extensions { extension(out out int i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS8328: The parameter modifier 'out' cannot be used with 'extension' // extension(out out int i) { } Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15), // (3,19): error CS8328: The parameter modifier 'out' cannot be used with 'extension' // extension(out out int i) { } Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 19)); } [Fact] public void ReceiverParameter_Out_04() { var src = """ public static class Extensions { extension(out int i) { void M2(bool b) { if (b) return; else return; } } static void M(this out int i, bool b) { if (b) return; else return; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS8328: The parameter modifier 'out' cannot be used with 'extension' // extension(out int i) Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15), // (5,34): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method // void M2(bool b) { if (b) return; else return; } Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("i").WithLocation(5, 34), // (5,47): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method // void M2(bool b) { if (b) return; else return; } Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("i").WithLocation(5, 47), // (7,24): error CS8328: The parameter modifier 'out' cannot be used with 'this' // static void M(this out int i, bool b) { if (b) return; else return; } Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "this").WithLocation(7, 24), // (7,52): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method // static void M(this out int i, bool b) { if (b) return; else return; } Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("i").WithLocation(7, 52), // (7,65): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method // static void M(this out int i, bool b) { if (b) return; else return; } Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("i").WithLocation(7, 65)); } [Fact] public void ReceiverParameter_Out_05() { var src = """ public static class Extensions { extension(out int i) { void M2(bool b) { i = 0; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS8328: The parameter modifier 'out' cannot be used with 'extension' // extension(out int i) Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15)); } [Fact] public void ReceiverParameter_In_01() { var src = """ public static class Extensions { extension(in int i) { } static void M(this in int i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void ReceiverParameter_In_02() { var src = """ public static class Extensions { extension(in in int i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,18): error CS1107: A parameter can only have one 'in' modifier // extension(in in int i) { } Diagnostic(ErrorCode.ERR_DupParamMod, "in").WithArguments("in").WithLocation(3, 18)); } [Fact] public void ReceiverParameter_In_03() { var src = """ public static class Extensions { extension(in int i) { } extension(in object o) { } extension<T>(in T t) { } extension<T>(in T t) where T : struct { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,18): error CS9301: The 'in' or 'ref readonly' receiver parameter of extension must be a concrete (non-generic) value type. // extension(in object o) { } Diagnostic(ErrorCode.ERR_InExtensionParameterMustBeValueType, "object").WithLocation(4, 18), // (5,21): error CS9301: The 'in' or 'ref readonly' receiver parameter of extension must be a concrete (non-generic) value type. // extension<T>(in T t) { } Diagnostic(ErrorCode.ERR_InExtensionParameterMustBeValueType, "T").WithLocation(5, 21), // (6,21): error CS9301: The 'in' or 'ref readonly' receiver parameter of extension must be a concrete (non-generic) value type. // extension<T>(in T t) where T : struct { } Diagnostic(ErrorCode.ERR_InExtensionParameterMustBeValueType, "T").WithLocation(6, 21)); } [Fact] public void ReceiverParameter_RefReadonly_01() { var src = """ int i = 42; i.M(); public static class Extensions { extension(ref readonly int i) { public void M() { System.Console.Write(i); } } static void M2(this ref readonly int i) { } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, symbolValidator: (m) => { Assert.Equal(RefKind.RefReadOnlyParameter, m.GlobalNamespace.GetTypeMember("Extensions").GetTypeMembers().Single().ExtensionParameter.RefKind); }, expectedOutput: "42").VerifyDiagnostics(); } [Fact] public void ReceiverParameter_RefReadonly_02() { var src = """ public static class E { extension(ref readonly int i) { } extension(ref readonly object o) { } extension<T>(ref readonly T o) { } extension<T>(ref readonly T o) where T : struct { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,28): error CS9301: The 'in' or 'ref readonly' receiver parameter of extension must be a concrete (non-generic) value type. // extension(ref readonly object o) { } Diagnostic(ErrorCode.ERR_InExtensionParameterMustBeValueType, "object").WithLocation(4, 28), // (5,31): error CS9301: The 'in' or 'ref readonly' receiver parameter of extension must be a concrete (non-generic) value type. // extension<T>(ref readonly T o) { } Diagnostic(ErrorCode.ERR_InExtensionParameterMustBeValueType, "T").WithLocation(5, 31), // (6,31): error CS9301: The 'in' or 'ref readonly' receiver parameter of extension must be a concrete (non-generic) value type. // extension<T>(ref readonly T o) where T : struct { } Diagnostic(ErrorCode.ERR_InExtensionParameterMustBeValueType, "T").WithLocation(6, 31)); } [Fact] public void ReceiverParameter_ReadonlyRef() { var src = """ public static class Extensions { extension(readonly ref int i) { } static void M(this readonly ref int i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS9190: 'readonly' modifier must be specified after 'ref'. // extension(readonly ref int i) { } Diagnostic(ErrorCode.ERR_RefReadOnlyWrongOrdering, "readonly").WithLocation(3, 15), // (4,24): error CS9190: 'readonly' modifier must be specified after 'ref'. // static void M(this readonly ref int i) { } Diagnostic(ErrorCode.ERR_RefReadOnlyWrongOrdering, "readonly").WithLocation(4, 24)); } [Fact] public void ReceiverParameter_ArgList_01() { var src = """ _ = object.M(); public static class Extensions { extension(__arglist) { void M(){} } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,12): error CS0117: 'object' does not contain a definition for 'M' // _ = object.M(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 12), // (5,15): error CS1669: __arglist is not valid in this context // extension(__arglist) Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(5, 15)); Assert.Empty(comp.GetTypeByMetadataName("Extensions").GetMembers().OfType<MethodSymbol>()); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); AssertEqualAndNoDuplicates(_objectMembers, model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); } [Fact] public void ReceiverParameter_ArgList_02() { var src = """ public static class Extensions { extension(__arglist, int i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS1669: __arglist is not valid in this context // extension(__arglist, int i) { } Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(3, 15), // (3,26): error CS9285: An extension container can have only one receiver parameter // extension(__arglist, int i) { } Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "int i").WithLocation(3, 26)); } [Fact] public void ReceiverParameter_StaticType_01() { var src = """ public static class Extensions { extension(Extensions) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void ReceiverParameter_StaticType_02() { var src = """ public static class Extensions { extension(object o, Extensions e) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,25): error CS9285: An extension container can have only one receiver parameter // extension(object o, Extensions e) { } Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "Extensions e").WithLocation(3, 25)); } [Fact] public void ReceiverParameter_StaticType_03() { var src = """ public static class Extensions { extension(Extensions e) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS0721: 'Extensions': static types cannot be used as parameters // extension(Extensions) { } Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "Extensions").WithArguments("Extensions").WithLocation(3, 15)); } [Fact] public void ReceiverParameter_StaticType_04() { var src = """ extension(C) { } extension(C c) { } public static class C { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(C) { } Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(1, 1), // (2,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(C c) { } Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(2, 1), // (2,11): error CS0721: 'C': static types cannot be used as parameters // extension(C c) { } Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "C").WithArguments("C").WithLocation(2, 11)); } [Fact] public void ReceiverParameter_StaticType_05() { var src = """ static class Extensions { extension(C) { } } static class C {} """; var comp = CreateCompilation(src); CompileAndVerify(comp).VerifyDiagnostics(); } [Fact] public void ReceiverParameter_InstanceType_01() { var src = """ public static class Extensions { extension(C c) { } extension(C) { } } public class C { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void ReceiverParameter_ShadowingTypeParameter() { var src = """ public static class Extensions<T> { extension(object T) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(object T) { } Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(3, 5)); } [Fact] public void ReceiverParameter_Ref() { var src = """ int i = 42; i.M(43); public static class Extensions { extension(ref int i) { public void M(int j) { System.Console.Write((i, j)); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); src = """ static class E { extension(ref string s) // 1 { public static void M() { } public static int P => 0; } extension<T>(ref T t) // 2 { public static void M2() { } public static int P2 => 0; } extension(ref int i) { public static void M3() { } public static int P3 => 0; } extension<T>(ref T t) where T : struct { public static void M4() { } public static int P4 => 0; } } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,19): error CS9300: The 'ref' receiver parameter of an extension block must be a value type or a generic type constrained to struct. // extension(ref string s) // 1 Diagnostic(ErrorCode.ERR_RefExtensionParameterMustBeValueTypeOrConstrainedToOne, "string").WithLocation(3, 19), // (8,22): error CS9300: The 'ref' receiver parameter of an extension block must be a value type or a generic type constrained to struct. // extension<T>(ref T t) // 2 Diagnostic(ErrorCode.ERR_RefExtensionParameterMustBeValueTypeOrConstrainedToOne, "T").WithLocation(8, 22)); } [Fact] public void ReceiverParameter_Scoped_01() { var src = """ public static class Extensions { extension(scoped int i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. // extension(scoped int i) { } Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped int i").WithLocation(3, 15)); } [Fact] public void ReceiverParameter_Scoped_02() { var src = """ public static class Extensions { extension(int i, scoped int j) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,22): error CS9285: An extension container can have only one receiver parameter // extension(int i, scoped int j) { } Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "scoped int j").WithLocation(3, 22)); } [Fact] public void ReceiverParameter_Scoped_03() { var src = """ public static class Extensions { extension(scoped System.Span<int> i) { } public static void M(this scoped System.Span<int> i) { } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); } [Fact] public void ReceiverParameter_Nullable_01() { var src = """ public static class Extensions { extension(string?) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,21): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // extension(string?) { } Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(3, 21)); } [Fact] public void ReceiverParameter_Nullable_02() { var src = """ #nullable enable public static class Extensions { extension(string?) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void ReceiverParameter_RestrictedType() { var src = """ public static class Extensions { extension(ref System.ArgIterator a) { } extension(ref System.Span<int> s) { } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (3,15): error CS1601: Cannot make reference to variable of type 'ArgIterator' // extension(ref System.ArgIterator a) { } Diagnostic(ErrorCode.ERR_MethodArgCantBeRefAny, "ref System.ArgIterator a").WithArguments("System.ArgIterator").WithLocation(3, 15)); } [Fact] public void ReceiverParameter_Empty() { var src = """ public static class Extensions { extension() { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,15): error CS1031: Type expected // extension() { } Diagnostic(ErrorCode.ERR_TypeExpected, ")").WithLocation(3, 15)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var type = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(type); AssertEx.Equal("?", symbol.ExtensionParameter.ToTestDisplayString()); Assert.True(symbol.ExtensionParameter.Type.IsErrorType()); } [Fact] public void ReceiverParameter_ConstraintsCheck() { var src = """ static class Extensions { extension(System.Nullable<string> receiver) { } extension(System.Nullable<string>) { } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (3,39): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Nullable<T>' // extension(System.Nullable<string> receiver) Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "receiver").WithArguments("System.Nullable<T>", "T", "string").WithLocation(3, 39), // (7,15): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Nullable<T>' // extension(System.Nullable<string>) Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "System.Nullable<string>").WithArguments("System.Nullable<T>", "T", "string").WithLocation(7, 15) ); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78491")] public void ReceiverParameter_RefScope_01() { var src = """ int i = 42; i.M(); static class Extensions { extension(scoped ref int receiver) { public void M() => System.Console.Write(receiver); } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42", symbolValidator: (m) => { AssertEx.Equal(ScopedKind.ScopedRef, m.GlobalNamespace.GetTypeMember("Extensions").GetTypeMembers().Single().ExtensionParameter.EffectiveScope); }).VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78491")] public void ReceiverParameter_RefScope_02() { var src = """ int i = 42; i.M(); static class Extensions { extension(scoped ref int receiver) { public ref int M() => ref receiver; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (8,35): error CS9075: Cannot return a parameter by reference 'receiver' because it is scoped to the current method // public ref int M() => ref receiver; Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "receiver").WithArguments("receiver").WithLocation(8, 35)); } [Fact] public void ReceiverParameter_Nullability() { var src = """ #nullable enable static class Extensions { extension(string? receiver) { } extension(string?) { } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, symbolValidator: (m) => { var extensions = m.GlobalNamespace.GetTypeMember("Extensions").GetTypeMembers(); AssertEx.Equal("System.String?", extensions[0].ExtensionParameter.TypeWithAnnotations.ToTestDisplayString()); AssertEx.Equal("System.String?", extensions[1].ExtensionParameter.TypeWithAnnotations.ToTestDisplayString()); }).VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var parameters = tree.GetRoot().DescendantNodes().OfType<ParameterSyntax>().ToArray(); AssertEx.Equal("System.String? receiver", model.GetDeclaredSymbol(parameters[0]).ToTestDisplayString(includeNonNullable: true)); AssertEx.Equal("System.String?", model.GetDeclaredSymbol(parameters[1]).ToTestDisplayString(includeNonNullable: true)); } [Fact] public void ReceiverParameter_NativeInteger() { var src = """ #nullable enable static class Extensions { extension(nint receiver) { } extension(nint) { } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, symbolValidator: (m) => { var extensions = m.GlobalNamespace.GetTypeMember("Extensions").GetTypeMembers(); Assert.True(extensions[0].ExtensionParameter.Type.IsNativeIntegerType); Assert.True(extensions[1].ExtensionParameter.Type.IsNativeIntegerType); }).VerifyDiagnostics(); } [Fact] public void ReceiverParameter_InconsistentTypeAccessibility_01() { var src = """ public static class Extensions { extension(C x) { public void M() {} public int P { get => 0; set {}} public int this[int i] { get => 0; set {}} private void M1() {} private int P1 { get => 0; set {}} private int this[long i] { get => 0; set {}} internal void M2() {} internal int P2 { get => 0; set {}} internal int this[byte i] { get => 0; set {}} } } class C {} """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,21): error CS0051: Inconsistent accessibility: parameter type 'C' is less accessible than method 'Extensions.extension(C).M()' // public void M() {} Diagnostic(ErrorCode.ERR_BadVisParamType, "M").WithArguments("Extensions.extension(C).M()", "C").WithLocation(5, 21), // (6,20): error CS0055: Inconsistent accessibility: parameter type 'C' is less accessible than indexer or property 'Extensions.extension(C).P' // public int P { get => 0; set {}} Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "P").WithArguments("Extensions.extension(C).P", "C").WithLocation(6, 20), // (7,20): error CS0055: Inconsistent accessibility: parameter type 'C' is less accessible than indexer or property 'Extensions.extension(C).this[int]' // public int this[int i] { get => 0; set {}} Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "this").WithArguments("Extensions.extension(C).this[int]", "C").WithLocation(7, 20) ); } [Fact] public void ReceiverParameter_InconsistentTypeAccessibility_02() { var src = """ public static class Extensions { extension(C x) { } private class C {} } """; var comp = CreateCompilation(src); CompileAndVerify(comp).VerifyDiagnostics().VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested private auto ansi beforefieldinit C extends [mscorlib]System.Object { // Methods .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x2067 // 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 } // end of class C .class nested public auto ansi sealed specialname '<G>$C3CD11E70DE99F353AE602995BB874BF' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$4D270477BCDFAB12B9E9B1A79213B9FB' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( class Extensions/C x ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x206f // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$4D270477BCDFAB12B9E9B1A79213B9FB'::'<Extension>$' } // end of class <M>$4D270477BCDFAB12B9E9B1A79213B9FB } // end of class <G>$C3CD11E70DE99F353AE602995BB874BF } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } [Fact] public void ReceiverParameter_InconsistentTypeAccessibility_03() { var src = """ public static class Extensions { extension(C x) { public void M() {} public int P { get => 0; set {}} public int this[int i] { get => 0; set {}} private void M1() {} private int P1 { get => 0; set {}} private int this[long i] { get => 0; set {}} internal void M2() {} internal int P2 { get => 0; set {}} internal int this[byte i] { get => 0; set {}} } private class C {} } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,21): error CS0051: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than method 'Extensions.extension(Extensions.C).M()' // public void M() {} Diagnostic(ErrorCode.ERR_BadVisParamType, "M").WithArguments("Extensions.extension(Extensions.C).M()", "Extensions.C").WithLocation(5, 21), // (6,20): error CS0055: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than indexer or property 'Extensions.extension(Extensions.C).P' // public int P { get => 0; set {}} Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "P").WithArguments("Extensions.extension(Extensions.C).P", "Extensions.C").WithLocation(6, 20), // (7,20): error CS0055: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than indexer or property 'Extensions.extension(Extensions.C).this[int]' // public int this[int i] { get => 0; set {}} Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "this").WithArguments("Extensions.extension(Extensions.C).this[int]", "Extensions.C").WithLocation(7, 20), // (13,23): error CS0051: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than method 'Extensions.extension(Extensions.C).M2()' // internal void M2() {} Diagnostic(ErrorCode.ERR_BadVisParamType, "M2").WithArguments("Extensions.extension(Extensions.C).M2()", "Extensions.C").WithLocation(13, 23), // (14,22): error CS0055: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than indexer or property 'Extensions.extension(Extensions.C).P2' // internal int P2 { get => 0; set {}} Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "P2").WithArguments("Extensions.extension(Extensions.C).P2", "Extensions.C").WithLocation(14, 22), // (15,22): error CS0055: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than indexer or property 'Extensions.extension(Extensions.C).this[byte]' // internal int this[byte i] { get => 0; set {}} Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "this").WithArguments("Extensions.extension(Extensions.C).this[byte]", "Extensions.C").WithLocation(15, 22) ); } [Fact] public void ReceiverParameter_InconsistentTypeAccessibility_04() { var src = """ public static class Extensions { extension(C x) { public static void M() { } public static int P { get => 0; set { } } } private class C { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,28): error CS0051: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than method 'Extensions.extension(Extensions.C).M()' // public static void M() { } Diagnostic(ErrorCode.ERR_BadVisParamType, "M").WithArguments("Extensions.extension(Extensions.C).M()", "Extensions.C").WithLocation(5, 28), // (6,27): error CS0055: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than indexer 'Extensions.extension(Extensions.C).P' // public static int P { get => 0; set { } } Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "P").WithArguments("Extensions.extension(Extensions.C).P", "Extensions.C").WithLocation(6, 27)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/81251")] public void ReceiverParameter_Name() { // Unnamed extension parameter should not default to "value" as its name when round-tripped var libSrc = """ using System; public static class ArrayEx { extension(Array) { public static T[] Init<T>(T value) => throw null; } } """; var libComp = CreateCompilation(libSrc); libComp.VerifyDiagnostics(); var src = """ using System; Array.Init(value: 10); """; var comp = CreateCompilation([src, libSrc]); comp.VerifyEmitDiagnostics(); validate(comp); comp = CreateCompilation(src, references: [libComp.EmitToImageReference()]); comp.VerifyEmitDiagnostics(); validate(comp); comp = CreateCompilation(src, references: [libComp.ToMetadataReference()]); comp.VerifyEmitDiagnostics(); validate(comp); void validate(CSharpCompilation comp) { var extension = comp.GlobalNamespace.GetTypeMember("ArrayEx").GetTypeMembers("").Single(); Assert.True(extension.IsExtension); Assert.Equal("", extension.ExtensionParameter.Name); } } [Fact] public void InconsistentTypeAccessibility_01() { var src = """ public static class Extensions { extension(int x) { public void M1(C c) {} private void M2(C c) {} } extension(long x) { public static void M3(int y) { y.M2(new C()); } } public static void M4(int x) { x.M2(new C()); } private class C {} } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,21): error CS0051: Inconsistent accessibility: parameter type 'Extensions.C' is less accessible than method 'Extensions.extension(int).M1(Extensions.C)' // public void M1(C c) {} Diagnostic(ErrorCode.ERR_BadVisParamType, "M1").WithArguments("Extensions.extension(int).M1(Extensions.C)", "Extensions.C").WithLocation(5, 21) ); } [Fact] public void InconsistentTypeAccessibility_02() { var src = """ public static class Extensions { extension(int x) { public C M1 => null; private C M2 => null; } extension(long x) { public static void M3(int y) { _ = y.M2; } } public static void M4(int x) { _ = x.M2; } private class C {} } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,18): error CS0053: Inconsistent accessibility: property type 'Extensions.C' is less accessible than property 'Extensions.extension(int).M1' // public C M1 => null; Diagnostic(ErrorCode.ERR_BadVisPropertyType, "M1").WithArguments("Extensions.extension(int).M1", "Extensions.C").WithLocation(5, 18) ); } [Fact] public void Inaccessible_01() { var src = """ static class Extensions { extension(int x) { private void M2() {} } private static void M3(this int x) {} } class C { void Test(int x) { x.M2(); x.M3(); Extensions.M2(x); Extensions.M3(x); } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (15,11): error CS1061: 'int' does not contain a definition for 'M2' and no accessible extension method 'M2' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) // x.M2(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M2").WithArguments("int", "M2").WithLocation(15, 11), // (16,11): error CS1061: 'int' does not contain a definition for 'M3' and no accessible extension method 'M3' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) // x.M3(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M3").WithArguments("int", "M3").WithLocation(16, 11), // (17,20): error CS0122: 'Extensions.M2(int)' is inaccessible due to its protection level // Extensions.M2(x); Diagnostic(ErrorCode.ERR_BadAccess, "M2").WithArguments("Extensions.M2(int)").WithLocation(17, 20), // (18,20): error CS0122: 'Extensions.M3(int)' is inaccessible due to its protection level // Extensions.M3(x); Diagnostic(ErrorCode.ERR_BadAccess, "M3").WithArguments("Extensions.M3(int)").WithLocation(18, 20) ); } [Fact] public void ReceiverParameter_FileType_01() { var src = """ file class C {} static class Extensions { extension(C x) { } private static void M3(this C x) {} } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,14): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'Extensions'. // extension(C x) Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "(").WithArguments("C", "Extensions").WithLocation(5, 14), // (9,25): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'Extensions'. // private static void M3(this C x) {} Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M3").WithArguments("C", "Extensions").WithLocation(9, 25) ); } [Fact] public void ReceiverParameter_FileType_02() { var src = """ file class C {} file static class Extensions { extension(C x) { public void M1() {} public int P => 0; public int this[int i] => 0; } public static void M2(this C x) {} private static void M3(this C x) {} } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void FileType_01() { var src = """ file class C {} file static class Extensions { extension(int x) { public void M1(C c) {} public C P => null; public C this[int y] => null; public int this[C y] => 0; } public static void M2(this int x, C c) {} } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void ReceiverParameter_PointerType() { string source = """ unsafe static class E { extension(int* i) { public static void M() { } public static int P => 0; } public static void M2(this int* i) { } } """; // Note: we disallow even if the extension block only has static members var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll); comp.VerifyEmitDiagnostics( // (3,15): error CS1103: The receiver parameter of an extension cannot be of type 'int*' // extension(int* i) Diagnostic(ErrorCode.ERR_BadTypeforThis, "int*").WithArguments("int*").WithLocation(3, 15), // (8,32): error CS1103: The receiver parameter of an extension cannot be of type 'int*' // public static void M2(this int* i) { } Diagnostic(ErrorCode.ERR_BadTypeforThis, "int*").WithArguments("int*").WithLocation(8, 32)); NamedTypeSymbol e = comp.GlobalNamespace.GetTypeMember("E"); Assert.IsType<SourceNamedTypeSymbol>(e); Assert.False(e.IsExtension); Assert.Null(e.ExtensionGroupingName); Assert.Null(e.ExtensionMarkerName); } [Fact] public void Skeleton_01() { var src = """ public static class Extensions { extension(object o) { void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyIL("Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", """ { // Code size 6 (0x6) .maxstack 1 IL_0000: newobj "System.NotSupportedException..ctor()" IL_0005: throw } """); verifier.VerifyIL("Extensions.M", """ { // Code size 11 (0xb) .maxstack 1 IL_0000: ldstr "ran" IL_0005: call "void System.Console.Write(string)" IL_000a: ret } """); } [Fact] public void Skeleton_02() { var src = """ public static class E { extension(object o) { internal void M() { } internal void M2() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp); // Both skeletons have the same RVA verifier.VerifyTypeIL("E", """ .class public auto ansi abstract sealed beforefieldinit E extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method assembly hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method assembly hidebysig instance void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x2080 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M .method assembly hidebysig instance void M2 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x2080 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M2 } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method assembly hidebysig static void M ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method E::M .method assembly hidebysig static void M2 ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method E::M2 } // end of class E """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } [Fact] public void Skeleton_03() { var src = """ public static class E { extension(object o) { internal void M() { } } } """; var comp = CreateCompilation(src); comp.MakeMemberMissing(WellKnownMember.System_NotSupportedException__ctor); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var ext = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var m = ext.DescendantNodes().OfType<MethodDeclarationSyntax>().First(); model.GetDiagnostics(m.Body.Span).Verify(); comp.VerifyDiagnostics(); comp.VerifyEmitDiagnostics( // (5,9): error CS0656: Missing compiler required member 'System.NotSupportedException..ctor' // internal void M() { } Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "internal void M() { }").WithArguments("System.NotSupportedException", ".ctor").WithLocation(5, 9)); } [Fact] public void GetDiagnosticsForSpan_NoReceiverParameter() { var src = """ public static class Extensions { extension(__arglist) { public int M() { return ""; } } } """; var comp = CreateCompilation(src); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var ext = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var m = ext.DescendantNodes().OfType<MethodDeclarationSyntax>().Single(); model.GetDiagnostics(ext.ParameterList.Span).Verify( // (3,15): error CS1669: __arglist is not valid in this context // extension(__arglist) Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(3, 15) ); model.GetDiagnostics(m.Body.Span).Verify( // (7,20): error CS0029: Cannot implicitly convert type 'string' to 'int' // return ""; Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "int").WithLocation(7, 20) ); comp.VerifyDiagnostics( // (7,20): error CS0029: Cannot implicitly convert type 'string' to 'int' // return ""; Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "int").WithLocation(7, 20), // (3,15): error CS1669: __arglist is not valid in this context // extension(__arglist) Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(3, 15) ); } [Fact] public void GetDiagnosticsForSpan_WithReceiverParameter() { var src = """ public static class Extensions { extension(object o = null) { public int M() { return ""; } } } """; var comp = CreateCompilation(src); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var ext = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var m = ext.DescendantNodes().OfType<MethodDeclarationSyntax>().Single(); model.GetDiagnostics(ext.ParameterList.Span).Verify( // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value // extension(object o = null) Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "object o = null").WithLocation(3, 15) ); model.GetDiagnostics(m.Body.Span).Verify( // (7,20): error CS0029: Cannot implicitly convert type 'string' to 'int' // return ""; Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "int").WithLocation(7, 20) ); comp.VerifyDiagnostics( // (3,15): error CS9284: The receiver parameter of an extension cannot have a default value // extension(object o = null) Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "object o = null").WithLocation(3, 15), // (7,20): error CS0029: Cannot implicitly convert type 'string' to 'int' // return ""; Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "int").WithLocation(7, 20) ); AssertEx.Equal("[System.Object o = null]", model.GetDeclaredSymbol(ext.ParameterList.Parameters[0]).ToTestDisplayString()); } [Fact] public void ReceiverInScopeButIllegalInStaticMember() { var src = """ public static class Extensions { extension(object o) { static object M1() => o; static object M2() { return o; } static object P1 => o; static object P2 { get { return o; } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,31): error CS9347: Static members cannot access the value of extension parameter 'o'. // static object M1() => o; Diagnostic(ErrorCode.ERR_ExtensionParameterInStaticContext, "o").WithArguments("o").WithLocation(5, 31), // (6,37): error CS9347: Static members cannot access the value of extension parameter 'o'. // static object M2() { return o; } Diagnostic(ErrorCode.ERR_ExtensionParameterInStaticContext, "o").WithArguments("o").WithLocation(6, 37), // (7,29): error CS9347: Static members cannot access the value of extension parameter 'o'. // static object P1 => o; Diagnostic(ErrorCode.ERR_ExtensionParameterInStaticContext, "o").WithArguments("o").WithLocation(7, 29), // (8,41): error CS9347: Static members cannot access the value of extension parameter 'o'. // static object P2 { get { return o; } } Diagnostic(ErrorCode.ERR_ExtensionParameterInStaticContext, "o").WithArguments("o").WithLocation(8, 41) ); } [Fact] public void ExtensionParameterInStaticContext_WithDifferentContexts() { var src = """ static class Extensions { extension(int p) { // CS9347: Static member of same extension static int M1() => p; // CS9293: Default parameter value void M3(int x = p) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,28): error CS9347: Static members cannot access the value of extension parameter 'p'. // static int M1() => p; Diagnostic(ErrorCode.ERR_ExtensionParameterInStaticContext, "p").WithArguments("p").WithLocation(6, 28), // (9,25): error CS9293: Cannot use extension parameter 'int p' in this context. // void M3(int x = p) { } Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(9, 25), // (9,25): error CS1736: Default parameter value for 'x' must be a compile-time constant // void M3(int x = p) { } Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "p").WithArguments("x").WithLocation(9, 25) ); } [Fact] public void PassingValueForARefReceiver_01() { var src = """ public class C { static void Main() { GetInt().M1(); GetInt().M2(); _ = GetInt().P; } static int GetInt() => 0; } static class Extensions { extension(ref int receiver) { public void M1() {} public int P => 0; } public static void M2 (this ref int receiver) { } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,9): error CS1510: A ref or out value must be an assignable variable // GetInt().M1(); Diagnostic(ErrorCode.ERR_RefLvalueExpected, "GetInt()").WithLocation(5, 9), // (6,9): error CS1510: A ref or out value must be an assignable variable // GetInt().M2(); Diagnostic(ErrorCode.ERR_RefLvalueExpected, "GetInt()").WithLocation(6, 9), // (7,13): error CS1510: A ref or out value must be an assignable variable // _ = GetInt().P; Diagnostic(ErrorCode.ERR_RefLvalueExpected, "GetInt()").WithLocation(7, 13) ); } [Fact] public void PassingValueForARefReceiver_02() { var src = """ public class C { static void Main() { GetInt().M1(); GetInt().M2(); _ = GetInt().P; } static int GetInt() => 0; } static class Extensions { extension(ref readonly int receiver) { public void M1() { System.Console.Write("ranM1 "); } public int P { get { System.Console.Write("ranP"); return 0; } } } public static void M2 (this ref readonly int receiver) { System.Console.Write("ranM2 "); } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // (5,9): warning CS9193: Argument 0 should be a variable because it is passed to a 'ref readonly' parameter // GetInt().M1(); Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "GetInt()").WithArguments("0").WithLocation(5, 9), // (6,9): warning CS9193: Argument 0 should be a variable because it is passed to a 'ref readonly' parameter // GetInt().M2(); Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "GetInt()").WithArguments("0").WithLocation(6, 9), // (7,13): warning CS9193: Argument 0 should be a variable because it is passed to a 'ref readonly' parameter // _ = GetInt().P; Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "GetInt()").WithArguments("0").WithLocation(7, 13) ); CompileAndVerify(comp, expectedOutput: "ranM1 ranM2 ranP"); } [Fact] public void PassingValueForARefReceiver_03() { var src = """ public class C { static void Main() { GetInt().M1(); GetInt().M2(); _ = GetInt().P; } static int GetInt() => 0; } static class Extensions { extension(in int receiver) { public void M1() { System.Console.Write("ranM1 "); } public int P { get { System.Console.Write("ranP"); return 0; } } } public static void M2(this in int receiver) { System.Console.Write("ranM2 "); } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "ranM1 ranM2 ranP").VerifyDiagnostics(); } [Fact] public void Implementation_InstanceMethod_01() { var src = """ public static class Extensions { extension(object o) { internal void M(string s) { o.ToString(); _ = s.Length; } } } """; var comp = CreateCompilation(src); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method assembly hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2095 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method assembly hidebysig instance void M ( string s ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x208e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method assembly hidebysig static void M ( object o, string s ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 15 (0xf) .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance string [mscorlib]System.Object::ToString() IL_0006: pop IL_0007: ldarg.1 IL_0008: callvirt instance int32 [mscorlib]System.String::get_Length() IL_000d: pop IL_000e: ret } // end of method Extensions::M } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); CompileAndVerify( comp, emitOptions: EmitOptions.Default.WithEmitMetadataOnly(true).WithIncludePrivateMembers(false), symbolValidator: (m) => { AssertEx.Equal("System.Object o", m.GlobalNamespace.GetTypeMember("Extensions").GetTypeMembers().Single().ExtensionParameter.ToTestDisplayString()); } ).VerifyDiagnostics(); } [Fact] public void Implementation_InstanceMethod_02() { var src1 = """ public static class Extensions { extension(object o) { public string M(string s) => o + s; } } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1, sourceSymbolValidator: verifySymbols, symbolValidator: verifySymbols).VerifyDiagnostics(); static void verifySymbols(ModuleSymbol m) { NamedTypeSymbol extensions = m.ContainingAssembly.GetTypeByMetadataName("Extensions"); MethodSymbol implementation = extensions.GetMembers().OfType<MethodSymbol>().Single(); Assert.True(implementation.IsStatic); Assert.Equal(MethodKind.Ordinary, implementation.MethodKind); Assert.Equal(2, implementation.ParameterCount); AssertEx.Equal("System.String Extensions.M(this System.Object o, System.String s)", implementation.ToTestDisplayString()); Assert.Equal(m is not PEModuleSymbol, implementation.IsImplicitlyDeclared); Assert.True(implementation.IsExtensionMethod); Assert.False(implementation.HasSpecialName); Assert.False(implementation.HasRuntimeSpecialName); Assert.True(implementation.ContainingType.MightContainExtensions); Assert.Contains("M", extensions.MemberNames); Assert.NotEmpty(extensions.GetSimpleNonTypeMembers("M")); if (m is PEModuleSymbol peModuleSymbol) { Assert.True(peModuleSymbol.Module.HasExtensionAttribute(((PEAssemblySymbol)peModuleSymbol.ContainingAssembly).Assembly.Handle, ignoreCase: false)); } } comp1 = CreateCompilation(src1); NamedTypeSymbol extensions = comp1.GetTypeByMetadataName("Extensions"); Assert.Contains("M", extensions.MemberNames); comp1 = CreateCompilation(src1); extensions = comp1.GetTypeByMetadataName("Extensions"); Assert.NotEmpty(extensions.GetSimpleNonTypeMembers("M")); var expectedTypeIL = """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2099 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method public hidebysig instance string M ( string s ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x2092 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method public hidebysig static string M ( object o, string s ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 19 (0x13) .maxstack 8 IL_0000: ldarg.0 IL_0001: brtrue.s IL_0006 IL_0003: ldnull IL_0004: br.s IL_000c IL_0006: ldarg.0 IL_0007: callvirt instance string [mscorlib]System.Object::ToString() IL_000c: ldarg.1 IL_000d: call string [mscorlib]System.String::Concat(string, string) IL_0012: ret } // end of method Extensions::M } // end of class Extensions """; verifier1.VerifyTypeIL("Extensions", expectedTypeIL.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write("3".M2("4")); } static string Test(object o) { return o.M("2"); } } static class Extensions { extension(object o) { public string M2(string s) => o.M(s); } } """; var comp1MetadataReference = comp1.ToMetadataReference(); var comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe); var verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); var testIL = @" { // Code size 17 (0x11) .maxstack 2 .locals init (string V_0) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldstr ""2"" IL_0007: call ""string Extensions.M(object, string)"" IL_000c: stloc.0 IL_000d: br.s IL_000f IL_000f: ldloc.0 IL_0010: ret } "; verifier2.VerifyIL("Program.Test", testIL); var m2IL = @" { // Code size 8 (0x8) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: call ""string Extensions.M(object, string)"" IL_0007: ret } "; verifier2.VerifyIL("Extensions.M2", m2IL); var comp1ImageReference = comp1.EmitToImageReference(); comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); verifier2.VerifyIL("Program.Test", testIL); verifier2.VerifyIL("Extensions.M2", m2IL); comp2 = CreateCompilationWithIL(src2, expectedTypeIL + ExtensionMarkerAttributeIL, options: TestOptions.DebugExe); CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); var remove = """ .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) """; comp2 = CreateCompilationWithIL(src2, expectedTypeIL.Remove(expectedTypeIL.IndexOf(remove), remove.Length) + ExtensionMarkerAttributeIL); comp2.VerifyDiagnostics( // (11,18): error CS1061: 'object' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // return o.M("2"); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("object", "M").WithLocation(11, 18), // (19,41): error CS1061: 'object' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // public string M2(string s) => o.M(s); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("object", "M").WithLocation(19, 41) ); src2 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write("3".M2("4")); } static string Test(object o) { return Extensions.M(o, "2"); } } static class Extensions_ { extension(object o) { public string M2(string s) => Extensions.M(o, s); } public static void NotUsed(this object o) {} } """; comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); verifier2.VerifyIL("Program.Test", testIL); verifier2.VerifyIL("Extensions_.M2", m2IL); comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); verifier2.VerifyIL("Program.Test", testIL); verifier2.VerifyIL("Extensions_.M2", m2IL); var vbComp = CreateVisualBasicCompilation(""" Class Program Shared Sub Main() System.Console.Write(Test1("1")) System.Console.Write(Test2("3")) End Sub Shared Function Test1(o As String) As String return o.M("2") End Function Shared Function Test2(o As String) As String return Extensions.M(o, "4") End Function End Class """, referencedAssemblies: comp2.References, compilationOptions: new VisualBasicCompilationOptions(OutputKind.ConsoleApplication)); CompileAndVerify(vbComp, expectedOutput: "1234").VerifyDiagnostics(); if (!CompilationExtensions.EnableVerifyUsedAssemblies) // Tracked by https://github.com/dotnet/roslyn/issues/77542 { var src4 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write("3".M2("4")); } static string Test(object o) { System.Func<string, string> d = o.M; return d("2"); } } static class Extensions { extension(object o) { public string M2(string s) => new System.Func<string, string>(o.M)(s); } } """; var comp4 = CreateCompilation(src4, references: [comp1MetadataReference], options: TestOptions.DebugExe); var verifier4 = CompileAndVerify(comp4, expectedOutput: "1234").VerifyDiagnostics(); testIL = @" { // Code size 30 (0x1e) .maxstack 2 .locals init (System.Func<string, string> V_0, //d string V_1) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldftn ""string Extensions.M(object, string)"" IL_0008: newobj ""System.Func<string, string>..ctor(object, System.IntPtr)"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: ldstr ""2"" IL_0014: callvirt ""string System.Func<string, string>.Invoke(string)"" IL_0019: stloc.1 IL_001a: br.s IL_001c IL_001c: ldloc.1 IL_001d: ret } "; verifier4.VerifyIL("Program.Test", testIL); m2IL = @" { // Code size 19 (0x13) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldftn ""string Extensions.M(object, string)"" IL_0007: newobj ""System.Func<string, string>..ctor(object, System.IntPtr)"" IL_000c: ldarg.1 IL_000d: callvirt ""string System.Func<string, string>.Invoke(string)"" IL_0012: ret } "; verifier4.VerifyIL("Extensions.M2", m2IL); comp4 = CreateCompilation(src4, references: [comp1ImageReference], options: TestOptions.DebugExe); verifier4 = CompileAndVerify(comp4, expectedOutput: "1234").VerifyDiagnostics(); verifier4.VerifyIL("Program.Test", testIL); verifier4.VerifyIL("Extensions.M2", m2IL); } var comp5 = CreateCompilation(src1); comp5.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); comp5.VerifyDiagnostics( // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // extension(object o) Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5) ); } [Fact(Skip = "https://github.com/dotnet/roslyn/issues/77542")] public void UseSiteInfoTracking_01() { var src1 = """ public static class Extensions { public static string M(this object o, string s) => o + s; } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); var src4 = """ class Program { static string Test(object o) { System.Func<string, string> d = o.M; return d("2"); } } """; var comp1MetadataReference = comp1.ToMetadataReference(); var comp4 = CreateCompilation(src4, references: [comp1MetadataReference]); comp4.VerifyEmitDiagnostics(); var refs = comp4.GetUsedAssemblyReferences(); Assert.Contains(comp1MetadataReference, refs); } [Fact] public void UseSiteInfoTracking_02() { var src1 = """ public static class Extensions { public static string M(this object o, string s) => o + s; } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); var src4 = """ class Program { static string Test(object o) { return o.M("2"); } } """; var comp1MetadataReference = comp1.ToMetadataReference(); var comp4 = CreateCompilation(src4, references: [comp1MetadataReference]); comp4.VerifyEmitDiagnostics(); var refs = comp4.GetUsedAssemblyReferences(); Assert.Contains(comp1MetadataReference, refs); } [Fact] public void Implementation_InstanceMethod_03_WithLocalFunction() { var src1 = """ public static class Extensions { extension(object o) { public string M(string s) { string local() => o + s; return local(); } } } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20ca // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method public hidebysig instance string M ( string s ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x20c3 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0' extends [mscorlib]System.ValueType { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public object o .field public string s } // end of class <>c__DisplayClass1_0 // Methods .method public hidebysig static string M ( object o, string s ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2080 // Code size 24 (0x18) .maxstack 2 .locals init ( [0] valuetype Extensions/'<>c__DisplayClass1_0' ) IL_0000: ldloca.s 0 IL_0002: ldarg.0 IL_0003: stfld object Extensions/'<>c__DisplayClass1_0'::o IL_0008: ldloca.s 0 IL_000a: ldarg.1 IL_000b: stfld string Extensions/'<>c__DisplayClass1_0'::s IL_0010: ldloca.s 0 IL_0012: call string Extensions::'<M>g__local|1_0'(valuetype Extensions/'<>c__DisplayClass1_0'&) IL_0017: ret } // end of method Extensions::M .method assembly hidebysig static string '<M>g__local|1_0' ( valuetype Extensions/'<>c__DisplayClass1_0'& '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20a4 // Code size 30 (0x1e) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld object Extensions/'<>c__DisplayClass1_0'::o IL_0006: dup IL_0007: brtrue.s IL_000d IL_0009: pop IL_000a: ldnull IL_000b: br.s IL_0012 IL_000d: callvirt instance string [mscorlib]System.Object::ToString() IL_0012: ldarg.0 IL_0013: ldfld string Extensions/'<>c__DisplayClass1_0'::s IL_0018: call string [mscorlib]System.String::Concat(string, string) IL_001d: ret } // end of method Extensions::'<M>g__local|1_0' } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension(object o) { string M(string s) { string local() => o + s; return local(); } } extension(object o) { string M(string s, int x) { string local() => o + s; return local(); } } } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); var src3 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write("3".M2("4")); } static string Test(object o) { string local() => o.M("2"); return local(); } } static class Extensions { extension(object o) { public string M2(string s) { string local() => o.M(s); return local(); } } } """; var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); } [Fact] public void Implementation_InstanceMethod_04_WithLambda() { var src1 = """ public static class Extensions { extension(object o) { public string M(string s) { System.Func<string> local = () => o + s; return local(); } } } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20d1 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method public hidebysig instance string M ( string s ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x20a3 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public object o .field public string s // Methods .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x20aa // 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__DisplayClass1_0'::.ctor .method assembly hidebysig instance string '<M>b__0' () cil managed { // Method begins at RVA 0x20b2 // Code size 30 (0x1e) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld object Extensions/'<>c__DisplayClass1_0'::o IL_0006: dup IL_0007: brtrue.s IL_000d IL_0009: pop IL_000a: ldnull IL_000b: br.s IL_0012 IL_000d: callvirt instance string [mscorlib]System.Object::ToString() IL_0012: ldarg.0 IL_0013: ldfld string Extensions/'<>c__DisplayClass1_0'::s IL_0018: call string [mscorlib]System.String::Concat(string, string) IL_001d: ret } // end of method '<>c__DisplayClass1_0'::'<M>b__0' } // end of class <>c__DisplayClass1_0 // Methods .method public hidebysig static string M ( object o, string s ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 36 (0x24) .maxstack 8 IL_0000: newobj instance void Extensions/'<>c__DisplayClass1_0'::.ctor() IL_0005: dup IL_0006: ldarg.0 IL_0007: stfld object Extensions/'<>c__DisplayClass1_0'::o IL_000c: dup IL_000d: ldarg.1 IL_000e: stfld string Extensions/'<>c__DisplayClass1_0'::s IL_0013: ldftn instance string Extensions/'<>c__DisplayClass1_0'::'<M>b__0'() IL_0019: newobj instance void class [mscorlib]System.Func`1<string>::.ctor(object, native int) IL_001e: callvirt instance !0 class [mscorlib]System.Func`1<string>::Invoke() IL_0023: ret } // end of method Extensions::M } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension(object o) { string M(string s) { System.Func<string> local = () => o + s; return local(); } } extension(object o) { string M(string s, int x) { System.Func<string> local = () => o + s; return local(); } } } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); var src3 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write("3".M2("4")); } static string Test(object o) { System.Func<string> local = () => o.M("2"); return local(); } } static class Extensions { extension(object o) { public string M2(string s) { System.Func<string> local = () => o.M(s); return local(); } } } """; var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); } [Fact] public void Implementation_InstanceMethod_05_Iterator() { var src1 = """ public static class Extensions { extension(object o) { public System.Collections.Generic.IEnumerable<string> M(string s) { yield return o + s; } } } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1, symbolValidator: (m) => { MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType<MethodSymbol>().Single(); AssertEx.Equal("System.Runtime.CompilerServices.IteratorStateMachineAttribute(typeof(Extensions.<M>d__1))", implementation.GetAttributes().Single().ToString()); }).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", (""" .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x217f // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method public hidebysig instance class [mscorlib]System.Collections.Generic.IEnumerable`1<string> M ( string s ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x2095 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 .class nested private auto ansi sealed beforefieldinit '<M>d__1' extends [mscorlib]System.Object implements class [mscorlib]System.Collections.Generic.IEnumerable`1<string>, [mscorlib]System.Collections.IEnumerable, class [mscorlib]System.Collections.Generic.IEnumerator`1<string>, """ + (ExecutionConditionUtil.IsMonoOrCoreClr ? """ [mscorlib]System.Collections.IEnumerator, [mscorlib]System.IDisposable """ : """ [mscorlib]System.IDisposable, [mscorlib]System.Collections.IEnumerator """) + """ { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field private int32 '<>1__state' .field private string '<>2__current' .field private int32 '<>l__initialThreadId' .field private object o .field public object '<>3__o' .field private string s .field public string '<>3__s' // Methods .method public hidebysig specialname rtspecialname instance void .ctor ( int32 '<>1__state' ) cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x209c // Code size 25 (0x19) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ldarg.0 IL_0007: ldarg.1 IL_0008: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_000d: ldarg.0 IL_000e: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() IL_0013: stfld int32 Extensions/'<M>d__1'::'<>l__initialThreadId' IL_0018: ret } // end of method '<M>d__1'::.ctor .method private final hidebysig newslot virtual instance void System.IDisposable.Dispose () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance void [mscorlib]System.IDisposable::Dispose() // Method begins at RVA 0x20b6 // Code size 9 (0x9) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldc.i4.s -2 IL_0003: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0008: ret } // end of method '<M>d__1'::System.IDisposable.Dispose .method private final hidebysig newslot virtual instance bool MoveNext () cil managed { .override method instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() // Method begins at RVA 0x20c0 // Code size 76 (0x4c) .maxstack 3 .locals init ( [0] int32 ) IL_0000: ldarg.0 IL_0001: ldfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: brfalse.s IL_0010 IL_000a: ldloc.0 IL_000b: ldc.i4.1 IL_000c: beq.s IL_0043 IL_000e: ldc.i4.0 IL_000f: ret IL_0010: ldarg.0 IL_0011: ldc.i4.m1 IL_0012: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0017: ldarg.0 IL_0018: ldarg.0 IL_0019: ldfld object Extensions/'<M>d__1'::o IL_001e: dup IL_001f: brtrue.s IL_0025 IL_0021: pop IL_0022: ldnull IL_0023: br.s IL_002a IL_0025: callvirt instance string [mscorlib]System.Object::ToString() IL_002a: ldarg.0 IL_002b: ldfld string Extensions/'<M>d__1'::s IL_0030: call string [mscorlib]System.String::Concat(string, string) IL_0035: stfld string Extensions/'<M>d__1'::'<>2__current' IL_003a: ldarg.0 IL_003b: ldc.i4.1 IL_003c: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0041: ldc.i4.1 IL_0042: ret IL_0043: ldarg.0 IL_0044: ldc.i4.m1 IL_0045: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_004a: ldc.i4.0 IL_004b: ret } // end of method '<M>d__1'::MoveNext .method private final hidebysig specialname newslot virtual instance string 'System.Collections.Generic.IEnumerator<System.String>.get_Current' () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current() // Method begins at RVA 0x2118 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld string Extensions/'<M>d__1'::'<>2__current' IL_0006: ret } // end of method '<M>d__1'::'System.Collections.Generic.IEnumerator<System.String>.get_Current' .method private final hidebysig newslot virtual instance void System.Collections.IEnumerator.Reset () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance void [mscorlib]System.Collections.IEnumerator::Reset() // Method begins at RVA 0x2120 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<M>d__1'::System.Collections.IEnumerator.Reset .method private final hidebysig specialname newslot virtual instance object System.Collections.IEnumerator.get_Current () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance object [mscorlib]System.Collections.IEnumerator::get_Current() // Method begins at RVA 0x2118 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld string Extensions/'<M>d__1'::'<>2__current' IL_0006: ret } // end of method '<M>d__1'::System.Collections.IEnumerator.get_Current .method private final hidebysig newslot virtual instance class [mscorlib]System.Collections.Generic.IEnumerator`1<string> 'System.Collections.Generic.IEnumerable<System.String>.GetEnumerator' () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<string>::GetEnumerator() // Method begins at RVA 0x2128 // Code size 67 (0x43) .maxstack 2 .locals init ( [0] class Extensions/'<M>d__1' ) IL_0000: ldarg.0 IL_0001: ldfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0006: ldc.i4.s -2 IL_0008: bne.un.s IL_0022 IL_000a: ldarg.0 IL_000b: ldfld int32 Extensions/'<M>d__1'::'<>l__initialThreadId' IL_0010: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() IL_0015: bne.un.s IL_0022 IL_0017: ldarg.0 IL_0018: ldc.i4.0 IL_0019: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_001e: ldarg.0 IL_001f: stloc.0 IL_0020: br.s IL_0029 IL_0022: ldc.i4.0 IL_0023: newobj instance void Extensions/'<M>d__1'::.ctor(int32) IL_0028: stloc.0 IL_0029: ldloc.0 IL_002a: ldarg.0 IL_002b: ldfld object Extensions/'<M>d__1'::'<>3__o' IL_0030: stfld object Extensions/'<M>d__1'::o IL_0035: ldloc.0 IL_0036: ldarg.0 IL_0037: ldfld string Extensions/'<M>d__1'::'<>3__s' IL_003c: stfld string Extensions/'<M>d__1'::s IL_0041: ldloc.0 IL_0042: ret } // end of method '<M>d__1'::'System.Collections.Generic.IEnumerable<System.String>.GetEnumerator' .method private final hidebysig newslot virtual instance class [mscorlib]System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator() // Method begins at RVA 0x2177 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance class [mscorlib]System.Collections.Generic.IEnumerator`1<string> Extensions/'<M>d__1'::'System.Collections.Generic.IEnumerable<System.String>.GetEnumerator'() IL_0006: ret } // end of method '<M>d__1'::System.Collections.IEnumerable.GetEnumerator // Properties .property instance string 'System.Collections.Generic.IEnumerator<System.String>.Current'() { .get instance string Extensions/'<M>d__1'::'System.Collections.Generic.IEnumerator<System.String>.get_Current'() } .property instance object System.Collections.IEnumerator.Current() { .get instance object Extensions/'<M>d__1'::System.Collections.IEnumerator.get_Current() } } // end of class <M>d__1 // Methods .method public hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<string> M ( object o, string s ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.IteratorStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( 01 00 12 45 78 74 65 6e 73 69 6f 6e 73 2b 3c 4d 3e 64 5f 5f 31 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 22 (0x16) .maxstack 8 IL_0000: ldc.i4.s -2 IL_0002: newobj instance void Extensions/'<M>d__1'::.ctor(int32) IL_0007: dup IL_0008: ldarg.0 IL_0009: stfld object Extensions/'<M>d__1'::'<>3__o' IL_000e: dup IL_000f: ldarg.1 IL_0010: stfld string Extensions/'<M>d__1'::'<>3__s' IL_0015: ret } // end of method Extensions::M } // end of class Extensions """).Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension(object o) { System.Collections.Generic.IEnumerable<string> M(string s) { yield return o + s; } } extension(object o) { System.Collections.Generic.IEnumerable<string> M(string s, int x) { yield return o + s; } } } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); var src3 = """ class Program { static void Main() { foreach (var s in Test("1")) System.Console.Write(s); foreach (var s in "3".M2("4")) System.Console.Write(s); } static System.Collections.Generic.IEnumerable<string> Test(object o) { return o.M("2"); } } static class Extensions { extension(object o) { public System.Collections.Generic.IEnumerable<string> M2(string s) => o.M(s); } } """; var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); var verifier3 = CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); var testIL = @" { // Code size 17 (0x11) .maxstack 2 .locals init (System.Collections.Generic.IEnumerable<string> V_0) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldstr ""2"" IL_0007: call ""System.Collections.Generic.IEnumerable<string> Extensions.M(object, string)"" IL_000c: stloc.0 IL_000d: br.s IL_000f IL_000f: ldloc.0 IL_0010: ret } "; verifier3.VerifyIL("Program.Test", testIL); var m2IL = @" { // Code size 8 (0x8) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: call ""System.Collections.Generic.IEnumerable<string> Extensions.M(object, string)"" IL_0007: ret } "; verifier3.VerifyIL("Extensions.M2", m2IL); comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); verifier3 = CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); verifier3.VerifyIL("Program.Test", testIL); verifier3.VerifyIL("Extensions.M2", m2IL); } [Fact] public void Implementation_InstanceMethod_06_Async() { var src1 = """ public static class Extensions { extension(object o) { public async System.Threading.Tasks.Task<string> M(string s) { await System.Threading.Tasks.Task.Yield(); return o + s; } } } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1, symbolValidator: (m) => { MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType<MethodSymbol>().Single(); AssertEx.Equal("System.Runtime.CompilerServices.AsyncStateMachineAttribute(typeof(Extensions.<M>d__1))", implementation.GetAttributes().Single().ToString()); }).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x21b2 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method public hidebysig instance class [mscorlib]System.Threading.Tasks.Task`1<string> M ( string s ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x20cb // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 .class nested private auto ansi sealed beforefieldinit '<M>d__1' extends [mscorlib]System.ValueType implements [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public int32 '<>1__state' .field public valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> '<>t__builder' .field public object o .field public string s .field private valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter '<>u__1' // Methods .method private final hidebysig newslot virtual instance void MoveNext () cil managed { .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext() // Method begins at RVA 0x20d4 // Code size 178 (0xb2) .maxstack 3 .locals init ( [0] int32, [1] string, [2] valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter, [3] valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable, [4] class [mscorlib]System.Exception ) IL_0000: ldarg.0 IL_0001: ldfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0006: stloc.0 .try { IL_0007: ldloc.0 IL_0008: brfalse.s IL_0041 IL_000a: call valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable [mscorlib]System.Threading.Tasks.Task::Yield() IL_000f: stloc.3 IL_0010: ldloca.s 3 IL_0012: call instance valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter [mscorlib]System.Runtime.CompilerServices.YieldAwaitable::GetAwaiter() IL_0017: stloc.2 IL_0018: ldloca.s 2 IL_001a: call instance bool [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter::get_IsCompleted() IL_001f: brtrue.s IL_005d IL_0021: ldarg.0 IL_0022: ldc.i4.0 IL_0023: dup IL_0024: stloc.0 IL_0025: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_002a: ldarg.0 IL_002b: ldloc.2 IL_002c: stfld valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter Extensions/'<M>d__1'::'<>u__1' IL_0031: ldarg.0 IL_0032: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_0037: ldloca.s 2 IL_0039: ldarg.0 IL_003a: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::AwaitUnsafeOnCompleted<valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter, valuetype Extensions/'<M>d__1'>(!!0&, !!1&) IL_003f: leave.s IL_00b1 IL_0041: ldarg.0 IL_0042: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter Extensions/'<M>d__1'::'<>u__1' IL_0047: stloc.2 IL_0048: ldarg.0 IL_0049: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter Extensions/'<M>d__1'::'<>u__1' IL_004e: initobj [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter IL_0054: ldarg.0 IL_0055: ldc.i4.m1 IL_0056: dup IL_0057: stloc.0 IL_0058: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_005d: ldloca.s 2 IL_005f: call instance void [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter::GetResult() IL_0064: ldarg.0 IL_0065: ldfld object Extensions/'<M>d__1'::o IL_006a: dup IL_006b: brtrue.s IL_0071 IL_006d: pop IL_006e: ldnull IL_006f: br.s IL_0076 IL_0071: callvirt instance string [mscorlib]System.Object::ToString() IL_0076: ldarg.0 IL_0077: ldfld string Extensions/'<M>d__1'::s IL_007c: call string [mscorlib]System.String::Concat(string, string) IL_0081: stloc.1 IL_0082: leave.s IL_009d } // end .try catch [mscorlib]System.Exception { IL_0084: stloc.s 4 IL_0086: ldarg.0 IL_0087: ldc.i4.s -2 IL_0089: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_008e: ldarg.0 IL_008f: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_0094: ldloc.s 4 IL_0096: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::SetException(class [mscorlib]System.Exception) IL_009b: leave.s IL_00b1 } // end handler IL_009d: ldarg.0 IL_009e: ldc.i4.s -2 IL_00a0: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_00a5: ldarg.0 IL_00a6: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_00ab: ldloc.1 IL_00ac: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::SetResult(!0) IL_00b1: ret } // end of method '<M>d__1'::MoveNext .method private final hidebysig newslot virtual instance void SetStateMachine ( class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine stateMachine ) cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) // Method begins at RVA 0x21a4 // Code size 13 (0xd) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_0006: ldarg.1 IL_0007: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) IL_000c: ret } // end of method '<M>d__1'::SetStateMachine } // end of class <M>d__1 // Methods .method public hidebysig static class [mscorlib]System.Threading.Tasks.Task`1<string> M ( object o, string s ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( 01 00 12 45 78 74 65 6e 73 69 6f 6e 73 2b 3c 4d 3e 64 5f 5f 31 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2080 // Code size 63 (0x3f) .maxstack 2 .locals init ( [0] valuetype Extensions/'<M>d__1' ) IL_0000: ldloca.s 0 IL_0002: call valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<!0> valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::Create() IL_0007: stfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_000c: ldloca.s 0 IL_000e: ldarg.0 IL_000f: stfld object Extensions/'<M>d__1'::o IL_0014: ldloca.s 0 IL_0016: ldarg.1 IL_0017: stfld string Extensions/'<M>d__1'::s IL_001c: ldloca.s 0 IL_001e: ldc.i4.m1 IL_001f: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0024: ldloca.s 0 IL_0026: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_002b: ldloca.s 0 IL_002d: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::Start<valuetype Extensions/'<M>d__1'>(!!0&) IL_0032: ldloca.s 0 IL_0034: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_0039: call instance class [mscorlib]System.Threading.Tasks.Task`1<!0> valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::get_Task() IL_003e: ret } // end of method Extensions::M } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension(object o) { async System.Threading.Tasks.Task<string> M(string s) { await System.Threading.Tasks.Task.Yield(); return o + s; } } extension(object o) { async System.Threading.Tasks.Task<string> M(string s, int x) { await System.Threading.Tasks.Task.Yield(); return o + s; } } } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); var src3 = """ class Program { static void Main() { System.Console.Write(Test("1").Result); System.Console.Write("3".M2("4").Result); } async static System.Threading.Tasks.Task<string> Test(object o) { await System.Threading.Tasks.Task.Yield(); return await o.M("2"); } } static class Extensions { extension(object o) { async public System.Threading.Tasks.Task<string> M2(string s) { await System.Threading.Tasks.Task.Yield(); return await o.M(s); } } } """; var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); } [Fact] public void Implementation_InstanceMethod_07_Generic() { var src1 = """ public static class Extensions { extension<T>(C<T> o) { public string M<U>(T t, U u) { return o.GetString() + u.ToString() + t.ToString(); } } } public class C<T>(string v) { public string GetString() => v; } """; var comp1 = CreateCompilation(src1); MethodSymbol implementation = comp1.GetTypeByMetadataName("Extensions").GetMembers().OfType<MethodSymbol>().Single(); Assert.True(implementation.IsStatic); Assert.Equal(MethodKind.Ordinary, implementation.MethodKind); Assert.Equal(3, implementation.ParameterCount); AssertEx.Equal("System.String Extensions.M<T, U>(this C<T> o, T t, U u)", implementation.ToTestDisplayString()); Assert.True(implementation.IsImplicitlyDeclared); Assert.True(implementation.IsExtensionMethod); Assert.False(implementation.HasSpecialName); Assert.False(implementation.HasRuntimeSpecialName); var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$D884D1E13988E83801B7574694E1C2C5'<T> extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( class C`1<!T> o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20c3 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$D884D1E13988E83801B7574694E1C2C5'::'<Extension>$' } // end of class <M>$D884D1E13988E83801B7574694E1C2C5 // Methods .method public hidebysig instance string M<U> ( !$T0 t, !!U u ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 44 38 38 34 44 31 45 31 33 39 38 38 45 38 33 38 30 31 42 37 35 37 34 36 39 34 45 31 43 32 43 35 00 00 ) // Method begins at RVA 0x20bc // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1'::M } // end of class <G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1 // Methods .method public hidebysig static string M<T, U> ( class C`1<!!T> o, !!T t, !!U u ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 38 (0x26) .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance string class C`1<!!T>::GetString() IL_0006: ldarga.s u IL_0008: constrained. !!U IL_000e: callvirt instance string [mscorlib]System.Object::ToString() IL_0013: ldarga.s t IL_0015: constrained. !!T IL_001b: callvirt instance string [mscorlib]System.Object::ToString() IL_0020: call string [mscorlib]System.String::Concat(string, string, string) IL_0025: ret } // end of method Extensions::M } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src3 = """ class Program { static void Main() { System.Console.Write(Test(new C<string>("1"), "2", 3)); System.Console.Write(new C<string>("4").M2("5", 6)); } static string Test<T, U>(C<T> o, T t, U u) { return o.M(t, u); } } static class Extensions { extension<T>(C<T> o) { public string M2<U>(T t, U u) => o.M(t, u); } } """; var comp1MetadataReference = comp1.ToMetadataReference(); var comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); var verifier3 = CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); var testIL = @" { // Code size 14 (0xe) .maxstack 3 .locals init (string V_0) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldarg.1 IL_0003: ldarg.2 IL_0004: call ""string Extensions.M<T, U>(C<T>, T, U)"" IL_0009: stloc.0 IL_000a: br.s IL_000c IL_000c: ldloc.0 IL_000d: ret } "; verifier3.VerifyIL("Program.Test<T, U>(C<T>, T, U)", testIL); var m2IL = @" { // Code size 9 (0x9) .maxstack 3 IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: ldarg.2 IL_0003: call ""string Extensions.M<T, U>(C<T>, T, U)"" IL_0008: ret } "; verifier3.VerifyIL("Extensions.M2<T, U>(this C<T>, T, U)", m2IL); var comp1ImageReference = comp1.EmitToImageReference(); comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); verifier3 = CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); verifier3.VerifyIL("Program.Test<T, U>(C<T>, T, U)", testIL); verifier3.VerifyIL("Extensions.M2<T, U>(this C<T>, T, U)", m2IL); if (!CompilationExtensions.EnableVerifyUsedAssemblies) // Tracked by https://github.com/dotnet/roslyn/issues/77542 { src3 = """ class Program { static void Main() { System.Console.Write(Test(new C<string>("1"), "2", 3)); System.Console.Write(new C<string>("4").M2("5", 6)); } static string Test<T, U>(C<T> o, T t, U u) { System.Func<T, U, string> d = o.M; return d(t, u); } } static class Extensions { extension<T>(C<T> o) { public string M2<U>(T t, U u) => new System.Func<T, U, string>(o.M)(t, u); } } """; comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); verifier3 = CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); testIL = @" { // Code size 27 (0x1b) .maxstack 3 .locals init (System.Func<T, U, string> V_0, //d string V_1) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldftn ""string Extensions.M<T, U>(C<T>, T, U)"" IL_0008: newobj ""System.Func<T, U, string>..ctor(object, System.IntPtr)"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: ldarg.1 IL_0010: ldarg.2 IL_0011: callvirt ""string System.Func<T, U, string>.Invoke(T, U)"" IL_0016: stloc.1 IL_0017: br.s IL_0019 IL_0019: ldloc.1 IL_001a: ret } "; verifier3.VerifyIL("Program.Test<T, U>(C<T>, T, U)", testIL); m2IL = @" { // Code size 20 (0x14) .maxstack 3 IL_0000: ldarg.0 IL_0001: ldftn ""string Extensions.M<T, U>(C<T>, T, U)"" IL_0007: newobj ""System.Func<T, U, string>..ctor(object, System.IntPtr)"" IL_000c: ldarg.1 IL_000d: ldarg.2 IL_000e: callvirt ""string System.Func<T, U, string>.Invoke(T, U)"" IL_0013: ret } "; verifier3.VerifyIL("Extensions.M2<T, U>(this C<T>, T, U)", m2IL); comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); verifier3 = CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); verifier3.VerifyIL("Program.Test<T, U>(C<T>, T, U)", testIL); verifier3.VerifyIL("Extensions.M2<T, U>(this C<T>, T, U)", m2IL); } } [Fact] public void Implementation_InstanceMethod_08_WithLocalFunction_Generic() { var src1 = """ public static class Extensions { extension<T>(C<T> o) { public C<U> M<U>(T t1, U u1) { C<U> local<X, Y, Z>(T t2, U u2, X x2, Y y2, Z z2) { return new C<U>(o.GetString() + u1.ToString() + t1.ToString() + u2.ToString() + t2.ToString() + x2.ToString() + y2.ToString() + z2.ToString()); }; return local(t1, u1, 0, t1, u1); } } } public class C<T>(string val) { public string GetString() => val; } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$D884D1E13988E83801B7574694E1C2C5'<T> extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( class C`1<!T> o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x218c // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$D884D1E13988E83801B7574694E1C2C5'::'<Extension>$' } // end of class <M>$D884D1E13988E83801B7574694E1C2C5 // Methods .method public hidebysig instance class C`1<!!U> M<U> ( !$T0 t1, !!U u1 ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 44 38 38 34 44 31 45 31 33 39 38 38 45 38 33 38 30 31 42 37 35 37 34 36 39 34 45 31 43 32 43 35 00 00 ) // Method begins at RVA 0x2185 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1'::M } // end of class <G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1 .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0`2'<T, U> extends [mscorlib]System.ValueType { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public class C`1<!T> o .field public !U u1 .field public !T t1 } // end of class <>c__DisplayClass1_0`2 // Methods .method public hidebysig static class C`1<!!U> M<T, U> ( class C`1<!!T> o, !!T t1, !!U u1 ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2080 // Code size 57 (0x39) .maxstack 6 .locals init ( [0] valuetype Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U> ) IL_0000: ldloca.s 0 IL_0002: ldarg.0 IL_0003: stfld class C`1<!0> valuetype Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::o IL_0008: ldloca.s 0 IL_000a: ldarg.2 IL_000b: stfld !1 valuetype Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::u1 IL_0010: ldloca.s 0 IL_0012: ldarg.1 IL_0013: stfld !0 valuetype Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::t1 IL_0018: ldloc.0 IL_0019: ldfld !0 valuetype Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::t1 IL_001e: ldloc.0 IL_001f: ldfld !1 valuetype Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::u1 IL_0024: ldc.i4.0 IL_0025: ldloc.0 IL_0026: ldfld !0 valuetype Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::t1 IL_002b: ldloc.0 IL_002c: ldfld !1 valuetype Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::u1 IL_0031: ldloca.s 0 IL_0033: call class C`1<!!1> Extensions::'<M>g__local|1_0'<!!T, !!U, int32, !!T, !!U>(!!0, !!1, !!2, !!3, !!4, valuetype Extensions/'<>c__DisplayClass1_0`2'<!!0, !!1>&) IL_0038: ret } // end of method Extensions::M .method assembly hidebysig static class C`1<!!U> '<M>g__local|1_0'<T, U, X, Y, Z> ( !!T t2, !!U u2, !!X x2, !!Y y2, !!Z z2, valuetype Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>& '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20c8 // Code size 154 (0x9a) .maxstack 4 IL_0000: ldc.i4.8 IL_0001: newarr [mscorlib]System.String IL_0006: dup IL_0007: ldc.i4.0 IL_0008: ldarg.s 5 IL_000a: ldfld class C`1<!0> valuetype Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::o IL_000f: callvirt instance string class C`1<!!T>::GetString() IL_0014: stelem.ref IL_0015: dup IL_0016: ldc.i4.1 IL_0017: ldarg.s 5 IL_0019: ldflda !1 valuetype Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::u1 IL_001e: constrained. !!U IL_0024: callvirt instance string [mscorlib]System.Object::ToString() IL_0029: stelem.ref IL_002a: dup IL_002b: ldc.i4.2 IL_002c: ldarg.s 5 IL_002e: ldflda !0 valuetype Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::t1 IL_0033: constrained. !!T IL_0039: callvirt instance string [mscorlib]System.Object::ToString() IL_003e: stelem.ref IL_003f: dup IL_0040: ldc.i4.3 IL_0041: ldarga.s u2 IL_0043: constrained. !!U IL_0049: callvirt instance string [mscorlib]System.Object::ToString() IL_004e: stelem.ref IL_004f: dup IL_0050: ldc.i4.4 IL_0051: ldarga.s t2 IL_0053: constrained. !!T IL_0059: callvirt instance string [mscorlib]System.Object::ToString() IL_005e: stelem.ref IL_005f: dup IL_0060: ldc.i4.5 IL_0061: ldarga.s x2 IL_0063: constrained. !!X IL_0069: callvirt instance string [mscorlib]System.Object::ToString() IL_006e: stelem.ref IL_006f: dup IL_0070: ldc.i4.6 IL_0071: ldarga.s y2 IL_0073: constrained. !!Y IL_0079: callvirt instance string [mscorlib]System.Object::ToString() IL_007e: stelem.ref IL_007f: dup IL_0080: ldc.i4.7 IL_0081: ldarga.s z2 IL_0083: constrained. !!Z IL_0089: callvirt instance string [mscorlib]System.Object::ToString() IL_008e: stelem.ref IL_008f: call string [mscorlib]System.String::Concat(string[]) IL_0094: newobj instance void class C`1<!!U>::.ctor(string) IL_0099: ret } // end of method Extensions::'<M>g__local|1_0' } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension<T>(C<T> o) { string M<U>(T t1, U u1) { U local<X, Y, Z>(T t2, U u2, X x2, Y y2, Z z2) { _ = o.GetString() + u1.ToString() + t1.ToString() + u2.ToString() + t2.ToString() + x2.ToString() + y2.ToString() + z2.ToString(); return u2; }; return local(t1, u1, 0, t1, u1).ToString(); } } extension<T>(C<T> o) { string M<U>(T t1, U u1, int x) { U local<X, Y, Z>(T t2, U u2, X x2, Y y2, Z z2) { _ = o.GetString() + u1.ToString() + t1.ToString() + u2.ToString() + t2.ToString() + x2.ToString() + y2.ToString() + z2.ToString(); return u2; }; return local(t1, u1, 0, t1, u1).ToString(); } } } public class C<T> { public string GetString() => null; } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); var src3 = """ class Program { static void Main() { System.Console.Write(Test(new C<long>("1"), 2, "3").GetString()); System.Console.Write(new C<long>("4").M2(5, "6").GetString()); } static C<U> Test<T, U>(C<T> o, T t1, U u1) { C<X> local<X>(T t2, X x2) { return o.M(t2, x2); }; return local(t1, u1); } } static class Extensions { extension<T>(C<T> o) { public C<U> M2<U>(T t1, U u1) { C<X> local<X>(T t2, X x2) { return o.M(t2, x2); }; return local(t1, u1); } } } """; var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1323202346565056").VerifyDiagnostics(); comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1323202346565056").VerifyDiagnostics(); } [Fact] public void Implementation_InstanceMethod_09_WithLambda_Generic() { var src1 = """ public static class Extensions { extension<T>(C<T> o) { public C<U> M<U>(T t1, U u1) { System.Func<T, U, C<U>> local = (T t2, U u2) => { return new C<U>(o.GetString() + u1.ToString() + t1.ToString() + u2.ToString() + t2.ToString()); }; return local(t1, u1); } } } public class C<T>(string val) { public string GetString() => val; } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$D884D1E13988E83801B7574694E1C2C5'<T> extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( class C`1<!T> o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x215f // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$D884D1E13988E83801B7574694E1C2C5'::'<Extension>$' } // end of class <M>$D884D1E13988E83801B7574694E1C2C5 // Methods .method public hidebysig instance class C`1<!!U> M<U> ( !$T0 t1, !!U u1 ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 44 38 38 34 44 31 45 31 33 39 38 38 45 38 33 38 30 31 42 37 35 37 34 36 39 34 45 31 43 32 43 35 00 00 ) // Method begins at RVA 0x20dc // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1'::M } // end of class <G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1 .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0`2'<T, U> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public class C`1<!T> o .field public !U u1 .field public !T t1 // Methods .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x20e3 // 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__DisplayClass1_0`2'::.ctor .method assembly hidebysig instance class C`1<!U> '<M>b__0' ( !T t2, !U u2 ) cil managed { // Method begins at RVA 0x20ec // Code size 103 (0x67) .maxstack 4 IL_0000: ldc.i4.5 IL_0001: newarr [mscorlib]System.String IL_0006: dup IL_0007: ldc.i4.0 IL_0008: ldarg.0 IL_0009: ldfld class C`1<!0> class Extensions/'<>c__DisplayClass1_0`2'<!T, !U>::o IL_000e: callvirt instance string class C`1<!T>::GetString() IL_0013: stelem.ref IL_0014: dup IL_0015: ldc.i4.1 IL_0016: ldarg.0 IL_0017: ldflda !1 class Extensions/'<>c__DisplayClass1_0`2'<!T, !U>::u1 IL_001c: constrained. !U IL_0022: callvirt instance string [mscorlib]System.Object::ToString() IL_0027: stelem.ref IL_0028: dup IL_0029: ldc.i4.2 IL_002a: ldarg.0 IL_002b: ldflda !0 class Extensions/'<>c__DisplayClass1_0`2'<!T, !U>::t1 IL_0030: constrained. !T IL_0036: callvirt instance string [mscorlib]System.Object::ToString() IL_003b: stelem.ref IL_003c: dup IL_003d: ldc.i4.3 IL_003e: ldarga.s u2 IL_0040: constrained. !U IL_0046: callvirt instance string [mscorlib]System.Object::ToString() IL_004b: stelem.ref IL_004c: dup IL_004d: ldc.i4.4 IL_004e: ldarga.s t2 IL_0050: constrained. !T IL_0056: callvirt instance string [mscorlib]System.Object::ToString() IL_005b: stelem.ref IL_005c: call string [mscorlib]System.String::Concat(string[]) IL_0061: newobj instance void class C`1<!U>::.ctor(string) IL_0066: ret } // end of method '<>c__DisplayClass1_0`2'::'<M>b__0' } // end of class <>c__DisplayClass1_0`2 // Methods .method public hidebysig static class C`1<!!U> M<T, U> ( class C`1<!!T> o, !!T t1, !!U u1 ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2080 // Code size 57 (0x39) .maxstack 3 .locals init ( [0] class Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U> ) IL_0000: newobj instance void class Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::.ctor() IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldarg.0 IL_0008: stfld class C`1<!0> class Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::o IL_000d: ldloc.0 IL_000e: ldarg.2 IL_000f: stfld !1 class Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::u1 IL_0014: ldloc.0 IL_0015: ldarg.1 IL_0016: stfld !0 class Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::t1 IL_001b: ldloc.0 IL_001c: ldftn instance class C`1<!1> class Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::'<M>b__0'(!0, !1) IL_0022: newobj instance void class [mscorlib]System.Func`3<!!T, !!U, class C`1<!!U>>::.ctor(object, native int) IL_0027: ldloc.0 IL_0028: ldfld !0 class Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::t1 IL_002d: ldloc.0 IL_002e: ldfld !1 class Extensions/'<>c__DisplayClass1_0`2'<!!T, !!U>::u1 IL_0033: callvirt instance !2 class [mscorlib]System.Func`3<!!T, !!U, class C`1<!!U>>::Invoke(!0, !1) IL_0038: ret } // end of method Extensions::M } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension<T>(C<T> o) { string M<U>(T t1, U u1) { System.Func<T, U, U> local = (T t2, U u2) => { _ = o.GetString() + u1.ToString() + t1.ToString() + u2.ToString() + t2.ToString(); return u2; }; return local(t1, u1).ToString(); } } extension<T>(C<T> o) { string M<U>(T t1, U u1, int x) { System.Func<T, U, U> local = (T t2, U u2) => { _ = o.GetString() + u1.ToString() + t1.ToString() + u2.ToString() + t2.ToString(); return u2; }; return local(t1, u1).ToString(); } } } public class C<T> { public string GetString() => null; } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); var src3 = """ class Program { static void Main() { System.Console.Write(Test(new C<long>("1"), 2, "3").GetString()); System.Console.Write(new C<long>("4").M2(5, "6").GetString()); } static C<U> Test<T, U>(C<T> o, T t1, U u1) { System.Func<T, U, C<U>> local = (T t2, U u2) => { return o.M(t2, u2); }; return local(t1, u1); } } static class Extensions { extension<T>(C<T> o) { public C<U> M2<U>(T t1, U u1) { System.Func<T, U, C<U>> local = (T t2, U u2) => { return o.M(t2, u2); }; return local(t1, u1); } } } """; var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1323246565").VerifyDiagnostics(); comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1323246565").VerifyDiagnostics(); } [Fact] public void Implementation_InstanceMethod_10_Iterator_Generic() { var src1 = """ public static class Extensions { extension<T>(C<T> o) { public System.Collections.Generic.IEnumerable<string> M<U>(T t1, U u1) { yield return o.GetString() + u1.ToString() + t1.ToString(); } } } public class C<T>(string val) { public string GetString() => val; } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1, symbolValidator: (m) => { MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType<MethodSymbol>().Single(); AssertEx.Equal("System.Runtime.CompilerServices.IteratorStateMachineAttribute(typeof(Extensions.<M>d__1<,>))", implementation.GetAttributes().Single().ToString()); }).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", (""" .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$D884D1E13988E83801B7574694E1C2C5'<T> extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( class C`1<!T> o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x21bf // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$D884D1E13988E83801B7574694E1C2C5'::'<Extension>$' } // end of class <M>$D884D1E13988E83801B7574694E1C2C5 // Methods .method public hidebysig instance class [mscorlib]System.Collections.Generic.IEnumerable`1<string> M<U> ( !$T0 t1, !!U u1 ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 44 38 38 34 44 31 45 31 33 39 38 38 45 38 33 38 30 31 42 37 35 37 34 36 39 34 45 31 43 32 43 35 00 00 ) // Method begins at RVA 0x20b3 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1'::M } // end of class <G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1 .class nested private auto ansi sealed beforefieldinit '<M>d__1`2'<T, U> extends [mscorlib]System.Object implements class [mscorlib]System.Collections.Generic.IEnumerable`1<string>, [mscorlib]System.Collections.IEnumerable, class [mscorlib]System.Collections.Generic.IEnumerator`1<string>, """ + (ExecutionConditionUtil.IsMonoOrCoreClr ? """ [mscorlib]System.Collections.IEnumerator, [mscorlib]System.IDisposable """ : """ [mscorlib]System.IDisposable, [mscorlib]System.Collections.IEnumerator """) + """ { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field private int32 '<>1__state' .field private string '<>2__current' .field private int32 '<>l__initialThreadId' .field private class C`1<!T> o .field public class C`1<!T> '<>3__o' .field private !U u1 .field public !U '<>3__u1' .field private !T t1 .field public !T '<>3__t1' // Methods .method public hidebysig specialname rtspecialname instance void .ctor ( int32 '<>1__state' ) cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20ba // Code size 25 (0x19) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ldarg.0 IL_0007: ldarg.1 IL_0008: stfld int32 class Extensions/'<M>d__1`2'<!T, !U>::'<>1__state' IL_000d: ldarg.0 IL_000e: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() IL_0013: stfld int32 class Extensions/'<M>d__1`2'<!T, !U>::'<>l__initialThreadId' IL_0018: ret } // end of method '<M>d__1`2'::.ctor .method private final hidebysig newslot virtual instance void System.IDisposable.Dispose () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance void [mscorlib]System.IDisposable::Dispose() // Method begins at RVA 0x20d4 // Code size 9 (0x9) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldc.i4.s -2 IL_0003: stfld int32 class Extensions/'<M>d__1`2'<!T, !U>::'<>1__state' IL_0008: ret } // end of method '<M>d__1`2'::System.IDisposable.Dispose .method private final hidebysig newslot virtual instance bool MoveNext () cil managed { .override method instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() // Method begins at RVA 0x20e0 // Code size 97 (0x61) .maxstack 4 .locals init ( [0] int32 ) IL_0000: ldarg.0 IL_0001: ldfld int32 class Extensions/'<M>d__1`2'<!T, !U>::'<>1__state' IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: brfalse.s IL_0010 IL_000a: ldloc.0 IL_000b: ldc.i4.1 IL_000c: beq.s IL_0058 IL_000e: ldc.i4.0 IL_000f: ret IL_0010: ldarg.0 IL_0011: ldc.i4.m1 IL_0012: stfld int32 class Extensions/'<M>d__1`2'<!T, !U>::'<>1__state' IL_0017: ldarg.0 IL_0018: ldarg.0 IL_0019: ldfld class C`1<!0> class Extensions/'<M>d__1`2'<!T, !U>::o IL_001e: callvirt instance string class C`1<!T>::GetString() IL_0023: ldarg.0 IL_0024: ldflda !1 class Extensions/'<M>d__1`2'<!T, !U>::u1 IL_0029: constrained. !U IL_002f: callvirt instance string [mscorlib]System.Object::ToString() IL_0034: ldarg.0 IL_0035: ldflda !0 class Extensions/'<M>d__1`2'<!T, !U>::t1 IL_003a: constrained. !T IL_0040: callvirt instance string [mscorlib]System.Object::ToString() IL_0045: call string [mscorlib]System.String::Concat(string, string, string) IL_004a: stfld string class Extensions/'<M>d__1`2'<!T, !U>::'<>2__current' IL_004f: ldarg.0 IL_0050: ldc.i4.1 IL_0051: stfld int32 class Extensions/'<M>d__1`2'<!T, !U>::'<>1__state' IL_0056: ldc.i4.1 IL_0057: ret IL_0058: ldarg.0 IL_0059: ldc.i4.m1 IL_005a: stfld int32 class Extensions/'<M>d__1`2'<!T, !U>::'<>1__state' IL_005f: ldc.i4.0 IL_0060: ret } // end of method '<M>d__1`2'::MoveNext .method private final hidebysig specialname newslot virtual instance string 'System.Collections.Generic.IEnumerator<System.String>.get_Current' () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current() // Method begins at RVA 0x214d // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld string class Extensions/'<M>d__1`2'<!T, !U>::'<>2__current' IL_0006: ret } // end of method '<M>d__1`2'::'System.Collections.Generic.IEnumerator<System.String>.get_Current' .method private final hidebysig newslot virtual instance void System.Collections.IEnumerator.Reset () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance void [mscorlib]System.Collections.IEnumerator::Reset() // Method begins at RVA 0x2155 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<M>d__1`2'::System.Collections.IEnumerator.Reset .method private final hidebysig specialname newslot virtual instance object System.Collections.IEnumerator.get_Current () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance object [mscorlib]System.Collections.IEnumerator::get_Current() // Method begins at RVA 0x214d // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld string class Extensions/'<M>d__1`2'<!T, !U>::'<>2__current' IL_0006: ret } // end of method '<M>d__1`2'::System.Collections.IEnumerator.get_Current .method private final hidebysig newslot virtual instance class [mscorlib]System.Collections.Generic.IEnumerator`1<string> 'System.Collections.Generic.IEnumerable<System.String>.GetEnumerator' () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<string>::GetEnumerator() // Method begins at RVA 0x215c // Code size 79 (0x4f) .maxstack 2 .locals init ( [0] class Extensions/'<M>d__1`2'<!T, !U> ) IL_0000: ldarg.0 IL_0001: ldfld int32 class Extensions/'<M>d__1`2'<!T, !U>::'<>1__state' IL_0006: ldc.i4.s -2 IL_0008: bne.un.s IL_0022 IL_000a: ldarg.0 IL_000b: ldfld int32 class Extensions/'<M>d__1`2'<!T, !U>::'<>l__initialThreadId' IL_0010: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() IL_0015: bne.un.s IL_0022 IL_0017: ldarg.0 IL_0018: ldc.i4.0 IL_0019: stfld int32 class Extensions/'<M>d__1`2'<!T, !U>::'<>1__state' IL_001e: ldarg.0 IL_001f: stloc.0 IL_0020: br.s IL_0029 IL_0022: ldc.i4.0 IL_0023: newobj instance void class Extensions/'<M>d__1`2'<!T, !U>::.ctor(int32) IL_0028: stloc.0 IL_0029: ldloc.0 IL_002a: ldarg.0 IL_002b: ldfld class C`1<!0> class Extensions/'<M>d__1`2'<!T, !U>::'<>3__o' IL_0030: stfld class C`1<!0> class Extensions/'<M>d__1`2'<!T, !U>::o IL_0035: ldloc.0 IL_0036: ldarg.0 IL_0037: ldfld !0 class Extensions/'<M>d__1`2'<!T, !U>::'<>3__t1' IL_003c: stfld !0 class Extensions/'<M>d__1`2'<!T, !U>::t1 IL_0041: ldloc.0 IL_0042: ldarg.0 IL_0043: ldfld !1 class Extensions/'<M>d__1`2'<!T, !U>::'<>3__u1' IL_0048: stfld !1 class Extensions/'<M>d__1`2'<!T, !U>::u1 IL_004d: ldloc.0 IL_004e: ret } // end of method '<M>d__1`2'::'System.Collections.Generic.IEnumerable<System.String>.GetEnumerator' .method private final hidebysig newslot virtual instance class [mscorlib]System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator() // Method begins at RVA 0x21b7 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance class [mscorlib]System.Collections.Generic.IEnumerator`1<string> class Extensions/'<M>d__1`2'<!T, !U>::'System.Collections.Generic.IEnumerable<System.String>.GetEnumerator'() IL_0006: ret } // end of method '<M>d__1`2'::System.Collections.IEnumerable.GetEnumerator // Properties .property instance string 'System.Collections.Generic.IEnumerator<System.String>.Current'() { .get instance string Extensions/'<M>d__1`2'::'System.Collections.Generic.IEnumerator<System.String>.get_Current'() } .property instance object System.Collections.IEnumerator.Current() { .get instance object Extensions/'<M>d__1`2'::System.Collections.IEnumerator.get_Current() } } // end of class <M>d__1`2 // Methods .method public hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<string> M<T, U> ( class C`1<!!T> o, !!T t1, !!U u1 ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.IteratorStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( 01 00 14 45 78 74 65 6e 73 69 6f 6e 73 2b 3c 4d 3e 64 5f 5f 31 60 32 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 29 (0x1d) .maxstack 8 IL_0000: ldc.i4.s -2 IL_0002: newobj instance void class Extensions/'<M>d__1`2'<!!T, !!U>::.ctor(int32) IL_0007: dup IL_0008: ldarg.0 IL_0009: stfld class C`1<!0> class Extensions/'<M>d__1`2'<!!T, !!U>::'<>3__o' IL_000e: dup IL_000f: ldarg.1 IL_0010: stfld !0 class Extensions/'<M>d__1`2'<!!T, !!U>::'<>3__t1' IL_0015: dup IL_0016: ldarg.2 IL_0017: stfld !1 class Extensions/'<M>d__1`2'<!!T, !!U>::'<>3__u1' IL_001c: ret } // end of method Extensions::M } // end of class Extensions """).Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension<T>(C<T> o) { System.Collections.Generic.IEnumerable<string> M<U>(T t1, U u1) { yield return o.GetString() + u1.ToString() + t1.ToString(); } } extension<T>(C<T> o) { System.Collections.Generic.IEnumerable<string> M<U>(T t1, U u1, int x) { yield return o.GetString() + u1.ToString() + t1.ToString(); } } } public class C<T> { public string GetString() => null; } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); var src3 = """ class Program { static void Main() { foreach (var s in Test(new C<long>("1"), 2, "3")) System.Console.Write(s); foreach (var s in new C<long>("4").M2(5, "6")) System.Console.Write(s); } static System.Collections.Generic.IEnumerable<string> Test<T, U>(C<T> o, T t1, U u1) { return o.M(t1, u1); } } static class Extensions { extension<T>(C<T> o) { public System.Collections.Generic.IEnumerable<string> M2<U>(T t1, U u1) => o.M(t1, u1); } } """; var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); } [Fact] public void Implementation_InstanceMethod_11_Async_Generic() { var src1 = """ public static class Extensions { extension<T>(C<T> o) { public async System.Threading.Tasks.Task<string> M<U>(T t1, U u1) { await System.Threading.Tasks.Task.Yield(); return o.GetString() + u1.ToString() + t1.ToString(); } } } public class C<T>(string val) { public string GetString() => val; } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1, symbolValidator: (m) => { MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType<MethodSymbol>().Single(); AssertEx.Equal("System.Runtime.CompilerServices.AsyncStateMachineAttribute(typeof(Extensions.<M>d__1<,>))", implementation.GetAttributes().Single().ToString()); }).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$D884D1E13988E83801B7574694E1C2C5'<T> extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( class C`1<!T> o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x21ea // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$D884D1E13988E83801B7574694E1C2C5'::'<Extension>$' } // end of class <M>$D884D1E13988E83801B7574694E1C2C5 // Methods .method public hidebysig instance class [mscorlib]System.Threading.Tasks.Task`1<string> M<U> ( !$T0 t1, !!U u1 ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 44 38 38 34 44 31 45 31 33 39 38 38 45 38 33 38 30 31 42 37 35 37 34 36 39 34 45 31 43 32 43 35 00 00 ) // Method begins at RVA 0x20ea // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1'::M } // end of class <G>$4A1E373BE5A70EE56E2FA5F469AC30F9`1 .class nested private auto ansi sealed beforefieldinit '<M>d__1`2'<T, U> extends [mscorlib]System.ValueType implements [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public int32 '<>1__state' .field public valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> '<>t__builder' .field public class C`1<!T> o .field public !U u1 .field public !T t1 .field private valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter '<>u__1' // Methods .method private final hidebysig newslot virtual instance void MoveNext () cil managed { .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext() // Method begins at RVA 0x20f4 // Code size 202 (0xca) .maxstack 3 .locals init ( [0] int32, [1] string, [2] valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter, [3] valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable, [4] class [mscorlib]System.Exception ) IL_0000: ldarg.0 IL_0001: ldfld int32 valuetype Extensions/'<M>d__1`2'<!T, !U>::'<>1__state' IL_0006: stloc.0 .try { IL_0007: ldloc.0 IL_0008: brfalse.s IL_0044 IL_000a: call valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable [mscorlib]System.Threading.Tasks.Task::Yield() IL_000f: stloc.3 IL_0010: ldloca.s 3 IL_0012: call instance valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter [mscorlib]System.Runtime.CompilerServices.YieldAwaitable::GetAwaiter() IL_0017: stloc.2 IL_0018: ldloca.s 2 IL_001a: call instance bool [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter::get_IsCompleted() IL_001f: brtrue.s IL_0060 IL_0021: ldarg.0 IL_0022: ldc.i4.0 IL_0023: dup IL_0024: stloc.0 IL_0025: stfld int32 valuetype Extensions/'<M>d__1`2'<!T, !U>::'<>1__state' IL_002a: ldarg.0 IL_002b: ldloc.2 IL_002c: stfld valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter valuetype Extensions/'<M>d__1`2'<!T, !U>::'<>u__1' IL_0031: ldarg.0 IL_0032: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> valuetype Extensions/'<M>d__1`2'<!T, !U>::'<>t__builder' IL_0037: ldloca.s 2 IL_0039: ldarg.0 IL_003a: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::AwaitUnsafeOnCompleted<valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter, valuetype Extensions/'<M>d__1`2'<!T, !U>>(!!0&, !!1&) IL_003f: leave IL_00c9 IL_0044: ldarg.0 IL_0045: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter valuetype Extensions/'<M>d__1`2'<!T, !U>::'<>u__1' IL_004a: stloc.2 IL_004b: ldarg.0 IL_004c: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter valuetype Extensions/'<M>d__1`2'<!T, !U>::'<>u__1' IL_0051: initobj [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter IL_0057: ldarg.0 IL_0058: ldc.i4.m1 IL_0059: dup IL_005a: stloc.0 IL_005b: stfld int32 valuetype Extensions/'<M>d__1`2'<!T, !U>::'<>1__state' IL_0060: ldloca.s 2 IL_0062: call instance void [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter::GetResult() IL_0067: ldarg.0 IL_0068: ldfld class C`1<!0> valuetype Extensions/'<M>d__1`2'<!T, !U>::o IL_006d: callvirt instance string class C`1<!T>::GetString() IL_0072: ldarg.0 IL_0073: ldflda !1 valuetype Extensions/'<M>d__1`2'<!T, !U>::u1 IL_0078: constrained. !U IL_007e: callvirt instance string [mscorlib]System.Object::ToString() IL_0083: ldarg.0 IL_0084: ldflda !0 valuetype Extensions/'<M>d__1`2'<!T, !U>::t1 IL_0089: constrained. !T IL_008f: callvirt instance string [mscorlib]System.Object::ToString() IL_0094: call string [mscorlib]System.String::Concat(string, string, string) IL_0099: stloc.1 IL_009a: leave.s IL_00b5 } // end .try catch [mscorlib]System.Exception { IL_009c: stloc.s 4 IL_009e: ldarg.0 IL_009f: ldc.i4.s -2 IL_00a1: stfld int32 valuetype Extensions/'<M>d__1`2'<!T, !U>::'<>1__state' IL_00a6: ldarg.0 IL_00a7: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> valuetype Extensions/'<M>d__1`2'<!T, !U>::'<>t__builder' IL_00ac: ldloc.s 4 IL_00ae: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::SetException(class [mscorlib]System.Exception) IL_00b3: leave.s IL_00c9 } // end handler IL_00b5: ldarg.0 IL_00b6: ldc.i4.s -2 IL_00b8: stfld int32 valuetype Extensions/'<M>d__1`2'<!T, !U>::'<>1__state' IL_00bd: ldarg.0 IL_00be: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> valuetype Extensions/'<M>d__1`2'<!T, !U>::'<>t__builder' IL_00c3: ldloc.1 IL_00c4: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::SetResult(!0) IL_00c9: ret } // end of method '<M>d__1`2'::MoveNext .method private final hidebysig newslot virtual instance void SetStateMachine ( class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine stateMachine ) cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) // Method begins at RVA 0x21dc // Code size 13 (0xd) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> valuetype Extensions/'<M>d__1`2'<!T, !U>::'<>t__builder' IL_0006: ldarg.1 IL_0007: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) IL_000c: ret } // end of method '<M>d__1`2'::SetStateMachine } // end of class <M>d__1`2 // Methods .method public hidebysig static class [mscorlib]System.Threading.Tasks.Task`1<string> M<T, U> ( class C`1<!!T> o, !!T t1, !!U u1 ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( 01 00 14 45 78 74 65 6e 73 69 6f 6e 73 2b 3c 4d 3e 64 5f 5f 31 60 32 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2080 // Code size 71 (0x47) .maxstack 2 .locals init ( [0] valuetype Extensions/'<M>d__1`2'<!!T, !!U> ) IL_0000: ldloca.s 0 IL_0002: call valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<!0> valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::Create() IL_0007: stfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> valuetype Extensions/'<M>d__1`2'<!!T, !!U>::'<>t__builder' IL_000c: ldloca.s 0 IL_000e: ldarg.0 IL_000f: stfld class C`1<!0> valuetype Extensions/'<M>d__1`2'<!!T, !!U>::o IL_0014: ldloca.s 0 IL_0016: ldarg.1 IL_0017: stfld !0 valuetype Extensions/'<M>d__1`2'<!!T, !!U>::t1 IL_001c: ldloca.s 0 IL_001e: ldarg.2 IL_001f: stfld !1 valuetype Extensions/'<M>d__1`2'<!!T, !!U>::u1 IL_0024: ldloca.s 0 IL_0026: ldc.i4.m1 IL_0027: stfld int32 valuetype Extensions/'<M>d__1`2'<!!T, !!U>::'<>1__state' IL_002c: ldloca.s 0 IL_002e: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> valuetype Extensions/'<M>d__1`2'<!!T, !!U>::'<>t__builder' IL_0033: ldloca.s 0 IL_0035: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::Start<valuetype Extensions/'<M>d__1`2'<!!T, !!U>>(!!0&) IL_003a: ldloca.s 0 IL_003c: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> valuetype Extensions/'<M>d__1`2'<!!T, !!U>::'<>t__builder' IL_0041: call instance class [mscorlib]System.Threading.Tasks.Task`1<!0> valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::get_Task() IL_0046: ret } // end of method Extensions::M } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension<T>(C<T> o) { async System.Threading.Tasks.Task<string> M<U>(T t1, U u1) { await System.Threading.Tasks.Task.Yield(); return o.GetString() + u1.ToString() + t1.ToString(); } } extension<T>(C<T> o) { async System.Threading.Tasks.Task<string> M<U>(T t1, U u1, int x) { await System.Threading.Tasks.Task.Yield(); return o.GetString() + u1.ToString() + t1.ToString(); } } } public class C<T> { public string GetString() => null; } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); var src3 = """ class Program { static void Main() { System.Console.Write(Test(new C<long>("1"), 2, "3").Result); System.Console.Write(new C<long>("4").M2(5, "6").Result); } async static System.Threading.Tasks.Task<string> Test<T, U>(C<T> o, T t1, U u1) { await System.Threading.Tasks.Task.Yield(); return await o.M(t1, u1); } } static class Extensions { extension<T>(C<T> o) { async public System.Threading.Tasks.Task<string> M2<U>(T t1, U u1) { await System.Threading.Tasks.Task.Yield(); return await o.M(t1, u1); } } } """; var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "132465").VerifyDiagnostics(); } [Fact] public void Implementation_StaticMethod_01() { var src1 = """ public static class Extensions { extension(object _) { public static string M(object o, string s) { return o + s; } } } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1, sourceSymbolValidator: verifySymbols, symbolValidator: verifySymbols).VerifyDiagnostics(); static void verifySymbols(ModuleSymbol m) { MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType<MethodSymbol>().Single(); Assert.True(implementation.IsStatic); Assert.Equal(MethodKind.Ordinary, implementation.MethodKind); Assert.Equal(2, implementation.ParameterCount); AssertEx.Equal("System.String Extensions.M(System.Object o, System.String s)", implementation.ToTestDisplayString()); Assert.Equal(m is not PEModuleSymbol, implementation.IsImplicitlyDeclared); Assert.False(implementation.IsExtensionMethod); Assert.False(implementation.HasSpecialName); Assert.False(implementation.HasRuntimeSpecialName); Assert.True(implementation.ContainingType.MightContainExtensions); if (m is PEModuleSymbol peModuleSymbol) { Assert.True(peModuleSymbol.Module.HasExtensionAttribute(((PEAssemblySymbol)peModuleSymbol.ContainingAssembly).Assembly.Handle, ignoreCase: false)); } } var expectedTypeIL = """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$3D34838CB2C73A4E406AE3905787D97D' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object _ ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2099 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$3D34838CB2C73A4E406AE3905787D97D'::'<Extension>$' } // end of class <M>$3D34838CB2C73A4E406AE3905787D97D // Methods .method public hidebysig static string M ( object o, string s ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 33 44 33 34 38 33 38 43 42 32 43 37 33 41 34 45 34 30 36 41 45 33 39 30 35 37 38 37 44 39 37 44 00 00 ) // Method begins at RVA 0x2092 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method public hidebysig static string M ( object o, string s ) cil managed { // Method begins at RVA 0x207e // Code size 19 (0x13) .maxstack 8 IL_0000: ldarg.0 IL_0001: brtrue.s IL_0006 IL_0003: ldnull IL_0004: br.s IL_000c IL_0006: ldarg.0 IL_0007: callvirt instance string [mscorlib]System.Object::ToString() IL_000c: ldarg.1 IL_000d: call string [mscorlib]System.String::Concat(string, string) IL_0012: ret } // end of method Extensions::M } // end of class Extensions """; verifier1.VerifyTypeIL("Extensions", expectedTypeIL.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write(object.M2("3", "4")); } static string Test(object o) { return object.M(o, "2"); } } static class Extensions { extension(object o) { public static string M2(object o1, string s) { return object.M(o1, s); } } } """; var comp1MetadataReference = comp1.ToMetadataReference(); var comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe); var verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); var testIL = @" { // Code size 17 (0x11) .maxstack 2 .locals init (string V_0) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldstr ""2"" IL_0007: call ""string Extensions.M(object, string)"" IL_000c: stloc.0 IL_000d: br.s IL_000f IL_000f: ldloc.0 IL_0010: ret } "; verifier2.VerifyIL("Program.Test", testIL); var m2IL = @" { // Code size 9 (0x9) .maxstack 2 IL_0000: nop IL_0001: ldarg.0 IL_0002: ldarg.1 IL_0003: call ""string Extensions.M(object, string)"" IL_0008: ret } "; verifier2.VerifyIL("Extensions.M2", m2IL); var comp1ImageReference = comp1.EmitToImageReference(); comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); verifier2.VerifyIL("Program.Test", testIL); verifier2.VerifyIL("Extensions.M2", m2IL); comp2 = CreateCompilationWithIL(src2, expectedTypeIL + ExtensionMarkerAttributeIL, options: TestOptions.DebugExe); CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); var remove = """ .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) """; comp2 = CreateCompilationWithIL(src2, expectedTypeIL.Remove(expectedTypeIL.IndexOf(remove), remove.Length) + ExtensionMarkerAttributeIL); comp2.VerifyDiagnostics( // (11,23): error CS0117: 'object' does not contain a definition for 'M' // return object.M(o, "2"); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(11, 23), // (21,27): error CS0117: 'object' does not contain a definition for 'M' // return object.M(o, s); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(21, 27) ); src2 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write(object.M2("3", "4")); } static string Test(object o) { return Extensions.M(o, "2"); } } static class Extensions_ { extension(object o) { public static string M2(object o1, string s) { return Extensions.M(o1, s); } } } """; comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); verifier2.VerifyIL("Program.Test", testIL); verifier2.VerifyIL("Extensions_.M2", m2IL); comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); verifier2.VerifyIL("Program.Test", testIL); verifier2.VerifyIL("Extensions_.M2", m2IL); var vbComp = CreateVisualBasicCompilation(""" Class Program Shared Sub Main() System.Console.Write(Test2("3")) End Sub Shared Function Test2(o As String) As String return Extensions.M(o, "4") End Function End Class """, referencedAssemblies: comp2.References, compilationOptions: new VisualBasicCompilationOptions(OutputKind.ConsoleApplication)); CompileAndVerify(vbComp, expectedOutput: "34").VerifyDiagnostics(); if (!CompilationExtensions.EnableVerifyUsedAssemblies) // Tracked by https://github.com/dotnet/roslyn/issues/77542 { src2 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write(object.M2("3", "4")); } static string Test(object o) { System.Func<object, string, string> d = object.M; return d(o, "2"); } } static class Extensions { extension(object o) { public static string M2(object o1, string s) { return new System.Func<object, string, string>(object.M)(o1, s); } } } """; comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); testIL = @" { // Code size 46 (0x2e) .maxstack 3 .locals init (System.Func<object, string, string> V_0, //d string V_1) IL_0000: nop IL_0001: ldsfld ""System.Func<object, string, string> Program.<>O.<0>__M"" IL_0006: dup IL_0007: brtrue.s IL_001c IL_0009: pop IL_000a: ldnull IL_000b: ldftn ""string Extensions.M(object, string)"" IL_0011: newobj ""System.Func<object, string, string>..ctor(object, System.IntPtr)"" IL_0016: dup IL_0017: stsfld ""System.Func<object, string, string> Program.<>O.<0>__M"" IL_001c: stloc.0 IL_001d: ldloc.0 IL_001e: ldarg.0 IL_001f: ldstr ""2"" IL_0024: callvirt ""string System.Func<object, string, string>.Invoke(object, string)"" IL_0029: stloc.1 IL_002a: br.s IL_002c IL_002c: ldloc.1 IL_002d: ret } "; verifier2.VerifyIL("Program.Test", testIL); m2IL = @" { // Code size 21 (0x15) .maxstack 3 IL_0000: nop IL_0001: ldnull IL_0002: ldftn ""string Extensions.M(object, string)"" IL_0008: newobj ""System.Func<object, string, string>..ctor(object, System.IntPtr)"" IL_000d: ldarg.0 IL_000e: ldarg.1 IL_000f: callvirt ""string System.Func<object, string, string>.Invoke(object, string)"" IL_0014: ret } "; verifier2.VerifyIL("Extensions.M2", m2IL); comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); verifier2.VerifyIL("Program.Test", testIL); verifier2.VerifyIL("Extensions.M2", m2IL); src2 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write(object.M2("3", "4")); } static string Test(object o) { System.Func<object, string, string> d = Extensions.M; return d(o, "2"); } } static class Extensions_ { extension(object o) { public static string M2(object o1, string s) { return new System.Func<object, string, string>(Extensions.M)(o1, s); } } } """; comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); verifier2.VerifyIL("Program.Test", testIL); verifier2.VerifyIL("Extensions_.M2", m2IL); comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234").VerifyDiagnostics(); verifier2.VerifyIL("Program.Test", testIL); verifier2.VerifyIL("Extensions_.M2", m2IL); src2 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write(object.M2("3", "4")); } unsafe static string Test(object o) { delegate*<object, string, string> d = &object.M; return d(o, "2"); } } static class Extensions { extension(object o) { unsafe public static string M2(object o1, string s) { return ((delegate*<object, string, string>)&object.M)(o1, s); } } } """; comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe.WithAllowUnsafe(true)); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234", verify: Verification.Skipped).VerifyDiagnostics(); testIL = @" { // Code size 27 (0x1b) .maxstack 3 .locals init (delegate*<object, string, string> V_0, //d delegate*<object, string, string> V_1, string V_2) IL_0000: nop IL_0001: ldftn ""string Extensions.M(object, string)"" IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: stloc.1 IL_000a: ldarg.0 IL_000b: ldstr ""2"" IL_0010: ldloc.1 IL_0011: calli ""delegate*<object, string, string>"" IL_0016: stloc.2 IL_0017: br.s IL_0019 IL_0019: ldloc.2 IL_001a: ret } "; verifier2.VerifyIL("Program.Test", testIL); m2IL = @" { // Code size 17 (0x11) .maxstack 3 .locals init (delegate*<object, string, string> V_0) IL_0000: nop IL_0001: ldftn ""string Extensions.M(object, string)"" IL_0007: stloc.0 IL_0008: ldarg.0 IL_0009: ldarg.1 IL_000a: ldloc.0 IL_000b: calli ""delegate*<object, string, string>"" IL_0010: ret } "; verifier2.VerifyIL("Extensions.M2", m2IL); comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe.WithAllowUnsafe(true)); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234", verify: Verification.Skipped).VerifyDiagnostics(); verifier2.VerifyIL("Program.Test", testIL); verifier2.VerifyIL("Extensions.M2", m2IL); src2 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write(object.M2("3", "4")); } unsafe static string Test(object o) { delegate*<object, string, string> d = &Extensions.M; return d(o, "2"); } } static class Extensions_ { extension(object o) { unsafe public static string M2(object o1, string s) { return ((delegate*<object, string, string>)&Extensions.M)(o1, s); } } } """; comp2 = CreateCompilation(src2, references: [comp1MetadataReference], options: TestOptions.DebugExe.WithAllowUnsafe(true)); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234", verify: Verification.Skipped).VerifyDiagnostics(); verifier2.VerifyIL("Program.Test", testIL); verifier2.VerifyIL("Extensions_.M2", m2IL); comp2 = CreateCompilation(src2, references: [comp1ImageReference], options: TestOptions.DebugExe.WithAllowUnsafe(true)); verifier2 = CompileAndVerify(comp2, expectedOutput: "1234", verify: Verification.Skipped).VerifyDiagnostics(); verifier2.VerifyIL("Program.Test", testIL); verifier2.VerifyIL("Extensions_.M2", m2IL); } var comp5 = CreateCompilation(src1); comp5.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); comp5.VerifyEmitDiagnostics( // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // extension(object _) Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5) ); } [Fact] public void Implementation_StaticMethod_02_WithLocalFunction() { var src1 = """ public static class Extensions { extension(object _) { public static string M(object o, string s) { string local() => o + s; return local(); } } } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$3D34838CB2C73A4E406AE3905787D97D' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object _ ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20ca // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$3D34838CB2C73A4E406AE3905787D97D'::'<Extension>$' } // end of class <M>$3D34838CB2C73A4E406AE3905787D97D // Methods .method public hidebysig static string M ( object o, string s ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 33 44 33 34 38 33 38 43 42 32 43 37 33 41 34 45 34 30 36 41 45 33 39 30 35 37 38 37 44 39 37 44 00 00 ) // Method begins at RVA 0x20c3 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0' extends [mscorlib]System.ValueType { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public object o .field public string s } // end of class <>c__DisplayClass1_0 // Methods .method public hidebysig static string M ( object o, string s ) cil managed { // Method begins at RVA 0x2080 // Code size 24 (0x18) .maxstack 2 .locals init ( [0] valuetype Extensions/'<>c__DisplayClass1_0' ) IL_0000: ldloca.s 0 IL_0002: ldarg.0 IL_0003: stfld object Extensions/'<>c__DisplayClass1_0'::o IL_0008: ldloca.s 0 IL_000a: ldarg.1 IL_000b: stfld string Extensions/'<>c__DisplayClass1_0'::s IL_0010: ldloca.s 0 IL_0012: call string Extensions::'<M>g__local|1_0'(valuetype Extensions/'<>c__DisplayClass1_0'&) IL_0017: ret } // end of method Extensions::M .method assembly hidebysig static string '<M>g__local|1_0' ( valuetype Extensions/'<>c__DisplayClass1_0'& '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20a4 // Code size 30 (0x1e) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld object Extensions/'<>c__DisplayClass1_0'::o IL_0006: dup IL_0007: brtrue.s IL_000d IL_0009: pop IL_000a: ldnull IL_000b: br.s IL_0012 IL_000d: callvirt instance string [mscorlib]System.Object::ToString() IL_0012: ldarg.0 IL_0013: ldfld string Extensions/'<>c__DisplayClass1_0'::s IL_0018: call string [mscorlib]System.String::Concat(string, string) IL_001d: ret } // end of method Extensions::'<M>g__local|1_0' } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension(object _) { public static string M(object o, string s) { string local() => o + s; return local(); } } extension(object) { public static string M(object o, string s, int x) { string local() => o + s; return local(); } } } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2, symbolValidator: (m) => { var container = m.GlobalNamespace.GetTypeMember("Extensions"); var extensions = container.GetTypeMembers(); AssertEx.Equal("System.Object _", extensions[0].ExtensionParameter.ToTestDisplayString()); AssertEx.Equal("<M>$3D34838CB2C73A4E406AE3905787D97D", extensions[0].MetadataName); Symbol m1 = extensions[0].GetMembers().Single(); AssertEx.Equal("Extensions.extension(object).M(object, string)", m1.ToDisplayString()); AssertEx.Equal([], m1.GetAttributes()); AssertEx.Equal("System.Object", extensions[1].ExtensionParameter.ToTestDisplayString()); AssertEx.Equal("<M>$C43E2675C7BBF9284AF22FB8A9BF0280", extensions[1].MetadataName); Symbol m2 = extensions[1].GetMembers().Single(); AssertEx.Equal("Extensions.extension(object).M(object, string, int)", m2.ToDisplayString()); AssertEx.Equal([], m2.GetAttributes()); }).VerifyDiagnostics(). VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$3D34838CB2C73A4E406AE3905787D97D' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object _ ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x210d // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$3D34838CB2C73A4E406AE3905787D97D'::'<Extension>$' } // end of class <M>$3D34838CB2C73A4E406AE3905787D97D .class nested public auto ansi abstract sealed specialname '<M>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x210d // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$C43E2675C7BBF9284AF22FB8A9BF0280'::'<Extension>$' } // end of class <M>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method public hidebysig static string M ( object o, string s ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 33 44 33 34 38 33 38 43 42 32 43 37 33 41 34 45 34 30 36 41 45 33 39 30 35 37 38 37 44 39 37 44 00 00 ) // Method begins at RVA 0x2106 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M .method public hidebysig static string M ( object o, string s, int32 x ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 43 34 33 45 32 36 37 35 43 37 42 42 46 39 32 38 34 41 46 32 32 46 42 38 41 39 42 46 30 32 38 30 00 00 ) // Method begins at RVA 0x2106 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0' extends [mscorlib]System.ValueType { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public object o .field public string s } // end of class <>c__DisplayClass1_0 .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass3_0' extends [mscorlib]System.ValueType { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public object o .field public string s } // end of class <>c__DisplayClass3_0 // Methods .method public hidebysig static string M ( object o, string s ) cil managed { // Method begins at RVA 0x2080 // Code size 24 (0x18) .maxstack 2 .locals init ( [0] valuetype Extensions/'<>c__DisplayClass1_0' ) IL_0000: ldloca.s 0 IL_0002: ldarg.0 IL_0003: stfld object Extensions/'<>c__DisplayClass1_0'::o IL_0008: ldloca.s 0 IL_000a: ldarg.1 IL_000b: stfld string Extensions/'<>c__DisplayClass1_0'::s IL_0010: ldloca.s 0 IL_0012: call string Extensions::'<M>g__local|1_0'(valuetype Extensions/'<>c__DisplayClass1_0'&) IL_0017: ret } // end of method Extensions::M .method public hidebysig static string M ( object o, string s, int32 x ) cil managed { // Method begins at RVA 0x20a4 // Code size 24 (0x18) .maxstack 2 .locals init ( [0] valuetype Extensions/'<>c__DisplayClass3_0' ) IL_0000: ldloca.s 0 IL_0002: ldarg.0 IL_0003: stfld object Extensions/'<>c__DisplayClass3_0'::o IL_0008: ldloca.s 0 IL_000a: ldarg.1 IL_000b: stfld string Extensions/'<>c__DisplayClass3_0'::s IL_0010: ldloca.s 0 IL_0012: call string Extensions::'<M>g__local|3_0'(valuetype Extensions/'<>c__DisplayClass3_0'&) IL_0017: ret } // end of method Extensions::M .method assembly hidebysig static string '<M>g__local|1_0' ( valuetype Extensions/'<>c__DisplayClass1_0'& '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20c8 // Code size 30 (0x1e) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld object Extensions/'<>c__DisplayClass1_0'::o IL_0006: dup IL_0007: brtrue.s IL_000d IL_0009: pop IL_000a: ldnull IL_000b: br.s IL_0012 IL_000d: callvirt instance string [mscorlib]System.Object::ToString() IL_0012: ldarg.0 IL_0013: ldfld string Extensions/'<>c__DisplayClass1_0'::s IL_0018: call string [mscorlib]System.String::Concat(string, string) IL_001d: ret } // end of method Extensions::'<M>g__local|1_0' .method assembly hidebysig static string '<M>g__local|3_0' ( valuetype Extensions/'<>c__DisplayClass3_0'& '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20e7 // Code size 30 (0x1e) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld object Extensions/'<>c__DisplayClass3_0'::o IL_0006: dup IL_0007: brtrue.s IL_000d IL_0009: pop IL_000a: ldnull IL_000b: br.s IL_0012 IL_000d: callvirt instance string [mscorlib]System.Object::ToString() IL_0012: ldarg.0 IL_0013: ldfld string Extensions/'<>c__DisplayClass3_0'::s IL_0018: call string [mscorlib]System.String::Concat(string, string) IL_001d: ret } // end of method Extensions::'<M>g__local|3_0' } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src3 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write(object.M2("3","4")); } static string Test(object o) { string local() => object.M(o, "2"); return local(); } } static class Extensions { extension(object _) { public static string M2(object o, string s) { string local() => object.M(o, s); return local(); } } } """; var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); } [Fact] public void Implementation_StaticMethod_03_WithLambda() { var src1 = """ public static class Extensions { extension(object _) { public static string M(object o, string s) { System.Func<string> local = () => o + s; return local(); } } } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$3D34838CB2C73A4E406AE3905787D97D' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object _ ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20d1 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$3D34838CB2C73A4E406AE3905787D97D'::'<Extension>$' } // end of class <M>$3D34838CB2C73A4E406AE3905787D97D // Methods .method public hidebysig static string M ( object o, string s ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 33 44 33 34 38 33 38 43 42 32 43 37 33 41 34 45 34 30 36 41 45 33 39 30 35 37 38 37 44 39 37 44 00 00 ) // Method begins at RVA 0x20a3 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public object o .field public string s // Methods .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x20aa // 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__DisplayClass1_0'::.ctor .method assembly hidebysig instance string '<M>b__0' () cil managed { // Method begins at RVA 0x20b2 // Code size 30 (0x1e) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld object Extensions/'<>c__DisplayClass1_0'::o IL_0006: dup IL_0007: brtrue.s IL_000d IL_0009: pop IL_000a: ldnull IL_000b: br.s IL_0012 IL_000d: callvirt instance string [mscorlib]System.Object::ToString() IL_0012: ldarg.0 IL_0013: ldfld string Extensions/'<>c__DisplayClass1_0'::s IL_0018: call string [mscorlib]System.String::Concat(string, string) IL_001d: ret } // end of method '<>c__DisplayClass1_0'::'<M>b__0' } // end of class <>c__DisplayClass1_0 // Methods .method public hidebysig static string M ( object o, string s ) cil managed { // Method begins at RVA 0x207e // Code size 36 (0x24) .maxstack 8 IL_0000: newobj instance void Extensions/'<>c__DisplayClass1_0'::.ctor() IL_0005: dup IL_0006: ldarg.0 IL_0007: stfld object Extensions/'<>c__DisplayClass1_0'::o IL_000c: dup IL_000d: ldarg.1 IL_000e: stfld string Extensions/'<>c__DisplayClass1_0'::s IL_0013: ldftn instance string Extensions/'<>c__DisplayClass1_0'::'<M>b__0'() IL_0019: newobj instance void class [mscorlib]System.Func`1<string>::.ctor(object, native int) IL_001e: callvirt instance !0 class [mscorlib]System.Func`1<string>::Invoke() IL_0023: ret } // end of method Extensions::M } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension(object _) { static string M(object o, string s) { System.Func<string> local = () => o + s; return local(); } } extension(object) { static string M(object o, string s, int x) { System.Func<string> local = () => o + s; return local(); } } } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); var src3 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write(object.M2("3","4")); } static string Test(object o) { System.Func<string> local = () => object.M(o, "2"); return local(); } } static class Extensions { extension(object _) { public static string M2(object o, string s) { System.Func<string> local = () => object.M(o, s); return local(); } } } """; var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); } [Fact] public void Implementation_StaticMethod_04_Iterator() { var src1 = """ public static class Extensions { extension(object _) { public static System.Collections.Generic.IEnumerable<string> M(object o, string s) { yield return o + s; } } } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1, symbolValidator: (m) => { MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType<MethodSymbol>().Single(); AssertEx.Equal("System.Runtime.CompilerServices.IteratorStateMachineAttribute(typeof(Extensions.<M>d__1))", implementation.GetAttributes().Single().ToString()); }).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", (""" .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$3D34838CB2C73A4E406AE3905787D97D' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object _ ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x217f // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$3D34838CB2C73A4E406AE3905787D97D'::'<Extension>$' } // end of class <M>$3D34838CB2C73A4E406AE3905787D97D // Methods .method public hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<string> M ( object o, string s ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 33 44 33 34 38 33 38 43 42 32 43 37 33 41 34 45 34 30 36 41 45 33 39 30 35 37 38 37 44 39 37 44 00 00 ) // Method begins at RVA 0x2095 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 .class nested private auto ansi sealed beforefieldinit '<M>d__1' extends [mscorlib]System.Object implements class [mscorlib]System.Collections.Generic.IEnumerable`1<string>, [mscorlib]System.Collections.IEnumerable, class [mscorlib]System.Collections.Generic.IEnumerator`1<string>, """ + (ExecutionConditionUtil.IsMonoOrCoreClr ? """ [mscorlib]System.Collections.IEnumerator, [mscorlib]System.IDisposable """ : """ [mscorlib]System.IDisposable, [mscorlib]System.Collections.IEnumerator """) + """ { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field private int32 '<>1__state' .field private string '<>2__current' .field private int32 '<>l__initialThreadId' .field private object o .field public object '<>3__o' .field private string s .field public string '<>3__s' // Methods .method public hidebysig specialname rtspecialname instance void .ctor ( int32 '<>1__state' ) cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x209c // Code size 25 (0x19) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ldarg.0 IL_0007: ldarg.1 IL_0008: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_000d: ldarg.0 IL_000e: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() IL_0013: stfld int32 Extensions/'<M>d__1'::'<>l__initialThreadId' IL_0018: ret } // end of method '<M>d__1'::.ctor .method private final hidebysig newslot virtual instance void System.IDisposable.Dispose () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance void [mscorlib]System.IDisposable::Dispose() // Method begins at RVA 0x20b6 // Code size 9 (0x9) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldc.i4.s -2 IL_0003: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0008: ret } // end of method '<M>d__1'::System.IDisposable.Dispose .method private final hidebysig newslot virtual instance bool MoveNext () cil managed { .override method instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() // Method begins at RVA 0x20c0 // Code size 76 (0x4c) .maxstack 3 .locals init ( [0] int32 ) IL_0000: ldarg.0 IL_0001: ldfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: brfalse.s IL_0010 IL_000a: ldloc.0 IL_000b: ldc.i4.1 IL_000c: beq.s IL_0043 IL_000e: ldc.i4.0 IL_000f: ret IL_0010: ldarg.0 IL_0011: ldc.i4.m1 IL_0012: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0017: ldarg.0 IL_0018: ldarg.0 IL_0019: ldfld object Extensions/'<M>d__1'::o IL_001e: dup IL_001f: brtrue.s IL_0025 IL_0021: pop IL_0022: ldnull IL_0023: br.s IL_002a IL_0025: callvirt instance string [mscorlib]System.Object::ToString() IL_002a: ldarg.0 IL_002b: ldfld string Extensions/'<M>d__1'::s IL_0030: call string [mscorlib]System.String::Concat(string, string) IL_0035: stfld string Extensions/'<M>d__1'::'<>2__current' IL_003a: ldarg.0 IL_003b: ldc.i4.1 IL_003c: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0041: ldc.i4.1 IL_0042: ret IL_0043: ldarg.0 IL_0044: ldc.i4.m1 IL_0045: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_004a: ldc.i4.0 IL_004b: ret } // end of method '<M>d__1'::MoveNext .method private final hidebysig specialname newslot virtual instance string 'System.Collections.Generic.IEnumerator<System.String>.get_Current' () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current() // Method begins at RVA 0x2118 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld string Extensions/'<M>d__1'::'<>2__current' IL_0006: ret } // end of method '<M>d__1'::'System.Collections.Generic.IEnumerator<System.String>.get_Current' .method private final hidebysig newslot virtual instance void System.Collections.IEnumerator.Reset () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance void [mscorlib]System.Collections.IEnumerator::Reset() // Method begins at RVA 0x2120 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<M>d__1'::System.Collections.IEnumerator.Reset .method private final hidebysig specialname newslot virtual instance object System.Collections.IEnumerator.get_Current () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance object [mscorlib]System.Collections.IEnumerator::get_Current() // Method begins at RVA 0x2118 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld string Extensions/'<M>d__1'::'<>2__current' IL_0006: ret } // end of method '<M>d__1'::System.Collections.IEnumerator.get_Current .method private final hidebysig newslot virtual instance class [mscorlib]System.Collections.Generic.IEnumerator`1<string> 'System.Collections.Generic.IEnumerable<System.String>.GetEnumerator' () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<string>::GetEnumerator() // Method begins at RVA 0x2128 // Code size 67 (0x43) .maxstack 2 .locals init ( [0] class Extensions/'<M>d__1' ) IL_0000: ldarg.0 IL_0001: ldfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0006: ldc.i4.s -2 IL_0008: bne.un.s IL_0022 IL_000a: ldarg.0 IL_000b: ldfld int32 Extensions/'<M>d__1'::'<>l__initialThreadId' IL_0010: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() IL_0015: bne.un.s IL_0022 IL_0017: ldarg.0 IL_0018: ldc.i4.0 IL_0019: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_001e: ldarg.0 IL_001f: stloc.0 IL_0020: br.s IL_0029 IL_0022: ldc.i4.0 IL_0023: newobj instance void Extensions/'<M>d__1'::.ctor(int32) IL_0028: stloc.0 IL_0029: ldloc.0 IL_002a: ldarg.0 IL_002b: ldfld object Extensions/'<M>d__1'::'<>3__o' IL_0030: stfld object Extensions/'<M>d__1'::o IL_0035: ldloc.0 IL_0036: ldarg.0 IL_0037: ldfld string Extensions/'<M>d__1'::'<>3__s' IL_003c: stfld string Extensions/'<M>d__1'::s IL_0041: ldloc.0 IL_0042: ret } // end of method '<M>d__1'::'System.Collections.Generic.IEnumerable<System.String>.GetEnumerator' .method private final hidebysig newslot virtual instance class [mscorlib]System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator() // Method begins at RVA 0x2177 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance class [mscorlib]System.Collections.Generic.IEnumerator`1<string> Extensions/'<M>d__1'::'System.Collections.Generic.IEnumerable<System.String>.GetEnumerator'() IL_0006: ret } // end of method '<M>d__1'::System.Collections.IEnumerable.GetEnumerator // Properties .property instance string 'System.Collections.Generic.IEnumerator<System.String>.Current'() { .get instance string Extensions/'<M>d__1'::'System.Collections.Generic.IEnumerator<System.String>.get_Current'() } .property instance object System.Collections.IEnumerator.Current() { .get instance object Extensions/'<M>d__1'::System.Collections.IEnumerator.get_Current() } } // end of class <M>d__1 // Methods .method public hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<string> M ( object o, string s ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.IteratorStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( 01 00 12 45 78 74 65 6e 73 69 6f 6e 73 2b 3c 4d 3e 64 5f 5f 31 00 00 ) // Method begins at RVA 0x207e // Code size 22 (0x16) .maxstack 8 IL_0000: ldc.i4.s -2 IL_0002: newobj instance void Extensions/'<M>d__1'::.ctor(int32) IL_0007: dup IL_0008: ldarg.0 IL_0009: stfld object Extensions/'<M>d__1'::'<>3__o' IL_000e: dup IL_000f: ldarg.1 IL_0010: stfld string Extensions/'<M>d__1'::'<>3__s' IL_0015: ret } // end of method Extensions::M } // end of class Extensions """).Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension(object _) { static System.Collections.Generic.IEnumerable<string> M(object o, string s) { yield return o + s; } } extension(object) { static System.Collections.Generic.IEnumerable<string> M(object o, string s, int x) { yield return o + s; } } } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); var src3 = """ class Program { static void Main() { foreach (var s in Test("1")) System.Console.Write(s); foreach (var s in object.M2("3", "4")) System.Console.Write(s); } static System.Collections.Generic.IEnumerable<string> Test(object o) { return object.M(o, "2"); } } static class Extensions { extension(object _) { public static System.Collections.Generic.IEnumerable<string> M2(object o, string s) => object.M(o, s); } } """; var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); } [Fact] public void Implementation_StaticMethod_05_Async() { var src1 = """ public static class Extensions { extension(object _) { public static async System.Threading.Tasks.Task<string> M(object o, string s) { await System.Threading.Tasks.Task.Yield(); return o + s; } } } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1, symbolValidator: (m) => { MethodSymbol implementation = m.ContainingAssembly.GetTypeByMetadataName("Extensions").GetMembers().OfType<MethodSymbol>().Single(); AssertEx.Equal("System.Runtime.CompilerServices.AsyncStateMachineAttribute(typeof(Extensions.<M>d__1))", implementation.GetAttributes().Single().ToString()); }).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$3D34838CB2C73A4E406AE3905787D97D' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object _ ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x21b2 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$3D34838CB2C73A4E406AE3905787D97D'::'<Extension>$' } // end of class <M>$3D34838CB2C73A4E406AE3905787D97D // Methods .method public hidebysig static class [mscorlib]System.Threading.Tasks.Task`1<string> M ( object o, string s ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 33 44 33 34 38 33 38 43 42 32 43 37 33 41 34 45 34 30 36 41 45 33 39 30 35 37 38 37 44 39 37 44 00 00 ) // Method begins at RVA 0x20cb // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 .class nested private auto ansi sealed beforefieldinit '<M>d__1' extends [mscorlib]System.ValueType implements [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public int32 '<>1__state' .field public valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> '<>t__builder' .field public object o .field public string s .field private valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter '<>u__1' // Methods .method private final hidebysig newslot virtual instance void MoveNext () cil managed { .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext() // Method begins at RVA 0x20d4 // Code size 178 (0xb2) .maxstack 3 .locals init ( [0] int32, [1] string, [2] valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter, [3] valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable, [4] class [mscorlib]System.Exception ) IL_0000: ldarg.0 IL_0001: ldfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0006: stloc.0 .try { IL_0007: ldloc.0 IL_0008: brfalse.s IL_0041 IL_000a: call valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable [mscorlib]System.Threading.Tasks.Task::Yield() IL_000f: stloc.3 IL_0010: ldloca.s 3 IL_0012: call instance valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter [mscorlib]System.Runtime.CompilerServices.YieldAwaitable::GetAwaiter() IL_0017: stloc.2 IL_0018: ldloca.s 2 IL_001a: call instance bool [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter::get_IsCompleted() IL_001f: brtrue.s IL_005d IL_0021: ldarg.0 IL_0022: ldc.i4.0 IL_0023: dup IL_0024: stloc.0 IL_0025: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_002a: ldarg.0 IL_002b: ldloc.2 IL_002c: stfld valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter Extensions/'<M>d__1'::'<>u__1' IL_0031: ldarg.0 IL_0032: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_0037: ldloca.s 2 IL_0039: ldarg.0 IL_003a: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::AwaitUnsafeOnCompleted<valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter, valuetype Extensions/'<M>d__1'>(!!0&, !!1&) IL_003f: leave.s IL_00b1 IL_0041: ldarg.0 IL_0042: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter Extensions/'<M>d__1'::'<>u__1' IL_0047: stloc.2 IL_0048: ldarg.0 IL_0049: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter Extensions/'<M>d__1'::'<>u__1' IL_004e: initobj [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter IL_0054: ldarg.0 IL_0055: ldc.i4.m1 IL_0056: dup IL_0057: stloc.0 IL_0058: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_005d: ldloca.s 2 IL_005f: call instance void [mscorlib]System.Runtime.CompilerServices.YieldAwaitable/YieldAwaiter::GetResult() IL_0064: ldarg.0 IL_0065: ldfld object Extensions/'<M>d__1'::o IL_006a: dup IL_006b: brtrue.s IL_0071 IL_006d: pop IL_006e: ldnull IL_006f: br.s IL_0076 IL_0071: callvirt instance string [mscorlib]System.Object::ToString() IL_0076: ldarg.0 IL_0077: ldfld string Extensions/'<M>d__1'::s IL_007c: call string [mscorlib]System.String::Concat(string, string) IL_0081: stloc.1 IL_0082: leave.s IL_009d } // end .try catch [mscorlib]System.Exception { IL_0084: stloc.s 4 IL_0086: ldarg.0 IL_0087: ldc.i4.s -2 IL_0089: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_008e: ldarg.0 IL_008f: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_0094: ldloc.s 4 IL_0096: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::SetException(class [mscorlib]System.Exception) IL_009b: leave.s IL_00b1 } // end handler IL_009d: ldarg.0 IL_009e: ldc.i4.s -2 IL_00a0: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_00a5: ldarg.0 IL_00a6: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_00ab: ldloc.1 IL_00ac: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::SetResult(!0) IL_00b1: ret } // end of method '<M>d__1'::MoveNext .method private final hidebysig newslot virtual instance void SetStateMachine ( class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine stateMachine ) cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) // Method begins at RVA 0x21a4 // Code size 13 (0xd) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_0006: ldarg.1 IL_0007: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) IL_000c: ret } // end of method '<M>d__1'::SetStateMachine } // end of class <M>d__1 // Methods .method public hidebysig static class [mscorlib]System.Threading.Tasks.Task`1<string> M ( object o, string s ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( 01 00 12 45 78 74 65 6e 73 69 6f 6e 73 2b 3c 4d 3e 64 5f 5f 31 00 00 ) // Method begins at RVA 0x2080 // Code size 63 (0x3f) .maxstack 2 .locals init ( [0] valuetype Extensions/'<M>d__1' ) IL_0000: ldloca.s 0 IL_0002: call valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<!0> valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::Create() IL_0007: stfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_000c: ldloca.s 0 IL_000e: ldarg.0 IL_000f: stfld object Extensions/'<M>d__1'::o IL_0014: ldloca.s 0 IL_0016: ldarg.1 IL_0017: stfld string Extensions/'<M>d__1'::s IL_001c: ldloca.s 0 IL_001e: ldc.i4.m1 IL_001f: stfld int32 Extensions/'<M>d__1'::'<>1__state' IL_0024: ldloca.s 0 IL_0026: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_002b: ldloca.s 0 IL_002d: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::Start<valuetype Extensions/'<M>d__1'>(!!0&) IL_0032: ldloca.s 0 IL_0034: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> Extensions/'<M>d__1'::'<>t__builder' IL_0039: call instance class [mscorlib]System.Threading.Tasks.Task`1<!0> valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::get_Task() IL_003e: ret } // end of method Extensions::M } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension(object _) { static async System.Threading.Tasks.Task<string> M(object o, string s) { await System.Threading.Tasks.Task.Yield(); return o + s; } } extension(object) { static async System.Threading.Tasks.Task<string> M(object o, string s, int x) { await System.Threading.Tasks.Task.Yield(); return o + s; } } } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); var src3 = """ class Program { static void Main() { System.Console.Write(Test("1").Result); System.Console.Write(object.M2("3", "4").Result); } async static System.Threading.Tasks.Task<string> Test(object o) { await System.Threading.Tasks.Task.Yield(); return await object.M(o, "2"); } } static class Extensions { extension(object _) { async public static System.Threading.Tasks.Task<string> M2(object o, string s) { await System.Threading.Tasks.Task.Yield(); return await object.M(o, s); } } } """; var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "1234").VerifyDiagnostics(); } [Fact] public void Implementation_InstanceProperty_01() { var src1 = """ public static class Extensions { extension(object o) { public string P => o.ToString(); } } """; var comp1 = CreateCompilation(src1); MethodSymbol implementation = comp1.GetTypeByMetadataName("Extensions").GetMembers().OfType<MethodSymbol>().Single(); Assert.True(implementation.IsStatic); Assert.Equal(MethodKind.Ordinary, implementation.MethodKind); Assert.Equal(1, implementation.ParameterCount); AssertEx.Equal("System.String Extensions.get_P(System.Object o)", implementation.ToTestDisplayString()); Assert.True(implementation.IsImplicitlyDeclared); Assert.False(implementation.IsExtensionMethod); Assert.False(implementation.HasSpecialName); Assert.False(implementation.HasRuntimeSpecialName); var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); var expectedTypeIL = """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x208d // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method public hidebysig specialname instance string get_P () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x2086 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::get_P // Properties .property instance string P() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) .get instance string Extensions/'<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::get_P() } } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method public hidebysig static string get_P ( object o ) cil managed { // Method begins at RVA 0x207e // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance string [mscorlib]System.Object::ToString() IL_0006: ret } // end of method Extensions::get_P } // end of class Extensions """; verifier1.VerifyTypeIL("Extensions", expectedTypeIL.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src3 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write("2".P2); } static string Test(object o) { return o.P; } } static class Extensions { extension(object o) { public string P2 => o.P; } } """; var comp1MetadataReference = comp1.ToMetadataReference(); var comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); var verifier3 = CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); var testIL = @" { // Code size 12 (0xc) .maxstack 1 .locals init (string V_0) IL_0000: nop IL_0001: ldarg.0 IL_0002: call ""string Extensions.get_P(object)"" IL_0007: stloc.0 IL_0008: br.s IL_000a IL_000a: ldloc.0 IL_000b: ret } "; verifier3.VerifyIL("Program.Test", testIL); var m2IL = @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call ""string Extensions.get_P(object)"" IL_0006: ret } "; verifier3.VerifyIL("Extensions.get_P2(object)", m2IL); var comp1ImageReference = comp1.EmitToImageReference(); comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); verifier3 = CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); verifier3.VerifyIL("Program.Test", testIL); verifier3.VerifyIL("Extensions.get_P2(object)", m2IL); comp3 = CreateCompilationWithIL(src3, expectedTypeIL + ExtensionMarkerAttributeIL, options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); var remove = """ .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) """; comp3 = CreateCompilationWithIL(src3, expectedTypeIL.Remove(expectedTypeIL.IndexOf(remove), remove.Length) + ExtensionMarkerAttributeIL); comp3.VerifyDiagnostics( // (11,18): error CS1061: 'object' does not contain a definition for 'P' and no accessible extension method 'P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // return o.P; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "P").WithArguments("object", "P").WithLocation(11, 18), // (19,31): error CS1061: 'object' does not contain a definition for 'P' and no accessible extension method 'P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // public string P2 => o.P; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "P").WithArguments("object", "P").WithLocation(19, 31) ); src3 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write("2".P2); } static string Test(object o) { return o.get_P(); } } static class Extensions { extension(object o) { public string P2 => o.get_P(); } } """; comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); comp3.VerifyDiagnostics( // (11,18): error CS1061: 'object' does not contain a definition for 'get_P' and no accessible extension method 'get_P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // return o.get_P(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "get_P").WithArguments("object", "get_P").WithLocation(11, 18), // (19,31): error CS1061: 'object' does not contain a definition for 'get_P' and no accessible extension method 'get_P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // public string P2 => o.get_P(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "get_P").WithArguments("object", "get_P").WithLocation(19, 31) ); comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); comp3.VerifyDiagnostics( // (11,18): error CS1061: 'object' does not contain a definition for 'get_P' and no accessible extension method 'get_P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // return o.get_P(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "get_P").WithArguments("object", "get_P").WithLocation(11, 18), // (19,31): error CS1061: 'object' does not contain a definition for 'get_P' and no accessible extension method 'get_P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // public string P2 => o.get_P(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "get_P").WithArguments("object", "get_P").WithLocation(19, 31) ); src3 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write("2".P2); } static string Test(object o) { return Extensions.get_P(o); } } static class Extensions_ { extension(object o) { public string P2 => Extensions.get_P(o); } } """; comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); verifier3 = CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); verifier3.VerifyIL("Program.Test", testIL); verifier3.VerifyIL("Extensions_.get_P2(object)", m2IL); comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); verifier3 = CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); verifier3.VerifyIL("Program.Test", testIL); verifier3.VerifyIL("Extensions_.get_P2(object)", m2IL); var vbComp = CreateVisualBasicCompilation(""" Class Program Shared Sub Main() System.Console.Write(Test2("3")) End Sub Shared Function Test2(o As String) As String return Extensions.get_P(o) End Function End Class """, referencedAssemblies: comp3.References, compilationOptions: new VisualBasicCompilationOptions(OutputKind.ConsoleApplication)); CompileAndVerify(vbComp, expectedOutput: "3").VerifyDiagnostics(); vbComp = CreateVisualBasicCompilation(""" Class Program Shared Sub Main() System.Console.Write(Test1("1")) End Sub Shared Function Test1(o As String) As String return o.get_P() End Function End Class """, referencedAssemblies: comp3.References, compilationOptions: new VisualBasicCompilationOptions(OutputKind.ConsoleApplication)); vbComp.VerifyDiagnostics( // error BC30456: 'get_P' is not a member of 'String'. Diagnostic(30456 /*ERRID.ERR_NameNotMember2*/, "o.get_P").WithArguments("get_P", "String").WithLocation(7, 16) ); var comp5 = CreateCompilation(src1); comp5.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); comp5.VerifyEmitDiagnostics( // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // extension(object o) Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5) ); } [Fact] public void Implementation_StaticProperty_01() { var src1 = """ public static class Extensions { extension(object) { public static string P => "P"; } } """; var comp1 = CreateCompilation(src1); MethodSymbol implementation = comp1.GetTypeByMetadataName("Extensions").GetMembers().OfType<MethodSymbol>().Single(); Assert.True(implementation.IsStatic); Assert.Equal(MethodKind.Ordinary, implementation.MethodKind); Assert.Equal(0, implementation.ParameterCount); AssertEx.Equal("System.String Extensions.get_P()", implementation.ToTestDisplayString()); Assert.True(implementation.IsImplicitlyDeclared); Assert.False(implementation.IsExtensionMethod); Assert.False(implementation.HasSpecialName); Assert.False(implementation.HasRuntimeSpecialName); var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); var expectedTypeIL = """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x208c // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$C43E2675C7BBF9284AF22FB8A9BF0280'::'<Extension>$' } // end of class <M>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method public hidebysig specialname static string get_P () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 43 34 33 45 32 36 37 35 43 37 42 42 46 39 32 38 34 41 46 32 32 46 42 38 41 39 42 46 30 32 38 30 00 00 ) // Method begins at RVA 0x2085 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::get_P // Properties .property string P() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 43 34 33 45 32 36 37 35 43 37 42 42 46 39 32 38 34 41 46 32 32 46 42 38 41 39 42 46 30 32 38 30 00 00 ) .get string Extensions/'<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::get_P() } } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method public hidebysig static string get_P () cil managed { // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: ldstr "P" IL_0005: ret } // end of method Extensions::get_P } // end of class Extensions """; verifier1.VerifyTypeIL("Extensions", expectedTypeIL.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src3 = """ class Program { static void Main() { System.Console.Write(Test()); System.Console.Write(object.P2); } static string Test() { return object.P; } } static class Extensions { extension(object o) { public static string P2 => object.P; } } """; var comp1MetadataReference = comp1.ToMetadataReference(); var comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); var verifier3 = CompileAndVerify(comp3, expectedOutput: "PP").VerifyDiagnostics(); var testIL = @" { // Code size 11 (0xb) .maxstack 1 .locals init (string V_0) IL_0000: nop IL_0001: call ""string Extensions.get_P()"" IL_0006: stloc.0 IL_0007: br.s IL_0009 IL_0009: ldloc.0 IL_000a: ret } "; verifier3.VerifyIL("Program.Test", testIL); var m2IL = @" { // Code size 6 (0x6) .maxstack 1 IL_0000: call ""string Extensions.get_P()"" IL_0005: ret } "; verifier3.VerifyIL("Extensions.get_P2()", m2IL); var comp1ImageReference = comp1.EmitToImageReference(); comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); verifier3 = CompileAndVerify(comp3, expectedOutput: "PP").VerifyDiagnostics(); verifier3.VerifyIL("Program.Test", testIL); verifier3.VerifyIL("Extensions.get_P2()", m2IL); comp3 = CreateCompilationWithIL(src3, expectedTypeIL + ExtensionMarkerAttributeIL, options: TestOptions.DebugExe); CompileAndVerify(comp3, expectedOutput: "PP").VerifyDiagnostics(); var remove = """ .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) """; comp3 = CreateCompilationWithIL(src3, expectedTypeIL.Remove(expectedTypeIL.IndexOf(remove), remove.Length) + ExtensionMarkerAttributeIL); comp3.VerifyDiagnostics( // (11,23): error CS0117: 'object' does not contain a definition for 'P' // return object.P; Diagnostic(ErrorCode.ERR_NoSuchMember, "P").WithArguments("object", "P").WithLocation(11, 23), // (19,43): error CS0117: 'object' does not contain a definition for 'P' // public static string P2 => object.P; Diagnostic(ErrorCode.ERR_NoSuchMember, "P").WithArguments("object", "P").WithLocation(19, 43) ); src3 = """ class Program { static void Main() { System.Console.Write(Test()); System.Console.Write(object.P2); } static string Test() { return Extensions.get_P(); } } static class Extensions_ { extension(object o) { public static string P2 => Extensions.get_P(); } } """; comp3 = CreateCompilation(src3, references: [comp1MetadataReference], options: TestOptions.DebugExe); verifier3 = CompileAndVerify(comp3, expectedOutput: "PP").VerifyDiagnostics(); verifier3.VerifyIL("Program.Test", testIL); verifier3.VerifyIL("Extensions_.get_P2()", m2IL); comp3 = CreateCompilation(src3, references: [comp1ImageReference], options: TestOptions.DebugExe); verifier3 = CompileAndVerify(comp3, expectedOutput: "PP").VerifyDiagnostics(); verifier3.VerifyIL("Program.Test", testIL); verifier3.VerifyIL("Extensions_.get_P2()", m2IL); var vbComp = CreateVisualBasicCompilation(""" Class Program Shared Sub Main() System.Console.Write(Test2()) End Sub Shared Function Test2() As String return Extensions.get_P() End Function End Class """, referencedAssemblies: comp3.References, compilationOptions: new VisualBasicCompilationOptions(OutputKind.ConsoleApplication)); CompileAndVerify(vbComp, expectedOutput: "P").VerifyDiagnostics(); var comp5 = CreateCompilation(src1); comp5.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); comp5.VerifyEmitDiagnostics( // (3,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? // extension(object) Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 5) ); } [Fact] public void Implementation_InstanceProperty_02() { var src1 = """ public static class Extensions { extension(object o) { public string P { get { return o.ToString(); } } } } """; var comp1 = CreateCompilation(src1); var verifier1 = CompileAndVerify(comp1).VerifyDiagnostics(); verifier1.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x208d // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method public hidebysig specialname instance string get_P () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x2086 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::get_P // Properties .property instance string P() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) .get instance string Extensions/'<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::get_P() } } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method public hidebysig static string get_P ( object o ) cil managed { // Method begins at RVA 0x207e // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance string [mscorlib]System.Object::ToString() IL_0006: ret } // end of method Extensions::get_P } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src3 = """ class Program { static void Main() { System.Console.Write(Test("1")); System.Console.Write("2".P2); } static string Test(object o) { return o.P; } } static class Extensions { extension(object o) { public string P2 => o.P; } } """; var comp3 = CreateCompilation(src3, references: [comp1.ToMetadataReference()], options: TestOptions.DebugExe); var verifier3 = CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); var testIL = @" { // Code size 12 (0xc) .maxstack 1 .locals init (string V_0) IL_0000: nop IL_0001: ldarg.0 IL_0002: call ""string Extensions.get_P(object)"" IL_0007: stloc.0 IL_0008: br.s IL_000a IL_000a: ldloc.0 IL_000b: ret } "; verifier3.VerifyIL("Program.Test", testIL); var m2IL = @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call ""string Extensions.get_P(object)"" IL_0006: ret } "; verifier3.VerifyIL("Extensions.get_P2(object)", m2IL); comp3 = CreateCompilation(src3, references: [comp1.EmitToImageReference()], options: TestOptions.DebugExe); verifier3 = CompileAndVerify(comp3, expectedOutput: "12").VerifyDiagnostics(); verifier3.VerifyIL("Program.Test", testIL); verifier3.VerifyIL("Extensions.get_P2(object)", m2IL); } [Fact] public void Implementation_DelegateCaching_01() { var src = """ 42.M2<int, string>(); public static class Extensions { extension<T>(T o) { public void M2<U>() { local<long>()(); System.Func<V> local<V>() { return C1.M1<T, U, V>; } } } } class C1 { static public V M1<T, U, V>() { System.Console.Write((typeof(T), typeof(U), typeof(V))); return default; } } """; var comp = CreateCompilation(src); var verifier = CompileAndVerify(comp, expectedOutput: "(System.Int32, System.String, System.Int64)").VerifyDiagnostics(); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$8048A6C8BE30A622530249B904B537EB`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$D3EAC011D93395A3E50DF069CE627102'<T> extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( !T o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2106 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$D3EAC011D93395A3E50DF069CE627102'::'<Extension>$' } // end of class <M>$D3EAC011D93395A3E50DF069CE627102 // Methods .method public hidebysig instance void M2<U> () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 44 33 45 41 43 30 31 31 44 39 33 33 39 35 41 33 45 35 30 44 46 30 36 39 43 45 36 32 37 31 30 32 00 00 ) // Method begins at RVA 0x20ff // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$8048A6C8BE30A622530249B904B537EB`1'::M2 } // end of class <G>$8048A6C8BE30A622530249B904B537EB`1 .class nested private auto ansi abstract sealed beforefieldinit '<local>O__1_0`3'<T, U, V> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public static class [mscorlib]System.Func`1<!V> '<0>__M1' } // end of class <local>O__1_0`3 // Methods .method public hidebysig static void M2<T, U> ( !!T o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x208f // Code size 12 (0xc) .maxstack 8 IL_0000: call class [mscorlib]System.Func`1<!!2> Extensions::'<M2>g__local|1_0'<!!T, !!U, int64>() IL_0005: callvirt instance !0 class [mscorlib]System.Func`1<int64>::Invoke() IL_000a: pop IL_000b: ret } // end of method Extensions::M2 .method assembly hidebysig static class [mscorlib]System.Func`1<!!V> '<M2>g__local|1_0'<T, U, V> () cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x209c // Code size 28 (0x1c) .maxstack 8 IL_0000: ldsfld class [mscorlib]System.Func`1<!2> class Extensions/'<local>O__1_0`3'<!!T, !!U, !!V>::'<0>__M1' IL_0005: dup IL_0006: brtrue.s IL_001b IL_0008: pop IL_0009: ldnull IL_000a: ldftn !!2 C1::M1<!!T, !!U, !!V>() IL_0010: newobj instance void class [mscorlib]System.Func`1<!!V>::.ctor(object, native int) IL_0015: dup IL_0016: stsfld class [mscorlib]System.Func`1<!2> class Extensions/'<local>O__1_0`3'<!!T, !!U, !!V>::'<0>__M1' IL_001b: ret } // end of method Extensions::'<M2>g__local|1_0' } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension<T>(T o) { void M2<U>() { #pragma warning disable CS8321 // The local function 'local' is declared but never used System.Func<V> local<V>() { return C1.M1<T, U, V>; } } } extension<T>(T o) { void M2<U>(int x) { System.Func<V> local<V>() { return C1.M1<T, U, V>; } } } } class C1 { static public V M1<T, U, V>() => default; } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); } [Fact] public void Implementation_DelegateCaching_02() { var src = """ 42.M2(); public static class Extensions { extension<T>(T o) { public void M2() { local()(); System.Action local() { return C1.M1<T>; } } } } class C1 { static public void M1<T>() { System.Console.Write(typeof(T)); } } """; var comp = CreateCompilation(src); var verifier = CompileAndVerify(comp, expectedOutput: "System.Int32").VerifyDiagnostics(); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$8048A6C8BE30A622530249B904B537EB`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$D3EAC011D93395A3E50DF069CE627102'<T> extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( !T o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20d0 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$D3EAC011D93395A3E50DF069CE627102'::'<Extension>$' } // end of class <M>$D3EAC011D93395A3E50DF069CE627102 // Methods .method public hidebysig instance void M2 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 44 33 45 41 43 30 31 31 44 39 33 33 39 35 41 33 45 35 30 44 46 30 36 39 43 45 36 32 37 31 30 32 00 00 ) // Method begins at RVA 0x20c9 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$8048A6C8BE30A622530249B904B537EB`1'::M2 } // end of class <G>$8048A6C8BE30A622530249B904B537EB`1 .class nested private auto ansi abstract sealed beforefieldinit '<>O__1_0`1'<T> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public static class [mscorlib]System.Action '<0>__M1' } // end of class <>O__1_0`1 // Methods .method public hidebysig static void M2<T> ( !!T o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x208f // Code size 11 (0xb) .maxstack 8 IL_0000: call class [mscorlib]System.Action Extensions::'<M2>g__local|1_0'<!!T>() IL_0005: callvirt instance void [mscorlib]System.Action::Invoke() IL_000a: ret } // end of method Extensions::M2 .method assembly hidebysig static class [mscorlib]System.Action '<M2>g__local|1_0'<T> () cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x209b // Code size 28 (0x1c) .maxstack 8 IL_0000: ldsfld class [mscorlib]System.Action class Extensions/'<>O__1_0`1'<!!T>::'<0>__M1' IL_0005: dup IL_0006: brtrue.s IL_001b IL_0008: pop IL_0009: ldnull IL_000a: ldftn void C1::M1<!!T>() IL_0010: newobj instance void [mscorlib]System.Action::.ctor(object, native int) IL_0015: dup IL_0016: stsfld class [mscorlib]System.Action class Extensions/'<>O__1_0`1'<!!T>::'<0>__M1' IL_001b: ret } // end of method Extensions::'<M2>g__local|1_0' } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension<T>(T o) { void M2() { #pragma warning disable CS8321 // The local function 'local' is declared but never used System.Action local() { return C1.M1<T>; } } } extension<T>(T o) { void M2(int x) { #pragma warning disable CS8321 // The local function 'local' is declared but never used System.Action local() { return C1.M1<T>; } } } } class C1 { static public void M1<T>() {} } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); } [Fact] public void Implementation_DelegateCaching_03() { var src = """ public static class Extensions { extension(object o) { void M2() { #pragma warning disable CS8321 // The local function 'local' is declared but never used System.Action local() { return C1.M1; } } } } class C1 { static public void M1() {} } """; var comp = CreateCompilation(src); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method private hidebysig instance void M2 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x20a5 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M2 } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 .class nested private auto ansi abstract sealed beforefieldinit '<>O' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public static class [mscorlib]System.Action '<0>__M1' } // end of class <>O // Methods .method private hidebysig static void M2 ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method Extensions::M2 .method assembly hidebysig static class [mscorlib]System.Action '<M2>g__local|1_0' () cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2080 // Code size 28 (0x1c) .maxstack 8 IL_0000: ldsfld class [mscorlib]System.Action Extensions/'<>O'::'<0>__M1' IL_0005: dup IL_0006: brtrue.s IL_001b IL_0008: pop IL_0009: ldnull IL_000a: ldftn void C1::M1() IL_0010: newobj instance void [mscorlib]System.Action::.ctor(object, native int) IL_0015: dup IL_0016: stsfld class [mscorlib]System.Action Extensions/'<>O'::'<0>__M1' IL_001b: ret } // end of method Extensions::'<M2>g__local|1_0' } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension(object o) { void M2() { #pragma warning disable CS8321 // The local function 'local' is declared but never used System.Action local() { return C1.M1; } } } extension(object o) { void M2(int x) { System.Action local() { return C1.M1; } } } } class C1 { static public void M1() {} } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); } [Fact] public void Implementation_DelegateCaching_04() { var src = """ public static class Extensions { extension<T>(T o) { System.Action M2() { return local; static void local() { typeof(T).ToString(); } } } } """; var comp = CreateCompilation(src); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$8048A6C8BE30A622530249B904B537EB`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$D3EAC011D93395A3E50DF069CE627102'<T> extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( !T o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20b4 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$D3EAC011D93395A3E50DF069CE627102'::'<Extension>$' } // end of class <M>$D3EAC011D93395A3E50DF069CE627102 // Methods .method private hidebysig instance class [mscorlib]System.Action M2 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 44 33 45 41 43 30 31 31 44 39 33 33 39 35 41 33 45 35 30 44 46 30 36 39 43 45 36 32 37 31 30 32 00 00 ) // Method begins at RVA 0x20ad // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$8048A6C8BE30A622530249B904B537EB`1'::M2 } // end of class <G>$8048A6C8BE30A622530249B904B537EB`1 .class nested private auto ansi abstract sealed beforefieldinit '<>O__1_0`1'<T> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public static class [mscorlib]System.Action '<0>__local' } // end of class <>O__1_0`1 // Methods .method private hidebysig static class [mscorlib]System.Action M2<T> ( !!T o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 28 (0x1c) .maxstack 8 IL_0000: ldsfld class [mscorlib]System.Action class Extensions/'<>O__1_0`1'<!!T>::'<0>__local' IL_0005: dup IL_0006: brtrue.s IL_001b IL_0008: pop IL_0009: ldnull IL_000a: ldftn void Extensions::'<M2>g__local|1_0'<!!T>() IL_0010: newobj instance void [mscorlib]System.Action::.ctor(object, native int) IL_0015: dup IL_0016: stsfld class [mscorlib]System.Action class Extensions/'<>O__1_0`1'<!!T>::'<0>__local' IL_001b: ret } // end of method Extensions::M2 .method assembly hidebysig static void '<M2>g__local|1_0'<T> () cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x209b // Code size 17 (0x11) .maxstack 8 IL_0000: ldtoken !!T IL_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_000a: callvirt instance string [mscorlib]System.Object::ToString() IL_000f: pop IL_0010: ret } // end of method Extensions::'<M2>g__local|1_0' } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension<T>(T o) { System.Action M2() { return local; static void local() { typeof(T).ToString(); } } } extension<T>(T o) { System.Action M2(int x) { return local; static void local() { typeof(T).ToString(); } } } } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); } [Fact] public void Implementation_DelegateCaching_05() { var src = """ public static class Extensions { extension(object o) { System.Action M2() { return local; static void local() { typeof(object).ToString(); } } } } """; var comp = CreateCompilation(src); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20b4 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method private hidebysig instance class [mscorlib]System.Action M2 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x20ad // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M2 } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 .class nested private auto ansi abstract sealed beforefieldinit '<>O' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public static class [mscorlib]System.Action '<0>__local' } // end of class <>O // Methods .method private hidebysig static class [mscorlib]System.Action M2 ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 28 (0x1c) .maxstack 8 IL_0000: ldsfld class [mscorlib]System.Action Extensions/'<>O'::'<0>__local' IL_0005: dup IL_0006: brtrue.s IL_001b IL_0008: pop IL_0009: ldnull IL_000a: ldftn void Extensions::'<M2>g__local|1_0'() IL_0010: newobj instance void [mscorlib]System.Action::.ctor(object, native int) IL_0015: dup IL_0016: stsfld class [mscorlib]System.Action Extensions/'<>O'::'<0>__local' IL_001b: ret } // end of method Extensions::M2 .method assembly hidebysig static void '<M2>g__local|1_0' () cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x209b // Code size 17 (0x11) .maxstack 8 IL_0000: ldtoken [mscorlib]System.Object IL_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_000a: callvirt instance string [mscorlib]System.Object::ToString() IL_000f: pop IL_0010: ret } // end of method Extensions::'<M2>g__local|1_0' } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ public static class Extensions { extension(object o) { System.Action M2() { return local; static void local() { typeof(object).ToString(); } } } extension(object o) { System.Action M2(int x) { return local; static void local() { typeof(object).ToString(); } } } } """; var comp2 = CreateCompilation(src2); CompileAndVerify(comp2).VerifyDiagnostics(); } [Fact] public void Implementation_DynamicCallSite_01() { var src = """ 42.M2<int, string>(); class D { public void M1<T, U, V>(T t, U u, V v) { System.Console.Write((typeof(T), typeof(U), typeof(V))); } } public static class Extensions { extension<T>(T o) { public void M2<U>() { local(new D(), default(T), default(U), 42L); void local<V>(dynamic d, T t, U u, V v) { d.M1(t, u, v); } } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: "(System.Int32, System.String, System.Int64)").VerifyDiagnostics(); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$8048A6C8BE30A622530249B904B537EB`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$D3EAC011D93395A3E50DF069CE627102'<T> extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( !T o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2171 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$D3EAC011D93395A3E50DF069CE627102'::'<Extension>$' } // end of class <M>$D3EAC011D93395A3E50DF069CE627102 // Methods .method public hidebysig instance void M2<U> () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 44 33 45 41 43 30 31 31 44 39 33 33 39 35 41 33 45 35 30 44 46 30 36 39 43 45 36 32 37 31 30 32 00 00 ) // Method begins at RVA 0x216a // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$8048A6C8BE30A622530249B904B537EB`1'::M2 } // end of class <G>$8048A6C8BE30A622530249B904B537EB`1 .class nested private auto ansi abstract sealed beforefieldinit '<>o__0|1`3'<T, U, V> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !T, !U, !V>> '<>p__0' } // end of class <>o__0|1`3 // Methods .method public hidebysig static void M2<T, U> ( !!T o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20c0 // Code size 32 (0x20) .maxstack 4 .locals init ( [0] !!T, [1] !!U ) IL_0000: newobj instance void D::.ctor() IL_0005: ldloca.s 0 IL_0007: initobj !!T IL_000d: ldloc.0 IL_000e: ldloca.s 1 IL_0010: initobj !!U IL_0016: ldloc.1 IL_0017: ldc.i4.s 42 IL_0019: conv.i8 IL_001a: call void Extensions::'<M2>g__local|1_0'<!!T, !!U, int64>(object, !!0, !!1, !!2) IL_001f: ret } // end of method Extensions::M2 .method assembly hidebysig static void '<M2>g__local|1_0'<T, U, V> ( object d, !!T t, !!U u, !!V v ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .param [1] .custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20ec // Code size 114 (0x72) .maxstack 9 IL_0000: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !0, !1, !2>> class Extensions/'<>o__0|1`3'<!!T, !!U, !!V>::'<>p__0' IL_0005: brtrue.s IL_0059 IL_0007: ldc.i4 256 IL_000c: ldstr "M1" IL_0011: ldnull IL_0012: ldtoken Extensions IL_0017: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_001c: ldc.i4.4 IL_001d: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo IL_0022: dup IL_0023: ldc.i4.0 IL_0024: ldc.i4.0 IL_0025: ldnull IL_0026: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) IL_002b: stelem.ref IL_002c: dup IL_002d: ldc.i4.1 IL_002e: ldc.i4.1 IL_002f: ldnull IL_0030: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) IL_0035: stelem.ref IL_0036: dup IL_0037: ldc.i4.2 IL_0038: ldc.i4.1 IL_0039: ldnull IL_003a: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) IL_003f: stelem.ref IL_0040: dup IL_0041: ldc.i4.3 IL_0042: ldc.i4.1 IL_0043: ldnull IL_0044: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) IL_0049: stelem.ref IL_004a: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>) IL_004f: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !!T, !!U, !!V>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder) IL_0054: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !0, !1, !2>> class Extensions/'<>o__0|1`3'<!!T, !!U, !!V>::'<>p__0' IL_0059: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !0, !1, !2>> class Extensions/'<>o__0|1`3'<!!T, !!U, !!V>::'<>p__0' IL_005e: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !!T, !!U, !!V>>::Target IL_0063: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !0, !1, !2>> class Extensions/'<>o__0|1`3'<!!T, !!U, !!V>::'<>p__0' IL_0068: ldarg.0 IL_0069: ldarg.1 IL_006a: ldarg.2 IL_006b: ldarg.3 IL_006c: callvirt instance void class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !!T, !!U, !!V>::Invoke(!0, !1, !2, !3, !4) IL_0071: ret } // end of method Extensions::'<M2>g__local|1_0' } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]"). Replace("[System.Core]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[System.Core]")); var src2 = """ public static class Extensions { extension<T>(T o) { void M2<U>() { #pragma warning disable CS8321 // The local function 'local' is declared but never used void local<V>(dynamic d, T t, U u, V v) { d.M1(t, u, v); } } } extension<T>(T o) { void M2<U>(int x) { void local<V>(dynamic d, T t, U u, V v) { d.M1(t, u, v); } } } } """; var comp2 = CreateCompilation(src2, targetFramework: TargetFramework.StandardAndCSharp); CompileAndVerify(comp2).VerifyDiagnostics(); } [Fact] public void Implementation_DynamicCallSite_02() { var src = """ public static class Extensions { extension<T>(T o) { public void M2() { #pragma warning disable CS8321 // The local function 'local' is declared but never used void local(dynamic d, T t) { d.M1(t); } } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$8048A6C8BE30A622530249B904B537EB`1'<$T0> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$D3EAC011D93395A3E50DF069CE627102'<T> extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( !T o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$D3EAC011D93395A3E50DF069CE627102'::'<Extension>$' } // end of class <M>$D3EAC011D93395A3E50DF069CE627102 // Methods .method public hidebysig instance void M2 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 44 33 45 41 43 30 31 31 44 39 33 33 39 35 41 33 45 35 30 44 46 30 36 39 43 45 36 32 37 31 30 32 00 00 ) // Method begins at RVA 0x20e8 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$8048A6C8BE30A622530249B904B537EB`1'::M2 } // end of class <G>$8048A6C8BE30A622530249B904B537EB`1 .class nested private auto ansi abstract sealed beforefieldinit '<>o__1`1'<T> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !T>> '<>p__0' } // end of class <>o__1`1 // Methods .method public hidebysig static void M2<T> ( !!T o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method Extensions::M2 .method assembly hidebysig static void '<M2>g__local|1_0'<T> ( object d, !!T t ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .param [1] .custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2080 // Code size 92 (0x5c) .maxstack 9 IL_0000: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !0>> class Extensions/'<>o__1`1'<!!T>::'<>p__0' IL_0005: brtrue.s IL_0045 IL_0007: ldc.i4 256 IL_000c: ldstr "M1" IL_0011: ldnull IL_0012: ldtoken Extensions IL_0017: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_001c: ldc.i4.2 IL_001d: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo IL_0022: dup IL_0023: ldc.i4.0 IL_0024: ldc.i4.0 IL_0025: ldnull IL_0026: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) IL_002b: stelem.ref IL_002c: dup IL_002d: ldc.i4.1 IL_002e: ldc.i4.1 IL_002f: ldnull IL_0030: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) IL_0035: stelem.ref IL_0036: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>) IL_003b: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !!T>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder) IL_0040: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !0>> class Extensions/'<>o__1`1'<!!T>::'<>p__0' IL_0045: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !0>> class Extensions/'<>o__1`1'<!!T>::'<>p__0' IL_004a: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !!T>>::Target IL_004f: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !0>> class Extensions/'<>o__1`1'<!!T>::'<>p__0' IL_0054: ldarg.0 IL_0055: ldarg.1 IL_0056: callvirt instance void class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, !!T>::Invoke(!0, !1, !2) IL_005b: ret } // end of method Extensions::'<M2>g__local|1_0' } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]"). Replace("[System.Core]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[System.Core]")); var src2 = """ public static class Extensions { extension<T>(T o) { void M2() { #pragma warning disable CS8321 // The local function 'local' is declared but never used void local(dynamic d, T t) { d.M1(t); } } } extension<T>(T o) { void M2(int x) { void local(dynamic d, T t) { d.M1(t); } } } } """; var comp2 = CreateCompilation(src2, targetFramework: TargetFramework.StandardAndCSharp); CompileAndVerify(comp2).VerifyDiagnostics(); } [Fact] public void Implementation_DynamicCallSite_03() { var src = """ public static class Extensions { extension(object o) { void M2() { #pragma warning disable CS8321 // The local function 'local' is declared but never used void local(dynamic d) { d.M1(); } } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyTypeIL("Extensions", """ .class public auto ansi abstract sealed beforefieldinit Extensions extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$119AA281C143547563250CAF89B48A76'::'<Extension>$' } // end of class <M>$119AA281C143547563250CAF89B48A76 // Methods .method private hidebysig instance void M2 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) // Method begins at RVA 0x20dd // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M2 } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 .class nested private auto ansi abstract sealed beforefieldinit '<>o__1' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`2<class [System.Core]System.Runtime.CompilerServices.CallSite, object>> '<>p__0' } // end of class <>o__1 // Methods .method private hidebysig static void M2 ( object o ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method Extensions::M2 .method assembly hidebysig static void '<M2>g__local|1_0' ( object d ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .param [1] .custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2080 // Code size 81 (0x51) .maxstack 9 IL_0000: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`2<class [System.Core]System.Runtime.CompilerServices.CallSite, object>> Extensions/'<>o__1'::'<>p__0' IL_0005: brtrue.s IL_003b IL_0007: ldc.i4 256 IL_000c: ldstr "M1" IL_0011: ldnull IL_0012: ldtoken Extensions IL_0017: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_001c: ldc.i4.1 IL_001d: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo IL_0022: dup IL_0023: ldc.i4.0 IL_0024: ldc.i4.0 IL_0025: ldnull IL_0026: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) IL_002b: stelem.ref IL_002c: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>) IL_0031: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`2<class [System.Core]System.Runtime.CompilerServices.CallSite, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder) IL_0036: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`2<class [System.Core]System.Runtime.CompilerServices.CallSite, object>> Extensions/'<>o__1'::'<>p__0' IL_003b: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`2<class [System.Core]System.Runtime.CompilerServices.CallSite, object>> Extensions/'<>o__1'::'<>p__0' IL_0040: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`2<class [System.Core]System.Runtime.CompilerServices.CallSite, object>>::Target IL_0045: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`2<class [System.Core]System.Runtime.CompilerServices.CallSite, object>> Extensions/'<>o__1'::'<>p__0' IL_004a: ldarg.0 IL_004b: callvirt instance void class [mscorlib]System.Action`2<class [System.Core]System.Runtime.CompilerServices.CallSite, object>::Invoke(!0, !1) IL_0050: ret } // end of method Extensions::'<M2>g__local|1_0' } // end of class Extensions """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]"). Replace("[System.Core]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[System.Core]")); var src2 = """ public static class Extensions { extension(object o) { void M2() { #pragma warning disable CS8321 // The local function 'local' is declared but never used void local(dynamic d) { d.M1(); } } } extension(object o) { void M2(int x) { #pragma warning disable CS8321 // The local function 'local' is declared but never used void local(dynamic d) { d.M1(); } } } } """; var comp2 = CreateCompilation(src2, targetFramework: TargetFramework.StandardAndCSharp); CompileAndVerify(comp2).VerifyDiagnostics(); } [Fact] public void InstanceMethodInvocation_Simple() { var src = """ new object().M(); public static class Extensions { extension(object o) { public void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new object().M()"); AssertEx.Equal("void Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); } [Fact] public void InstanceMethodInvocation_Inaccessible() { var src = """ new object().M(); public static class Extensions { extension(object o) { void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,14): error CS1061: 'object' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // new object().M(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("object", "M").WithLocation(1, 14)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new object().M()"); Assert.Null(model.GetSymbolInfo(invocation).Symbol); Assert.Equal([], model.GetSymbolInfo(invocation).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); AssertEx.SequenceEqual(["void Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); src = """ new object().M(); public static class Extensions { private static void M(this object o) { } } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,14): error CS1061: 'object' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // new object().M(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("object", "M").WithLocation(1, 14)); tree = comp.SyntaxTrees[0]; model = comp.GetSemanticModel(tree); invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new object().M()"); Assert.Null(model.GetSymbolInfo(invocation).Symbol); Assert.Equal([], model.GetSymbolInfo(invocation).CandidateSymbols.ToTestDisplayStrings()); memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void System.Object.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); AssertEx.SequenceEqual(["void System.Object.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_Inaccessible_02() { var src = """ new object().M(); public static class E1 { extension(object o) { void M() { } } } public static class E2 { extension(object o) { public void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new object().M()"); AssertEx.Equal("void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.Equal("void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); src = """ new object().M(); public static class E1 { private static void M(this object o) { } } public static class E2 { public static void M(this object o) { } } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); tree = comp.SyntaxTrees[0]; model = comp.GetSemanticModel(tree); invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new object().M()"); AssertEx.Equal("void System.Object.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.Equal("void System.Object.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void System.Object.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_GenericReceiverParameter() { var src = """ new object().M(); public static class Extensions { extension<T>(T t) { public void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new object().M()"); AssertEx.Equal("void Extensions.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.SequenceEqual(["void Extensions.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void StaticMethodInvocation_GenericReceiverParameter_Constrained() { var src = """ object.M(); int.M(); new object().M2(); public static class Extensions { extension<T>(T) where T : struct { public static void M() { } } public static void M2<T>(this T t) where T : struct { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,8): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Extensions.extension<T>(T)' // object.M(); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M").WithArguments("Extensions.extension<T>(T)", "T", "object").WithLocation(1, 8), // (3,14): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Extensions.M2<T>(T)' // new object().M2(); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M2").WithArguments("Extensions.M2<T>(T)", "T", "object").WithLocation(3, 14)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "object.M()"); Assert.Null(model.GetSymbolInfo(invocation).Symbol); invocation = GetSyntax<InvocationExpressionSyntax>(tree, "int.M()"); AssertEx.Equal("void Extensions.<G>$BCF902721DDD961E5243C324D8379E5C<System.Int32>.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.M"); AssertEx.SequenceEqual(["void Extensions.<G>$BCF902721DDD961E5243C324D8379E5C<System.Int32>.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void PropertyAccess_GenericReceiverParameter_Constrained() { var src = """ _ = object.P; _ = int.P; public static class E { extension<T>(T) where T : struct { public static int P => 0; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,5): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.extension<T>(T)' // _ = object.P; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "object.P").WithArguments("E.extension<T>(T)", "T", "object").WithLocation(1, 5)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.P"); AssertEx.Equal("System.Int32 E.<G>$BCF902721DDD961E5243C324D8379E5C<T>.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : handle GetMemberGroup on a property access memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.P"); AssertEx.Equal("System.Int32 E.<G>$BCF902721DDD961E5243C324D8379E5C<System.Int32>.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : handle GetMemberGroup on a property access } [Fact] public void ReceiverParameter_TypeWithUseSiteError() { var lib1_cs = "public class MissingBase { }"; var comp1 = CreateCompilation(lib1_cs, assemblyName: "missing"); comp1.VerifyDiagnostics(); var lib2_cs = "public class UseSiteError : MissingBase { }"; var comp2 = CreateCompilation(lib2_cs, [comp1.EmitToImageReference()]); comp2.VerifyDiagnostics(); var src = """ class C<T> { } static class Extensions { extension(UseSiteError) { } extension(C<UseSiteError>) { } } class C1 { void M(UseSiteError x) { } void M(C<UseSiteError> x) { } } """; var comp = CreateCompilation(src, [comp2.EmitToImageReference()]); comp.VerifyEmitDiagnostics(); } [Fact] public void ReceiverParameter_SuppressConstraintChecksInitially() { var text = @" public class C1<T> where T : struct { } public static class Extensions { extension<T>(C1<T>) { } } "; var comp = CreateCompilation(text); comp.VerifyEmitDiagnostics( // (6,18): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'C1<T>' // extension<T>(C1<T>) { } Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "C1<T>").WithArguments("C1<T>", "T", "T").WithLocation(6, 18)); } [Fact] public void ReceiverParameter_SuppressConstraintChecksInitially_PointerAsTypeArgument() { var text = @" public class C<T> { } unsafe static class Extensions { extension(C<int*>) { } } "; var comp = CreateCompilation(text, options: TestOptions.UnsafeDebugDll); comp.VerifyEmitDiagnostics( // (6,15): error CS0306: The type 'int*' may not be used as a type argument // extension(C<int*>) { } Diagnostic(ErrorCode.ERR_BadTypeArgument, "C<int*>").WithArguments("int*").WithLocation(6, 15)); } [Fact] public void InstanceMethodInvocation_VariousScopes_Errors() { var cSrc = """ class C { public static void Main() { new object().Method(); _ = new object().Property; } } """; var eSrc = """ static class Extensions { extension(object o) { public void Method() => throw null; public int Property => throw null; } } """; var src1 = $$""" namespace N { {{cSrc}} namespace N2 { {{eSrc}} } } """; verify(src1, // (7,22): error CS1061: 'object' does not contain a definition for 'Method' and no accessible extension method 'Method' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // new object().Method(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Method").WithArguments("object", "Method").WithLocation(7, 22), // (8,26): error CS1061: 'object' does not contain a definition for 'Property' and no accessible extension method 'Property' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // _ = new object().Property; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Property").WithArguments("object", "Property").WithLocation(8, 26)); var src2 = $$""" file {{eSrc}} """; verify(new[] { cSrc, src2 }, // 0.cs(5,22): error CS1061: 'object' does not contain a definition for 'Method' and no accessible extension method 'Method' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // new object().Method(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Method").WithArguments("object", "Method").WithLocation(5, 22), // 0.cs(6,26): error CS1061: 'object' does not contain a definition for 'Property' and no accessible extension method 'Property' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // _ = new object().Property; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Property").WithArguments("object", "Property").WithLocation(6, 26)); static void verify(CSharpTestSource src, params DiagnosticDescription[] expected) { var comp = CreateCompilation(src, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics(expected); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var method = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().Method"); Assert.Null(model.GetSymbolInfo(method).Symbol); Assert.Empty(model.GetMemberGroup(method)); var property = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().Property"); Assert.Null(model.GetSymbolInfo(property).Symbol); Assert.Empty(model.GetMemberGroup(property)); } } [Fact] public void InstanceMethodInvocation_FromUsingNamespace() { var cSrc = """ class C { public static void Main() { new object().Method(); } } """; var eSrc = """ namespace N2 { static class E { extension(object o) { public void Method() { System.Console.Write("ran"); } } } } """; var src1 = $$""" using N2; {{cSrc}} {{eSrc}} """; verify(src1, "N2.E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280"); var src2 = $$""" using N2; using N2; // 1, 2 {{cSrc}} {{eSrc}} """; var comp = CreateCompilation(src2, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. // using N2; // 1, 2 Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N2;").WithLocation(2, 1), // (2,7): warning CS0105: The using directive for 'N2' appeared previously in this namespace // using N2; // 1, 2 Diagnostic(ErrorCode.WRN_DuplicateUsing, "N2").WithArguments("N2").WithLocation(2, 7) ); var src3 = $$""" namespace N3 { using N2; namespace N4 { {{cSrc}} } {{eSrc}} } """; verify(src3, "N3.N2.E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280"); void verify(string src, string extensionName) { var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().Method"); AssertEx.Equal($$"""void {{extensionName}}.Method()""", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); AssertEx.Equal([$$"""void {{extensionName}}.Method()"""], model.GetMemberGroup(invocation).ToTestDisplayStrings()); } } [Fact] public void InstanceMethodInvocation_UsingNamespaceNecessity() { var src = """ using N; class C { public static void Main() { new object().Method(); } } """; var eSrc = """ namespace N { public static class E { extension(object o) { public void Method() { System.Console.Write("method"); } } } } """; var comp = CreateCompilation([src, eSrc], options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "method").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().Method"); AssertEx.Equal("void N.E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void N.E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method()"], model.GetMemberGroup(invocation).ToTestDisplayStrings()); src = """ using N; class C { public static void Main() { } } namespace N { public static class Extensions { extension(object o) { public void Method() { } } } } """; comp = CreateCompilation([src, eSrc]); comp.VerifyEmitDiagnostics( // (1,1): hidden CS8019: Unnecessary using directive. // using N; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N;").WithLocation(1, 1)); } [Theory, CombinatorialData] public void InstanceMethodInvocation_Ambiguity(bool e1BeforeE2) { var e1 = """ static class E1 { extension(object o) { public void Method() => throw null; } } """; var e2 = """ static class E2 { extension(object o) { public void Method() => throw null; } } """; var src = $$""" new object().Method(); {{(e1BeforeE2 ? e1 : e2)}} {{(e1BeforeE2 ? e2 : e1)}} """; var comp = CreateCompilation(src); if (!e1BeforeE2) { comp.VerifyEmitDiagnostics( // (1,14): error CS0121: The call is ambiguous between the following methods or properties: 'E2.extension(object).Method()' and 'E1.extension(object).Method()' // new object().Method(); Diagnostic(ErrorCode.ERR_AmbigCall, "Method").WithArguments("E2.extension(object).Method()", "E1.extension(object).Method()").WithLocation(1, 14)); } else { comp.VerifyEmitDiagnostics( // (1,14): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(object).Method()' and 'E2.extension(object).Method()' // new object().Method(); Diagnostic(ErrorCode.ERR_AmbigCall, "Method").WithArguments("E1.extension(object).Method()", "E2.extension(object).Method()").WithLocation(1, 14)); } } [Fact] public void InstanceMethodInvocation_Overloads() { var src = """ new object().Method(42); new object().Method("hello"); static class E1 { extension(object o) { public void Method(int i) { System.Console.Write($"E1.Method({i}) "); } } } static class E2 { extension(object o) { public void Method(string s) { System.Console.Write($"E2.Method({s}) "); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "E1.Method(42) E2.Method(hello)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var invocation1 = GetSyntax<InvocationExpressionSyntax>(tree, "new object().Method(42)"); AssertEx.Equal("void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.Int32 i)", model.GetSymbolInfo(invocation1).Symbol.ToTestDisplayString()); Assert.Empty(model.GetMemberGroup(invocation1)); var invocation2 = GetSyntax<InvocationExpressionSyntax>(tree, """new object().Method("hello")"""); AssertEx.Equal("void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.String s)", model.GetSymbolInfo(invocation2).Symbol.ToTestDisplayString()); Assert.Empty(model.GetMemberGroup(invocation2)); var memberAccess1 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "new object().Method").First(); AssertEx.SequenceEqual(["void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.Int32 i)", "void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.String s)"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); var memberAccess2 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "new object().Method").Last(); AssertEx.SequenceEqual(["void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.Int32 i)", "void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.String s)"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_Overloads_DifferentScopes_NestedNamespace() { var src = """ namespace N1 { static class E1 { extension(object o) { public void Method(int i) { System.Console.Write($"E1.Method({i}) "); } } } namespace N2 { static class E2 { extension(object o) { public void Method(string s) { System.Console.Write($"E2.Method({s}) "); } } } class C { public static void Main() { new object().Method(42); new object().Method("hello"); } } } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "E1.Method(42) E2.Method(hello)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var invocation1 = GetSyntax<InvocationExpressionSyntax>(tree, "new object().Method(42)"); AssertEx.Equal("void N1.E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.Int32 i)", model.GetSymbolInfo(invocation1).Symbol.ToTestDisplayString()); Assert.Empty(model.GetMemberGroup(invocation1)); var invocation2 = GetSyntax<InvocationExpressionSyntax>(tree, """new object().Method("hello")"""); AssertEx.Equal("void N1.N2.E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.String s)", model.GetSymbolInfo(invocation2).Symbol.ToTestDisplayString()); Assert.Empty(model.GetMemberGroup(invocation2)); var memberAccess1 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "new object().Method").First(); AssertEx.SequenceEqual(["void N1.N2.E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.String s)", "void N1.E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.Int32 i)"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); var memberAccess2 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "new object().Method").Last(); AssertEx.SequenceEqual(["void N1.N2.E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.String s)", "void N1.E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.Int32 i)"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_NamespaceVsUsing_FromNamespace() { var src = """ using N2; new object().Method(42); new object().Method("hello"); new object().Method(default); static class E1 { extension(object o) { public void Method(int i) { System.Console.Write("E1.Method "); } } } namespace N2 { static class E2 { extension(object o) { public void Method(string s) { System.Console.Write("E2.Method "); } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "E1.Method E2.Method E1.Method").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var invocation1 = GetSyntax<InvocationExpressionSyntax>(tree, "new object().Method(42)"); AssertEx.Equal("void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.Int32 i)", model.GetSymbolInfo(invocation1).Symbol.ToTestDisplayString()); Assert.Empty(model.GetMemberGroup(invocation1)); AssertEx.SequenceEqual(["void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.Int32 i)", "void N2.E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.String s)"], model.GetMemberGroup(invocation1.Expression).ToTestDisplayStrings()); var invocation2 = GetSyntax<InvocationExpressionSyntax>(tree, """new object().Method("hello")"""); AssertEx.Equal("void N2.E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.String s)", model.GetSymbolInfo(invocation2).Symbol.ToTestDisplayString()); Assert.Empty(model.GetMemberGroup(invocation2)); AssertEx.SequenceEqual(["void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.Int32 i)", "void N2.E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.String s)"], model.GetMemberGroup(invocation2.Expression).ToTestDisplayStrings()); var invocation3 = GetSyntax<InvocationExpressionSyntax>(tree, "new object().Method(default)"); AssertEx.Equal("void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.Int32 i)", model.GetSymbolInfo(invocation3).Symbol.ToTestDisplayString()); Assert.Empty(model.GetMemberGroup(invocation3)); AssertEx.SequenceEqual(["void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.Int32 i)", "void N2.E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.String s)"], model.GetMemberGroup(invocation3.Expression).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_DerivedDerivedType() { var src = """ new Derived().M(); class Base { } class Derived : Base { } static class E { extension(object o) { public void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new Derived().M()"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); Assert.Empty(model.GetMemberGroup(invocation)); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new Derived().M"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_ImplementedInterface() { var src = """ new C().M(); interface I { } class C : I { } static class E { extension(I i) { public void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new C().M()"); AssertEx.Equal("void E.<G>$3EADBD08A82F6ABA9495623CB335729C.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); Assert.Empty(model.GetMemberGroup(invocation)); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); AssertEx.Equal("void E.<G>$3EADBD08A82F6ABA9495623CB335729C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$3EADBD08A82F6ABA9495623CB335729C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_IndirectlyImplementedInterface() { var src = """ new C().M(); interface I { } interface Indirect : I { } class C : Indirect { } static class E { extension(I i) { public void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new C().M()"); AssertEx.Equal("void E.<G>$3EADBD08A82F6ABA9495623CB335729C.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); Assert.Empty(model.GetMemberGroup(invocation)); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); AssertEx.Equal("void E.<G>$3EADBD08A82F6ABA9495623CB335729C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$3EADBD08A82F6ABA9495623CB335729C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_TypeParameterImplementedInterface() { var src = """ class C { void M<T>(T t) where T : I { t.M(); } } interface I { } static class E { extension(I i) { public void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "t.M()"); AssertEx.Equal("void E.<G>$3EADBD08A82F6ABA9495623CB335729C.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "t.M"); AssertEx.Equal("void E.<G>$3EADBD08A82F6ABA9495623CB335729C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$3EADBD08A82F6ABA9495623CB335729C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void StaticMethodInvocation_MatchingExtendedType_TypeParameterImplementedInterface() { var src = """ class C { void M<T>() where T : I { T.M(); } } interface I { } static class E { extension(I) { public static void M() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,9): error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter // T.M(); Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(5, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "T.M"); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_TypeParameterWithBaseClass() { var src = """ D.M(new D()); class C<T> { } class D : C<D> { public static void M<T>(T t) where T : C<T> { t.M2(); } } static class E { extension<T>(C<T> c) { public void M2() { System.Console.Write(typeof(C<T>)); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "C`1[D]").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "t.M2()"); AssertEx.Equal("void E.<G>$4A1E373BE5A70EE56E2FA5F469AC30F9<T>.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "t.M2"); AssertEx.SequenceEqual(["void E.<G>$4A1E373BE5A70EE56E2FA5F469AC30F9<T>.M2()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_ConstrainedTypeParameter() { var src = $$""" D.M<string>(""); class D { public static void M<T>(T t) where T : class { t.M2(); } } static class E1 { extension<T>(T t) where T : struct { public void M2() { } } } static class E2 { extension<T>(T t) where T : class { public void M2() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "t.M2()"); AssertEx.Equal("void E2.<G>$66F77D1E46F965A5B22D4932892FA78B<T>.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "t.M2"); AssertEx.SequenceEqual(["void E2.<G>$66F77D1E46F965A5B22D4932892FA78B<T>.M2()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_BaseType() { var src = """ new object().M(); new object().M2(); static class E { extension(string s) { public void M() => throw null; } public static void M2(this string s) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS1929: 'object' does not contain a definition for 'M' and the best extension method overload 'E.extension(string).M()' requires a receiver of type 'string' // new object().M(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new object()").WithArguments("object", "M", "E.extension(string).M()", "string").WithLocation(1, 1), // (2,1): error CS1929: 'object' does not contain a definition for 'M2' and the best extension method overload 'E.M2(string)' requires a receiver of type 'string' // new object().M2(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new object()").WithArguments("object", "M2", "E.M2(string)", "string").WithLocation(2, 1) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); Assert.Empty(model.GetMemberGroup(memberAccess)); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_GenericType() { var src = """ new C<int>().M(); class C<T> { } static class E { extension<T>(C<T> c) { public void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new C<int>().M()"); AssertEx.Equal("void E.<G>$4A1E373BE5A70EE56E2FA5F469AC30F9<System.Int32>.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$4A1E373BE5A70EE56E2FA5F469AC30F9<System.Int32>.M()"], model.GetMemberGroup(invocation.Expression).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_GenericType_GenericMember_01() { var src = """ new C<int>().M<string>(); class C<T> { } static class E { extension<T>(C<T> c) { public void M<U>() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,14): error CS1061: 'C<int>' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'C<int>' could be found (are you missing a using directive or an assembly reference?) // new C<int>().M<string>(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M<string>").WithArguments("C<int>", "M").WithLocation(1, 14)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new C<int>().M<string>()"); Assert.Null(model.GetSymbolInfo(invocation).Symbol); Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C<int>().M<string>"); AssertEx.Empty(model.GetMemberGroup(memberAccess)); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_GenericType_GenericMember_02() { var src = """ new C<int>().M<int, string>(); class C<T> { } static class E { extension<T>(C<T> c) { public void M<U>() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new C<int>().M<int, string>()"); AssertEx.Equal("void E.<G>$4A1E373BE5A70EE56E2FA5F469AC30F9<System.Int32>.M<System.String>()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); AssertEx.SequenceEqual(["void E.<G>$4A1E373BE5A70EE56E2FA5F469AC30F9<System.Int32>.M<System.String>()"], model.GetMemberGroup(invocation.Expression).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_GenericType_GenericMember_OmittedTypeArgument_01() { var src = """ new C<int>().M<,>(); class C<T> { } static class E { extension<T>(C<T> c) { public void M<U, V>() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS8389: Omitting the type argument is not allowed in the current context // new C<int>().M<,>(); Diagnostic(ErrorCode.ERR_OmittedTypeArgument, "new C<int>().M<,>").WithLocation(1, 1), // (1,14): error CS1061: 'C<int>' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'C<int>' could be found (are you missing a using directive or an assembly reference?) // new C<int>().M<,>(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M<,>").WithArguments("C<int>", "M").WithLocation(1, 14)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new C<int>().M<,>()"); Assert.Null(model.GetSymbolInfo(invocation).Symbol); Assert.Empty(model.GetMemberGroup(invocation)); Assert.Empty(model.GetMemberGroup(invocation.Expression)); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_GenericType_GenericMember_OmittedTypeArgument_02() { var src = """ new C<int>().M<,,>(); class C<T> { } static class E { extension<T>(C<T> c) { public void M<U, V>() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS8389: Omitting the type argument is not allowed in the current context // new C<int>().M<,,>(); Diagnostic(ErrorCode.ERR_OmittedTypeArgument, "new C<int>().M<,,>").WithLocation(1, 1), // (1,1): error CS1929: 'C<int>' does not contain a definition for 'M' and the best extension method overload 'E.extension<?>(C<?>).M<?, ?>()' requires a receiver of type 'C<?>' // new C<int>().M<,,>(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new C<int>()").WithArguments("C<int>", "M", "E.extension<?>(C<?>).M<?, ?>()", "C<?>").WithLocation(1, 1)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new C<int>().M<,,>()"); Assert.Null(model.GetSymbolInfo(invocation).Symbol); Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); Assert.Equal([], model.GetMemberGroup(invocation.Expression).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_GenericType_GenericMember_BrokenConstraint() { var src = """ new C<int>().M<int, string>(); class C<T> { } static class E { extension<T>(C<T> c) { public void M<U>() where U : struct => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,14): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'U' in the generic type or method 'E.extension<int>(C<int>).M<U>()' // new C<int>().M<int, string>(); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M<int, string>").WithArguments("E.extension<int>(C<int>).M<U>()", "U", "string").WithLocation(1, 14)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new C<int>().M<int, string>()"); Assert.Null(model.GetSymbolInfo(invocation).Symbol); Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); Assert.Equal([], model.GetMemberGroup(invocation.Expression).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_BrokenConstraint() { var source = """ new object().Method(); new object().Method2(); static class E { extension<T>(T t) where T : struct { public void Method() { } } public static void Method2<T>(this T t) where T : struct { } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,14): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.extension<T>(T)' // new object().Method(); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "Method").WithArguments("E.extension<T>(T)", "T", "object").WithLocation(1, 14), // (2,14): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.Method2<T>(T)' // new object().Method2(); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "Method2").WithArguments("E.Method2<T>(T)", "T", "object").WithLocation(2, 14) ); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_BrokenConstraint_Nullability() { var source = """ #nullable enable bool b = true; var o = b ? null : new object(); o.Method(); static class E { extension<T>(T t) where T : notnull { public void Method() { System.Console.Write(t is null); } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (4,1): warning CS8714: The type 'object?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(T)'. Nullability of type argument 'object?' doesn't match 'notnull' constraint. // o.Method(); Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "o.Method").WithArguments("E.extension<T>(T)", "T", "object?").WithLocation(4, 1)); CompileAndVerify(comp, expectedOutput: "True"); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "o.Method"); AssertEx.Equal("void E.extension<System.Object?>(System.Object?).Method()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void ReceiverParameter_AliasType() { var source = """ using Alias = C; new Alias().M(); class C { } static class E { extension(Alias a) { public void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new Alias().M"); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void InstanceMethodInvocation_DynamicArgument() { // No extension members in dynamic invocation var src = """ dynamic d = null; new object().M(d); new object().M2(d); static class E { extension(object o) { public void M(object o1) => throw null; } public static void M2(this object o, object o2) => throw null; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,1): error CS1973: 'object' has no applicable method named 'M' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. // new object().M(d); Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, "new object().M(d)").WithArguments("object", "M").WithLocation(2, 1), // (3,1): error CS1973: 'object' has no applicable method named 'M2' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. // new object().M2(d); Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, "new object().M2(d)").WithArguments("object", "M2").WithLocation(3, 1)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M(System.Object o1)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_DynamicDifference_Nested() { var src = """ new C<dynamic>().M(); class C<T> { } static class E { extension(C<object> c) { public void M() { System.Console.Write("M"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "M").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C<dynamic>().M"); AssertEx.Equal("void E.<G>$BCD00C90E683E728071BA88912DD74BD.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$BCD00C90E683E728071BA88912DD74BD.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_DynamicDifference_InBase() { var src = """ new D().M(); class C<T> { } class D : C<dynamic> { } static class E { extension(C<object> c) { public void M() { System.Console.Write("M"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "M").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new D().M"); AssertEx.Equal("void E.<G>$BCD00C90E683E728071BA88912DD74BD.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$BCD00C90E683E728071BA88912DD74BD.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_DynamicDifference_InInterface() { var src = """ new D().M(); interface I<T> { } class D : I<dynamic> { } static class E { extension(I<object> i) { public void M() { System.Console.Write("M"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,11): error CS1966: 'D': cannot implement a dynamic interface 'I<dynamic>' // class D : I<dynamic> { } Diagnostic(ErrorCode.ERR_DeriveFromConstructedDynamic, "I<dynamic>").WithArguments("D", "I<dynamic>").WithLocation(4, 11)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new D().M"); AssertEx.SequenceEqual(["void E.<G>$2B406085AC5EBECC11B16BCD2A24DF4E.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_TupleNamesDifference() { var src = """ new C<(int a, int b)>().M(); new C<(int, int)>().M(); new C<(int other, int)>().M(); class C<T> { } static class E { extension(C<(int a, int b)> c) { public void M() { System.Console.Write("M"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "MMM").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C<(int a, int b)>().M"); AssertEx.SequenceEqual(["void E.<G>$F9AFEE2D1546C3A2A4599051616A8F6D.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C<(int, int)>().M"); AssertEx.SequenceEqual(["void E.<G>$F9AFEE2D1546C3A2A4599051616A8F6D.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C<(int other, int)>().M"); AssertEx.SequenceEqual(["void E.<G>$F9AFEE2D1546C3A2A4599051616A8F6D.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); src = """ new C<(int a, int b)>().M(); new C<(int, int)>().M(); new C<(int other, int)>().M(); class C<T> { } static class E { public static void M(this C<(int a, int b)> c) { System.Console.Write("M"); } } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_TupleNamesDifference_InBase() { var src = """ new D1().M(); new D2().M(); new D3().M(); class C<T> { } class D1 : C<(int a, int b)> { } class D2 : C<(int, int)> { } class D3 : C<(int other, int)> { } static class E { extension(C<(int a, int b)> c) { public void M() { System.Console.Write("M"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "MMM").VerifyDiagnostics(); } [Fact] public void InstanceMethodInvocation_MatchingExtendedType_TupleNamesDifference_InInterface() { var src = """ new D1().M(); new D2().M(); new D3().M(); class I<T> { } class D1 : I<(int a, int b)> { } class D2 : I<(int, int)> { } class D3 : I<(int other, int)> { } static class E { extension(I<(int a, int b)> i) { public void M() { System.Console.Write("M"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "MMM").VerifyDiagnostics(); } [Fact] public void InstanceMethodInvocation_Nameof() { var src = """ object o = null; System.Console.Write($"{nameof(o.M)} "); static class E { extension(object o) { public void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,32): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. // System.Console.Write($"{nameof(o.M)} "); Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "o.M").WithLocation(2, 32)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "o.M"); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_Nameof_ViaType() { var src = """ System.Console.Write($"{nameof(E.M)} "); static class E { extension(object o) { public void M() { } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "M").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "E.M"); AssertEx.SequenceEqual(["void E.M(this System.Object o)", "void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_Nameof_Overloads() { var src = """ object o = null; System.Console.Write($"{nameof(o.M)} "); static class E { extension(object o) { public void M() { } public void M(int i) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,32): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. // System.Console.Write($"{nameof(o.M)} "); Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "o.M").WithLocation(2, 32)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "o.M"); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_Nameof_SimpleName() { var src = """ class C { void M() { _ = nameof(Method); } } static class E { extension(object o) { public void Method() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,20): error CS0103: The name 'Method' does not exist in the current context // _ = nameof(Method); Diagnostic(ErrorCode.ERR_NameNotInContext, "Method").WithArguments("Method").WithLocation(5, 20)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var identifier = GetSyntax<IdentifierNameSyntax>(tree, "Method"); Assert.Equal([], model.GetMemberGroup(identifier).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_Null_Method() { var src = """ #nullable enable object? o = null; o.Method(); static class E { extension(object o) { public void Method() { System.Console.Write("Method"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,1): warning CS8604: Possible null reference argument for parameter 'o' in 'E.extension(object)'. // o.Method(); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "o").WithArguments("o", "E.extension(object)").WithLocation(4, 1)); CompileAndVerify(comp, expectedOutput: "Method"); } [Fact] public void InstanceMethodInvocation_ColorColor_Method() { var src = """ C.M(new C()); class C { public static void M(C C) { C.Method(); } } static class E { extension(C c) { public void Method() { System.Console.Write("Method "); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "Method").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.Method"); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Method()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Method()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_ColorColor_Static_Method() { var src = """ C.M(null); class C { public static void M(C C) { C.Method(); } } static class E { extension(C c) { public void Method() { System.Console.Write("Method"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: "Method").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.Method"); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Method()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Method()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_PatternBased_ForEach_MoveNext() { var src = """ foreach (var x in new C()) { } class C { } class D { public int Current => 42; } static class E { extension(C c) { public D GetEnumerator() => new D(); } extension(D d) { public bool MoveNext() => true; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,19): error CS0117: 'D' does not contain a definition for 'MoveNext' // foreach (var x in new C()) Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("D", "MoveNext").WithLocation(1, 19), // (1,19): error CS0202: foreach requires that the return type 'D' of 'E.extension(C).GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property // foreach (var x in new C()) Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("D", "E.extension(C).GetEnumerator()").WithLocation(1, 19) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var loop = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single(); Assert.Null(model.GetForEachStatementInfo(loop).GetEnumeratorMethod); Assert.Null(model.GetForEachStatementInfo(loop).MoveNextMethod); Assert.Null(model.GetForEachStatementInfo(loop).CurrentProperty); } [Fact] public void InstanceMethodInvocation_PatternBased_ForEach_Current() { var src = """ foreach (var x in new C()) { } class C { } class D { public bool MoveNext() => true; } static class E { extension(C c) { public D GetEnumerator() => new D(); } extension(D d) { public int Current => 42; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,19): error CS0117: 'D' does not contain a definition for 'Current' // foreach (var x in new C()) Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("D", "Current").WithLocation(1, 19), // (1,19): error CS0202: foreach requires that the return type 'D' of 'E.extension(C).GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property // foreach (var x in new C()) Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("D", "E.extension(C).GetEnumerator()").WithLocation(1, 19) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var loop = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single(); Assert.Null(model.GetForEachStatementInfo(loop).GetEnumeratorMethod); Assert.Null(model.GetForEachStatementInfo(loop).MoveNextMethod); Assert.Null(model.GetForEachStatementInfo(loop).CurrentProperty); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78828")] public void InstanceMethodInvocation_PatternBased_ForEach_GetEnumerator_Conversion_Classic() { var src = """ foreach (var x in new C()) { System.Console.Write(x); break; } class C { } class D { public bool MoveNext() => true; public int Current => 42; } static class E { public static D GetEnumerator(this object obj) => new D(); } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78828")] public void Foreach_GetEnumerator_ReceiverNullableWarning() { var src = """ #nullable enable foreach (var x in ((C?)null).Id()) // 1 { } class C { public C Id() => this; } static class E { extension(C c) { public System.Collections.Generic.IEnumerator<int> GetEnumerator() => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,20): warning CS8602: Dereference of a possibly null reference. // foreach (var x in ((C?)null).Id()) // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(C?)null").WithLocation(3, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78828")] public void InstanceMethodInvocation_PatternBased_ForEach_GetEnumerator_Conversion() { var src = """ foreach (var x in new C()) { System.Console.Write(x); break; } class C { } class D { public bool MoveNext() => true; public int Current => 42; } static class E { extension(object o) { public D GetEnumerator() => new D(); } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78828")] public void ExtensionGetEnumerator_NullReceiver() { var src = """ #nullable enable C? c = null; foreach (var x in c) // 1 { System.Console.Write(x); break; } class C { } static class E { extension(C c) { public System.Collections.Generic.IEnumerator<int> GetEnumerator() => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,19): warning CS8604: Possible null reference argument for parameter 'c' in 'extension(C)'. // foreach (var x in c) // 1 Diagnostic(ErrorCode.WRN_NullReferenceArgument, "c").WithArguments("c", "E.extension(C)").WithLocation(3, 19)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78828")] public void ExtensionGetEnumerator_NullReceiver_Classic() { var src = """ #nullable enable C? c = null; foreach (var x in c) // 1 { System.Console.Write(x); break; } class C { } static class E { public static System.Collections.Generic.IEnumerator<int> GetEnumerator(this C c) => throw null!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,19): warning CS8604: Possible null reference argument for parameter 'c' in 'IEnumerator<int> E.GetEnumerator(C c)'. // foreach (var x in c) // 1 Diagnostic(ErrorCode.WRN_NullReferenceArgument, "c").WithArguments("c", "IEnumerator<int> E.GetEnumerator(C c)").WithLocation(3, 19)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78828")] public void ExtensionGetEnumerator_Reinference() { var src = """ #nullable enable var s = "a"; if (string.Empty == "") s = null; var c = M(s); // 'C<string?>' foreach (var x in c) { x.ToString(); // 1 } var d = M("a"); // 'C<string>' foreach (var x in d) { x.ToString(); // ok } C<T> M<T>(T item) => throw null!; class C<T> { } static class E { extension<T>(C<T> c) { public System.Collections.Generic.IEnumerator<T> GetEnumerator() => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (9,5): warning CS8602: Dereference of a possibly null reference. // x.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(9, 5)); } [Fact] public void InstanceMethodInvocation_NameOf_SingleParameter() { var src = """ class C { public static void Main() { string x = ""; System.Console.Write(nameof(x)); } } static class E { extension(C c) { public string nameof(string s) => throw null; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "x").VerifyDiagnostics(); } [Fact] public void InstanceMethodInvocation_Simple_ExpressionTree() { var source = """ using System.Linq.Expressions; Expression<System.Action> x = () => new C().M(42); System.Console.Write(x.Dump()); System.Action a = x.Compile(); a(); class C { public void M() => throw null; } static class E { extension(C c) { public void M(int i) { System.Console.Write(" ran"); } } } """; var comp = CreateCompilation([source, ExpressionTestLibrary]); CompileAndVerify(comp, expectedOutput: "Call(null.[Void M(C, Int32)](New([Void .ctor()]() Type:C), Constant(42 Type:System.Int32)) Type:System.Void) ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void C.M()", "void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_NextScope() { // If overload resolution on extension type methods yields no applicable candidates, // we look in the next scope. var source = """ using N; new C().M(42); class C { public void M() => throw null; } static class E1 { extension(C c) { public void M(string s) => throw null; } } namespace N { static class E2 { extension(C c) { public void M(int i) { System.Console.Write($"E2.M({i})"); } } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "E2.M(42)"); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); AssertEx.Equal("void N.E2.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void C.M()", "void E1.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.String s)", "void N.E2.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_NewExtensionPriority() { var source = """ new C().M(42); class C { public void M() => throw null; } static class E1 { extension(C c) { public void M(int i) => throw null; } } static class E2 { public static void M(this C c, int i) => throw null; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,9): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(C).M(int)' and 'E2.M(C, int)' // new C().M(42); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E1.extension(C).M(int)", "E2.M(C, int)").WithLocation(1, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void C.M()", "void E1.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", "void C.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_NewExtensionPriority_02() { var source = """ new C().M(42); class C { public void M() => throw null; } static class E { extension(C c) { public void M(int i) => throw null; } public static void M(this C c, int i) => throw null; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,9): error CS0121: The call is ambiguous between the following methods or properties: 'E.extension(C).M(int)' and 'E.M(C, int)' // new C().M(42); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E.extension(C).M(int)", "E.M(C, int)").WithLocation(1, 9), // (12,21): error CS0111: Type 'E' already defines a member called 'M' with the same parameter types // public void M(int i) => throw null; Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "E").WithLocation(12, 21) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void C.M()", "void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", "void C.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_FallbackToExtensionMethod() { // The extension method is picked up if extension declaration candidates were not applicable var source = """ new C().M(42); class C { public static void M() => throw null; } static class E1 { extension(C c) { public void M(string s) => throw null; public void M(char c1) => throw null; } } static class E2 { public static void M(this C c, int i) { System.Console.Write($"E2.M({i})"); } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "E2.M(42)"); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); AssertEx.Equal("void C.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void C.M()", "void E1.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.String s)", "void E1.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Char c1)", "void C.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_SimpleName() { // Extension invocation comes into play on an invocation on a member access but not an invocation on a simple name var source = """ class C { public void M() => throw null; void M2() { M(42); // 1 } } static class E { extension(C c) { public void M(int i) => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // 0.cs(7,9): error CS1501: No overload for method 'M' takes 1 arguments // M(42); // 1 Diagnostic(ErrorCode.ERR_BadArgCount, "M").WithArguments("M", "1").WithLocation(7, 9) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M(42)"); Assert.Null(model.GetSymbolInfo(invocation).Symbol); Assert.Empty(model.GetMemberGroup(invocation)); AssertEx.SequenceEqual(["void C.M()"], model.GetMemberGroup(invocation.Expression).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_ArgumentName() { // Instance method with incompatible parameter name is skipped in favor of extension declaration method var source = """ new C().M(b: 42); class C { public void M(int a) => throw null; } static class E1 { extension(C c) { public void M(int b) { System.Console.Write($"E1.M({b})"); } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: "E1.M(42)"); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); AssertEx.Equal("void E1.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 b)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void C.M(System.Int32 a)", "void E1.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 b)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_ArgumentName_02() { // Extension declaration method with incompatible parameter name is skipped in favor of extension method var source = """ new C().M(c: 42); public class C { public static void M(int a) => throw null; } static class E1 { extension(C c) { public void M(int b) => throw null; } } public static class E2 { public static void M(this C self, int c) { System.Console.Write($"E2.M({c})"); } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "E2.M(42)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); AssertEx.Equal("void C.M(System.Int32 c)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void C.M(System.Int32 a)", "void E1.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 b)", "void C.M(System.Int32 c)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_ArgumentName_03() { var source = """ new object().M(c: 43, b: 42); static class E { extension(object o) { public void M(int b, int c) { System.Console.Write($"E.M({b}, {c})"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "E.M(42, 43)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M(System.Int32 b, System.Int32 c)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void InstanceMethodInvocation_ArgumentName_04() { var source = """ new object().M(o: new object()); static class E { extension(object o) { public void M(object o2) => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,16): error CS1744: Named argument 'o' specifies a parameter for which a positional argument has already been given // new object().M(o: new object()); Diagnostic(ErrorCode.ERR_NamedArgumentUsedInPositional, "o").WithArguments("o").WithLocation(1, 16)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); } [Fact] public void InstanceMethodInvocation_RefKind() { var source = """ int i = 42; int j; new object().M(ref i, out j); static class E { extension(object o) { public void M(ref int b, out int c) { c = 43; System.Console.Write($"E.M({b}, {c})"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "E.M(42, 43)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M(ref System.Int32 b, out System.Int32 c)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void InstanceMethodInvocation_AmbiguityWithExtensionOnBaseType_PreferMoreSpecific() { var source = """ System.Console.Write(new C().M(42)); class Base { } class C : Base { } static class E1 { extension(Base b) { public int M(int i) => throw null; } } static class E2 { extension(C c) { public int M(int i) => i; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); AssertEx.Equal("System.Int32 E2.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["System.Int32 E1.<G>$76A32DFFBBF61DFEA0C27B13F12F6EFB.M(System.Int32 i)", "System.Int32 E2.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); source = """ System.Console.Write(new C().M(42)); public class Base { } public class C : Base { } public static class E1 { public static int M(this Base b, int i) => throw null; } public static class E2 { public static int M(this C c, int i) => i; } """; comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); } [Fact] public void InstanceMethodInvocation_TypeArguments() { var source = """ new C().M<object>(42); class C { } static class E { extension(C c) { public void M(int i) => throw null; public void M<T>(int i) { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M<object>"); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M<System.Object>(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M<System.Object>(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_TypeArguments_WrongNumber() { var source = """ new C().M<object, object>(42); class C { } static class E { extension(C c) { public void M(int i) => throw null; public void M<T>(int i) => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // 0.cs(1,9): error CS1061: 'C' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) // new C().M<object, object>(42); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M<object, object>").WithArguments("C", "M").WithLocation(1, 9) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M<object, object>"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Empty(model.GetSymbolInfo(memberAccess).CandidateSymbols); Assert.Empty(model.GetMemberGroup(memberAccess)); } [Fact] public void InstanceMethodInvocation_TypeArguments_Omitted() { var source = """ new C().M<>(42); class C { } static class E { extension(C c) { public void M<T>(int i) => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,1): error CS8389: Omitting the type argument is not allowed in the current context // new C().M<>(42); Diagnostic(ErrorCode.ERR_OmittedTypeArgument, "new C().M<>").WithLocation(1, 1) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M<>"); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M<?>(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M<?>(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_TypeArguments_Inferred() { // No type arguments passed, but the extension declaration method is found and the type parameter inferred var source = """ new C().M(42); class C { } static class E { extension(C c) { public void M<T>(T t) { System.Console.Write($"M({t})"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "M(42)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M<System.Int32>(System.Int32 t)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M<T>(T t)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void StaticMethodInvocation_InstanceExtensionMethod() { // The extension method is not static, but the receiver is a type var source = """ C.M(); class C { } static class E { extension(C c) { public void M() => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,1): error CS0120: An object reference is required for the non-static field, method, or property 'E.extension(C).M()' // C.M(); Diagnostic(ErrorCode.ERR_ObjectRequired, "C.M").WithArguments("E.extension(C).M()").WithLocation(1, 1)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); source = """ C.Method(); public class C { } public static class E { public static void Method(this C c) { } } """; comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // 0.cs(1,1): error CS0120: An object reference is required for the non-static field, method, or property 'E.Method(C)' // C.Method(); Diagnostic(ErrorCode.ERR_ObjectRequired, "C.Method").WithArguments("E.Method(C)").WithLocation(1, 1)); } [Fact] public void InstanceMethodInvocation_StaticExtensionMethod() { // The extension method is static but the receiver is a value var source = """ new C().M(); class C { } static class E { extension(C c) { public static void M() => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,1): error CS0176: Member 'E.extension(C).M()' cannot be accessed with an instance reference; qualify it with a type name instead // new C().M(); Diagnostic(ErrorCode.ERR_ObjectProhibited, "new C().M").WithArguments("E.extension(C).M()").WithLocation(1, 1)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_GenericType() { var src = """ new C<int>().StaticType<string>(); class C<T> { } static class E { extension<T>(C<T> c) { public static class StaticType<U> { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,14): error CS1061: 'C<int>' does not contain a definition for 'StaticType' and no accessible extension method 'StaticType' accepting a first argument of type 'C<int>' could be found (are you missing a using directive or an assembly reference?) // new C<int>().StaticType<string>(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "StaticType<string>").WithArguments("C<int>", "StaticType").WithLocation(1, 14), // (9,29): error CS9282: This member is not allowed in an extension block // public static class StaticType<U> { } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "StaticType").WithLocation(9, 29)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C<int>().StaticType<string>"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess).CandidateReason); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_RefOmittedComCall() { // For COM import type, omitting the ref is allowed string source = @" using System; using System.Runtime.InteropServices; [ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] class C { } static class E { extension(C c) { public void M(ref short p) { } public void M(sbyte p) { } public void I(ref int p) { } } } class X { public static void Goo() { short x = 123; C c = new C(); c.M(x); c.I(123); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_ExtensionDeclarationMethods() { // See ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_Method var source = """ struct S1(Color Color) { public void Test() { Color.M1(this); } } class Color { } static class E { extension(Color c) { public void M1(S1 x, int y = 0) { System.Console.WriteLine("instance"); } public static void M1<T>(T x) where T : unmanaged { System.Console.WriteLine("static"); } } } """; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll); comp.VerifyEmitDiagnostics( // (5,9): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. // Color.M1(this); Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(5, 9) ); Assert.NotEmpty(comp.GetTypeByMetadataName("S1").InstanceConstructors.OfType<SynthesizedPrimaryConstructor>().Single().GetCapturedParameters()); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.M1"); AssertEx.Equal("void E.<G>$2404CFB602D7DEE90BDDEF217EC37C58.M1(S1 x, [System.Int32 y = 0])", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_ExtensionDeclarationMembersVsExtensionMethod() { var source = """ public struct S1(Color Color) { public void Test() { Color.M1(this); } } public class Color { } public static class E1 { public static void M1(this Color c, S1 x, int y = 0) { System.Console.WriteLine("instance"); } } static class E2 { extension(Color c) { public static void M1<T>(T x) where T : unmanaged { System.Console.WriteLine("static"); } } } """; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll); comp.VerifyEmitDiagnostics( // (5,9): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. // Color.M1(this); Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(5, 9) ); Assert.NotEmpty(comp.GetTypeByMetadataName("S1").InstanceConstructors.OfType<SynthesizedPrimaryConstructor>().Single().GetCapturedParameters()); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.M1"); AssertEx.Equal("void Color.M1(S1 x, [System.Int32 y = 0])", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void InstanceMethodInvocation_NotOnBase() { // Unlike `this`, `base` is not an expression in itself. // "Extension invocation" and "extension member lookup" do not apply to `base_access` syntax. var src = """ class Base { } class Derived : Base { void Main() { M(); // 1 base.M(); // 2 } } static class E { extension(Base b) { public void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,9): error CS0103: The name 'M' does not exist in the current context // M(); // 1 Diagnostic(ErrorCode.ERR_NameNotInContext, "M").WithArguments("M").WithLocation(7, 9), // (8,14): error CS0117: 'Base' does not contain a definition for 'M' // base.M(); // 2 Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("Base", "M").WithLocation(8, 14)); } [Fact] public void LookupKind_Invocation() { // Non-invocable extension member in inner scope is skipped in favor of invocable one from outer scope var src = """ using N; new object().Member(); static class E { extension(object o) { public int Member => 0; } } namespace N { static class E2 { extension(object o) { public void Member() { System.Console.Write("ran "); } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().Member"); AssertEx.Equal("void N.E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void InstanceMethodInvocation_Generic_NotUnique() { var src = """ new C<object, dynamic>().M(); new C<dynamic, object>().M(); new C<object, dynamic>().M2(); new C<dynamic, object>().M2(); class C<T, U> { } static class E { extension<T>(C<T, T> c) { public string M() => "hi"; } public static string M2<T>(this C<T, T> c) => "hi"; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,26): error CS0411: The type arguments for method 'E.extension<T>(C<T, T>).M()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // new C<object, dynamic>().M(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("E.extension<T>(C<T, T>).M()").WithLocation(1, 26), // (2,26): error CS0411: The type arguments for method 'E.extension<T>(C<T, T>).M()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // new C<dynamic, object>().M(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("E.extension<T>(C<T, T>).M()").WithLocation(2, 26), // (4,26): error CS0411: The type arguments for method 'E.M2<T>(C<T, T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // new C<object, dynamic>().M2(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M2").WithArguments("E.M2<T>(C<T, T>)").WithLocation(4, 26), // (5,26): error CS0411: The type arguments for method 'E.M2<T>(C<T, T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // new C<dynamic, object>().M2(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M2").WithArguments("E.M2<T>(C<T, T>)").WithLocation(5, 26)); } [Fact] public void InstanceMethodInvocation_Generic_NestedTuples() { var src = """ var s = new C<(string, string)>.Nested<(int, int)>().M(); System.Console.Write(s); class C<T> { internal class Nested<U> { } } static class E { extension<T1, T2>(C<(T1, T1)>.Nested<(T2, T2)> cn) { public string M() => "hi"; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "hi").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C<(string, string)>.Nested<(int, int)>().M"); AssertEx.Equal("System.String E.<G>$FD79C355D693194B747A629F6876929C<System.String, System.Int32>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void InstanceMethodInvocation_Generic_PointerArray() { var src = """ unsafe { string s = new C<long*[]>.Nested<int*[]>().M(); System.Console.Write(s); } unsafe class C<T> { internal class Nested<U> { } } unsafe static class E { extension<T1, T2>(C<T1*[]>.Nested<T2*[]> cn) where T1 : unmanaged where T2 : unmanaged { public string M() => "hi"; } } """; var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe); CompileAndVerify(comp, expectedOutput: "hi").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C<long*[]>.Nested<int*[]>().M"); AssertEx.Equal("System.String E.<G>$C781704B647A2CCC8FD47AE9790BA08B<System.Int64, System.Int32>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void InstanceMethodInvocation_Generic_Pointer() { var src = """ unsafe { new C<long*[]>.Nested<int*[]>().M(); new C<long*[]>.Nested<int*[]>().M2(); } unsafe class C<T> { internal class Nested<U> { } } static class E { extension<T1, T2>(C<T1[]>.Nested<T2[]> cn) { public string M() => null; } public static string M2<T1, T2>(this C<T1[]>.Nested<T2[]> cn) => null; } """; var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe); comp.VerifyEmitDiagnostics( // (3,37): error CS0306: The type 'long*' may not be used as a type argument // new C<long*[]>.Nested<int*[]>().M(); Diagnostic(ErrorCode.ERR_BadTypeArgument, "M").WithArguments("long*").WithLocation(3, 37), // (3,37): error CS0306: The type 'int*' may not be used as a type argument // new C<long*[]>.Nested<int*[]>().M(); Diagnostic(ErrorCode.ERR_BadTypeArgument, "M").WithArguments("int*").WithLocation(3, 37), // (4,37): error CS0306: The type 'long*' may not be used as a type argument // new C<long*[]>.Nested<int*[]>().M2(); Diagnostic(ErrorCode.ERR_BadTypeArgument, "M2").WithArguments("long*").WithLocation(4, 37), // (4,37): error CS0306: The type 'int*' may not be used as a type argument // new C<long*[]>.Nested<int*[]>().M2(); Diagnostic(ErrorCode.ERR_BadTypeArgument, "M2").WithArguments("int*").WithLocation(4, 37) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C<long*[]>.Nested<int*[]>().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); } [Fact] public void InstanceMethodInvocation_Generic_FunctionPointer() { var src = """ unsafe { string s = new C<delegate*<int>[]>.Nested<delegate*<long>[]>().M(); System.Console.Write(s); } unsafe class C<T> { internal class Nested<U> { } } unsafe static class E { extension<T1, T2>(C<delegate*<T1>[]>.Nested<delegate*<T2>[]> cn) { public string M() => "hi"; } } """; var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C<delegate*<int>[]>.Nested<delegate*<long>[]>().M"); AssertEx.Equal("System.String E.<G>$5F3142482E98DE8C6B0C70A682DD0496<System.Int32, System.Int64>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void InstanceMethodInvocation_Generic_ForInterface() { var src = """ string s = new C<int>().M(); System.Console.Write(s); class C<T> : I<T> { } interface I<T> { } static class E { extension<T>(I<T> i) { public string M() => "hi"; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "hi").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C<int>().M"); AssertEx.Equal("System.String E.<G>$74EBC78B2187AB07A25EEFC1322000B0<System.Int32>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void InstanceMethodInvocation_Generic_ForBaseInterface() { var src = """ string s = new C<int>().M(); System.Console.Write(s); class C<T> : I<T> { } interface I<T> : I2<T> { } interface I2<T> { } static class E { extension<T>(I2<T> i) { public string M() => "hi"; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "hi").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C<int>().M"); AssertEx.Equal("System.String E.<G>$5D7EC0FD2C9001515B0ADE0CEE121AB0<System.Int32>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void InstanceMethodInvocation_Generic_ForBase() { var src = """ string s = new C<int, string>().M(); System.Console.Write(s); class Base<T, U> { } class C<T, U> : Base<U, T> { } static class E { extension<T, U>(Base<T, U> b) { public string M() => "hi"; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "hi").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C<int, string>().M"); AssertEx.Equal("System.String E.<G>$414BE9969A3DFDFF167B842681736663<System.String, System.Int32>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void InstanceMethodInvocation_Obsolete() { var src = """ new object().Method(); static class E { extension(object o) { [System.Obsolete("Method is obsolete", true)] public void Method() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS0619: 'E.extension(object).Method()' is obsolete: 'Method is obsolete' // new object().Method(); Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "new object().Method()").WithArguments("E.extension(object).Method()", "Method is obsolete").WithLocation(1, 1)); } [Fact] public void InstanceMethodInvocation_BrokenConstraintMethodOuterExtension() { var src = """ static class E2 { extension(object o) { public void M<T>() => throw null; } } namespace Inner { class C { public static void Main() { new C().M<object>(); } } static class E1 { extension(C c) { public string M<T>() where T : struct => throw null; } } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M<object>"); AssertEx.Equal("void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M<System.Object>()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M<System.Object>()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethodInvocation_MultipleSubstitutions() { var src = """ new C().M(); interface I<T> { } class C : I<int>, I<string> { } static class E { extension<T>(I<T> i) { public void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,9): error CS0411: The type arguments for method 'E.extension<T>(I<T>).M()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // new C().M(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("E.extension<T>(I<T>).M()").WithLocation(1, 9)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Empty(model.GetMemberGroup(memberAccess)); } [Theory, CombinatorialData] public void InstanceMethodInvocation_MultipleExtensions(bool e1BeforeE2) { var e1 = """ static class E1 { extension(object o) { public string M() => throw null; } } """; var e2 = """ static class E2 { extension(object o) { public string M() => throw null; } } """; var src = $$""" new object().M(); {{(e1BeforeE2 ? e1 : e2)}} {{(e1BeforeE2 ? e2 : e1)}} """; var comp = CreateCompilation(src); if (!e1BeforeE2) { comp.VerifyEmitDiagnostics( // (1,14): error CS0121: The call is ambiguous between the following methods or properties: 'E2.extension(object).M()' and 'E1.extension(object).M()' // new object().M(); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E2.extension(object).M()", "E1.extension(object).M()").WithLocation(1, 14)); } else { comp.VerifyEmitDiagnostics( // (1,14): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(object).M()' and 'E2.extension(object).M()' // new object().M(); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E1.extension(object).M()", "E2.extension(object).M()").WithLocation(1, 14)); } var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); if (e1BeforeE2) { AssertEx.SequenceEqual(["System.String E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "System.String E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } else { AssertEx.SequenceEqual(["System.String E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "System.String E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } } public class ThreePermutationGenerator : IEnumerable<object[]> { private readonly List<object[]> _data = [ [0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]; public IEnumerator<object[]> GetEnumerator() => _data.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } [Theory, ClassData(typeof(ThreePermutationGenerator))] public void InstanceMethodInvocation_InterfaceAppearsTwice(int first, int second, int third) { string[] segments = [ """ static class E1 { extension<T>(I1<T> i) { public string M() => null; } } """, """ static class E2 { extension(I2 i) { } } """, """ static class E3 { extension(C c) { } } """]; var src = $$""" System.Console.Write(new C().M()); interface I1<T> { } interface I2 : I1<string> { } class C : I1<int>, I2 { } {{segments[first]}} {{segments[second]}} {{segments[third]}} """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,30): error CS0411: The type arguments for method 'E1.extension<T>(I1<T>).M()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // System.Console.Write(new C().M()); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("E1.extension<T>(I1<T>).M()").WithLocation(1, 30)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Empty(model.GetMemberGroup(memberAccess)); } [Fact] public void InstanceMethodInvocation_SingleStageInference() { var src = """ public class C { public void M(I<string> i, out object o) { i.M(out o); i.M2(out o); } } public static class E { public static void M<T>(this I<T> i, out T t) { t = default; } } static class E2 { extension<T>(I<T> i) { public void M2(out T t) { t = default; } } } public interface I<out T> { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "i.M"); AssertEx.Equal("void I<System.Object>.M<System.Object>(out System.Object t)", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); AssertEx.SequenceEqual(["void I<System.String>.M<System.String>(out System.String t)"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "i.M2"); AssertEx.Equal("void E2.<G>$74EBC78B2187AB07A25EEFC1322000B0<System.Object>.M2(out System.Object t)", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); AssertEx.SequenceEqual(["void E2.<G>$74EBC78B2187AB07A25EEFC1322000B0<System.String>.M2(out System.String t)"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); } [Fact] public void GetCompatibleExtension_Conversion_01() { var src = """ using System.Collections.Generic; IEnumerable<string> i = null; i.M(); _ = i.P; static class E { extension(IEnumerable<object> o) { public void M() { System.Console.Write(o is null); } public int P { get { System.Console.Write(o is null); return 0; } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "TrueTrue").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "i.M"); AssertEx.Equal("void E.<G>$977919F21861BE18BA139544085CA0BD.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$977919F21861BE18BA139544085CA0BD.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "i.P"); AssertEx.Equal("System.Int32 E.<G>$977919F21861BE18BA139544085CA0BD.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); src = """ using System.Collections.Generic; IEnumerable<object> i = null; i.M(); _ = i.P; static class E { extension(IEnumerable<string> o) { public static void M() { } public static int P => throw null; } } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,1): error CS1929: 'IEnumerable<object>' does not contain a definition for 'M' and the best extension method overload 'E.extension(IEnumerable<string>).M()' requires a receiver of type 'System.Collections.Generic.IEnumerable<string>' // i.M(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "i").WithArguments("System.Collections.Generic.IEnumerable<object>", "M", "E.extension(System.Collections.Generic.IEnumerable<string>).M()", "System.Collections.Generic.IEnumerable<string>").WithLocation(4, 1), // (5,5): error CS1929: 'IEnumerable<object>' does not contain a definition for 'P' and the best extension method overload 'E.extension(IEnumerable<string>).P' requires a receiver of type 'System.Collections.Generic.IEnumerable<string>' // _ = i.P; Diagnostic(ErrorCode.ERR_BadInstanceArgType, "i").WithArguments("System.Collections.Generic.IEnumerable<object>", "P", "E.extension(System.Collections.Generic.IEnumerable<string>).P", "System.Collections.Generic.IEnumerable<string>").WithLocation(5, 5) ); } [Fact] public void GetCompatibleExtension_Conversion_02() { var src = """ string.M(); _ = string.P; static class E { extension(object) { public static void M() { System.Console.Write("ran "); } public static int P { get { System.Console.Write("ran2"); return 0; } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran ran2").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "string.M"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void GetCompatibleExtension_Conversion_03() { var src = """ int.M(); _ = int.P; static class E { extension(object) { public static void M() { System.Console.Write("ran "); } public static int P { get { System.Console.Write("ran2"); return 0; } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran ran2").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.M"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void GetCompatibleExtension_Conversion_04() { var src = """ int.M(); 42.M2(); _ = int.P; _ = 42.P2; static class E { extension(int? i) { public static void M() { } public static int P => 0; public int P2 => 0; } public static void M2(this int? i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS1929: 'int' does not contain a definition for 'M' and the best extension method overload 'E.extension(int?).M()' requires a receiver of type 'int?' // int.M(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "int").WithArguments("int", "M", "E.extension(int?).M()", "int?").WithLocation(1, 1), // (2,1): error CS1929: 'int' does not contain a definition for 'M2' and the best extension method overload 'E.M2(int?)' requires a receiver of type 'int?' // 42.M2(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "42").WithArguments("int", "M2", "E.M2(int?)", "int?").WithLocation(2, 1), // (4,5): error CS1929: 'int' does not contain a definition for 'P' and the best extension method overload 'E.extension(int?).P' requires a receiver of type 'int?' // _ = int.P; Diagnostic(ErrorCode.ERR_BadInstanceArgType, "int").WithArguments("int", "P", "E.extension(int?).P", "int?").WithLocation(4, 5), // (5,5): error CS1929: 'int' does not contain a definition for 'P2' and the best extension method overload 'E.extension(int?).P2' requires a receiver of type 'int?' // _ = 42.P2; Diagnostic(ErrorCode.ERR_BadInstanceArgType, "42").WithArguments("int", "P2", "E.extension(int?).P2", "int?").WithLocation(5, 5)); } [Fact] public void GetCompatibleExtension_Conversion_05() { var src = """ MyEnum.Zero.M(); enum MyEnum { Zero } static class E { extension(System.Enum e) { public void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void GetCompatibleExtension_Conversion_06() { var src = """ dynamic d = new C(); d.M(); d.M2(); static class E { extension(object o) { public void M() => throw null; } public static void M2(this object o) => throw null; } class C { public void M() { System.Console.Write("ran "); } public void M2() { System.Console.Write("ran2"); } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("ran ran2"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void GetCompatibleExtension_Conversion_07() { var src = """ object o = null; o.M(); o.M2(); static class E { extension(dynamic d) { public void M() { } } public static void M2(this dynamic d) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,3): error CS1061: 'object' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // o.M(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("object", "M").WithLocation(2, 3), // (3,3): error CS1061: 'object' does not contain a definition for 'M2' and no accessible extension method 'M2' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // o.M2(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M2").WithArguments("object", "M2").WithLocation(3, 3), // (7,15): error CS1103: The receiver parameter of an extension cannot be of type 'dynamic' // extension(dynamic d) Diagnostic(ErrorCode.ERR_BadTypeforThis, "dynamic").WithArguments("dynamic").WithLocation(7, 15), // (12,32): error CS1103: The receiver parameter of an extension cannot be of type 'dynamic' // public static void M2(this dynamic d) { } Diagnostic(ErrorCode.ERR_BadTypeforThis, "dynamic").WithArguments("dynamic").WithLocation(12, 32)); } [Fact] public void GetCompatibleExtension_Conversion_08() { var src = """ (int a, int b) t = default; t.M(); t.M2(); static class E { extension((int c, int d) t) { public void M() { } } public static void M2(this (int c, int d) t) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void GetCompatibleExtension_Conversion_09() { var src = """ int[] i = default; i.M(); i.M2(); static class E { extension(System.ReadOnlySpan<int> ros) { public void M() { } } public static void M2(this System.ReadOnlySpan<int> ros) { } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); } [Fact] public void GetCompatibleExtension_Conversion_10() { var missingSrc = """ public class Missing { } """; var missingRef = CreateCompilation(missingSrc, assemblyName: "missing").EmitToImageReference(); var derivedSrc = """ public class Derived : Missing { } """; var derivedRef = CreateCompilation(derivedSrc, references: [missingRef]).EmitToImageReference(); var src = """ new Derived().M(); new Derived().M2(); class Other { } static class E { extension(Other o) { public void M() { } } public static void M2(this Other o) { } } """; var comp = CreateCompilation(src, references: [derivedRef]); comp.VerifyEmitDiagnostics( // (1,1): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // new Derived().M(); Diagnostic(ErrorCode.ERR_NoTypeDef, "new Derived().M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 1), // (1,1): error CS1929: 'Derived' does not contain a definition for 'M' and the best extension method overload 'E.extension(Other).M()' requires a receiver of type 'Other' // new Derived().M(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new Derived()").WithArguments("Derived", "M", "E.extension(Other).M()", "Other").WithLocation(1, 1), // (1,15): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // new Derived().M(); Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 15), // (2,1): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // new Derived().M2(); Diagnostic(ErrorCode.ERR_NoTypeDef, "new Derived().M2").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(2, 1), // (2,1): error CS1929: 'Derived' does not contain a definition for 'M2' and the best extension method overload 'E.M2(Other)' requires a receiver of type 'Other' // new Derived().M2(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new Derived()").WithArguments("Derived", "M2", "E.M2(Other)", "Other").WithLocation(2, 1), // (2,15): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // new Derived().M2(); Diagnostic(ErrorCode.ERR_NoTypeDef, "M2").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(2, 15)); } [Fact] public void GetCompatibleExtension_Conversion_11() { var missingSrc = """ public class Missing { } """; var missingRef = CreateCompilation(missingSrc, assemblyName: "missing").EmitToImageReference(); var derivedSrc = """ public class Derived : Missing { } """; var derivedRef = CreateCompilation(derivedSrc, references: [missingRef]).EmitToImageReference(); var src = """ new Derived().M(); new Derived().M2(); static class E { extension(Derived d) { public void M() { } } public static void M2(this Derived d) { } } """; var comp = CreateCompilation(src, references: [derivedRef]); comp.VerifyEmitDiagnostics( // (1,15): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // new Derived().M(); Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 15), // (2,15): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // new Derived().M2(); Diagnostic(ErrorCode.ERR_NoTypeDef, "M2").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(2, 15)); } [Fact] public void GetCompatibleExtension_Conversion_12() { var missingSrc = """ public class Missing { } """; var missingRef = CreateCompilation(missingSrc, assemblyName: "missing").EmitToImageReference(); var derivedSrc = """ public class I<T> { } public class Derived : I<Missing> { } """; var derivedRef = CreateCompilation(derivedSrc, references: [missingRef]).EmitToImageReference(); var src = """ new Derived().M(); new Derived().M2(); static class E { extension(I<object> i) { public void M() { } } public static void M2(this I<object> i) { } } """; var comp = CreateCompilation(src, references: [derivedRef]); comp.VerifyEmitDiagnostics( // (1,1): error CS1929: 'Derived' does not contain a definition for 'M' and the best extension method overload 'E.extension(I<object>).M()' requires a receiver of type 'I<object>' // new Derived().M(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new Derived()").WithArguments("Derived", "M", "E.extension(I<object>).M()", "I<object>").WithLocation(1, 1), // (2,1): error CS1929: 'Derived' does not contain a definition for 'M2' and the best extension method overload 'E.M2(I<object>)' requires a receiver of type 'I<object>' // new Derived().M2(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new Derived()").WithArguments("Derived", "M2", "E.M2(I<object>)", "I<object>").WithLocation(2, 1)); } [Fact] public void GetCompatibleExtension_TypeInference_01() { var src = """ I<object, string>.M(); interface I<out T1, out T2> { } static class E { extension<T>(I<T, T>) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "I<object, string>.M"); AssertEx.Equal("void E.<G>$B135BA58FDFC6D88E9886008265BE41B<System.Object>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void GetCompatibleExtension_TypeInference_02() { var src = """ I<object, string>.M(); interface I<in T1, in T2> { } static class E { extension<T>(I<T, T>) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "I<object, string>.M"); AssertEx.Equal("void E.<G>$B135BA58FDFC6D88E9886008265BE41B<System.String>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void GetCompatibleExtension_TypeInference_03() { var src = """ I<object, string>.M(); interface I<T1, T2> { } static class E { extension<T>(I<T, T>) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,19): error CS0411: The type arguments for method 'E.extension<T>(I<T, T>).M()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // I<object, string>.M(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("E.extension<T>(I<T, T>).M()").WithLocation(1, 19)); } [Fact] public void GetCompatibleExtension_Constraint_UseSiteInfo_01() { var missingSrc = """ public struct Missing { public int i; } """; var missingRef = CreateCompilation(missingSrc, assemblyName: "missing").EmitToImageReference(); var containerSrc = """ public struct Container { public Missing field; } """; var containerRef = CreateCompilation(containerSrc, references: [missingRef]).EmitToImageReference(); var src = """ Container.M(); static class E { extension<T>(T t) where T : unmanaged { public static void M() { } } } """; var comp = CreateCompilation(src, references: [containerRef]); comp.VerifyEmitDiagnostics( // (1,11): error CS8377: The type 'Container' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'E.extension<T>(T)' // Container.M(); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("E.extension<T>(T)", "T", "Container").WithLocation(1, 11), // (1,11): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // Container.M(); Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 11)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Container.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); src = """ new Container().M(); static class E { public static void M<T>(this T t) where T : unmanaged { } } """; comp = CreateCompilation(src, references: [containerRef]); comp.VerifyEmitDiagnostics( // (1,17): error CS8377: The type 'Container' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'E.M<T>(T)' // new Container().M(); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("E.M<T>(T)", "T", "Container").WithLocation(1, 17), // (1,17): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // new Container().M(); Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 17)); src = """ new object().M(new Container()); static class E { public static void M<T>(this object o, T t) where T : unmanaged { } } """; comp = CreateCompilation(src, references: [containerRef]); comp.VerifyEmitDiagnostics( // (1,14): error CS8377: The type 'Container' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'E.M<T>(object, T)' // new object().M(new Container()); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("E.M<T>(object, T)", "T", "Container").WithLocation(1, 14), // (1,14): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // new object().M(new Container()); Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 14)); } [Fact] public void GetCompatibleExtension_Constraint_UseSiteInfo_02() { var missingSrc = """ public struct Missing { public int i; } """; var missingRef = CreateCompilation(missingSrc, assemblyName: "missing").EmitToImageReference(); var containerSrc = """ public struct Container { public Missing field; } """; var containerRef = CreateCompilation(containerSrc, references: [missingRef]).EmitToImageReference(); var src = """ using N; Container.M(); static class E { extension<T>(T t) where T : unmanaged { public static void M(int inapplicable) => throw null; } } namespace N { static class E2 { extension<T>(T t) { public static void M() { } } } } """; var comp = CreateCompilation(src, references: [containerRef]); comp.VerifyEmitDiagnostics(); // The inapplicable candidate gets rejected before we get to check its constraints var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Container.M"); AssertEx.Equal("void N.E2.<G>$8048A6C8BE30A622530249B904B537EB<Container>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); src = """ Container.M(); static class E { extension<T>(T t) where T : unmanaged { public static void M(int inapplicable) => throw null; } } """; comp = CreateCompilation(src, references: [containerRef]); comp.VerifyEmitDiagnostics( // (1,11): error CS7036: There is no argument given that corresponds to the required parameter 'inapplicable' of 'E.extension<T>(T).M(int)' // Container.M(); Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M").WithArguments("inapplicable", "E.extension<T>(T).M(int)").WithLocation(1, 11)); src = """ using N; Container.M(); static class E { extension<T>(T t) where T : unmanaged { public static void M() => throw null; // applicable to arguments } } namespace N { static class E2 { extension<T>(T t) { public static void M() => throw null; } } } """; comp = CreateCompilation(src, references: [containerRef]); comp.VerifyEmitDiagnostics(); tree = comp.SyntaxTrees.Single(); model = comp.GetSemanticModel(tree); memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Container.M"); AssertEx.Equal("void N.E2.<G>$8048A6C8BE30A622530249B904B537EB<Container>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); src = """ using N; new Container().M(); static class E { public static void M<T>(this T t) where T : unmanaged { } } namespace N { static class E2 { public static void M<T>(this T t) { } } } """; // Expecting an error to be reported since we're not able to check whether the constraint is violated // Tracked by https://github.com/dotnet/roslyn/issues/77407 comp = CreateCompilation(src, references: [containerRef]); comp.VerifyEmitDiagnostics(); } [Fact] public void GetCompatibleExtension_Constraint_UseSiteInfo_03() { var missingSrc = """ public struct Missing { public int i; } """; var missingRef = CreateCompilation(missingSrc, assemblyName: "missing").EmitToImageReference(); var containerSrc = """ public struct Container { public Missing field; } """; var containerRef = CreateCompilation(containerSrc, references: [missingRef]).EmitToImageReference(); var src = """ int.M(new Container()); static class E { extension(int) { public static void M<T>(T t) where T : unmanaged { } } } """; var comp = CreateCompilation(src, references: [containerRef]); comp.VerifyEmitDiagnostics( // (1,5): error CS8377: The type 'Container' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'E.extension(int).M<T>(T)' // int.M(new Container()); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("E.extension(int).M<T>(T)", "T", "Container").WithLocation(1, 5), // (1,5): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // int.M(new Container()); Diagnostic(ErrorCode.ERR_NoTypeDef, "M").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 5)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); } [Fact] public void InstancePropertyAccess_Simple() { var src = """ System.Console.Write(new object().P); public static class Extensions { extension(object o) { public int P => 42; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().P"); AssertEx.Equal("System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void InstancePropertyAccess_StaticExtensionProperty() { var src = """ System.Console.Write(new object().P); public static class Extensions { extension(object o) { public static int P => 42; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,22): error CS0176: Member 'Extensions.extension(object).P' cannot be accessed with an instance reference; qualify it with a type name instead // System.Console.Write(new object().P); Diagnostic(ErrorCode.ERR_ObjectProhibited, "new object()").WithArguments("Extensions.extension(object).P").WithLocation(1, 22)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().P"); AssertEx.Equal("System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void InstancePropertyAccess_Invoked() { var src = """ new object().P(); public static class Extensions { extension(object o) { public int P => 42; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,14): error CS1061: 'object' does not contain a definition for 'P' and no accessible extension method 'P' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // new object().P(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "P").WithArguments("object", "P").WithLocation(1, 14)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "new object().P()"); Assert.Null(model.GetSymbolInfo(invocation).Symbol); Assert.Equal([], model.GetSymbolInfo(invocation).CandidateSymbols.ToTestDisplayStrings()); AssertEx.SequenceEqual(["System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.P { get; }"], model.GetMemberGroup(invocation.Expression).ToTestDisplayStrings()); } [Fact] public void InstancePropertyAccess_Invoked_Invocable() { var src = """ new object().P(); public static class Extensions { extension(object o) { public System.Action P { get { return () => { System.Console.Write("ran"); }; } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().P"); AssertEx.Equal("System.Action Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : handle GetMemberGroup on a property access } [Fact] public void StaticMethodInvocation_Simple() { var src = """ object.M(); public static class Extensions { extension(object) { public static int M() => 42; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "object.M()"); AssertEx.Equal("System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(invocation).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void StaticMethodInvocation_TypeArguments() { var source = """ C.M<object>(42); class C { } static class E { extension(C) { public static void M(int i) => throw null; public static void M<T>(int i) { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran"); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.M<object>"); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M<System.Object>(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M<System.Object>(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData] public void StaticMethodInvocation_Ambiguity_Method(bool e1BeforeE2) { var e1 = """ static class E1 { extension(object) { public static void Method() => throw null; } } """; var e2 = """ static class E2 { extension(object) { public static void Method() => throw null; } } """; var src = $$""" object.Method(); {{(e1BeforeE2 ? e1 : e2)}} {{(e1BeforeE2 ? e2 : e1)}} """; var comp = CreateCompilation(src); if (!e1BeforeE2) { comp.VerifyEmitDiagnostics( // (1,8): error CS0121: The call is ambiguous between the following methods or properties: 'E2.extension(object).Method()' and 'E1.extension(object).Method()' // object.Method(); Diagnostic(ErrorCode.ERR_AmbigCall, "Method").WithArguments("E2.extension(object).Method()", "E1.extension(object).Method()").WithLocation(1, 8)); } else { comp.VerifyEmitDiagnostics( // (1,8): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(object).Method()' and 'E2.extension(object).Method()' // object.Method(); Diagnostic(ErrorCode.ERR_AmbigCall, "Method").WithArguments("E1.extension(object).Method()", "E2.extension(object).Method()").WithLocation(1, 8)); } } [Fact] public void StaticPropertyAccess_InstanceExtensionProperty() { var src = """ System.Console.Write(new object().P); public static class Extensions { extension(object o) { public static int P => 42; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,22): error CS0176: Member 'Extensions.extension(object).P' cannot be accessed with an instance reference; qualify it with a type name instead // System.Console.Write(new object().P); Diagnostic(ErrorCode.ERR_ObjectProhibited, "new object()").WithArguments("Extensions.extension(object).P").WithLocation(1, 22)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().P"); AssertEx.Equal("System.Int32 Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void ResolveAll_ConditionalOperator_Static_ExtensionMethod() { var source = """ bool b = true; var x = b ? object.M : object.M; static class E { extension(object o) { public static void M() { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (2,9): error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'method group' and 'method group' // var x = b ? object.M : object.M; Diagnostic(ErrorCode.ERR_InvalidQM, "b ? object.M : object.M").WithArguments("method group", "method group").WithLocation(2, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.M").ToArray(); Assert.Null(model.GetSymbolInfo(memberAccess[0]).Symbol); Assert.Null(model.GetSymbolInfo(memberAccess[1]).Symbol); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess[0]).ToTestDisplayStrings()); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess[1]).ToTestDisplayStrings()); } [Fact] public void ResolveAll_ConditionalOperator_Static_ExtensionProperty() { var source = """ bool b = true; var x = b ? object.StaticProperty : object.StaticProperty; System.Console.Write(x); static class E { extension(object o) { public static int StaticProperty => 42; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.StaticProperty").ToArray(); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.StaticProperty { get; }", model.GetSymbolInfo(memberAccess[0]).Symbol.ToTestDisplayString()); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.StaticProperty { get; }", model.GetSymbolInfo(memberAccess[1]).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_ConditionalOperator_Static_DifferentTypes() { var source = """ bool b = true; var x = b ? object.StaticProperty : object.StaticProperty2; System.Console.Write(x.ToString()); static class E { extension(object o) { public static int StaticProperty => 42; public static long StaticProperty2 => 43; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.StaticProperty"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.StaticProperty { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.Equal("System.Int32", model.GetTypeInfo(memberAccess).Type.ToTestDisplayString()); AssertEx.Equal("System.Int64", model.GetTypeInfo(memberAccess).ConvertedType.ToTestDisplayString()); } [Fact] public void ResolveAll_ConditionalOperator_Static_WithTargetType() { var source = """ bool b = true; long x = b ? object.StaticProperty : object.StaticProperty; System.Console.Write(x.ToString()); static class E { extension(object o) { public static int StaticProperty => 42; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.StaticProperty").ToArray(); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.StaticProperty { get; }", model.GetSymbolInfo(memberAccess[0]).Symbol.ToTestDisplayString()); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.StaticProperty { get; }", model.GetSymbolInfo(memberAccess[1]).Symbol.ToTestDisplayString()); AssertEx.Equal("System.Int32", model.GetTypeInfo(memberAccess[0]).Type.ToTestDisplayString()); AssertEx.Equal("System.Int32", model.GetTypeInfo(memberAccess[0]).ConvertedType.ToTestDisplayString()); AssertEx.Equal("System.Int32", model.GetTypeInfo(memberAccess[1]).Type.ToTestDisplayString()); AssertEx.Equal("System.Int32", model.GetTypeInfo(memberAccess[1]).ConvertedType.ToTestDisplayString()); } [Fact] public void ResolveAll_ConditionalOperator_Static_TwoExtensions_WithTargetType() { var source = """ bool b = true; string x = b ? D.f : D.f; System.Console.Write(x); class D { } static class E1 { extension(D) { public static string f => "ran"; } } static class E2 { extension(object o) { public static void f() { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (2,16): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(object).f()' and 'E1.extension(D).f' // string x = b ? D.f : D.f; Diagnostic(ErrorCode.ERR_AmbigExtension, "D.f").WithArguments("E2.extension(object).f()", "E1.extension(D).f").WithLocation(2, 16), // (2,22): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(object).f()' and 'E1.extension(D).f' // string x = b ? D.f : D.f; Diagnostic(ErrorCode.ERR_AmbigExtension, "D.f").WithArguments("E2.extension(object).f()", "E1.extension(D).f").WithLocation(2, 22)); } [Fact] public void ResolveAll_ConditionalOperator_Static_TwoExtensions_WithTargetDelegateType() { var source = """ bool b = true; System.Action x = b ? D.f : D.f; System.Console.Write(x); class D { } static class E { extension(D) { public static string f => null; } } static class E2 { extension(object o) { public static void f() { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (2,23): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(object).f()' and 'E.extension(D).f' // System.Action x = b ? D.f : D.f; Diagnostic(ErrorCode.ERR_AmbigExtension, "D.f").WithArguments("E2.extension(object).f()", "E.extension(D).f").WithLocation(2, 23), // (2,29): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(object).f()' and 'E.extension(D).f' // System.Action x = b ? D.f : D.f; Diagnostic(ErrorCode.ERR_AmbigExtension, "D.f").WithArguments("E2.extension(object).f()", "E.extension(D).f").WithLocation(2, 29)); } [Fact] public void ResolveAll_Cast_Static_Operand() { var source = """ var x = (long)object.StaticProperty; System.Console.Write(x.ToString()); static class E { extension(object o) { public static int StaticProperty => 42; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.StaticProperty"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.StaticProperty { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.Equal("System.Int32", model.GetTypeInfo(memberAccess).Type.ToTestDisplayString()); AssertEx.Equal("System.Int32", model.GetTypeInfo(memberAccess).ConvertedType.ToTestDisplayString()); } [Fact] public void ResolveAll_Cast_Static_Operand_TwoExtensions() { var source = """ var x = (string)D.f; System.Console.Write(x); class D { } static class E1 { extension(D) { public static string f => "ran"; } } static class E2 { extension(object) { public static void f() { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,17): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(object).f()' and 'E1.extension(D).f' // var x = (string)D.f; Diagnostic(ErrorCode.ERR_AmbigExtension, "D.f").WithArguments("E2.extension(object).f()", "E1.extension(D).f").WithLocation(1, 17)); } [Fact] public void ResolveAll_Cast_Static_Operand_TwoExtensions_DelegateType() { var source = """ var x = (System.Action)D.f; System.Action a = D.f; class D { } static class E1 { extension(D) { public static string f => null; } } static class E2 { extension(object) { public static void f() => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,24): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(object).f()' and 'E1.extension(D).f' // var x = (System.Action)D.f; Diagnostic(ErrorCode.ERR_AmbigExtension, "D.f").WithArguments("E2.extension(object).f()", "E1.extension(D).f").WithLocation(1, 24), // (2,19): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(object).f()' and 'E1.extension(D).f' // System.Action a = D.f; Diagnostic(ErrorCode.ERR_AmbigExtension, "D.f").WithArguments("E2.extension(object).f()", "E1.extension(D).f").WithLocation(2, 19)); // Note: a conversion to a delegate type does not provide invocation context for resolving the member access source = """ var x = (System.Action)D.f; System.Action a = D.f; class C { public static void f() { } } class D : C { public static new string f => null!; } """; comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,9): error CS0030: Cannot convert type 'string' to 'System.Action' // var x = (System.Action)D.f; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(System.Action)D.f").WithArguments("string", "System.Action").WithLocation(1, 9), // (2,19): error CS0029: Cannot implicitly convert type 'string' to 'System.Action' // System.Action a = D.f; Diagnostic(ErrorCode.ERR_NoImplicitConv, "D.f").WithArguments("string", "System.Action").WithLocation(2, 19)); } [Fact] public void ResolveAll_MethodTypeInference() { var source = """ write(object.M); void write<T>(T t) { System.Console.Write(t.ToString()); } static class E { extension(object) { public static int M => 42; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.Equal("System.Int32", model.GetTypeInfo(memberAccess).Type.ToTestDisplayString()); AssertEx.Equal("System.Int32", model.GetTypeInfo(memberAccess).ConvertedType.ToTestDisplayString()); } [Fact] public void ResolveAll_ArrayCreation_Initializer_Static() { var source = """ var x = new[] { object.StaticProperty, object.StaticProperty }; System.Console.Write((x[0], x[1])); static class E { extension(object) { public static int StaticProperty => 42; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "(42, 42)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.StaticProperty").ToArray(); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.StaticProperty { get; }", model.GetSymbolInfo(memberAccess[0]).Symbol.ToTestDisplayString()); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.StaticProperty { get; }", model.GetSymbolInfo(memberAccess[1]).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_ArrayCreation_Rank() { var source = """ var x = new object[object.StaticProperty]; System.Console.Write(x.Length.ToString()); static class E { extension(object o) { public static int StaticProperty => 42; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.StaticProperty"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.StaticProperty { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_Deconstruction_Declaration() { var source = """ var (x, y) = object.M; System.Console.Write((x, y)); static class E { extension(object) { public static (int, int) M => (42, 43); } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("(System.Int32, System.Int32) E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_Deconstruction_Assignment() { var source = """ int x, y; (x, y) = object.M; System.Console.Write((x, y)); static class E { extension(object o) { public static (int, int) M => (42, 43); } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("(System.Int32, System.Int32) E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_TupleExpression() { var source = """ System.Console.Write((object.M, object.M)); static class E { extension(object o) { public static int M => 42; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "(42, 42)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.M").ToArray(); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess[0]).Symbol.ToTestDisplayString()); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess[1]).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_CollectionExpression() { var source = """ int[] x = [object.M]; System.Console.Write(x[0].ToString()); static class E { extension(object o) { public static int M => 42; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_CollectionExpression_ExtensionAddMethod() { var source = """ using System.Collections; using System.Collections.Generic; MyCollection c = [42]; static class E { extension(MyCollection c) { public void Add(int i) { System.Console.Write("ran"); } } } public class MyCollection : IEnumerable<int> { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void ResolveAll_CollectionExpression_ExtensionAddMethod_RefReceiverParameter() { // The receiver argument gets an implicit `ref` when the parameter is `ref` var source = """ using System.Collections; using System.Collections.Generic; MyCollection c = [42]; System.Console.Write(c.field); static class E { extension(ref MyCollection c) { public void Add(int i) { System.Console.Write("ran "); c = new MyCollection() { field = i }; } } } public struct MyCollection : IEnumerable<int> { public int field; IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran 42").VerifyDiagnostics(); } [Fact] public void ResolveAll_CollectionExpression_ExtensionAddMethod_InReceiverParameter() { var source = """ using System.Collections; using System.Collections.Generic; MyCollection c = [42]; static class E { extension(in MyCollection c) { public void Add(int i) { System.Console.Write("ran"); } } } public struct MyCollection : IEnumerable<int> { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void ResolveAll_CollectionExpression_ExtensionAddMethod_RefParameter() { var source = """ using System.Collections; using System.Collections.Generic; MyCollection c = [42]; static class E { extension(MyCollection c) { public void Add(ref int i) { } } } public class MyCollection : IEnumerable<int> { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (4,18): error CS1954: The best overloaded method match 'E.extension(MyCollection).Add(ref int)' for the collection initializer element cannot be used. Collection initializer 'Add' methods cannot have ref or out parameters. // MyCollection c = [42]; Diagnostic(ErrorCode.ERR_InitializerAddHasParamModifiers, "[42]").WithArguments("E.extension(MyCollection).Add(ref int)").WithLocation(4, 18)); } [Fact] public void ResolveAll_CollectionExpression_ExtensionAdd_DelegateTypeProperty() { var source = """ using System.Collections; using System.Collections.Generic; MyCollection c = [42]; static class E { extension(MyCollection c) { public System.Action<int> Add => (int i) => { }; } } public class MyCollection : IEnumerable<int> { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (4,18): error CS1061: 'MyCollection' does not contain a definition for 'Add' and no accessible extension method 'Add' accepting a first argument of type 'MyCollection' could be found (are you missing a using directive or an assembly reference?) // MyCollection c = [42]; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "[42]").WithArguments("MyCollection", "Add").WithLocation(4, 18) ); source = """ using System.Collections; using System.Collections.Generic; MyCollection c = [42]; public class MyCollection : IEnumerable<int> { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; public System.Action<int> Add => (int i) => { }; } """; comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (4,18): error CS0118: 'Add' is a property but is used like a method // MyCollection c = [42]; Diagnostic(ErrorCode.ERR_BadSKknown, "[42]").WithArguments("Add", "property", "method").WithLocation(4, 18)); } [Fact] public void ResolveAll_CollectionExpression_ExtensionAdd_DynamicTypeProperty() { var source = """ using System.Collections; using System.Collections.Generic; MyCollection c = [42]; static class E { extension(MyCollection c) { public dynamic Add => throw null; } } public class MyCollection : IEnumerable<int> { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (4,18): error CS1061: 'MyCollection' does not contain a definition for 'Add' and no accessible extension method 'Add' accepting a first argument of type 'MyCollection' could be found (are you missing a using directive or an assembly reference?) // MyCollection c = [42]; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "[42]").WithArguments("MyCollection", "Add").WithLocation(4, 18)); source = """ using System.Collections; using System.Collections.Generic; MyCollection c = [42]; public class MyCollection : IEnumerable<int> { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; public dynamic Add => throw null; } """; comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (4,18): error CS0118: 'Add' is a property but is used like a method // MyCollection c = [42]; Diagnostic(ErrorCode.ERR_BadSKknown, "[42]").WithArguments("Add", "property", "method").WithLocation(4, 18)); } [Fact] public void ResolveAll_Initializer_Property() { var source = """ var x = new System.Collections.Generic.List<int>() { object.M }; System.Console.Write(x[0]); static class E { extension(object o) { public static int M => 42; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_Initializer_Method() { var source = """ var x = new System.Collections.Generic.List<int>() { object.M }; static class E { extension(object o) { public static void M() => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,54): error CS1950: The best overloaded Add method 'List<int>.Add(int)' for the collection initializer has some invalid arguments // var x = new System.Collections.Generic.List<int>() { object.M }; Diagnostic(ErrorCode.ERR_BadArgTypesForCollectionAdd, "object.M").WithArguments("System.Collections.Generic.List<int>.Add(int)").WithLocation(1, 54), // (1,54): error CS1503: Argument 1: cannot convert from 'method group' to 'int' // var x = new System.Collections.Generic.List<int>() { object.M }; Diagnostic(ErrorCode.ERR_BadArgType, "object.M").WithArguments("1", "method group", "int").WithLocation(1, 54)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.OverloadResolutionFailure, model.GetSymbolInfo(memberAccess).CandidateReason); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ResolveAll_Initializer_ObjectInitializer() { var source = """ var x = new C() { f = object.M }; System.Console.Write(x.f.ToString()); class C { public int f; } static class E { extension(object o) { public static int M => 42; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_ConditionalAccess_Receiver() { var source = """ System.Console.Write(object.M?.ToString()); static class E { extension(object o) { public static string M => "ran"; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_ConditionalAccess_WhenNotNull_Property() { var source = """ var x = new object()?.M; System.Console.Write(x.ToString()); static class E { extension(object o) { public string M => "ran"; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberBinding = GetSyntax<MemberBindingExpressionSyntax>(tree, ".M"); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberBinding).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_ConditionalAccess_WhenNotNull_Invocation() { var source = """ var x = new object()?.M(); System.Console.Write(x.ToString()); static class E { extension(object o) { public string M() => "ran"; public string M(int i) => throw null; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberBinding = GetSyntax<MemberBindingExpressionSyntax>(tree, ".M"); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberBinding).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_CompoundAssignment_Left() { var source = """ object.M += 41; System.Console.Write(E.M.ToString()); static class E { extension(object o) { public static int M { get => 42; set { } } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; set; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_CompoundAssignment_Right() { var source = """ int x = 1; x += object.M; System.Console.Write(x.ToString()); static class E { extension(object o) { public static int M => 41; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_BinaryOperator_UserDefinedOperator() { var source = """ var x = object.M + object.M; System.Console.Write(x.ToString()); public class C { public static int operator+(C c1, C c2) => 42; } static class E { extension(object o) { public static C M => new C(); } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.M").ToArray(); AssertEx.Equal("C E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess[0]).Symbol.ToTestDisplayString()); AssertEx.Equal("C E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess[1]).Symbol.ToTestDisplayString()); var binaryOp = GetSyntax<BinaryExpressionSyntax>(tree, "object.M + object.M"); AssertEx.Equal("System.Int32 C.op_Addition(C c1, C c2)", model.GetSymbolInfo(binaryOp).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_BinaryOperator_NoUserDefinedOperator() { var source = """ var x = object.M + object.M; System.Console.Write(x.ToString()); public class C { } static class E { extension(object o) { public static C M => new C(); } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,9): error CS0019: Operator '+' cannot be applied to operands of type 'C' and 'C' // var x = object.M + object.M; Diagnostic(ErrorCode.ERR_BadBinaryOps, "object.M + object.M").WithArguments("+", "C", "C").WithLocation(1, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.M").ToArray(); AssertEx.Equal("C E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess[0]).Symbol.ToTestDisplayString()); AssertEx.Equal("C E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess[1]).Symbol.ToTestDisplayString()); var binaryOp = GetSyntax<BinaryExpressionSyntax>(tree, "object.M + object.M"); Assert.Null(model.GetSymbolInfo(binaryOp).Symbol); } [Fact] public void ResolveAll_IncrementOperator() { var source = """ object.M++; public class C { } static class E { extension(object o) { public static int M { get { System.Console.Write("get "); return 41; } set { System.Console.Write($"set({value}) "); } } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "get set(42)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; set; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); var unaryOp = GetSyntax<PostfixUnaryExpressionSyntax>(tree, "object.M++"); AssertEx.Equal("System.Int32 System.Int32.op_Increment(System.Int32 value)", model.GetSymbolInfo(unaryOp).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_UnaryOperator() { var source = """ _ = !object.M; public class C { } static class E { extension(object o) { public static bool M { get { System.Console.Write("ran"); return true; } } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Boolean E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); var unaryOp = GetSyntax<PrefixUnaryExpressionSyntax>(tree, "!object.M"); AssertEx.Equal("System.Boolean System.Boolean.op_LogicalNot(System.Boolean value)", model.GetSymbolInfo(unaryOp).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_NullCoalescingOperator() { var source = """ var x = object.M ?? object.M2; System.Console.Write(x); static class E { extension(object o) { public static string M => null; public static string M2 => "ran"; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M2"); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M2 { get; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_NullCoalescingAssignmentOperator() { var source = """ object.M ??= object.M2; static class E { extension(object o) { public static string M { get { System.Console.Write("get "); return null; } set { System.Console.Write($"set({value}) "); } } public static string M2 => "ran"; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "get set(ran)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M2"); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M2 { get; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_Query_Select() { var source = """ using System.Linq; int[] array = [1]; var r = from int i in array select object.M; foreach (var x in r) { System.Console.Write(x.ToString()); } static class E { extension(object o) { public static string M => "ran"; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_Query_Where_DelegateTypeProperty() { var src = """ var x = from i in new C() where i is not null select i; System.Console.Write(x); public class C { } public static class E { extension(C c) { public System.Func<System.Func<C, bool>, C> Where => (System.Func<C, bool> f) => { System.Console.Write(f(c)); return c; }; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "TrueC").VerifyDiagnostics(); src = """ var x = from i in new C() where i is not null select i; System.Console.Write(x); public class C { public System.Func<System.Func<C, bool>, C> Where => (System.Func<C, bool> f) => { System.Console.Write(f(this)); return this; }; } """; comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "TrueC").VerifyDiagnostics(); } [Fact] public void ResolveAll_Query_Where_DynamicTypeProperty() { var src = """ var x = from i in new C() where i is not null select i; public class C { } public static class E { extension(C c) { public dynamic Where => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,15): error CS1977: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type. // where i is not null Diagnostic(ErrorCode.ERR_BadDynamicMethodArgLambda, "i is not null").WithLocation(2, 15)); src = """ var x = from i in new C() where i is not null select i; public class C { public dynamic Where => throw null; } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,9): error CS1979: Query expressions over source type 'dynamic' or with a join sequence of type 'dynamic' are not allowed // where i is not null Diagnostic(ErrorCode.ERR_BadDynamicQuery, "where i is not null").WithLocation(2, 9)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80008")] public void ResolveAll_Query_Cast_StaticProperty() { var source = """ using System.Linq; var r = from string s in object.M from string s2 in object.M2 select s.ToString(); foreach (var x in r) { System.Console.Write(x.ToString()); } static class E { extension(object o) { public static object[] M => ["ran"]; public static object[] M2 => [""]; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Object[] E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M2"); AssertEx.Equal("System.Object[] E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M2 { get; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80008")] public void ResolveAll_Query_Cast_InstanceProperty() { var source = """ using System.Linq; var o = new object(); var r = from string s in o.M from string s2 in o.M2 select s.ToString(); foreach (var x in r) { System.Console.Write(x.ToString()); } static class E { extension(object o) { public object[] M => ["ran"]; public object[] M2 => [""]; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "o.M"); AssertEx.Equal("System.Object[] E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "o.M2"); AssertEx.Equal("System.Object[] E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M2 { get; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_Return_Lambda() { var source = """ var x = () => { bool b = true; if (b) return object.M; else return object.M2; }; System.Console.Write(x().ToString()); static class E { extension(object o) { public static int M => 42; public static int M2 => 0; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M2"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M2 { get; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_ExpressionBodiedLambda() { var source = """ var x = () => object.M; System.Console.Write(x().ToString()); static class E { extension(object o) { public static int M => 42; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_YieldReturn() { var source = """ foreach (var y in local()) { System.Console.Write(y.ToString()); } System.Collections.Generic.IEnumerable<int> local() { bool b = true; if (b) yield return object.M; else yield return object.M2; } static class E { extension(object o) { public static int M => 42; public static int M2 => 0; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M2"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M2 { get; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_YieldReturn_Lambda() { var source = """ var x = System.Collections.Generic.IEnumerable<int> () => { bool b = true; if (b) yield return object.M; else yield return object.M2; }; foreach (var y in x()) { System.Console.Write(y.ToString()); } static class E { extension(object o) { public static int M => 42; public static int M2 => 0; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,56): error CS1643: Not all code paths return a value in lambda expression of type 'Func<IEnumerable<int>>' // var x = System.Collections.Generic.IEnumerable<int> () => Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "System.Func<System.Collections.Generic.IEnumerable<int>>").WithLocation(1, 56), // (5,13): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression // yield return object.M; Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(5, 13), // (7,13): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression // yield return object.M2; Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(7, 13)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M2"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M2 { get; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_Throw() { var source = """ try { throw object.M; } catch (System.Exception e) { System.Console.Write(e.Message); } static class E { extension(object o) { public static System.Exception M => new System.Exception("ran"); } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.Exception E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_FieldInitializer() { var source = """ System.Console.Write(C.field.ToString()); class C { public static string field = object.M; } static class E { extension(object o) { public static string M => "ran"; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_Invocation_Static() { var src = """ local(object.M); void local(string s) { System.Console.Write(s); } static class E { extension(object o) { public static string M => "ran"; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.M").First(); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_Invocation_Static_DelegateTypeParameter() { var src = """ local(object.M); void local(System.Func<string> d) { System.Console.Write(d()); } static class E { extension(object o) { public static string M() => "ran"; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.M").First(); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_Invocation_Static_Inferred() { var src = """ System.Console.Write(local(object.M)); T local<T>(T t) { return t; } static class E { extension(object o) { public static string M => "ran"; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.M").First(); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_Invocation_Static_DelegateTypeParameter_InapplicableInstanceMember() { var src = """ local(object.ToString); void local(System.Func<int, string> d) { System.Console.Write(d(42)); } static class E { extension(object o) { public static string ToString(int i) => "ran"; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.ToString").First(); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.ToString(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_Invocation_Static_DelegateTypeParameter_PropertyAndMethod() { var src = """ var o = new object(); C.M(o.Member); class C { public static void M(System.Action a) { a(); } } static class E1 { extension(object o) { public string Member => throw null; } } public static class E2 { public static void Member(this object o) => throw null; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,5): error CS9339: The extension resolution is ambiguous between the following members: 'E2.Member(object)' and 'E1.extension(object).Member' // C.M(o.Member); Diagnostic(ErrorCode.ERR_AmbigExtension, "o.Member").WithArguments("E2.Member(object)", "E1.extension(object).Member").WithLocation(2, 5)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "o.Member"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); AssertEx.SequenceEqual(["System.String E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Member { get; }", "void E2.Member(this System.Object o)"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void ResolveAll_ObjectCreation_Static() { var source = """ new C(object.M); class C { public C(string s) { System.Console.Write(s); } } static class E { extension(object o) { public static string M => "ran"; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_BinaryOperator_Static_TwoExtensions() { var src = """ bool b = D.f + D.f; class C { public static bool operator +(C c, System.Action a) => true; } class D { } static class E1 { extension(D d) { public static C f => null; } } static class E2 { extension(object o) { public static void f() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,10): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(object).f()' and 'E1.extension(D).f' // bool b = D.f + D.f; Diagnostic(ErrorCode.ERR_AmbigExtension, "D.f").WithArguments("E2.extension(object).f()", "E1.extension(D).f").WithLocation(1, 10), // (1,16): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(object).f()' and 'E1.extension(D).f' // bool b = D.f + D.f; Diagnostic(ErrorCode.ERR_AmbigExtension, "D.f").WithArguments("E2.extension(object).f()", "E1.extension(D).f").WithLocation(1, 16)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78830")] public void ResolveAll_Lambda_Static_TwoAsGoodExtensions_LambdaConverted() { var src = """ System.Func<System.Action> l = () => object.f; static class E1 { extension(object o) { public static string f => null; } } static class E2 { extension(object o) { public static void f() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,38): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(object).f()' and 'E1.extension(object).f' // System.Func<System.Action> l = () => object.f; Diagnostic(ErrorCode.ERR_AmbigExtension, "object.f").WithArguments("E2.extension(object).f()", "E1.extension(object).f").WithLocation(1, 38) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.f").First(); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.String E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.f { get; }", "void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.f()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void ResolveAll_Lambda_Instance_ExtensionMethodVsExtensionMember() { var src = """ System.Func<System.Action> lambda = () => new object().Member; static class E { extension(object o) { public string Member => throw null; } public static void Member(this object o) => throw null; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,43): error CS9339: The extension resolution is ambiguous between the following members: 'E.Member(object)' and 'E.extension(object).Member' // System.Func<System.Action> lambda = () => new object().Member; Diagnostic(ErrorCode.ERR_AmbigExtension, "new object().Member").WithArguments("E.Member(object)", "E.extension(object).Member").WithLocation(1, 43)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().Member"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); } [Fact] public void ResolveAll_Lambda_Instance_MethodGroupWithMultipleOverloads() { var src = """ System.Func<System.Action> lambda = () => new object().Member; lambda()(); static class E { extension(object o) { public void Member() { System.Console.Write("ran"); } public void Member(int i) => throw null; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().Member"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ResolveAll_Lambda_Static_TwoExtensions_ConversionToDelegateType_ExplicitReturnType() { var src = """ var l = System.Action () => D.f; class D { } static class E1 { extension(object o) { public static string f => null; } } static class E2 { extension(object o) { public static void f() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,29): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(object).f()' and 'E1.extension(object).f' // var l = System.Action () => D.f; Diagnostic(ErrorCode.ERR_AmbigExtension, "D.f").WithArguments("E2.extension(object).f()", "E1.extension(object).f").WithLocation(1, 29) ); } [Fact] public void ResolveAll_Lambda_Static_TwoExtensions_ConversionToDelegateType() { var src = """ System.Func<System.Action> l = () => D.f; class D { } static class E1 { extension(D) { public static string f => null; } } static class E2 { extension(object) { public static void f() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,38): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(object).f()' and 'E1.extension(D).f' // System.Func<System.Action> l = () => D.f; Diagnostic(ErrorCode.ERR_AmbigExtension, "D.f").WithArguments("E2.extension(object).f()", "E1.extension(D).f").WithLocation(1, 38) ); } [Fact] public void ResolveAll_SwitchExpression_Static_Default() { var src = """ bool b = true; var s = b switch { true => object.f, false => default }; System.Console.Write(s); static class E { extension(object) { public static string f => "hi"; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "hi").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.f").First(); AssertEx.Equal("System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.f { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); var defaultExpr = GetSyntax<LiteralExpressionSyntax>(tree, "default"); AssertEx.Equal("System.String", model.GetTypeInfo(defaultExpr).Type.ToTestDisplayString()); AssertEx.Equal("System.String", model.GetTypeInfo(defaultExpr).ConvertedType.ToTestDisplayString()); } [Fact] public void ResolveAll_RefTernary() { var src = """ bool b = true; string s1 = "ran"; string s2 = null; var x = b ? ref s1.f : ref s2.f; System.Console.Write(x); static class E { extension(ref string s) { public ref string f => ref s; } public static ref string M(this ref string s) => ref s; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,20): error CS1061: 'string' does not contain a definition for 'f' and no accessible extension method 'f' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) // var x = b ? ref s1.f : ref s2.f; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "f").WithArguments("string", "f").WithLocation(5, 20), // (5,31): error CS1061: 'string' does not contain a definition for 'f' and no accessible extension method 'f' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) // var x = b ? ref s1.f : ref s2.f; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "f").WithArguments("string", "f").WithLocation(5, 31), // (10,19): error CS9300: The 'ref' receiver parameter of an extension block must be a value type or a generic type constrained to struct. // extension(ref string s) Diagnostic(ErrorCode.ERR_RefExtensionParameterMustBeValueTypeOrConstrainedToOne, "string").WithLocation(10, 19), // (15,30): error CS8337: The first parameter of a 'ref' extension method 'M' must be a value type or a generic type constrained to struct. // public static ref string M(this ref string s) => ref s; Diagnostic(ErrorCode.ERR_RefExtensionMustBeValueTypeOrConstrainedToOne, "M").WithArguments("M").WithLocation(15, 30)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s1.f"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); } [Fact] public void ResolveAll_Query_Static_InstanceMethodGroup() { var src = """ string query = from x in object.ToString select x; static class E { extension(object) { public static string ToString() => null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,33): error CS0119: 'object.ToString()' is a method, which is not valid in the given context // string query = from x in object.ToString select x; Diagnostic(ErrorCode.ERR_BadSKunknown, "ToString").WithArguments("object.ToString()", "method").WithLocation(1, 33)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.ToString"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.String System.Object.ToString()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ResolveAll_Query_Static_ExtensionMethodGroup() { var src = """ string query = from x in object.M select x; static class E { extension(object o) { public static string M() => null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,33): error CS0119: 'E.extension(object).M()' is a method, which is not valid in the given context // string query = from x in object.M select x; Diagnostic(ErrorCode.ERR_BadSKunknown, "M").WithArguments("E.extension(object).M()", "method").WithLocation(1, 33)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Empty(model.GetMemberGroup(memberAccess)); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : consider handling BoundBadExpression better } [Fact] public void ResolveAll_Instance_Invocation_InnerInapplicableExtensionMethodVsOuterInvocableExtensionProperty() { var src = """ namespace N { public class C { public static void Main() { new object().M(); } } public static class Extension { public static void M(this object o, int i) { } // not applicable because of second parameter } } static class E { extension(object o) { public System.Action M => () => { System.Console.Write("ran"); }; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.Equal("System.Action E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : handle GetMemberGroup on a property access } [Fact] public void ResolveAll_Instance_Invocation_InnerIrrelevantExtensionMethodVsOuterInvocableExtensionProperty() { var src = """ namespace N { public class C { public static void Main() { new object().M(); } } public static class Extension { public static void M(this string o, int i) { } // not eligible because of `this` parameter } } static class E { extension(object o) { public System.Action M => () => { System.Console.Write("ran"); }; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.Equal("System.Action E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : handle GetMemberGroup on a property access } [Fact] public void ResolveAll_Instance_InferredVariable_InnerExtensionMethodVsOuterInvocableExtensionProperty() { var src = """ namespace N { public class C { public static void Main() { var x = new object().M; x(42); } } public static class Extension { public static void M(this object o, int i) { System.Console.Write("ran"); } } } static class E { extension(object o) { public System.Action M => () => throw null; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.Equal("void System.Object.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void System.Object.M(System.Int32 i)", "System.Action E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ResolveAll_Instance_LocalDeclaration_InnerExtensionMethodVsOuterExtensionProperty() { var src = """ namespace N { public class C { public static void Main() { int x = new object().M; } } public static class Extension { public static void M(this object o, int i) { } } } static class E { extension(object o) { public int M => 42; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // (7,34): error CS0428: Cannot convert method group 'M' to non-delegate type 'int'. Did you intend to invoke the method? // int x = new object().M; Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "M").WithArguments("M", "int").WithLocation(7, 34)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void System.Object.M(System.Int32 i)", "System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ResolveAll_Static_LocalDeclaration_InnerExtensionMethodVsOuterExtensionProperty() { var src = """ namespace N { public class C { public static void Main() { int x = object.M; } } public static class Extension { public static void M(this object o, int i) { } } } static class E { extension(object o) { public static int M => 42; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // (7,28): error CS0428: Cannot convert method group 'M' to non-delegate type 'int'. Did you intend to invoke the method? // int x = object.M; Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "M").WithArguments("M", "int").WithLocation(7, 28)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void System.Object.M(System.Int32 i)", "System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ResolveAll_Static_LocalDeclaration_InstanceInnerExtensionTypeMethodVsOuterExtensionProperty() { var src = """ namespace N { public class C { public static void Main() { int x = object.M; } } static class E1 { extension(object o) { public void M(int i) { } } } } static class E2 { extension(object) { public static int M => 42; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // (7,28): error CS0428: Cannot convert method group 'M' to non-delegate type 'int'. Did you intend to invoke the method? // int x = object.M; Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "M").WithArguments("M", "int").WithLocation(7, 28)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void N.E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M(System.Int32 i)", "System.Int32 E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ResolveAll_Instance_LocalDeclaration_StaticInnerExtensionTypeMethodVsOuterExtensionProperty() { var src = """ namespace N { public class C { public static void Main() { int x = new object().M; } } static class E1 { extension(object) { public static void M(int i) => throw null; } } } static class E2 { extension(object o) { public int M => 42; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // (7,34): error CS0428: Cannot convert method group 'M' to non-delegate type 'int'. Did you intend to invoke the method? // int x = new object().M; Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "M").WithArguments("M", "int").WithLocation(7, 34)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void N.E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M(System.Int32 i)", "System.Int32 E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ResolveAll_Instance_LocalDeclaration_InnerIrrelevantExtensionMethodVsOuterExtensionProperty() { var src = """ namespace N { public class C { public static void Main() { int x = new object().M; System.Console.Write(x); } } public static class Extension { public static void M(this string o, int i) { } // not eligible because of `this` parameter } } static class E { extension(object o) { public int M => 42; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : handle GetMemberGroup on a property access } [Fact] public void ResolveAll_Instance_LocalDeclaration_DelegateType_InnerInapplicableExtensionMethodVsOuterExtensionProperty() { var src = """ namespace N { public class C { public static void Main() { System.Action x = new object().M; x(); } } public static class Extension { public static void M(this object o, int i) { } } } static class E { extension(object o) { public void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void System.Object.M(System.Int32 i)", "void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ResolveAll_Instance_LocalDeclaration_DelegateType_InnerIrrelevantExtensionMethodVsOuterExtensionProperty() { var src = """ namespace N { public class C { public static void Main() { System.Action x = new object().M; x(); } } public static class Extension { public static void M(this string o, int i) { } // not eligible because of `this` parameter } } static class E { extension(object o) { public void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ResolveAll_ConditionalOperator_Static_TwoAsGoodExtensions_Property() { var source = """ bool b = true; var x = b ? object.StaticProperty : object.StaticProperty; static class E1 { extension(object) { public static int StaticProperty => 42; } } static class E2 { extension(object) { public static int StaticProperty => 42; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (2,13): error CS9339: The extension resolution is ambiguous between the following members: 'E1.extension(object).StaticProperty' and 'E2.extension(object).StaticProperty' // var x = b ? object.StaticProperty : object.StaticProperty; Diagnostic(ErrorCode.ERR_AmbigExtension, "object.StaticProperty").WithArguments("E1.extension(object).StaticProperty", "E2.extension(object).StaticProperty").WithLocation(2, 13), // (2,37): error CS9339: The extension resolution is ambiguous between the following members: 'E1.extension(object).StaticProperty' and 'E2.extension(object).StaticProperty' // var x = b ? object.StaticProperty : object.StaticProperty; Diagnostic(ErrorCode.ERR_AmbigExtension, "object.StaticProperty").WithArguments("E1.extension(object).StaticProperty", "E2.extension(object).StaticProperty").WithLocation(2, 37)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.StaticProperty").ToArray(); Assert.Null(model.GetSymbolInfo(memberAccess[0]).Symbol); Assert.Null(model.GetSymbolInfo(memberAccess[1]).Symbol); } [Fact] public void DelegateConversion_TypeReceiver() { var source = """ D d = C.M; d(42); delegate void D(int i); class C { } static class E { extension(C) { public static void M(int i) { System.Console.Write($"E.M({i})"); } } } """; var comp = CreateCompilation(source); var verifier = CompileAndVerify(comp, expectedOutput: "E.M(42)").VerifyDiagnostics(); verifier.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 35 (0x23) .maxstack 2 IL_0000: ldsfld "D Program.<>O.<0>__M" IL_0005: dup IL_0006: brtrue.s IL_001b IL_0008: pop IL_0009: ldnull IL_000a: ldftn "void E.M(int)" IL_0010: newobj "D..ctor(object, System.IntPtr)" IL_0015: dup IL_0016: stsfld "D Program.<>O.<0>__M" IL_001b: ldc.i4.s 42 IL_001d: callvirt "void D.Invoke(int)" IL_0022: ret } """); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.M"); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Null(model.GetTypeInfo(memberAccess).Type); AssertEx.Equal("D", model.GetTypeInfo(memberAccess).ConvertedType.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); Assert.Equal(ConversionKind.MethodGroup, model.GetConversion(memberAccess).Kind); } [Fact] public void DelegateConversion_TypeReceiver_Creation() { var source = """ D d = new D(C.M); d(42); delegate void D(int i); class C { } static class E { extension(C) { public static void M(int i) { System.Console.Write($"E.M({i})"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "E.M(42)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.M"); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Null(model.GetTypeInfo(memberAccess).Type); AssertEx.Equal("D", model.GetTypeInfo(memberAccess).ConvertedType.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); Assert.Equal(ConversionKind.MethodGroup, model.GetConversion(memberAccess).Kind); } [Fact] public void DelegateConversion_InstanceReceiver_Creation() { var source = """ D d = new D(new C().M); d(42); delegate void D(int i); class C { } static class E { extension(C c) { public void M(int i) { System.Console.Write($"E.M({i})"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "E.M(42)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M"); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Null(model.GetTypeInfo(memberAccess).Type); AssertEx.Equal("D", model.GetTypeInfo(memberAccess).ConvertedType.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); Assert.Equal(ConversionKind.MethodGroup, model.GetConversion(memberAccess).Kind); } [Fact] public void DelegateConversion_InstanceReceiver() { var source = """ D d = new C(42).M; d(43); delegate void D(int i); class C(int x) { public int x = x; public void M() => throw null; } static class E { extension(C c) { public void M(int i) { System.Console.Write($"{c.x}.M({i})"); } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: "42.M(43)").VerifyDiagnostics(); verifier.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 26 (0x1a) .maxstack 2 IL_0000: ldc.i4.s 42 IL_0002: newobj "C..ctor(int)" IL_0007: ldftn "void E.M(C, int)" IL_000d: newobj "D..ctor(object, System.IntPtr)" IL_0012: ldc.i4.s 43 IL_0014: callvirt "void D.Invoke(int)" IL_0019: ret } """); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C(42).M"); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void C.M()", "void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); Assert.Equal(ConversionKind.MethodGroup, model.GetConversion(memberAccess).Kind); } [Fact] public void DelegateConversion_TypeReceiver_Overloads() { var source = """ D d = C.M; d(42); C.M(42); delegate void D(int i); class C { } static class E { extension(C) { public static void M(int i) { System.Console.Write("ran "); } public static void M(string s) => throw null; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "C.M").First(); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", "void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.String s)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_ValueReceiver_Overloads() { var source = """ D d = new C().M; d(42); new C().M(42); delegate void D(int i); class C { } static class E { extension(C c) { public void M(int i) { System.Console.Write("ran "); } public void M(string s) => throw null; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "new C().M").First(); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", "void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.String s)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_TypeReceiver_Overloads_DifferentExtensions() { var source = """ D d = C.M; d(42); C.M(42); delegate void D(int i); class C { } static class E1 { extension(C) { public static void M(int i) { System.Console.Write("ran "); } } } static class E2 { extension(C) { public static void M(string s) => throw null; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "C.M").First(); AssertEx.Equal("void E1.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E1.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", "void E2.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.String s)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_WrongSignature() { var source = """ D d = new C().M; d(42); new C().M(42); delegate void D(int i); class C { } static class E { extension(C c) { public void M(string s) => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,15): error CS0123: No overload for 'M' matches delegate 'D' // D d = new C().M; Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M").WithArguments("M", "D").WithLocation(1, 15), // (4,11): error CS1503: Argument 2: cannot convert from 'int' to 'string' // new C().M(42); Diagnostic(ErrorCode.ERR_BadArgType, "42").WithArguments("2", "int", "string").WithLocation(4, 11)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "new C().M").First(); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.String s)"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.String s)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_TypeReceiver_ZeroArityMatchesAny() { var source = """ D d = object.Method; d(""); d = object.Method<string>; d(""); delegate void D(string s); static class E { extension(object) { public static void Method(int i) => throw null; public static void Method<T>(T t) { System.Console.Write("Method "); } public static void Method<T1, T2>(T1 t1, T2 t2) => throw null; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "Method Method").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.Method"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method<System.String>(System.String t)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method(System.Int32 i)", "void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method<T>(T t)", "void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method<T1, T2>(T1 t1, T2 t2)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_ValueReceiver_Overloads_OuterScope_WithInapplicableInstanceMember() { var source = """ using N; D d = new C().M; d(42); new C().M(42); delegate void D(int i); class C { public void M(char c) { } } namespace N { static class E1 { extension(C c) { public void M(int i) { System.Console.Write("ran "); } } } } static class E2 { extension(C c) { public void M(string s) => throw null; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "new C().M").First(); AssertEx.Equal("void N.E1.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void C.M(System.Char c)", "void E2.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.String s)", "void N.E1.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_TypeReceiver_Overloads_InnerScope() { var source = """ using N; D d = C.M; d(42); delegate void D(int i); class C { } static class E1 { extension(C) { public static void M(int i) { System.Console.Write("ran"); } } } namespace N { static class E2 { extension(C) { public static void M(int i) => throw null; } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // 0.cs(1,1): hidden CS8019: Unnecessary using directive. // using N; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N;").WithLocation(1, 1)); CompileAndVerify(comp, expectedOutput: "ran"); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.M"); AssertEx.Equal("void E1.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E1.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)", "void N.E2.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_TypeReceiver_TypeArguments_01() { var source = """ D d = object.M<object>; d(42); delegate void D(int i); static class E { extension(object) { public static void M(int i) => throw null; public static void M<T>(int i) { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M<object>"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M<System.Object>(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M<System.Object>(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_TypeReceiver_TypeArguments_02() { var source = """ D d = object.M<object, int>; d(42); delegate void D(int i); static class E { extension(object) { public static void M<T>(T t) { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,14): error CS0117: 'object' does not contain a definition for 'M' // D d = object.M<object, int>; Diagnostic(ErrorCode.ERR_NoSuchMember, "M<object, int>").WithArguments("object", "M").WithLocation(1, 14)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M<object, int>"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Empty(model.GetMemberGroup(memberAccess)); } [Fact] public void DelegateConversion_TypeReceiver_TypeArguments_03() { var source = """ D d = object.M<object, int>; d(42); delegate void D(int i); static class E { extension<T>(T t) { public static void M<U>(U u) { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M<object, int>"); AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M<System.Int32>(System.Int32 u)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M<System.Int32>(System.Int32 u)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_TypeReceiver_TypeArguments_04() { var source = """ D d = object.M<object>; d(42); delegate void D(int i); static class E { extension<T>(T) { public static void M(int i) { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M<object>"); AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_TypeReceiver_OptionalParameter() { var source = """ System.Action a = object.M; System.Action a2 = E.M2; static class E { extension(object) { public static void M(int i = 0) => throw null; } public static void M2(int i = 0) => throw null; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,26): error CS0123: No overload for 'M' matches delegate 'Action' // System.Action a = object.M; Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M").WithArguments("M", "System.Action").WithLocation(1, 26), // (2,22): error CS0123: No overload for 'M2' matches delegate 'Action' // System.Action a2 = E.M2; Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M2").WithArguments("M2", "System.Action").WithLocation(2, 22)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M([System.Int32 i = 0])"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); source = """ static class E { static void Main() { System.Action a2 = E.M2; } public static void M2(int i = 0) => throw null; } """; comp = CreateCompilation(source, parseOptions: TestOptions.Regular7); comp.VerifyEmitDiagnostics( // (5,30): error CS0123: No overload for 'M2' matches delegate 'Action' // System.Action a2 = E.M2; Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M2").WithArguments("M2", "System.Action").WithLocation(5, 30)); } [Fact] public void DelegateConversion_TypeReceiver_ReturnRefKindMismatch() { var source = """ D d = object.M; delegate int D(); static class E { extension(object) { public static ref int M() => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,7): error CS8189: Ref mismatch between 'E.extension(object).M()' and delegate 'D' // D d = object.M; Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "object.M").WithArguments("E.extension(object).M()", "D").WithLocation(1, 7)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.SequenceEqual(["ref System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_TypeReceiver_ReturnTypeMismatch() { var source = """ D d = object.M; delegate int D(); static class E { extension(object) { public static string M() => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,7): error CS0407: 'string E.extension(object).M()' has the wrong return type // D d = object.M; Diagnostic(ErrorCode.ERR_BadRetType, "object.M").WithArguments("E.extension(object).M()", "string").WithLocation(1, 7)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.SequenceEqual(["System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_TypeReceiver_BadParameterConversion() { var source = """ D d = object.M; D2 d2 = object.M2; delegate void D(long l); delegate void D2(int i); static class E { extension(object) { public static void M(int i) => throw null; public static void M2(long l) => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,14): error CS0123: No overload for 'M' matches delegate 'D' // D d = object.M; Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M").WithArguments("M", "D").WithLocation(1, 14), // (2,9): error CS0123: No overload for 'E.extension(object).M2(long)' matches delegate 'D2' // D2 d2 = object.M2; Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "object.M2").WithArguments("E.extension(object).M2(long)", "D2").WithLocation(2, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M(System.Int32 i)"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M2"); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M2(System.Int64 l)"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_TypeReceiver_Conditional() { var source = """ System.Action a = object.M; static class E { extension(object) { [System.Diagnostics.Conditional("DEBUG")] public static void M() => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,19): error CS1618: Cannot create delegate with 'E.extension(object).M()' because it or a method it overrides has a Conditional attribute // System.Action a = object.M; Diagnostic(ErrorCode.ERR_DelegateOnConditional, "object.M").WithArguments("E.extension(object).M()").WithLocation(1, 19)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_TypeReceiver_Partial() { var source = """ System.Action a = object.M; static partial class E { extension(object) { static partial void M(); } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,26): error CS0117: 'object' does not contain a definition for 'M' // System.Action a = object.M; Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("object", "M").WithLocation(1, 26), // (7,29): error CS0751: A partial member must be declared within a partial type // static partial void M(); Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "M").WithLocation(7, 29)); } [Fact] public void DelegateConversion_TypeReceiver_Pointer() { var source = """ D d = object.M; unsafe delegate int* D(); unsafe static class E { extension(object) { public static int* M() => throw null; } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular14, options: TestOptions.UnsafeDebugExe); comp.VerifyEmitDiagnostics( // (1,7): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // D d = object.M; Diagnostic(ErrorCode.ERR_UnsafeNeeded, "object.M").WithLocation(1, 7)); DiagnosticDescription[] expectedPreviewDiagnostics = [ // (1,7): error CS9363: 'E.extension(object).M()' must be used in an unsafe context because it has pointers in its signature // D d = object.M; Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "object.M").WithArguments("E.extension(object).M()").WithLocation(1, 7), ]; comp = CreateCompilation(source, options: TestOptions.UnsafeDebugExe); comp.VerifyEmitDiagnostics(expectedPreviewDiagnostics); comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeDebugExe); comp.VerifyEmitDiagnostics(expectedPreviewDiagnostics); } [Fact] public void DelegateConversion_TypeReceiver_RefReadonlyMismatch() { var source = """ D d = object.M; D2 d2 = object.M2; D d3 = E.M3; D2 d4 = E.M4; delegate void D(ref int i); delegate void D2(ref readonly int i); static class E { extension(object) { public static void M(ref readonly int i) => throw null; public static void M2(ref int i) => throw null; } public static void M3(ref readonly int i) => throw null; public static void M4(ref int i) => throw null; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,7): warning CS9198: Reference kind modifier of parameter 'ref readonly int i' doesn't match the corresponding parameter 'ref int i' in target. // D d = object.M; Diagnostic(ErrorCode.WRN_TargetDifferentRefness, "object.M").WithArguments("ref readonly int i", "ref int i").WithLocation(1, 7), // (2,16): error CS0123: No overload for 'M2' matches delegate 'D2' // D2 d2 = object.M2; Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M2").WithArguments("M2", "D2").WithLocation(2, 16), // (4,8): warning CS9198: Reference kind modifier of parameter 'ref readonly int i' doesn't match the corresponding parameter 'ref int i' in target. // D d3 = E.M3; Diagnostic(ErrorCode.WRN_TargetDifferentRefness, "E.M3").WithArguments("ref readonly int i", "ref int i").WithLocation(4, 8), // (5,11): error CS0123: No overload for 'M4' matches delegate 'D2' // D2 d4 = E.M4; Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "M4").WithArguments("M4", "D2").WithLocation(5, 11)); } [Fact] public void DelegateConversion_TypeReceiver_Obsolete() { var source = """ System.Action a = object.M; static class E { extension(object) { [System.Obsolete("obsolete", true)] public static void M() { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,19): error CS0619: 'E.extension(object).M()' is obsolete: 'obsolete' // System.Action a = object.M; Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "object.M").WithArguments("E.extension(object).M()", "obsolete").WithLocation(1, 19)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_TypeReceiver_ReceiverTypeKind_01() { var source = """ System.Action a = object.M; System.Action a2 = int.M; a(); a2(); static class E { extension(object) { public static void M() { System.Console.Write("ran "); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran ran").VerifyDiagnostics(); } [Fact] public void DelegateConversion_TypeReceiver_ReceiverTypeKind_02() { var source = """ System.Action a2 = int.M; a2(); static class E { extension(int) { public static void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void DelegateConversion_InstanceReceiver_ReceiverTypeKind() { var source = """ object o = null; int i = 0; System.Action a = o.M; System.Action a2 = i.M; static class E { extension(object o) { public void M() => throw null; } extension(int i) { public void M() => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,20): error CS1113: Extension method 'E.extension(int).M()' defined on value type 'int' cannot be used to create delegates // System.Action a2 = i.M; Diagnostic(ErrorCode.ERR_ValueTypeExtDelegate, "i.M").WithArguments("E.extension(int).M()", "int").WithLocation(5, 20)); } [Fact] public void DelegateConversion_InstanceReceiver_RefStructReceiver() { var source = """ System.Span<int> s = default; System.Action a = s.M; static class E { extension(object o) { public void M() => throw null; } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (3,21): error CS1061: 'Span<int>' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'Span<int>' could be found (are you missing a using directive or an assembly reference?) // System.Action a = s.M; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("System.Span<int>", "M").WithLocation(3, 21)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.M"); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void DelegateConversion_TypeReceiver_RefStructReceiver() { var source = """ System.Action a = System.Span<int>.M; static class E { extension(object) { public static void M() => throw null; } } """; // Note: we apply the same conversion requirements even though no conversion on the receiver // is needed in a static scenario. var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (1,36): error CS0117: 'Span<int>' does not contain a definition for 'M' // System.Action a = System.Span<int>.M; Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("System.Span<int>", "M").WithLocation(1, 36)); } [Fact] public void InstancePropertyAccess_Obsolete() { var src = """ _ = new object().Property; new object().Property = 43; static class E { extension(object o) { [System.Obsolete("Property is obsolete", true)] public int Property { get => 42; set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,5): error CS0619: 'E.extension(object).Property' is obsolete: 'Property is obsolete' // _ = new object().Property; Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "new object().Property").WithArguments("E.extension(object).Property", "Property is obsolete").WithLocation(1, 5), // (2,1): error CS0619: 'E.extension(object).Property' is obsolete: 'Property is obsolete' // new object().Property = 43; Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "new object().Property").WithArguments("E.extension(object).Property", "Property is obsolete").WithLocation(2, 1)); } [Fact] public void StaticPropertyAccess_Obsolete() { var src = """ _ = object.Property; object.Property = 43; static class E { extension(object) { [System.Obsolete("Property is obsolete", true)] public static int Property { get => 42; set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,5): error CS0619: 'E.extension(object).Property' is obsolete: 'Property is obsolete' // _ = object.Property; Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "object.Property").WithArguments("E.extension(object).Property", "Property is obsolete").WithLocation(1, 5), // (2,1): error CS0619: 'E.extension(object).Property' is obsolete: 'Property is obsolete' // object.Property = 43; Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "object.Property").WithArguments("E.extension(object).Property", "Property is obsolete").WithLocation(2, 1)); } [Fact] public void InstancePropertyAccess_Obsolete_InInvocation() { var src = """ new object().Property(); static class E { extension(object o) { [System.Obsolete("Property is obsolete", true)] public System.Action Property { get => throw null; set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS0619: 'E.extension(object).Property' is obsolete: 'Property is obsolete' // new object().Property(); Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "new object().Property").WithArguments("E.extension(object).Property", "Property is obsolete").WithLocation(1, 1)); } [Fact] public void InstancePropertyAccess_ColorColor() { var src = """ C.M(new C()); class C { public static void M(C C) { C.Property = 42; } } static class E { extension(C c) { public int Property { set { System.Console.Write(value); } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var property = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.Property"); AssertEx.Equal("System.Int32 E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Property { set; }", model.GetSymbolInfo(property).Symbol.ToTestDisplayString()); Assert.Empty(model.GetMemberGroup(property)); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : handle GetMemberGroup on a property access } [Fact] public void StaticPropertyAccess_ColorColor() { var src = """ C.M(null); class C { public static void M(C C) { C.Property = 42; } } static class E { extension(C c) { public static int Property { set { System.Console.Write("Property"); } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "Property").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var property = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.Property"); AssertEx.Equal("System.Int32 E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Property { set; }", model.GetSymbolInfo(property).Symbol.ToTestDisplayString()); Assert.Empty(model.GetMemberGroup(property)); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : handle GetMemberGroup on a property access } [Fact] public void ConditionalReceiver_Property_MemberAccess() { var src = """ bool b = true; System.Console.Write((b ? "" : null).Property.ToString()); static class E { extension(string s) { public int Property => 42; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, """(b ? "" : null).Property"""); AssertEx.Equal("System.Int32 E.<G>$34505F560D9EACF86A87F3ED1F85E448.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PropertyAccess_ReturnNotLValue() { var src = """ object.Property.field = 1; public struct S { public int field; } static class E { extension(object) { public static S Property { get => throw null; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS1612: Cannot modify the return value of 'E.extension(object).Property' because it is not a variable // object.Property.field = 1; Diagnostic(ErrorCode.ERR_ReturnNotLValue, "object.Property").WithArguments("E.extension(object).Property").WithLocation(1, 1)); } [Fact] public void StaticPropertyAccess_RefProperty_01() { var src = """ localFuncRef(ref object.Property); localFuncOut(out object.Property); void localFuncRef(ref int i) => throw null; void localFuncOut(out int i) => throw null; static class E { extension(object) { public static int Property { get => throw null; set => throw null; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,18): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value // localFuncRef(ref object.Property); Diagnostic(ErrorCode.ERR_RefProperty, "object.Property").WithLocation(1, 18), // (2,18): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value // localFuncOut(out object.Property); Diagnostic(ErrorCode.ERR_RefProperty, "object.Property").WithLocation(2, 18)); } [Fact] public void StaticPropertyAccess_RefProperty_02() { var src = """ localFuncRef(ref object.Property); System.Console.Write(E.field); void localFuncRef(ref int i) { i++; } static class E { public static int field = 42; extension(object) { public static ref int Property { get => ref E.field; } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "43").VerifyDiagnostics(); } [Fact] public void StaticPropertyAccess_AssignReadonlyNotField() { var src = """ object.Property = 1; static class E { extension(object) { public static ref readonly int Property { get => throw null; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS8331: Cannot assign to property 'Property' or use it as the right hand side of a ref assignment because it is a readonly variable // object.Property = 1; Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "object.Property").WithArguments("property", "Property").WithLocation(1, 1)); } [Fact] public void StaticPropertyAccess_AssgReadonlyProp() { var src = """ object.Property = 1; static class E { extension(object) { public static int Property { get => throw null; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS0200: Property or indexer 'E.extension(object).Property' cannot be assigned to -- it is read only // object.Property = 1; Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "object.Property").WithArguments("E.extension(object).Property").WithLocation(1, 1)); } [Fact] public void StaticPropertyAccess_InitOnlyProperty() { var src = """ object.Property = 1; static class E { extension(object) { public static int Property { init => throw null; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,38): error CS8856: The 'init' accessor is not valid on static members // public static int Property { init => throw null; } Diagnostic(ErrorCode.ERR_BadInitAccessor, "init").WithLocation(7, 38)); } [Fact] public void InstancePropertyAccess_InitOnlyProperty() { var src = """ new object().Property = 1; static class E { extension(object o) { public int Property { init => throw null; } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (1,1): error CS8852: Init-only property or indexer 'E.extension(object).Property' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor. // new object().Property = 1; Diagnostic(ErrorCode.ERR_AssignmentInitOnly, "new object().Property").WithArguments("E.extension(object).Property").WithLocation(1, 1), // (7,31): error CS9304: 'E.extension(object).Property': cannot declare init-only accessors in an extension block // public int Property { init => throw null; } Diagnostic(ErrorCode.ERR_InitInExtension, "init").WithArguments("E.extension(object).Property").WithLocation(7, 31)); } [Fact] public void InstancePropertyAccess_InitOnlyProperty_ObjectInitializer() { var src = """ _ = new object() { Property = 1 }; static class E { extension(object o) { public int Property { init => throw null; } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (7,31): error CS9304: 'E.extension(object).Property': cannot declare init-only accessors in an extension block // public int Property { init => throw null; } Diagnostic(ErrorCode.ERR_InitInExtension, "init").WithArguments("E.extension(object).Property").WithLocation(7, 31)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntax<AssignmentExpressionSyntax>(tree, "Property = 1"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { init; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString()); } [Fact] public void StaticPropertyAccess_InaccessibleSetter() { var src = """ object.Property = 1; static class E { extension(object) { public static int Property { get => throw null; private set => throw null; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS0272: The property or indexer 'E.extension(object).Property' cannot be used in this context because the set accessor is inaccessible // object.Property = 1; Diagnostic(ErrorCode.ERR_InaccessibleSetter, "object.Property").WithArguments("E.extension(object).Property").WithLocation(1, 1)); } [Fact] public void ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_ExtensionTypeMethods() { // See ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_Method var source = """ struct S1(Color Color) { public void Test() { Color.M1(this); } } class Color { } static class E { extension(Color c) { public void M1(S1 x, int y = 0) { System.Console.WriteLine("instance"); } public static void M1<T>(T x) where T : unmanaged { System.Console.WriteLine("static"); } } } """; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll); comp.VerifyEmitDiagnostics( // (5,9): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. // Color.M1(this); Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(5, 9) ); Assert.NotEmpty(comp.GetTypeByMetadataName("S1").InstanceConstructors.OfType<SynthesizedPrimaryConstructor>().Single().GetCapturedParameters()); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.M1"); AssertEx.Equal("void E.<G>$2404CFB602D7DEE90BDDEF217EC37C58.M1(S1 x, [System.Int32 y = 0])", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_ExtensionTypeProperties() { var source = """ struct S1(Color Color) { public void Test() { _ = Color.P1; } } class Color { } static class E1 { extension(Color c) { public int P1 => 0; } } static class E2 { extension(Color) { public static int P1 => 0; } } """; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll); comp.VerifyEmitDiagnostics( // (5,13): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. // _ = Color.P1; Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(5, 13)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.P1"); AssertEx.Equal("System.Int32 E1.<G>$2404CFB602D7DEE90BDDEF217EC37C58.P1 { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void ParameterCapturing_023_ColorColor_MemberAccess_InstanceAndStatic_ExtensionTypeMembersVsExtensionMethod() { var source = """ public struct S1(Color Color) { public void Test() { Color.M1(this); } } public class Color { } public static class E1 { public static void M1(this Color c, S1 x, int y = 0) { System.Console.WriteLine("instance"); } } static class E { extension(Color) { public static void M1<T>(T x) where T : unmanaged { System.Console.WriteLine("static"); } } } """; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll); comp.VerifyEmitDiagnostics( // (5,9): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. // Color.M1(this); Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(5, 9) ); Assert.NotEmpty(comp.GetTypeByMetadataName("S1").InstanceConstructors.OfType<SynthesizedPrimaryConstructor>().Single().GetCapturedParameters()); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.M1"); AssertEx.Equal("void Color.M1(S1 x, [System.Int32 y = 0])", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_01() { var source = """ struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } class Color { } static class E1 { extension(Color c) { public System.Action Member => null; } } static class E2 { extension(Color) { public static int Member => 0; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,9): error CS8377: The type 'S1' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'S1.M<T>(T)' // M(this); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("S1.M<T>(T)", "T", "S1").WithLocation(6, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("System.Action E1.<G>$2404CFB602D7DEE90BDDEF217EC37C58.Member { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_02() { var source = """ struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } class Color { public static int Member => 0; } static class E1 { public static void Member(this Color c) { } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,9): error CS8377: The type 'S1' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'S1.M<T>(T)' // M(this); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("S1.M<T>(T)", "T", "S1").WithLocation(6, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("void Color.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_03() { // Non-invocable candidate is out of the picture, so we're left with only the instance candidate var source = """ struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } class Color { } static class E1 { extension(Color c) { public void Member() { } } } static class E2 { extension(Color) { public static int Member => 0; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,9): error CS8377: The type 'S1' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'S1.M<T>(T)' // M(this); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("S1.M<T>(T)", "T", "S1").WithLocation(6, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("void E1.<G>$2404CFB602D7DEE90BDDEF217EC37C58.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_04() { // Non-invocable candidate is out of the picture, so we're left with only the static candidate var source = """ struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } class Color { } static class E1 { extension(Color) { public static void Member() { } } } static class E2 { extension(Color c) { public int Member => 0; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,17): warning CS9113: Parameter 'Color' is unread. // struct S1(Color Color) Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "Color").WithArguments("Color").WithLocation(1, 17)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("void E1.<G>$2404CFB602D7DEE90BDDEF217EC37C58.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_05() { var source = """ struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } class Color { } static class E1 { extension(Color c) { public void Member() { } } } static class E2 { extension(Color) { public static System.Action Member => null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,9): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. // Color.Member(); Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(5, 9), // (6,9): error CS8377: The type 'S1' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'S1.M<T>(T)' // M(this); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("S1.M<T>(T)", "T", "S1").WithLocation(6, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("void E1.<G>$2404CFB602D7DEE90BDDEF217EC37C58.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_06() { var source = """ struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } class Color { } static class E1 { extension(Color c) { public void Member() { } } } static class E2 { extension(Color) { public static void Member(int i) { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,9): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. // Color.Member(); Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(5, 9), // (6,9): error CS8377: The type 'S1' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'S1.M<T>(T)' // M(this); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("S1.M<T>(T)", "T", "S1").WithLocation(6, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("void E1.<G>$2404CFB602D7DEE90BDDEF217EC37C58.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_07() { // instance extension method in inner scope, static extension method in outer scope var source = """ namespace N { struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } static class E1 { extension(Color c) { public void Member() { } } } } class Color { } static class E2 { extension(Color) { public static void Member() { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (7,13): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. // Color.Member(); Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(7, 13), // (8,13): error CS8377: The type 'S1' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'S1.M<T>(T)' // M(this); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("N.S1.M<T>(T)", "T", "N.S1").WithLocation(8, 13)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("void N.E1.<G>$2404CFB602D7DEE90BDDEF217EC37C58.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_08() { // static extension method in inner scope, instance extension method in outer scope var source = """ namespace N { struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } static class E1 { extension(Color) { public static void Member() { } } } } class Color { } static class E2 { extension(Color c) { public void Member() { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (7,13): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. // Color.Member(); Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(7, 13), // (8,13): error CS8377: The type 'S1' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'S1.M<T>(T)' // M(this); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("N.S1.M<T>(T)", "T", "N.S1").WithLocation(8, 13)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("void E2.<G>$2404CFB602D7DEE90BDDEF217EC37C58.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_09() { // static extension property in inner scope, instance extension method in outer scope var source = """ namespace N { struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } static class E1 { extension(Color) { public static System.Action Member => throw null; } } } class Color { } static class E2 { extension(Color c) { public void Member() { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (7,13): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. // Color.Member(); Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(7, 13), // (8,13): error CS8377: The type 'S1' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'S1.M<T>(T)' // M(this); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("N.S1.M<T>(T)", "T", "N.S1").WithLocation(8, 13)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("void E2.<G>$2404CFB602D7DEE90BDDEF217EC37C58.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_10() { // inapplicable candidate var source = """ struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } class Color { } static class E1 { extension<T>(T t) where T : struct { public void Member() { } } } static class E2 { extension(Color) { public static void Member() { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,17): warning CS9113: Parameter 'Color' is unread. // struct S1(Color Color) Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "Color").WithArguments("Color").WithLocation(1, 17)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("void E2.<G>$2404CFB602D7DEE90BDDEF217EC37C58.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_11() { // inapplicable candidate var source = """ struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } class Color { } static class E1 { extension<T>(T) where T : struct { public static void Member() { } } } static class E2 { extension(Color c) { public void Member() { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,9): error CS8377: The type 'S1' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'S1.M<T>(T)' // M(this); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("S1.M<T>(T)", "T", "S1").WithLocation(6, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("void E2.<G>$2404CFB602D7DEE90BDDEF217EC37C58.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_12() { // only static candidate method var source = """ struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } class Color { } static class E { extension(Color) { public static void Member() { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,17): warning CS9113: Parameter 'Color' is unread. // struct S1(Color Color) Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "Color").WithArguments("Color").WithLocation(1, 17)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("void E.<G>$2404CFB602D7DEE90BDDEF217EC37C58.Member()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_13() { // only static candidate property, invocable var source = """ struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } class Color { } static class E { extension(Color) { public static System.Action Member => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,17): warning CS9113: Parameter 'Color' is unread. // struct S1(Color Color) Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "Color").WithArguments("Color").WithLocation(1, 17)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("System.Action E.<G>$2404CFB602D7DEE90BDDEF217EC37C58.Member { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_14() { // only static candidate property, non-invocable var source = """ struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } class Color { } static class E { extension(Color) { public static int Member => 0; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,17): warning CS9113: Parameter 'Color' is unread. // struct S1(Color Color) Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "Color").WithArguments("Color").WithLocation(1, 17), // (5,15): error CS1061: 'Color' does not contain a definition for 'Member' and no accessible extension method 'Member' accepting a first argument of type 'Color' could be found (are you missing a using directive or an assembly reference?) // Color.Member(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Member").WithArguments("Color", "Member").WithLocation(5, 15)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); } [Fact] public void PrimaryCtorParameterCapturing_15() { // only instance candidate property, invocable var source = """ struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } class Color { } static class E { extension(Color c) { public System.Action Member => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,9): error CS8377: The type 'S1' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'S1.M<T>(T)' // M(this); Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("S1.M<T>(T)", "T", "S1").WithLocation(6, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); AssertEx.Equal("System.Action E.<G>$2404CFB602D7DEE90BDDEF217EC37C58.Member { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PrimaryCtorParameterCapturing_16() { // only instance candidate property, non-invocable var source = """ struct S1(Color Color) { public void Test() { Color.Member(); M(this); } public static void M<T>(T x) where T : unmanaged { } } class Color { } static class E { extension(Color c) { public int Member => 0; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,17): warning CS9113: Parameter 'Color' is unread. // struct S1(Color Color) Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "Color").WithArguments("Color").WithLocation(1, 17), // (5,15): error CS1061: 'Color' does not contain a definition for 'Member' and no accessible extension method 'Member' accepting a first argument of type 'Color' could be found (are you missing a using directive or an assembly reference?) // Color.Member(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Member").WithArguments("Color", "Member").WithLocation(5, 15)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.Member"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); } [Fact] public void PrimaryCtorParameterCapturing_17() { // non-extension method not applicable due to arity var source = """ new S1(new Color()).Test(); struct S1(Color Color) { public void Test() { Color.Member<int>(0); } } class Color { public static void Member(int x) => throw null; } static class E { extension(Color c) { public void Member<T>(T x) { System.Console.WriteLine("extension"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "extension").VerifyDiagnostics(); Assert.NotEmpty(comp.GetTypeByMetadataName("S1").InstanceConstructors.OfType<SynthesizedPrimaryConstructor>().Single().GetCapturedParameters()); } [Fact] public void PrimaryCtorParameterCapturing_18() { // non-extension method not applicable due to arity, and non-extension method applicable, and instance extension method var source = """ struct S1(Color Color) { public void Test() { Color.Member<int>(0); } } class Color { public static void Member(int x) => throw null; public static void Member<T>(T x) => throw null; } static class E { extension(Color c) { public void Member<T>(T x) { System.Console.WriteLine("extension"); } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,9): error CS9106: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context. // Color.Member<int>(0); Diagnostic(ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver, "Color").WithArguments("Color", "Color", "Color Color").WithLocation(5, 9)); } [Fact] public void PrimaryCtorParameterCapturing_19() { // non-extension method not applicable due to arity, and non-extension method applicable, and static extension method var source = """ new S1(new Color()).Test(); struct S1(Color Color) { public void Test() { Color.Member<int>(0); } } class Color { public static void Member(int x) => throw null; public static void Member<T>(T x) => throw null; } static class E { extension(Color) { public static void Member<T>(T x) { System.Console.WriteLine("extension"); } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (3,17): warning CS9113: Parameter 'Color' is unread. // struct S1(Color Color) Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "Color").WithArguments("Color").WithLocation(3, 17)); } [Fact] public void InstanceMethod_MemberAccess() { var src = """ new object().M.ToString(); static class E { extension(object o) { public int M() => 42; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,14): error CS0119: 'E.extension(object).M()' is a method, which is not valid in the given context // new object().M.ToString(); Diagnostic(ErrorCode.ERR_BadSKunknown, "M").WithArguments("E.extension(object).M()", "method").WithLocation(1, 14)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); src = """ new object().M.ToString(); static class E { public static int M(this object o) => 42; } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,14): error CS0119: 'E.M(object)' is a method, which is not valid in the given context // new object().M.ToString(); Diagnostic(ErrorCode.ERR_BadSKunknown, "M").WithArguments("E.M(object)", "method").WithLocation(1, 14)); tree = comp.SyntaxTrees.Single(); model = comp.GetSemanticModel(tree); memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void InstanceMethod_MemberAccess_Missing() { var src = """ new object().M.ToString(); """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,14): error CS1061: 'object' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // new object().M.ToString(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("object", "M").WithLocation(1, 14)); } [Fact] public void CheckValueKind_AssignToMethodGroup() { var src = """ object.M = null; static class E { extension(object) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS1656: Cannot assign to 'M' because it is a 'method group' // object.M = null; Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "object.M").WithArguments("M", "method group").WithLocation(1, 1)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.NotAVariable, model.GetSymbolInfo(memberAccess).CandidateReason); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void AccessOnVoid_Invocation() { var src = """ object.M().ToString(); static class E { extension(object) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,11): error CS0023: Operator '.' cannot be applied to operand of type 'void' // object.M().ToString(); Diagnostic(ErrorCode.ERR_BadUnaryOp, ".").WithArguments(".", "void").WithLocation(1, 11)); } [Fact] public void ExtensionMemberLookup_InaccessibleMembers_01() { var src = """ object.Method(); _ = object.Property; static class E { extension(object o) { private static void Method() => throw null; private static int Property => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,8): error CS0117: 'object' does not contain a definition for 'Method' // object.Method(); Diagnostic(ErrorCode.ERR_NoSuchMember, "Method").WithArguments("object", "Method").WithLocation(1, 8), // (2,12): error CS0117: 'object' does not contain a definition for 'Property' // _ = object.Property; Diagnostic(ErrorCode.ERR_NoSuchMember, "Property").WithArguments("object", "Property").WithLocation(2, 12)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.Method"); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method()"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.Property"); Assert.Equal([], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : handle GetMemberGroup on a property access } [Fact] public void ExtensionMemberLookup_InaccessibleMembers_02() { var src = """ /*<bind>*/ object.Member = 42; /*</bind>*/ object.Member.ToString(); object.Member++; public static class E { extension(object) { private static int Member { get => 0; set { } } } } """; DiagnosticDescription[] expectedDiagnostics = [ // (2,8): error CS0117: 'object' does not contain a definition for 'Member' // object.Member = 42; Diagnostic(ErrorCode.ERR_NoSuchMember, "Member").WithArguments("object", "Member").WithLocation(2, 8), // (5,8): error CS0117: 'object' does not contain a definition for 'Member' // object.Member.ToString(); Diagnostic(ErrorCode.ERR_NoSuchMember, "Member").WithArguments("object", "Member").WithLocation(5, 8), // (6,8): error CS0117: 'object' does not contain a definition for 'Member' // object.Member++; Diagnostic(ErrorCode.ERR_NoSuchMember, "Member").WithArguments("object", "Member").WithLocation(6, 8)]; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(expectedDiagnostics); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "object.Member").First(); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); string expectedOperationTree = """ IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'object.Member = 42;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?, IsInvalid) (Syntax: 'object.Member = 42') Left: IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'object.Member') Children(1): IOperation: (OperationKind.None, Type: System.Object) (Syntax: 'object') Right: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') """; VerifyOperationTreeAndDiagnosticsForTest<ExpressionStatementSyntax>(src, expectedOperationTree, expectedDiagnostics); } [Fact] public void ExtensionMemberLookup_InterpolationHandler_Simple() { var src = """ _ = f($"{(object)1} {f2()}"); static int f(InterpolationHandler s) => 0; static string f2() => "hello"; [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount) => throw null; public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics(); } [Fact] public void ExtensionMemberLookup_InterpolationHandler_AppendLiteralExtensionMethod() { var src = """ _ = f($"{(object)1} {f2()}"); static int f(InterpolationHandler s) => 0; static string f2() => "hello"; [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount) => throw null; public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class Extensions { public static void AppendLiteral(this InterpolationHandler ih, string value) { } } """; // Interpolation handlers don't allow extension methods var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (1,20): error CS1061: 'InterpolationHandler' does not contain a definition for 'AppendLiteral' and no accessible extension method 'AppendLiteral' accepting a first argument of type 'InterpolationHandler' could be found (are you missing a using directive or an assembly reference?) // _ = f($"{(object)1} {f2()}"); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, " ").WithArguments("InterpolationHandler", "AppendLiteral").WithLocation(1, 20), // (1,20): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. // _ = f($"{(object)1} {f2()}"); Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, " ").WithArguments("?.()").WithLocation(1, 20)); } [Fact] public void ExtensionMemberLookup_InterpolationHandler_AppendLiteralExtensionDeclarationMethod() { var src = """ _ = f($"{(object)1} {f2()}"); static int f(InterpolationHandler s) => 0; static string f2() => "hello"; [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount) => throw null; public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } static class E { extension(InterpolationHandler i) { public void AppendLiteral(string value) { } } } """; // Interpolation handlers don't allow extension methods var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (1,20): error CS1061: 'InterpolationHandler' does not contain a definition for 'AppendLiteral' and no accessible extension method 'AppendLiteral' accepting a first argument of type 'InterpolationHandler' could be found (are you missing a using directive or an assembly reference?) // _ = f($"{(object)1} {f2()}"); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, " ").WithArguments("InterpolationHandler", "AppendLiteral").WithLocation(1, 20), // (1,20): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. // _ = f($"{(object)1} {f2()}"); Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, " ").WithArguments("?.()").WithLocation(1, 20)); } [Fact] public void ExtensionMemberLookup_InterpolationHandler_AppendFormattedExtensionMethod() { var src = """ /*<bind>*/ _ = f($"{(object)1} {f2()}"); /*</bind>*/ static int f(InterpolationHandler s) => 0; static string f2() => "hello"; [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount) => throw null; public void AppendLiteral(string value) { } } public static class Extensions { public static void AppendFormatted<T>(this InterpolationHandler ih, T hole, int alignment = 0, string format = null) { } } """; // Interpolation handlers don't allow extension methods var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (2,9): error CS1061: 'InterpolationHandler' does not contain a definition for 'AppendFormatted' and no accessible extension method 'AppendFormatted' accepting a first argument of type 'InterpolationHandler' could be found (are you missing a using directive or an assembly reference?) // _ = f($"{(object)1} {f2()}"); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "{(object)1}").WithArguments("InterpolationHandler", "AppendFormatted").WithLocation(2, 9), // (2,9): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. // _ = f($"{(object)1} {f2()}"); Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "{(object)1}").WithArguments("?.()").WithLocation(2, 9), // (2,21): error CS1061: 'InterpolationHandler' does not contain a definition for 'AppendFormatted' and no accessible extension method 'AppendFormatted' accepting a first argument of type 'InterpolationHandler' could be found (are you missing a using directive or an assembly reference?) // _ = f($"{(object)1} {f2()}"); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "{f2()}").WithArguments("InterpolationHandler", "AppendFormatted").WithLocation(2, 21), // (2,21): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. // _ = f($"{(object)1} {f2()}"); Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "{f2()}").WithArguments("?.()").WithLocation(2, 21) ); } [Fact] public void ExtensionMemberLookup_InterpolationHandler_AppendFormattedExtensionTypeMethod() { var src = """ _ = f($"{(object)1} {f2()}"); static int f(InterpolationHandler s) => 0; static string f2() => "hello"; [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount) => throw null; public void AppendLiteral(string value) { } } static class E { extension(InterpolationHandler i) { public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) { } } } """; // Interpolation handlers don't allow extension methods var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (1,9): error CS1061: 'InterpolationHandler' does not contain a definition for 'AppendFormatted' and no accessible extension method 'AppendFormatted' accepting a first argument of type 'InterpolationHandler' could be found (are you missing a using directive or an assembly reference?) // _ = f($"{(object)1} {f2()}"); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "{(object)1}").WithArguments("InterpolationHandler", "AppendFormatted").WithLocation(1, 9), // (1,9): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. // _ = f($"{(object)1} {f2()}"); Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "{(object)1}").WithArguments("?.()").WithLocation(1, 9), // (1,21): error CS1061: 'InterpolationHandler' does not contain a definition for 'AppendFormatted' and no accessible extension method 'AppendFormatted' accepting a first argument of type 'InterpolationHandler' could be found (are you missing a using directive or an assembly reference?) // _ = f($"{(object)1} {f2()}"); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "{f2()}").WithArguments("InterpolationHandler", "AppendFormatted").WithLocation(1, 21), // (1,21): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. // _ = f($"{(object)1} {f2()}"); Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "{f2()}").WithArguments("?.()").WithLocation(1, 21)); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_Identity(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, string s) { System.Console.Write(s); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension(string s) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h) {} } } """; var exeSource = """ "1".M($""); E.M("2", $""); """; var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "12" : null; CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); var verifier = CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) .VerifyDiagnostics(); verifier.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 41 (0x29) .maxstack 4 .locals init (string V_0) IL_0000: ldstr "1" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldc.i4.0 IL_0008: ldc.i4.0 IL_0009: ldloc.0 IL_000a: newobj "InterpolationHandler..ctor(int, int, string)" IL_000f: call "void E.M(string, InterpolationHandler)" IL_0014: ldstr "2" IL_0019: stloc.0 IL_001a: ldloc.0 IL_001b: ldc.i4.0 IL_001c: ldc.i4.0 IL_001d: ldloc.0 IL_001e: newobj "InterpolationHandler..ctor(int, int, string)" IL_0023: call "void E.M(string, InterpolationHandler)" IL_0028: ret } """); var comp = (CSharpCompilation)verifier.Compilation; var tree = comp.SyntaxTrees[0]; var compRoot = tree.GetCompilationUnitRoot(); var model = comp.GetSemanticModel(tree); var opRoot = model.GetOperation(compRoot); VerifyOperationTree(comp, opRoot, expectedOperationTree: """ IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: '"1".M($""); ... ("2", $"");') BlockBody: IBlockOperation (2 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: '"1".M($""); ... ("2", $"");') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '"1".M($"");') Expression: IInvocationOperation ( void E.<G>$34505F560D9EACF86A87F3ED1F85E448.M(InterpolationHandler h)) (OperationKind.Invocation, Type: System.Void) (Syntax: '"1".M($"")') Instance Receiver: ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "1") (Syntax: '"1"') Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: h) (OperationKind.Argument, Type: null) (Syntax: '$""') IInterpolatedStringHandlerCreationOperation (HandlerAppendCallsReturnBool: False, HandlerCreationHasSuccessParameter: False) (OperationKind.InterpolatedStringHandlerCreation, Type: InterpolationHandler, IsImplicit) (Syntax: '$""') Creation: IObjectCreationOperation (Constructor: InterpolationHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount, System.String s)) (OperationKind.ObjectCreation, Type: InterpolationHandler, IsImplicit) (Syntax: '$""') Arguments(3): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$""') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$""') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$""') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$""') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: s) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '"1"') IInterpolatedStringHandlerArgumentPlaceholderOperation (CallsiteReceiver) (OperationKind.InterpolatedStringHandlerArgumentPlaceholder, Type: null, IsImplicit) (Syntax: '"1"') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Initializer: null Content: IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String, Constant: "") (Syntax: '$""') Parts(0) InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'E.M("2", $"");') Expression: IInvocationOperation (void E.M(this System.String s, InterpolationHandler h)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'E.M("2", $"")') Instance Receiver: null Arguments(2): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: s) (OperationKind.Argument, Type: null) (Syntax: '"2"') ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "2") (Syntax: '"2"') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: h) (OperationKind.Argument, Type: null) (Syntax: '$""') IInterpolatedStringHandlerCreationOperation (HandlerAppendCallsReturnBool: False, HandlerCreationHasSuccessParameter: False) (OperationKind.InterpolatedStringHandlerCreation, Type: InterpolationHandler, IsImplicit) (Syntax: '$""') Creation: IObjectCreationOperation (Constructor: InterpolationHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount, System.String s)) (OperationKind.ObjectCreation, Type: InterpolationHandler, IsImplicit) (Syntax: '$""') Arguments(3): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$""') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$""') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$""') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$""') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: s) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '"2"') IInterpolatedStringHandlerArgumentPlaceholderOperation (ArgumentIndex: 0) (OperationKind.InterpolatedStringHandlerArgumentPlaceholder, Type: null, IsImplicit) (Syntax: '"2"') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Initializer: null Content: IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String, Constant: "") (Syntax: '$""') Parts(0) InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) ExpressionBody: null """); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_MultipleEvaluation(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, string s) { System.Console.Write(s); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension(string s) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h) {} } } """; var exeSource = """ Get("1").M($""); E.M(Get("2"), $""); static T Get<T>(T t) { System.Console.Write("Get"); return t; } """; var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "Get1Get2" : null; CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) .VerifyDiagnostics(); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_WithOtherParameters(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, string s1, string s2) { System.Console.Write(s1); System.Console.Write(s2); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension(string s1) { public void M(string s2, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1", "s2")] InterpolationHandler h) {} } } """; var exeSource = """ "1".M("2", $""); E.M("3", "4", $""); """; var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "1234" : null; CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); var verifier = CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) .VerifyDiagnostics(); var comp = (CSharpCompilation)verifier.Compilation; var tree = comp.SyntaxTrees[0]; var compRoot = tree.GetCompilationUnitRoot(); var model = comp.GetSemanticModel(tree); var opRoot = model.GetOperation(compRoot); VerifyOperationTree(comp, opRoot, expectedOperationTree: """ IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: '"1".M("2", ... "4", $"");') BlockBody: IBlockOperation (2 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: '"1".M("2", ... "4", $"");') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '"1".M("2", $"");') Expression: IInvocationOperation ( void E.<G>$34505F560D9EACF86A87F3ED1F85E448.M(System.String s2, InterpolationHandler h)) (OperationKind.Invocation, Type: System.Void) (Syntax: '"1".M("2", $"")') Instance Receiver: ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "1") (Syntax: '"1"') Arguments(2): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: s2) (OperationKind.Argument, Type: null) (Syntax: '"2"') ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "2") (Syntax: '"2"') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: h) (OperationKind.Argument, Type: null) (Syntax: '$""') IInterpolatedStringHandlerCreationOperation (HandlerAppendCallsReturnBool: False, HandlerCreationHasSuccessParameter: False) (OperationKind.InterpolatedStringHandlerCreation, Type: InterpolationHandler, IsImplicit) (Syntax: '$""') Creation: IObjectCreationOperation (Constructor: InterpolationHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount, System.String s1, System.String s2)) (OperationKind.ObjectCreation, Type: InterpolationHandler, IsImplicit) (Syntax: '$""') Arguments(4): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$""') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$""') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$""') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$""') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: s1) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '"1"') IInterpolatedStringHandlerArgumentPlaceholderOperation (CallsiteReceiver) (OperationKind.InterpolatedStringHandlerArgumentPlaceholder, Type: null, IsImplicit) (Syntax: '"1"') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: s2) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '"2"') IInterpolatedStringHandlerArgumentPlaceholderOperation (ArgumentIndex: 0) (OperationKind.InterpolatedStringHandlerArgumentPlaceholder, Type: null, IsImplicit) (Syntax: '"2"') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Initializer: null Content: IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String, Constant: "") (Syntax: '$""') Parts(0) InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'E.M("3", "4", $"");') Expression: IInvocationOperation (void E.M(this System.String s1, System.String s2, InterpolationHandler h)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'E.M("3", "4", $"")') Instance Receiver: null Arguments(3): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: s1) (OperationKind.Argument, Type: null) (Syntax: '"3"') ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "3") (Syntax: '"3"') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: s2) (OperationKind.Argument, Type: null) (Syntax: '"4"') ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "4") (Syntax: '"4"') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: h) (OperationKind.Argument, Type: null) (Syntax: '$""') IInterpolatedStringHandlerCreationOperation (HandlerAppendCallsReturnBool: False, HandlerCreationHasSuccessParameter: False) (OperationKind.InterpolatedStringHandlerCreation, Type: InterpolationHandler, IsImplicit) (Syntax: '$""') Creation: IObjectCreationOperation (Constructor: InterpolationHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount, System.String s1, System.String s2)) (OperationKind.ObjectCreation, Type: InterpolationHandler, IsImplicit) (Syntax: '$""') Arguments(4): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$""') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$""') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$""') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$""') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: s1) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '"3"') IInterpolatedStringHandlerArgumentPlaceholderOperation (ArgumentIndex: 0) (OperationKind.InterpolatedStringHandlerArgumentPlaceholder, Type: null, IsImplicit) (Syntax: '"3"') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: s2) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '"4"') IInterpolatedStringHandlerArgumentPlaceholderOperation (ArgumentIndex: 1) (OperationKind.InterpolatedStringHandlerArgumentPlaceholder, Type: null, IsImplicit) (Syntax: '"4"') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Initializer: null Content: IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String, Constant: "") (Syntax: '$""') Parts(0) InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) ExpressionBody: null """); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_WithConversion(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, object o) { System.Console.Write(o); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension(object o) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("o")] InterpolationHandler h) {} } } """; // The receiver is a string, so there's a BoundConversion to object as the receiver of the extension method var exeSource = """ "1".M($""); E.M("2", $""); """; var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "12" : null; var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 41 (0x29) .maxstack 4 .locals init (object V_0) IL_0000: ldstr "1" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldc.i4.0 IL_0008: ldc.i4.0 IL_0009: ldloc.0 IL_000a: newobj "InterpolationHandler..ctor(int, int, object)" IL_000f: call "void E.M(object, InterpolationHandler)" IL_0014: ldstr "2" IL_0019: stloc.0 IL_001a: ldloc.0 IL_001b: ldc.i4.0 IL_001c: ldc.i4.0 IL_001d: ldloc.0 IL_001e: newobj "InterpolationHandler..ctor(int, int, object)" IL_0023: call "void E.M(object, InterpolationHandler)" IL_0028: ret } """); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) .VerifyDiagnostics(); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_WithConversion_ExtensionParameterNarrowerThanConstructor(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, object o) { System.Console.Write(o); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension(string o) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("o")] InterpolationHandler h) {} } } """; var exeSource = """ "1".M($""); E.M("2", $""); """; var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "12" : null; CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) .VerifyDiagnostics(); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_WithConversion_ExtensionParameterWiderThanConstructor(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, string s) { System.Console.WriteLine(s); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension(object o) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("o")] InterpolationHandler h) {} } } """; var exeSource = """ "1".M($""); E.M("2", $""); """; var expectedDiagnostics = new[] { // (1,1): error CS1503: Argument 3: cannot convert from 'object' to 'string' // "1".M($""); Diagnostic(ErrorCode.ERR_BadArgType, @"""1""").WithArguments("3", "object", "string").WithLocation(1, 1), // (2,5): error CS1503: Argument 3: cannot convert from 'object' to 'string' // E.M("2", $""); Diagnostic(ErrorCode.ERR_BadArgType, @"""2""").WithArguments("3", "object", "string").WithLocation(2, 5) }; CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net90).VerifyDiagnostics(expectedDiagnostics); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CreateCompilation(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90).VerifyDiagnostics(expectedDiagnostics); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [WorkItem("https://github.com/dotnet/roslyn/issues/79379")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_ByRef(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, ref int i) { System.Console.Write(i); i = 2; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension(ref int i) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h) { System.Console.Write(i); i = 3; } } } """; var exeSource = """ class Program { static void Main() { int i = 1; Test1(ref i); System.Console.Write(i); i = 4; Test2(ref i); System.Console.Write(i); } static void Test1(ref int i) { i.M($""); } static void Test2(ref int i) { E.M(ref i, $""); } } """; var expectedOutput = "123423"; var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", """ { // Code size 17 (0x11) .maxstack 4 .locals init (int& V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: ldc.i4.0 IL_0004: ldc.i4.0 IL_0005: ldloc.0 IL_0006: newobj "InterpolationHandler..ctor(int, int, ref int)" IL_000b: call "void E.M(ref int, InterpolationHandler)" IL_0010: ret } """); verifier.VerifyIL("Program.Test2", """ { // Code size 17 (0x11) .maxstack 4 .locals init (int& V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: ldc.i4.0 IL_0004: ldc.i4.0 IL_0005: ldloc.0 IL_0006: newobj "InterpolationHandler..ctor(int, int, ref int)" IL_000b: call "void E.M(ref int, InterpolationHandler)" IL_0010: ret } """); var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], expectedOutput: expectedOutput) .VerifyDiagnostics(); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78433"), WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_ByRef_WithConstantReceiver(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, ref int i) { System.Console.Write(i); System.Runtime.CompilerServices.Unsafe.AsRef(in i)++; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension(ref int i) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h) { System.Console.Write(i); } } } """; var exeSource = """ 1.M($""); E.M(3, $""); """; var expectedDiagnostic = new DiagnosticDescription[] { // (1,1): error CS1510: A ref or out value must be an assignable variable // 1.M($""); Diagnostic(ErrorCode.ERR_RefLvalueExpected, "1").WithLocation(1, 1), // (2,5): error CS1620: Argument 1 must be passed with the 'ref' keyword // E.M(3, $""); Diagnostic(ErrorCode.ERR_BadArgRef, "3").WithArguments("1", "ref").WithLocation(2, 5) }; CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net90).VerifyDiagnostics(expectedDiagnostic); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CreateCompilation(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90).VerifyDiagnostics(expectedDiagnostic); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [WorkItem("https://github.com/dotnet/roslyn/issues/79379")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_Generic_ByRef(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler<TR> { public InterpolationHandler(int literalLength, int formattedCount, ref TR i) { System.Console.Write(i); i = (TR)(object)2; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension<T>(ref T i) where T : struct { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler<T> h) { System.Console.Write(i); i = (T)(object)3; } } } """; var exeSource = """ class Program { static void Main() { int i = 1; Test1(ref i); System.Console.Write(i); i = 4; Test2(ref i); System.Console.Write(i); } static void Test1<T>(ref T i) where T : struct { i.M($""); } static void Test2<T>(ref T i) where T : struct { E.M(ref i, $""); } } """; var expectedOutput = "123423"; var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1<T>", """ { // Code size 17 (0x11) .maxstack 4 .locals init (T& V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: ldc.i4.0 IL_0004: ldc.i4.0 IL_0005: ldloc.0 IL_0006: newobj "InterpolationHandler<T>..ctor(int, int, ref T)" IL_000b: call "void E.M<T>(ref T, InterpolationHandler<T>)" IL_0010: ret } """); verifier.VerifyIL("Program.Test2<T>", """ { // Code size 17 (0x11) .maxstack 4 .locals init (T& V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: ldc.i4.0 IL_0004: ldc.i4.0 IL_0005: ldloc.0 IL_0006: newobj "InterpolationHandler<T>..ctor(int, int, ref T)" IL_000b: call "void E.M<T>(ref T, InterpolationHandler<T>)" IL_0010: ret } """); var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], expectedOutput: expectedOutput) .VerifyDiagnostics(); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [WorkItem("https://github.com/dotnet/roslyn/issues/79379")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_ByIn_WithConstantReceiver(bool useMetadataRef, [CombinatorialValues("ref readonly", "in")] string refkind) { var src = $$$""" [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, {{{refkind}}} int i) { System.Console.Write(i); System.Runtime.CompilerServices.Unsafe.AsRef(in i)++; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension({{{refkind}}} int i) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h) { System.Console.Write(i); } } } """; var exeSource = """ #pragma warning disable CS9193 // Argument 0 should be a variable because it is passed to a 'ref readonly' parameter class Program { static void Main() { Test1(); Test2(); } static void Test1() { 1.M($""); } static void Test2() { E.M(3, $""); } } """; var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "1234" : null; var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", $$$""" { // Code size 19 (0x13) .maxstack 4 .locals init (int V_0) IL_0000: ldc.i4.1 IL_0001: stloc.0 IL_0002: ldloca.s V_0 IL_0004: ldc.i4.0 IL_0005: ldc.i4.0 IL_0006: ldloca.s V_0 IL_0008: newobj "InterpolationHandler..ctor(int, int, {{{refkind}}} int)" IL_000d: call "void E.M({{{refkind}}} int, InterpolationHandler)" IL_0012: ret } """); verifier.VerifyIL("Program.Test2", $$$""" { // Code size 19 (0x13) .maxstack 4 .locals init (int V_0) IL_0000: ldc.i4.3 IL_0001: stloc.0 IL_0002: ldloca.s V_0 IL_0004: ldc.i4.0 IL_0005: ldc.i4.0 IL_0006: ldloca.s V_0 IL_0008: newobj "InterpolationHandler..ctor(int, int, {{{refkind}}} int)" IL_000d: call "void E.M({{{refkind}}} int, InterpolationHandler)" IL_0012: ret } """); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_ByIn_WithLocalReceiver(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, in int i) { System.Console.Write(i); System.Runtime.CompilerServices.Unsafe.AsRef(in i)++; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension(in int i) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h) { System.Console.Write(i); System.Runtime.CompilerServices.Unsafe.AsRef(in i)++; } } } """; var exeSource = """ int i = 1; i.M($""); System.Console.Write(i); E.M(i, $""); System.Console.Write(i); """; var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "123345" : null; var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 49 (0x31) .maxstack 4 .locals init (int V_0, //i int& V_1) IL_0000: ldc.i4.1 IL_0001: stloc.0 IL_0002: ldloca.s V_0 IL_0004: stloc.1 IL_0005: ldloc.1 IL_0006: ldc.i4.0 IL_0007: ldc.i4.0 IL_0008: ldloc.1 IL_0009: newobj "InterpolationHandler..ctor(int, int, in int)" IL_000e: call "void E.M(in int, InterpolationHandler)" IL_0013: ldloc.0 IL_0014: call "void System.Console.Write(int)" IL_0019: ldloca.s V_0 IL_001b: stloc.1 IL_001c: ldloc.1 IL_001d: ldc.i4.0 IL_001e: ldc.i4.0 IL_001f: ldloc.1 IL_0020: newobj "InterpolationHandler..ctor(int, int, in int)" IL_0025: call "void E.M(in int, InterpolationHandler)" IL_002a: ldloc.0 IL_002b: call "void System.Console.Write(int)" IL_0030: ret } """); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) .VerifyDiagnostics(); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_ByRefMismatch_01(bool useMetadataRef, [CombinatorialValues("ref readonly", "in", "")] string refkind) { var src = $$""" [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, ref int i) { System.Console.Write(i); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension({{refkind}} int i) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h) {} } } """; var exeSource = $$""" int i = 1; i.M($""); E.M({{(refkind == "" ? "" : "in ")}}i, $""); """; var expectedDiagnostic = new[] { // (2,1): error CS1620: Argument 3 must be passed with the 'ref' keyword // i.M($""); Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "ref").WithLocation(2, 1), // (3,5): error CS1620: Argument 3 must be passed with the 'ref' keyword // E.M(i, $""); Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "ref").WithLocation(3, 5 + (refkind == "" ? 0 : 3)) }; CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net90).VerifyDiagnostics(expectedDiagnostic); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CreateCompilation(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90).VerifyDiagnostics(expectedDiagnostic); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_ByRefMismatch_02(bool useMetadataRef, [CombinatorialValues("ref readonly", "in")] string refkind) { var src = $$""" [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, {{refkind}} int i) { System.Console.Write(i); System.Runtime.CompilerServices.Unsafe.AsRef(in i)++; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension(ref int i) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h) { System.Console.Write(i); i++; } } } """; var exeSource = """ int i = 1; i.M($""); System.Console.Write(i); E.M(ref i, $""); System.Console.Write(i); """; var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "123345" : null; CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) .VerifyDiagnostics(); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_ByRefMismatch_03(bool useMetadataRef) { var src = $$""" [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, int i) { System.Console.WriteLine(i); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension(ref int i) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h) {} } } """; var exeSource = """ int i = 1; i.M($""); E.M(ref i, $""); """; var expectedDiagnostics = new[] { // (2,1): error CS1615: Argument 3 may not be passed with the 'ref' keyword // i.M($""); Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("3", "ref").WithLocation(2, 1), // (3,9): error CS1615: Argument 3 may not be passed with the 'ref' keyword // E.M(ref i, $""); Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("3", "ref").WithLocation(3, 9) }; CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net90).VerifyDiagnostics(expectedDiagnostics); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CreateCompilation(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90).VerifyDiagnostics(expectedDiagnostics); } [Theory] [CombinatorialData] public void InterpolationHandler_StructReceiverParameter_ByValue(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, MyStruct s) { System.Console.Write(s.i); s.i++; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public struct MyStruct { public int i; } public static class E { extension(MyStruct s) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h) { System.Console.Write(s.i); s.i++; } } } """; var exeSource = """ new MyStruct().M($""); E.M(new MyStruct(), $""); """; var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "0000" : null; var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) .VerifyDiagnostics(); verifier.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 45 (0x2d) .maxstack 4 .locals init (MyStruct V_0) IL_0000: ldloca.s V_0 IL_0002: initobj "MyStruct" IL_0008: ldloc.0 IL_0009: ldc.i4.0 IL_000a: ldc.i4.0 IL_000b: ldloc.0 IL_000c: newobj "InterpolationHandler..ctor(int, int, MyStruct)" IL_0011: call "void E.M(MyStruct, InterpolationHandler)" IL_0016: ldloca.s V_0 IL_0018: initobj "MyStruct" IL_001e: ldloc.0 IL_001f: ldc.i4.0 IL_0020: ldc.i4.0 IL_0021: ldloc.0 IL_0022: newobj "InterpolationHandler..ctor(int, int, MyStruct)" IL_0027: call "void E.M(MyStruct, InterpolationHandler)" IL_002c: ret } """); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) .VerifyDiagnostics(); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/79379")] [CombinatorialData] public void InterpolationHandler_StructReceiverParameter_ByValueThroughField(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, MyStruct s) { System.Console.Write(s.i); E.field.i++; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public struct MyStruct { public int i; } public static class E { extension(MyStruct s) { public void M(int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h) { System.Console.Write(s.i); E.field.i++; } } public static MyStruct field; } """; var exeSource = """ E.field.M(Increment(), $""); E.M(E.field, Increment(), $""); int Increment() => E.field.i++; """; var expectedOutput = "0033"; var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) .VerifyDiagnostics(); verifier.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 51 (0x33) .maxstack 5 .locals init (MyStruct V_0) IL_0000: ldsfld "MyStruct E.field" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: call "int Program.<<Main>$>g__Increment|0_0()" IL_000c: ldc.i4.0 IL_000d: ldc.i4.0 IL_000e: ldloc.0 IL_000f: newobj "InterpolationHandler..ctor(int, int, MyStruct)" IL_0014: call "void E.M(MyStruct, int, InterpolationHandler)" IL_0019: ldsfld "MyStruct E.field" IL_001e: stloc.0 IL_001f: ldloc.0 IL_0020: call "int Program.<<Main>$>g__Increment|0_0()" IL_0025: ldc.i4.0 IL_0026: ldc.i4.0 IL_0027: ldloc.0 IL_0028: newobj "InterpolationHandler..ctor(int, int, MyStruct)" IL_002d: call "void E.M(MyStruct, int, InterpolationHandler)" IL_0032: ret } """); var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], expectedOutput: expectedOutput) .VerifyDiagnostics(); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/79379")] [CombinatorialData] public void InterpolationHandler_StructReceiverParameter_Generic_ByValueThroughField(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler<TR> { public InterpolationHandler(int literalLength, int formattedCount, TR s) { System.Console.Write(((MyStruct)(object)s).i); E<MyStruct>.field.i++; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public struct MyStruct { public int i; } public static class E { extension<T>(T s) { public void M(int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler<T> h) { System.Console.Write(((MyStruct)(object)s).i); E<MyStruct>.field.i++; } } } public static class E<T> { public static T field; } """; var exeSource = """ class Porgram { static void Main() { Test1<MyStruct>(); Test2<MyStruct>(); Test3<MyStruct>(); Test4<MyStruct>(); } static void Test1<T>() { E<T>.field.M(Increment(), $""); } static void Test2<T>() { E.M(E<T>.field, Increment(), $""); } static void Test3<T>() where T : struct { E<T>.field.M(Increment(), $""); } static void Test4<T>() where T : struct { E.M(E<T>.field, Increment(), $""); } static int Increment() => E<MyStruct>.field.i++; } """; var expectedOutput = "00336699"; var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) .VerifyDiagnostics(); var expectedIL = """ { // Code size 26 (0x1a) .maxstack 5 .locals init (T V_0) IL_0000: ldsfld "T E<T>.field" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: call "int Porgram.Increment()" IL_000c: ldc.i4.0 IL_000d: ldc.i4.0 IL_000e: ldloc.0 IL_000f: newobj "InterpolationHandler<T>..ctor(int, int, T)" IL_0014: call "void E.M<T>(T, int, InterpolationHandler<T>)" IL_0019: ret } """; verifier.VerifyIL("Porgram.Test1<T>", expectedIL); verifier.VerifyIL("Porgram.Test2<T>", expectedIL); verifier.VerifyIL("Porgram.Test3<T>", expectedIL); verifier.VerifyIL("Porgram.Test4<T>", expectedIL); var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], expectedOutput: expectedOutput) .VerifyDiagnostics(); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/79379")] [CombinatorialData] public void InterpolationHandler_StructReceiverParameter_GenericStruct_ByValueThroughField(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler<TR> { public InterpolationHandler(int literalLength, int formattedCount, TR s) { System.Console.Write(((MyStruct)(object)s).i); E<MyStruct>.field.i++; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public struct MyStruct { public int i; } public static class E { extension<T>(T s) where T : struct { public void M(int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler<T> h) { System.Console.Write(((MyStruct)(object)s).i); E<MyStruct>.field.i++; } } } public static class E<T> { public static T field; } """; var exeSource = """ class Porgram { static void Main() { Test3<MyStruct>(); Test4<MyStruct>(); } static void Test3<T>() where T : struct { E<T>.field.M(Increment(), $""); } static void Test4<T>() where T : struct { E.M(E<T>.field, Increment(), $""); } static int Increment() => E<MyStruct>.field.i++; } """; var expectedOutput = "0033"; var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) .VerifyDiagnostics(); var expectedIL = """ { // Code size 26 (0x1a) .maxstack 5 .locals init (T V_0) IL_0000: ldsfld "T E<T>.field" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: call "int Porgram.Increment()" IL_000c: ldc.i4.0 IL_000d: ldc.i4.0 IL_000e: ldloc.0 IL_000f: newobj "InterpolationHandler<T>..ctor(int, int, T)" IL_0014: call "void E.M<T>(T, int, InterpolationHandler<T>)" IL_0019: ret } """; verifier.VerifyIL("Porgram.Test3<T>", expectedIL); verifier.VerifyIL("Porgram.Test4<T>", expectedIL); var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], expectedOutput: expectedOutput) .VerifyDiagnostics(); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/79379")] [CombinatorialData] public void InterpolationHandler_ClassReceiverParameter_GenericClass_ByValueThroughField(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler<TR> { public InterpolationHandler(int literalLength, int formattedCount, TR s) { System.Console.Write(((MyClass)(object)s).i); E<MyClass>.field = new MyClass() { i = E<MyClass>.field.i + 1 }; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public class MyClass { public int i; } public static class E { extension<T>(T s) { public void M(int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler<T> h) { System.Console.Write(((MyClass)(object)s).i); E<MyClass>.field = new MyClass() { i = E<MyClass>.field.i + 1 }; } } } public static class E<T> { public static T field; } """; var exeSource = """ class Porgram { static void Main() { E<MyClass>.field = new MyClass(); Test1<MyClass>(); Test2<MyClass>(); Test3<MyClass>(); Test4<MyClass>(); } static void Test1<T>() { E<T>.field.M(Increment(), $""); } static void Test2<T>() { E.M(E<T>.field, Increment(), $""); } static void Test3<T>() where T : class { E<T>.field.M(Increment(), $""); } static void Test4<T>() where T : class { E.M(E<T>.field, Increment(), $""); } static int Increment() => (E<MyClass>.field = new MyClass() { i = E<MyClass>.field.i + 1 }).i; } """; var expectedOutput = "00336699"; var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) .VerifyDiagnostics(); var expectedIL = """ { // Code size 26 (0x1a) .maxstack 5 .locals init (T V_0) IL_0000: ldsfld "T E<T>.field" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: call "int Porgram.Increment()" IL_000c: ldc.i4.0 IL_000d: ldc.i4.0 IL_000e: ldloc.0 IL_000f: newobj "InterpolationHandler<T>..ctor(int, int, T)" IL_0014: call "void E.M<T>(T, int, InterpolationHandler<T>)" IL_0019: ret } """; verifier.VerifyIL("Porgram.Test1<T>", expectedIL); verifier.VerifyIL("Porgram.Test2<T>", expectedIL); verifier.VerifyIL("Porgram.Test3<T>", expectedIL); verifier.VerifyIL("Porgram.Test4<T>", expectedIL); var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], expectedOutput: expectedOutput) .VerifyDiagnostics(); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/79379")] [CombinatorialData] public void InterpolationHandler_ClassReceiverParameter_Generic_ByValueThroughField(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler<TR> { public InterpolationHandler(int literalLength, int formattedCount, TR s) { System.Console.Write(((MyClass)(object)s).i); E<MyClass>.field = new MyClass() { i = E<MyClass>.field.i + 1 }; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public class MyClass { public int i; } public static class E { extension<T>(T s) where T : class { public void M(int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler<T> h) { System.Console.Write(((MyClass)(object)s).i); E<MyClass>.field = new MyClass() { i = E<MyClass>.field.i + 1 }; } } } public static class E<T> { public static T field; } """; var exeSource = """ class Porgram { static void Main() { E<MyClass>.field = new MyClass(); Test3<MyClass>(); Test4<MyClass>(); } static void Test3<T>() where T : class { E<T>.field.M(Increment(), $""); } static void Test4<T>() where T : class { E.M(E<T>.field, Increment(), $""); } static int Increment() => (E<MyClass>.field = new MyClass() { i = E<MyClass>.field.i + 1 }).i; } """; var expectedOutput = "0033"; var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) .VerifyDiagnostics(); verifier.VerifyIL("Porgram.Test3<T>", """ { // Code size 26 (0x1a) .maxstack 5 .locals init (T V_0) IL_0000: ldsfld "T E<T>.field" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: call "int Porgram.Increment()" IL_000c: ldc.i4.0 IL_000d: ldc.i4.0 IL_000e: ldloc.0 IL_000f: newobj "InterpolationHandler<T>..ctor(int, int, T)" IL_0014: call "void E.M<T>(T, int, InterpolationHandler<T>)" IL_0019: ret } """); verifier.VerifyIL("Porgram.Test4<T>", """ { // Code size 26 (0x1a) .maxstack 5 .locals init (T V_0) IL_0000: ldsfld "T E<T>.field" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: call "int Porgram.Increment()" IL_000c: ldc.i4.0 IL_000d: ldc.i4.0 IL_000e: ldloc.0 IL_000f: newobj "InterpolationHandler<T>..ctor(int, int, T)" IL_0014: call "void E.M<T>(T, int, InterpolationHandler<T>)" IL_0019: ret } """); var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], expectedOutput: expectedOutput) .VerifyDiagnostics(); } [Theory] [CombinatorialData] public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_01(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public ref struct InterpolationHandler { #pragma warning disable CS0169 // The field 'InterpolationHandler.i' is never used private ref int i; #pragma warning restore CS0169 // The field 'InterpolationHandler.i' is never used public InterpolationHandler(int literalLength, int formattedCount, scoped MyStruct s) { } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public ref struct MyStruct { public ref int i; } public static class E { extension(MyStruct s) { public MyStruct M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h) { return new(); } } } """; var exeSource = """ #pragma warning disable CS8321 // The local function 'localFunc' is declared but never used MyStruct localFunc() #pragma warning restore CS8321 // The local function 'localFunc' is declared but never used { return new MyStruct().M($""); } """; var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net90, verify: Verification.Fails).VerifyDiagnostics(); verifier.VerifyIL("Program.<<Main>$>g__localFunc|0_0()", """ { // Code size 23 (0x17) .maxstack 4 .locals init (MyStruct V_0) IL_0000: ldloca.s V_0 IL_0002: initobj "MyStruct" IL_0008: ldloc.0 IL_0009: ldc.i4.0 IL_000a: ldc.i4.0 IL_000b: ldloc.0 IL_000c: newobj "InterpolationHandler..ctor(int, int, scoped MyStruct)" IL_0011: call "MyStruct E.M(MyStruct, InterpolationHandler)" IL_0016: ret } """); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90, verify: Verification.Fails) .VerifyDiagnostics(); } [Fact] public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_02() { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public ref struct InterpolationHandler { public ref int i; public InterpolationHandler(int literalLength, int formattedCount, MyStruct s2) { i = ref s2.i; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public ref struct MyStruct { public ref int i; } public static class E { extension(MyStruct s1) { public MyStruct M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1")] InterpolationHandler h) { return new() { i = ref h.i }; } } } """; var exeSource = """ #pragma warning disable CS8321 // The local function 'localFunc' is declared but never used MyStruct localFunc() #pragma warning restore CS8321 // The local function 'localFunc' is declared but never used { int i = 0; return new MyStruct() { i = ref i }.M($""); } """; CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net90).VerifyDiagnostics( // (6,27): error CS8352: Cannot use variable 'i = ref i' in this context because it may expose referenced variables outside of their declaration scope // return new MyStruct() { i = ref i }.M($""); Diagnostic(ErrorCode.ERR_EscapeVariable, "{ i = ref i }").WithArguments("i = ref i").WithLocation(6, 27), // (6,12): error CS8347: Cannot use a result of 'E.extension(MyStruct).M(InterpolationHandler)' in this context because it may expose variables referenced by parameter 's1' outside of their declaration scope // return new MyStruct() { i = ref i }.M($""); Diagnostic(ErrorCode.ERR_EscapeCall, @"new MyStruct() { i = ref i }.M($"""")").WithArguments("E.extension(MyStruct).M(InterpolationHandler)", "s1").WithLocation(6, 12) ); } [Fact] public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_03() { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public ref struct InterpolationHandler { public ref int i; public InterpolationHandler(int literalLength, int formattedCount, MyStruct s2) { i = ref s2.i; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public ref struct MyStruct { public ref int i; } public static class E { extension(MyStruct s1) { public MyStruct M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1")] ref InterpolationHandler h) { return new() { i = ref h.i }; } } } """; var exeSource = """ #pragma warning disable CS8321 // The local function 'localFunc' is declared but never used MyStruct localFunc() #pragma warning restore CS8321 // The local function 'localFunc' is declared but never used { var myStruct = new MyStruct(); return myStruct.M($""); } """; CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net90).VerifyDiagnostics( // (6,12): error CS8347: Cannot use a result of 'E.extension(MyStruct).M(ref InterpolationHandler)' in this context because it may expose variables referenced by parameter 'h' outside of their declaration scope // return myStruct.M($""); Diagnostic(ErrorCode.ERR_EscapeCall, @"myStruct.M($"""")").WithArguments("E.extension(MyStruct).M(ref InterpolationHandler)", "h").WithLocation(6, 12), // (6,23): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // return myStruct.M($""); Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, @"$""""").WithLocation(6, 23) ); } [Fact] public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_04() { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public ref struct InterpolationHandler { public ref int i; public InterpolationHandler(int literalLength, int formattedCount, MyStruct s2) { i = ref s2.i; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public ref struct MyStruct { public ref int i; } public static class E { extension(MyStruct s1) { public MyStruct M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1"), System.Diagnostics.CodeAnalysis.UnscopedRef] ref InterpolationHandler h) { return new() { i = ref h.i }; } } } """; var exeSource = """ #pragma warning disable CS8321 // The local function 'localFunc' is declared but never used MyStruct localFunc() #pragma warning restore CS8321 // The local function 'localFunc' is declared but never used { int i = 0; return new MyStruct() { i = ref i }.M($""); } """; CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net90).VerifyDiagnostics( // (6,12): error CS8347: Cannot use a result of 'E.extension(MyStruct).M(ref InterpolationHandler)' in this context because it may expose variables referenced by parameter 's1' outside of their declaration scope // return new MyStruct() { i = ref i }.M($""); Diagnostic(ErrorCode.ERR_EscapeCall, @"new MyStruct() { i = ref i }.M($"""")").WithArguments("E.extension(MyStruct).M(ref InterpolationHandler)", "s1").WithLocation(6, 12), // (6,27): error CS8352: Cannot use variable 'i = ref i' in this context because it may expose referenced variables outside of their declaration scope // return new MyStruct() { i = ref i }.M($""); Diagnostic(ErrorCode.ERR_EscapeVariable, "{ i = ref i }").WithArguments("i = ref i").WithLocation(6, 27) ); } [Fact] public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_05() { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public ref struct InterpolationHandler { public ref int i; public InterpolationHandler(int literalLength, int formattedCount, MyStruct s2) { i = ref s2.i; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public ref struct MyStruct { public ref int i; } public static class E { extension(scoped MyStruct s1) { public MyStruct M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1")] InterpolationHandler h) { return new() { i = ref h.i }; } } } """; var exeSource = """ #pragma warning disable CS8321 // The local function 'localFunc' is declared but never used MyStruct localFunc() #pragma warning restore CS8321 // The local function 'localFunc' is declared but never used { int i = 0; return new MyStruct() { i = ref i }.M($""); } """; CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net90).VerifyDiagnostics( // (6,12): error CS8352: Cannot use variable 'new MyStruct() { i = ref i }' in this context because it may expose referenced variables outside of their declaration scope // return new MyStruct() { i = ref i }.M($""); Diagnostic(ErrorCode.ERR_EscapeVariable, "new MyStruct() { i = ref i }").WithArguments("new MyStruct() { i = ref i }").WithLocation(6, 12), // (6,12): error CS8347: Cannot use a result of 'E.extension(scoped MyStruct).M(InterpolationHandler)' in this context because it may expose variables referenced by parameter 'h' outside of their declaration scope // return new MyStruct() { i = ref i }.M($""); Diagnostic(ErrorCode.ERR_EscapeCall, @"new MyStruct() { i = ref i }.M($"""")").WithArguments("E.extension(scoped MyStruct).M(InterpolationHandler)", "h").WithLocation(6, 12), // (6,43): error CS8347: Cannot use a result of 'InterpolationHandler.InterpolationHandler(int, int, MyStruct)' in this context because it may expose variables referenced by parameter 's2' outside of their declaration scope // return new MyStruct() { i = ref i }.M($""); Diagnostic(ErrorCode.ERR_EscapeCall, @"$""""").WithArguments("InterpolationHandler.InterpolationHandler(int, int, MyStruct)", "s2").WithLocation(6, 43) ); } [Fact] public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_06() { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public ref struct InterpolationHandler { public ref int i; public InterpolationHandler(int literalLength, int formattedCount, MyStruct s2) { i = ref s2.i; } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public ref struct MyStruct { public ref int i; } public static class E { extension(scoped MyStruct s1) { public MyStruct M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1")] scoped InterpolationHandler h) { return new() { i = ref h.i }; } } } """; var exeSource = """ #pragma warning disable CS8321 // The local function 'localFunc' is declared but never used MyStruct localFunc() #pragma warning restore CS8321 // The local function 'localFunc' is declared but never used { int i = 0; return new MyStruct() { i = ref i }.M($""); } """; CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net90).VerifyDiagnostics( // (25,26): error CS8352: Cannot use variable 'i = ref h.i' in this context because it may expose referenced variables outside of their declaration scope // return new() { i = ref h.i }; Diagnostic(ErrorCode.ERR_EscapeVariable, "{ i = ref h.i }").WithArguments("i = ref h.i").WithLocation(25, 26) ); } [Theory, CombinatorialData] public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_07(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public ref struct InterpolationHandler { #pragma warning disable CS0169 // The field 'InterpolationHandler.i' is never used private ref int i; #pragma warning restore CS0169 // The field 'InterpolationHandler.i' is never used public InterpolationHandler(int literalLength, int formattedCount, scoped MyStruct s2) { } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public ref struct MyStruct { public ref int i; } public static class E { extension(scoped MyStruct s1) { public MyStruct M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1")] scoped InterpolationHandler h) { return new(); } } } """; var exeSource = """ #pragma warning disable CS8321 // The local function 'localFunc' is declared but never used MyStruct localFunc() #pragma warning restore CS8321 // The local function 'localFunc' is declared but never used { int i = 0; return new MyStruct() { i = ref i }.M($""); } """; var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net90, verify: Verification.Fails).VerifyDiagnostics(); verifier.VerifyIL("Program.<<Main>$>g__localFunc|0_0()", """ { // Code size 36 (0x24) .maxstack 4 .locals init (int V_0, //i MyStruct V_1, MyStruct V_2) IL_0000: ldc.i4.0 IL_0001: stloc.0 IL_0002: ldloca.s V_2 IL_0004: initobj "MyStruct" IL_000a: ldloca.s V_2 IL_000c: ldloca.s V_0 IL_000e: stfld "ref int MyStruct.i" IL_0013: ldloc.2 IL_0014: stloc.1 IL_0015: ldloc.1 IL_0016: ldc.i4.0 IL_0017: ldc.i4.0 IL_0018: ldloc.1 IL_0019: newobj "InterpolationHandler..ctor(int, int, scoped MyStruct)" IL_001e: call "MyStruct E.M(scoped MyStruct, scoped InterpolationHandler)" IL_0023: ret } """); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90, verify: Verification.Fails) .VerifyDiagnostics(); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_NullableMismatch_01(bool useMetadataRef, bool useOut) { string outParam = useOut ? ", out bool valid" : ""; var src = $$""" #nullable enable [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{{outParam}}) { System.Console.Write(s1); System.Console.Write(s2); {{(useOut ? "valid = true;" : "")}} } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string? format = null) => throw null!; } public static class E { extension(string? s1) { public void M(string? s2, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1", "s2")] InterpolationHandler h) {} } } """; var exeSource = """ #nullable enable ((string?)null).M(null, $""); ((string?)null).M("", $""); "".M(null, $""); "".M("", $""); E.M(null, null, $""); E.M("", null, $""); E.M(null, "", $""); E.M("", "", $""); """; var expectedDiagnostics = new[] { // (2,2): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // ((string?)null).M(null, $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "(string?)null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(2, 2), // (2,19): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // ((string?)null).M(null, $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(2, 19), // (3,2): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // ((string?)null).M("", $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "(string?)null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(3, 2), // (4,6): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // "".M(null, $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(4, 6), // (6,5): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // E.M(null, null, $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(6, 5), // (6,11): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // E.M(null, null, $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(6, 11), // (7,9): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // E.M("", null, $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(7, 9), // (8,5): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // E.M(null, "", $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(8, 5) }; CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net90).VerifyDiagnostics(expectedDiagnostics); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CreateCompilation(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90).VerifyDiagnostics(expectedDiagnostics); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_ReceiverParameter_NullableMismatch_02(bool useMetadataRef, bool useOut) { string outParam = useOut ? ", out bool valid" : ""; var src = $$""" #nullable enable [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{{outParam}}) { System.Console.Write(s1); System.Console.Write(s2); {{(useOut ? "valid = true;" : "")}} } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string? format = null) => throw null!; } public static class E { extension(string? s1) { public void M(string? s2, string? s3, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s2", "s3")] InterpolationHandler h) {} } } """; var exeSource = """ #nullable enable "".M(null, null, $""); "".M(null, "", $""); "".M("", null, $""); "".M("", "", $""); E.M("", null, null, $""); E.M("", "", null, $""); E.M("", null, "", $""); E.M("", "", "", $""); """; var expectedDiagnostics = new[] { // (2,6): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // "".M(null, null, $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(2, 6), // (2,12): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // "".M(null, null, $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(2, 12), // (3,6): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // "".M(null, "", $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(3, 6), // (4,10): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // "".M("", null, $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(4, 10), // (6,9): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // E.M("", null, null, $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(6, 9), // (6,15): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // E.M("", null, null, $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(6, 15), // (7,13): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // E.M("", "", null, $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(7, 13), // (8,9): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. // E.M("", null, "", $""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(8, 9) }; CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net90).VerifyDiagnostics(expectedDiagnostics); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CreateCompilation(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90).VerifyDiagnostics(expectedDiagnostics); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] public void InterpolationHandler_ParameterErrors_MappedCorrectly_01() { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, int i) { System.Console.WriteLine(i); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension(int i) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("nonexistent")] InterpolationHandler h) {} } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyDiagnostics( // (17,24): error CS8945: 'nonexistent' is not a valid parameter name from 'E.extension(int).M(InterpolationHandler)'. // public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("nonexistent")] InterpolationHandler h) {} Diagnostic(ErrorCode.ERR_InvalidInterpolatedStringHandlerArgumentName, @"System.Runtime.CompilerServices.InterpolatedStringHandlerArgument(""nonexistent"")").WithArguments("nonexistent", "E.extension(int).M(InterpolationHandler)").WithLocation(17, 24) ); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertExtensionDeclaration(symbol); var underlying = symbol.GetSymbol<NamedTypeSymbol>(); var m = underlying.GetMember<MethodSymbol>("M"); Assert.False(underlying.ExtensionParameter.HasInterpolatedStringHandlerArgumentError); Assert.True(underlying.ExtensionParameter.InterpolatedStringHandlerArgumentIndexes.IsEmpty); Assert.True(m.Parameters[0].HasInterpolatedStringHandlerArgumentError); Assert.True(m.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); var implM = underlying.ContainingType.GetMember<MethodSymbol>("M"); Assert.False(implM.Parameters[0].HasInterpolatedStringHandlerArgumentError); Assert.True(implM.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); Assert.True(implM.Parameters[1].HasInterpolatedStringHandlerArgumentError); Assert.True(implM.Parameters[1].InterpolatedStringHandlerArgumentIndexes.IsEmpty); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [InlineData("i")] [InlineData("")] [InlineData("nonexistent")] public void InterpolationHandler_ParameterErrors_MappedCorrectly_02(string attributeValue) { var src = $$""" [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, InterpolationHandler i) { System.Console.WriteLine(i); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("{{attributeValue}}")] InterpolationHandler i) { public void M() {} } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyDiagnostics( // (15,16): error CS9325: Interpolated string handler arguments are not allowed in this context. // extension([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("")] InterpolationHandler i) Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentDisallowed, $@"System.Runtime.CompilerServices.InterpolatedStringHandlerArgument(""{attributeValue}"")").WithLocation(15, 16) ); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertExtensionDeclaration(symbol); var underlying = symbol.GetSymbol<NamedTypeSymbol>(); Assert.True(underlying.ExtensionParameter.HasInterpolatedStringHandlerArgumentError); Assert.True(underlying.ExtensionParameter.InterpolatedStringHandlerArgumentIndexes.IsEmpty); var implM = underlying.ContainingType.GetMember<MethodSymbol>("M"); Assert.True(implM.Parameters[0].HasInterpolatedStringHandlerArgumentError); Assert.True(implM.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [InlineData("01 00 01 69 00 00")] // "i" [InlineData("01 00 00 00 00")] // "" [InlineData("01 00 0b 6e 6f 6e 65 78 69 73 74 65 6e 74 00 00")] // "nonexistent" public void InterpolationHandler_ParameterErrors_MappedCorrectly_02_FromMetadata(string attributeValue) { // Equivalent to: // [System.Runtime.CompilerServices.InterpolatedStringHandler] // public struct InterpolationHandler // { // public InterpolationHandler(int literalLength, int formattedCount, InterpolationHandler i) // { // System.Console.WriteLine(i); // } // public void AppendLiteral(string value) { } // public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; // } // public static class E // { // extension([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("{attributeValue}")] InterpolationHandler i) // { // public void M() {} // } // } // Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading) var il = $$""" .class public sequential ansi sealed beforefieldinit InterpolationHandler extends [mscorlib]System.ValueType { .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute::.ctor() = (01 00 00 00) .pack 0 .size 1 // Methods .method public hidebysig specialname rtspecialname instance void .ctor (int32 literalLength, int32 formattedCount, valuetype InterpolationHandler param) cil managed { nop ret } // end of method InterpolationHandler::.ctor .method public hidebysig instance void AppendLiteral (string 'value') cil managed { nop ret } // end of method InterpolationHandler::AppendLiteral .method public hidebysig instance void AppendFormatted<T> (!!T hole, [opt] int32 'alignment', [opt] string format) cil managed { .param [2] = int32(0) .param [3] = nullref nop ret } // end of method InterpolationHandler::AppendFormatted } // end of class InterpolationHandler .class public auto ansi abstract sealed beforefieldinit E extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi sealed specialname '<Extension>$E159F66A155642BDC88178F886EFBCA4' extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi abstract sealed specialname '<Marker>$4325EE76DDCC76651231F283DA59D9E9' extends System.Object { .method public hidebysig specialname static void '<Extension>$' ( valuetype InterpolationHandler i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .param [1] .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute::.ctor(string) = ({{attributeValue}}) IL_0000: ret } } .method public hidebysig instance void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 34 33 32 35 45 45 37 36 44 44 43 43 37 36 36 35 31 32 33 31 46 32 38 33 44 41 35 39 44 39 45 39 00 00 ) IL_0000: ldnull IL_0001: throw } } .method public hidebysig static void M ( valuetype InterpolationHandler i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .param [1] .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute::.ctor(string) = ({{attributeValue}}) IL_0000: ret } } """ + ExtensionMarkerAttributeIL; var src = """ $"".M(); E.M($""); """; var comp = CreateCompilationWithIL(src, ilSource: il, targetFramework: TargetFramework.Net90); comp.VerifyDiagnostics( // (1,1): error CS1929: 'string' does not contain a definition for 'M' and the best extension method overload 'E.extension(InterpolationHandler).M()' requires a receiver of type 'InterpolationHandler' // $"".M(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, @"$""""").WithArguments("string", "M", "E.extension(InterpolationHandler).M()", "InterpolationHandler").WithLocation(1, 1), // (2,5): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'InterpolationHandler i' is malformed and cannot be interpreted. Construct an instance of 'InterpolationHandler' manually. // E.M($""); Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("InterpolationHandler i", "InterpolationHandler").WithLocation(2, 5), // (2,5): error CS7036: There is no argument given that corresponds to the required parameter 'param' of 'InterpolationHandler.InterpolationHandler(int, int, InterpolationHandler)' // E.M($""); Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, @"$""""").WithArguments("param", "InterpolationHandler.InterpolationHandler(int, int, InterpolationHandler)").WithLocation(2, 5), // (2,5): error CS1615: Argument 3 may not be passed with the 'out' keyword // E.M($""); Diagnostic(ErrorCode.ERR_BadArgExtraRef, @"$""""").WithArguments("3", "out").WithLocation(2, 5) ); var e = comp.GetTypeByMetadataName("E"); var symbol = e.GetTypeMembers().Single(); Assert.True(symbol.ExtensionParameter.HasInterpolatedStringHandlerArgumentError); Assert.True(symbol.ExtensionParameter.InterpolatedStringHandlerArgumentIndexes.IsEmpty); var implM = symbol.ContainingType.GetMember<MethodSymbol>("M"); Assert.True(implM.Parameters[0].HasInterpolatedStringHandlerArgumentError); Assert.True(implM.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] public void InterpolationHandler_ParameterErrors_MappedCorrectly_03() { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, int i) { System.Console.WriteLine(i); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null; } public static class E { extension(int i) { public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("")] InterpolationHandler h) {} } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyDiagnostics( // (17,24): error CS8944: 'E.extension(int).M(InterpolationHandler)' is not an instance method, the receiver or extension receiver parameter cannot be an interpolated string handler argument. // public void M([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("")] InterpolationHandler h) {} Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("""")").WithArguments("E.extension(int).M(InterpolationHandler)").WithLocation(17, 24) ); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); AssertExtensionDeclaration(symbol); var underlying = symbol.GetSymbol<NamedTypeSymbol>(); var m = underlying.GetMember<MethodSymbol>("M"); Assert.False(underlying.ExtensionParameter.HasInterpolatedStringHandlerArgumentError); Assert.True(underlying.ExtensionParameter.InterpolatedStringHandlerArgumentIndexes.IsEmpty); Assert.True(m.Parameters[0].HasInterpolatedStringHandlerArgumentError); Assert.True(m.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); var implM = underlying.ContainingType.GetMember<MethodSymbol>("M"); Assert.False(implM.Parameters[0].HasInterpolatedStringHandlerArgumentError); Assert.True(implM.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); Assert.True(implM.Parameters[1].HasInterpolatedStringHandlerArgumentError); Assert.True(implM.Parameters[1].InterpolatedStringHandlerArgumentIndexes.IsEmpty); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] public void InterpolationHandler_ExtensionIndexer_Basic() { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, int receiver, int index) { System.Console.Write(receiver); System.Console.Write(index); } public void AppendLiteral(string value) { System.Console.Write(value); } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) { System.Console.Write(hole); } } public static class E { extension(int i) { public int this[int j, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i", "j")] InterpolationHandler h] { get => 1; set { } } } } """; var exeSource = """ int i1 = 1; i1[2, $""] = 2; int i3 = 3; _ = i3[4, $""]; E.set_Item(5, 6, $"", 0); E.get_Item(7, 8, $""); """; var comp = CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net90); CompileAndVerify(comp, expectedOutput: ExpectedOutput("12345678"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] public void InterpolationHandler_ExtensionIndexer_NullableWarnings() { var src = """ #nullable enable [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, C receiver, string key) { System.Console.Write($"receiver: {receiver}, key: {key}"); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string? format = null) { } } public static class E { extension(C? c) { public string this[string key, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("c", "key")] InterpolationHandler h] { set { } } } } public class C { } """; var exeSource = """ #nullable enable ((C?)null)["key", $""] = ""; new C()[null, $""] = ""; E.set_Item((C?)null, "key", $"", ""); E.set_Item(new C(), null, $"", ""); """; CreateCompilation([src, exeSource], targetFramework: TargetFramework.Net90).VerifyDiagnostics( // (2,2): warning CS8604: Possible null reference argument for parameter 'receiver' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C receiver, string key)'. // ((C?)null)["key", $""] = ""; Diagnostic(ErrorCode.WRN_NullReferenceArgument, "(C?)null").WithArguments("receiver", "InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C receiver, string key)").WithLocation(2, 2), // (3,9): warning CS8625: Cannot convert null literal to non-nullable reference type. // new C()[null, $""] = ""; Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(3, 9), // (3,9): warning CS8604: Possible null reference argument for parameter 'key' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C receiver, string key)'. // new C()[null, $""] = ""; Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("key", "InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C receiver, string key)").WithLocation(3, 9), // (4,12): warning CS8604: Possible null reference argument for parameter 'receiver' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C receiver, string key)'. // E.set_Item((C?)null, "key", $"", ""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "(C?)null").WithArguments("receiver", "InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C receiver, string key)").WithLocation(4, 12), // (5,21): warning CS8625: Cannot convert null literal to non-nullable reference type. // E.set_Item(new C(), null, $"", ""); Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(5, 21), // (5,21): warning CS8604: Possible null reference argument for parameter 'key' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C receiver, string key)'. // E.set_Item(new C(), null, $"", ""); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("key", "InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C receiver, string key)").WithLocation(5, 21) ); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [CombinatorialData] public void InterpolationHandler_StaticExtensionMethod_Basic(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, int param1) { System.Console.Write(param1); } public void AppendLiteral(string value) { System.Console.Write(value); } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) { System.Console.Write(hole); } } public static class E { extension(int) { public static void StaticMethod(int param1, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("param1")] InterpolationHandler h) { } } } """; var exeSource = """ int.StaticMethod(1, $""); E.StaticMethod(2, $""); """; var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "12" : null; CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net90, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) .VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] public void InterpolationHandler_StaticExtensionMethod_ParameterMismatch() { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, string param) { System.Console.WriteLine(param); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) { } } public static class E { extension(int) { public static void StaticMethod([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("nonexistent")] InterpolationHandler h) { } } } """; CreateCompilation(src, targetFramework: TargetFramework.Net90, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics( // (16,42): error CS8945: 'nonexistent' is not a valid parameter name from 'E.extension(int).StaticMethod(InterpolationHandler)'. // public static void StaticMethod([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("nonexistent")] InterpolationHandler h) Diagnostic(ErrorCode.ERR_InvalidInterpolatedStringHandlerArgumentName, @"System.Runtime.CompilerServices.InterpolatedStringHandlerArgument(""nonexistent"")").WithArguments("nonexistent", "E.extension(int).StaticMethod(InterpolationHandler)").WithLocation(16, 42) ); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [InlineData("i")] [InlineData("")] public void InterpolationHandler_StaticExtensionMethod_ReferencesExtensionParameter(string argument) { var src = $$""" [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, string param) { System.Console.WriteLine(param); } public void AppendLiteral(string value) { } public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) { } } public static class E { extension(int i) { public static void StaticMethod([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("{{argument}}")] InterpolationHandler h) { } } } """; CreateCompilation(src, parseOptions: TestOptions.RegularPreview, targetFramework: TargetFramework.Net90).VerifyDiagnostics( // (16,42): error CS8944: 'E.extension(int).StaticMethod(InterpolationHandler)' is not an instance method, the receiver or extension receiver parameter cannot be an interpolated string handler argument. // public static void StaticMethod([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h) Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @$"System.Runtime.CompilerServices.InterpolatedStringHandlerArgument(""{argument}"")").WithArguments("E.extension(int).StaticMethod(InterpolationHandler)").WithLocation(16, 42) ); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/78137")] [InlineData("01 00 01 69 00 00")] // "i" [InlineData("01 00 00 00 00")] // "" public void InterpolationHandler_StaticExtensionMethod_ReferencesExtensionParameter_FromMetadata(string argument) { // Equivalent to: // [System.Runtime.CompilerServices.InterpolatedStringHandler] // public struct InterpolationHandler // { // public InterpolationHandler(int literalLength, int formattedCount, string param) // { // } // public void AppendLiteral(string value) { } // public void AppendFormatted<T>(T hole, int alignment = 0, string? format = null) { } // } // public static class E // { // extension(int i) // { // public static void StaticMethod([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument({argument})] InterpolationHandler h) // { // } // } // } // Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading) var il = $$""" .class public sequential ansi sealed beforefieldinit InterpolationHandler extends [mscorlib]System.ValueType { .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute::.ctor() = (01 00 00 00) .pack 0 .size 1 // Methods .method public hidebysig specialname rtspecialname instance void .ctor (int32 literalLength, int32 formattedCount, int32 param) cil managed { nop ret } // end of method InterpolationHandler::.ctor .method public hidebysig instance void AppendLiteral (string 'value') cil managed { nop ret } // end of method InterpolationHandler::AppendLiteral .method public hidebysig instance void AppendFormatted<T> (!!T hole, [opt] int32 'alignment', [opt] string format) cil managed { .param [2] = int32(0) .param [3] = nullref nop ret } // end of method InterpolationHandler::AppendFormatted } // end of class InterpolationHandler .class public auto ansi abstract sealed beforefieldinit E extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi abstract sealed specialname '<Marker>$F4B4FFE41AB49E80A4ECF390CF6EB372' extends System.Object { .method public hidebysig specialname static void '<Extension>$' ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) ret } } .method public hidebysig static void StaticMethod ( valuetype InterpolationHandler h ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) .param [1] .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute::.ctor(string) = ({{argument}}) ldnull throw } } .method public hidebysig static void StaticMethod ( valuetype InterpolationHandler h ) cil managed { .param [1] .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute::.ctor(string) = ({{argument}}) ret } } """ + ExtensionMarkerAttributeIL; var src = """ int.StaticMethod($""); E.StaticMethod($""); """; CreateCompilationWithIL(src, ilSource: il, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics( // (1,18): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'InterpolationHandler h' is malformed and cannot be interpreted. Construct an instance of 'InterpolationHandler' manually. // int.StaticMethod($""); Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("InterpolationHandler h", "InterpolationHandler").WithLocation(1, 18), // (1,18): error CS7036: There is no argument given that corresponds to the required parameter 'param' of 'InterpolationHandler.InterpolationHandler(int, int, int)' // int.StaticMethod($""); Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, @"$""""").WithArguments("param", "InterpolationHandler.InterpolationHandler(int, int, int)").WithLocation(1, 18), // (1,18): error CS1615: Argument 3 may not be passed with the 'out' keyword // int.StaticMethod($""); Diagnostic(ErrorCode.ERR_BadArgExtraRef, @"$""""").WithArguments("3", "out").WithLocation(1, 18), // (2,16): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'InterpolationHandler h' is malformed and cannot be interpreted. Construct an instance of 'InterpolationHandler' manually. // E.StaticMethod($""); Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("InterpolationHandler h", "InterpolationHandler").WithLocation(2, 16), // (2,16): error CS7036: There is no argument given that corresponds to the required parameter 'param' of 'InterpolationHandler.InterpolationHandler(int, int, int)' // E.StaticMethod($""); Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, @"$""""").WithArguments("param", "InterpolationHandler.InterpolationHandler(int, int, int)").WithLocation(2, 16), // (2,16): error CS1615: Argument 3 may not be passed with the 'out' keyword // E.StaticMethod($""); Diagnostic(ErrorCode.ERR_BadArgExtraRef, @"$""""").WithArguments("3", "out").WithLocation(2, 16) ); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78137")] public void InterpolationHandler_InstanceExtensionMethod_ReferencesInstanceParameter_FromMetadata() { // Equivalent to: // [System.Runtime.CompilerServices.InterpolatedStringHandler] // public struct InterpolationHandler // { // public InterpolationHandler(int literalLength, int formattedCount, string param) // { // } // public void AppendLiteral(string value) { } // public void AppendFormatted<T>(T hole, int alignment = 0, string? format = null) { } // } // public static class E // { // extension(int i) // { // public void InstanceMethod([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("")] InterpolationHandler h) // { // } // } // } // Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading) var il = """ .class public sequential ansi sealed beforefieldinit InterpolationHandler extends [mscorlib]System.ValueType { .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute::.ctor() = (01 00 00 00) .pack 0 .size 1 // Methods .method public hidebysig specialname rtspecialname instance void .ctor (int32 literalLength, int32 formattedCount, int32 param) cil managed { nop ret } // end of method InterpolationHandler::.ctor .method public hidebysig instance void AppendLiteral (string 'value') cil managed { nop ret } // end of method InterpolationHandler::AppendLiteral .method public hidebysig instance void AppendFormatted<T> (!!T hole, [opt] int32 'alignment', [opt] string format) cil managed { .param [2] = int32(0) .param [3] = nullref nop ret } // end of method InterpolationHandler::AppendFormatted } // end of class InterpolationHandler .class public auto ansi abstract sealed beforefieldinit E extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi abstract sealed specialname '<Marker>$F4B4FFE41AB49E80A4ECF390CF6EB372' extends System.Object { .method public hidebysig specialname static void '<Extension>$' ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) ret } } .method public hidebysig instance void InstanceMethod ( valuetype InterpolationHandler h ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) .param [1] .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute::.ctor(string) = (01 00 00 00 00) ldnull throw } } .method public hidebysig static void InstanceMethod ( int32 i, valuetype InterpolationHandler h ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .param [2] .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute::.ctor(string) = (01 00 00 00 00) ret } } """ + ExtensionMarkerAttributeIL; var src = """ 1.InstanceMethod($""); E.InstanceMethod(1, $""); """; CreateCompilationWithIL(src, ilSource: il, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics( // (1,18): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'InterpolationHandler h' is malformed and cannot be interpreted. Construct an instance of 'InterpolationHandler' manually. // 1.InstanceMethod($""); Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("InterpolationHandler h", "InterpolationHandler").WithLocation(1, 18), // (1,18): error CS7036: There is no argument given that corresponds to the required parameter 'param' of 'InterpolationHandler.InterpolationHandler(int, int, int)' // 1.InstanceMethod($""); Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, @"$""""").WithArguments("param", "InterpolationHandler.InterpolationHandler(int, int, int)").WithLocation(1, 18), // (1,18): error CS1615: Argument 3 may not be passed with the 'out' keyword // 1.InstanceMethod($""); Diagnostic(ErrorCode.ERR_BadArgExtraRef, @"$""""").WithArguments("3", "out").WithLocation(1, 18), // (2,21): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'InterpolationHandler h' is malformed and cannot be interpreted. Construct an instance of 'InterpolationHandler' manually. // E.InstanceMethod(1, $""); Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("InterpolationHandler h", "InterpolationHandler").WithLocation(2, 21), // (2,21): error CS7036: There is no argument given that corresponds to the required parameter 'param' of 'InterpolationHandler.InterpolationHandler(int, int, int)' // E.InstanceMethod(1, $""); Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, @"$""""").WithArguments("param", "InterpolationHandler.InterpolationHandler(int, int, int)").WithLocation(2, 21), // (2,21): error CS1615: Argument 3 may not be passed with the 'out' keyword // E.InstanceMethod(1, $""); Diagnostic(ErrorCode.ERR_BadArgExtraRef, @"$""""").WithArguments("3", "out").WithLocation(2, 21) ); } [Fact(Skip = "Tracked by https://github.com/dotnet/roslyn/issues/82273")] public void InterpolationHandler_Indexer_InObjectInitializer() { // Tracked by https://github.com/dotnet/roslyn/issues/82273 // Crashes in Release and hits an assertion (AssertContainingContextIsForThisCreation) in Debug in ControlFlowGraphBuilder var code = """ public class Program { public static void Main() { /*<bind>*/ _ = new C() { [$"{1}"] = 1 }; /*</bind>*/ } } public class C { } [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct CustomHandler { public CustomHandler(int literalLength, int formattedCount, C c) { } public void AppendFormatted(int i) {} } public static class CExt { extension(C c) { public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("c")] CustomHandler h] { get => throw null!; } } } """; DiagnosticDescription[] expectedDiagnostics = [ // (6,24): error CS8976: Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. // _ = new C() { [$"{1}"] = 1 }; Diagnostic(ErrorCode.ERR_InterpolatedStringsReferencingInstanceCannotBeInObjectInitializers, @"$""{1}""").WithLocation(6, 24) ]; var comp = CreateCompilation(code, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics(expectedDiagnostics); string expectedOperationTree = """ IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: '_ = new C() ... 1}"] = 1 };') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C, IsInvalid) (Syntax: '_ = new C() ... {1}"] = 1 }') Left: IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') Right: IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C, IsInvalid) (Syntax: 'new C() { [$"{1}"] = 1 }') Arguments(0) Initializer: IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C, IsInvalid) (Syntax: '{ [$"{1}"] = 1 }') Initializers(1): ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsInvalid) (Syntax: '[$"{1}"] = 1') Left: IInvalidOperation (OperationKind.Invalid, Type: System.Int32, IsInvalid) (Syntax: '[$"{1}"]') Children(1): IInterpolatedStringHandlerCreationOperation (HandlerAppendCallsReturnBool: False, HandlerCreationHasSuccessParameter: False) (OperationKind.InterpolatedStringHandlerCreation, Type: CustomHandler, IsInvalid, IsImplicit) (Syntax: '$"{1}"') Creation: IObjectCreationOperation (Constructor: CustomHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount, C c)) (OperationKind.ObjectCreation, Type: CustomHandler, IsInvalid, IsImplicit) (Syntax: '$"{1}"') Arguments(3): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsInvalid, IsImplicit) (Syntax: '$"{1}"') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsInvalid, IsImplicit) (Syntax: '$"{1}"') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsInvalid, IsImplicit) (Syntax: '$"{1}"') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid, IsImplicit) (Syntax: '$"{1}"') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: c) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'C') IInterpolatedStringHandlerArgumentPlaceholderOperation (CallsiteReceiver) (OperationKind.InterpolatedStringHandlerArgumentPlaceholder, Type: null, IsImplicit) (Syntax: 'C') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Initializer: null Content: IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String, IsInvalid) (Syntax: '$"{1}"') Parts(1): IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsInvalid, IsImplicit) (Syntax: '{1}') AppendCall: IInvocationOperation ( void CustomHandler.AppendFormatted(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsInvalid, IsImplicit) (Syntax: '{1}') Instance Receiver: IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsInvalid, IsImplicit) (Syntax: '$"{1}"') Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsInvalid, IsImplicit) (Syntax: '1') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Right: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') """; VerifyOperationTreeAndDiagnosticsForTest<ExpressionStatementSyntax>(comp, expectedOperationTree, expectedDiagnostics); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var mainDeclaration = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().First(); var (graph, symbol) = ControlFlowGraphVerifier.GetControlFlowGraph(mainDeclaration.Body, model); ControlFlowGraphVerifier.VerifyGraph(comp, """ """, graph, symbol); } [Fact] public void LiteralReceiver_Property_Enum_Set() { var src = """ Enum.Zero.Property = 1; enum Enum { Zero } static class E { extension(Enum e) { public int Property { set => throw null; } } } """; var comp = CreateCompilation(src); // Consider improving the error message comp.VerifyEmitDiagnostics( // (1,1): error CS0131: The left-hand side of an assignment must be a variable, property or indexer // Enum.Zero.Property = 1; Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "Enum.Zero.Property").WithLocation(1, 1)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Enum.Zero.Property"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.Int32 E.<G>$5BDAAC939B0896D4F1349316F7C8CE0F.Property { set; }"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.NotAVariable, model.GetSymbolInfo(memberAccess).CandidateReason); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : handle GetMemberGroup on a property access } [Fact] public void LiteralReceiver_Property_Integer_ForLong() { var src = """ 1.Property = 42; _ = 2.Property; static class E { extension(long l) { public int Property { get { System.Console.Write("get "); return 42; } set { System.Console.Write("set "); } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS1929: 'int' does not contain a definition for 'Property' and the best extension method overload 'E.extension(long).Property' requires a receiver of type 'long' // 1.Property = 42; Diagnostic(ErrorCode.ERR_BadInstanceArgType, "1").WithArguments("int", "Property", "E.extension(long).Property", "long").WithLocation(1, 1), // (2,5): error CS1929: 'int' does not contain a definition for 'Property' and the best extension method overload 'E.extension(long).Property' requires a receiver of type 'long' // _ = 2.Property; Diagnostic(ErrorCode.ERR_BadInstanceArgType, "2").WithArguments("int", "Property", "E.extension(long).Property", "long").WithLocation(2, 5)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "1.Property"); AssertEx.Equal("System.Int32 E.<G>$E8CA98ACBCAEE63BB261A3FD4AF31675.Property { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess1).CandidateReason); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "2.Property"); AssertEx.Equal("System.Int32 E.<G>$E8CA98ACBCAEE63BB261A3FD4AF31675.Property { get; set; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess2).CandidateReason); } [Fact] public void LiteralReceiver_Property_String() { var src = """ "".Property = 42; _ = "".Property; static class E { extension(string s) { public int Property { get { System.Console.Write("get "); return 42; } set { System.Console.Write("set "); } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "set get").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "\"\".Property").First(); AssertEx.Equal("System.Int32 E.<G>$34505F560D9EACF86A87F3ED1F85E448.Property { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); var memberAccess2 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "\"\".Property").Last(); AssertEx.Equal("System.Int32 E.<G>$34505F560D9EACF86A87F3ED1F85E448.Property { get; set; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); } [Fact] public void SwitchReceiver_Property_String() { var src = """ bool b = true; (b switch { true => "", _ => "" }).Property = 42; _ = (b switch { true => "", _ => "" }).Property; static class E { extension(string s) { public int Property { get { System.Console.Write("get "); return 42; } set { System.Console.Write("set "); } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "set get").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, """(b switch { true => "", _ => "" }).Property""").First(); AssertEx.Equal("System.Int32 E.<G>$34505F560D9EACF86A87F3ED1F85E448.Property { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); var memberAccess2 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, """(b switch { true => "", _ => "" }).Property""").Last(); AssertEx.Equal("System.Int32 E.<G>$34505F560D9EACF86A87F3ED1F85E448.Property { get; set; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); } [Fact] public void ConditionalReceiver_Property_String() { var src = """ bool b = true; (b ? "" : null).Property = 42; _ = (b ? "" : null).Property; static class E { extension(string s) { public int Property { get { System.Console.Write("get "); return 42; } set { System.Console.Write("set "); } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "set get").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, """(b ? "" : null).Property""").First(); AssertEx.Equal("System.Int32 E.<G>$34505F560D9EACF86A87F3ED1F85E448.Property { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); var memberAccess2 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, """(b ? "" : null).Property""").Last(); AssertEx.Equal("System.Int32 E.<G>$34505F560D9EACF86A87F3ED1F85E448.Property { get; set; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); } [Fact] public void LiteralReceiver_Property_Integer_Get() { var src = """ _ = 1.Property; static class E { extension(int i) { public int Property { get { System.Console.Write("get"); return 42; } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "get").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "1.Property"); AssertEx.Equal("System.Int32 E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void LiteralReceiver_Property_Integer_Set() { var src = """ 1.Property = 1; static class E { extension(int i) { public int Property { set => throw null; } } } """; var comp = CreateCompilation(src); // Consider improving the error message comp.VerifyEmitDiagnostics( // (1,1): error CS0131: The left-hand side of an assignment must be a variable, property or indexer // 1.Property = 1; Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "1.Property").WithLocation(1, 1)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "1.Property"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.Int32 E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.Property { set; }"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.NotAVariable, model.GetSymbolInfo(memberAccess).CandidateReason); } [Fact] public void LiteralReceiver_Property_Null() { var src = """ null.Property = 1; _ = null.Property; static class E { extension(object o) { public int Property { get => throw null; set => throw null; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS0023: Operator '.' cannot be applied to operand of type '<null>' // null.Property = 1; Diagnostic(ErrorCode.ERR_BadUnaryOp, "null.Property").WithArguments(".", "<null>").WithLocation(1, 1), // (2,5): error CS0023: Operator '.' cannot be applied to operand of type '<null>' // _ = null.Property; Diagnostic(ErrorCode.ERR_BadUnaryOp, "null.Property").WithArguments(".", "<null>").WithLocation(2, 5)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "null.Property").First(); Assert.Null(model.GetSymbolInfo(memberAccess1).Symbol); Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess1).CandidateReason); var memberAccess2 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "null.Property").Last(); Assert.Null(model.GetSymbolInfo(memberAccess2).Symbol); Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess2).CandidateReason); } [Fact] public void LiteralReceiver_Property_Default() { var src = """ default.Property = 1; _ = default.Property; static class E { extension(object o) { public int Property { get => throw null; set => throw null; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS8716: There is no target type for the default literal. // default.Property = 1; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(1, 1), // (2,5): error CS8716: There is no target type for the default literal. // _ = default.Property; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(2, 5)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "default.Property").First(); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess1).CandidateReason); var memberAccess2 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "default.Property").Last(); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; set; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess2).CandidateReason); } [Fact] public void LiteralReceiver_Property_Tuple_Get() { var src = """ _ = (1, 2).Property; static class E { extension((int, int) t) { public int Property { get { System.Console.Write("get "); return 42; } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "get").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "(1, 2).Property"); AssertEx.Equal("System.Int32 E.<G>$49AAF2D3C1326E88AED3848611C299DA.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void LiteralReceiver_Property_Tuple_Set() { var src = """ (1, 2).Property = 1; static class E { extension((int, int) t) { public int Property { set { System.Console.Write($"set(value)"); }} } } """; var comp = CreateCompilation(src); // Consider improving the error message comp.VerifyEmitDiagnostics( // (1,1): error CS0131: The left-hand side of an assignment must be a variable, property or indexer // (1, 2).Property = 1; Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "(1, 2).Property").WithLocation(1, 1)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "(1, 2).Property"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.Int32 E.<G>$49AAF2D3C1326E88AED3848611C299DA.Property { set; }"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.NotAVariable, model.GetSymbolInfo(memberAccess).CandidateReason); } [Fact] public void LiteralReceiver_Property_Tuple_Default() { var src = """ (default, default).Property = 1; _ = (default, default).Property; static class E { extension((object, object) t) { public int Property { get => throw null; set => throw null; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,2): error CS8716: There is no target type for the default literal. // (default, default).Property = 1; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(1, 2), // (1,11): error CS8716: There is no target type for the default literal. // (default, default).Property = 1; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(1, 11), // (2,6): error CS8716: There is no target type for the default literal. // _ = (default, default).Property; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(2, 6), // (2,15): error CS8716: There is no target type for the default literal. // _ = (default, default).Property; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(2, 15)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "(default, default).Property").First(); Assert.Null(model.GetSymbolInfo(memberAccess1).Symbol); Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess1).CandidateReason); var memberAccess2 = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "(default, default).Property").Last(); Assert.Null(model.GetSymbolInfo(memberAccess2).Symbol); Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess2).CandidateReason); } [Fact] public void LiteralReceiver_Property_Tuple_Integer_ForLong() { var src = """ (1, 1).Property = 1; _ = (2, 2).Property; static class E { extension((long, long) t) { public int Property { get => throw null; set => throw null; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS1929: '(int, int)' does not contain a definition for 'Property' and the best extension method overload 'E.extension((long, long)).Property' requires a receiver of type '(long, long)' // (1, 1).Property = 1; Diagnostic(ErrorCode.ERR_BadInstanceArgType, "(1, 1)").WithArguments("(int, int)", "Property", "E.extension((long, long)).Property", "(long, long)").WithLocation(1, 1), // (2,5): error CS1929: '(int, int)' does not contain a definition for 'Property' and the best extension method overload 'E.extension((long, long)).Property' requires a receiver of type '(long, long)' // _ = (2, 2).Property; Diagnostic(ErrorCode.ERR_BadInstanceArgType, "(2, 2)").WithArguments("(int, int)", "Property", "E.extension((long, long)).Property", "(long, long)").WithLocation(2, 5)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "(1, 1).Property"); AssertEx.Equal("System.Int32 E.<G>$8477960720B8106C28CEADF5CDF3A674.Property { get; set; }", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess1).CandidateReason); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "(2, 2).Property"); AssertEx.Equal("System.Int32 E.<G>$8477960720B8106C28CEADF5CDF3A674.Property { get; set; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal(CandidateReason.None, model.GetSymbolInfo(memberAccess2).CandidateReason); } [Fact] public void PreferMoreSpecific_Static_MethodAndProperty() { var src = """ System.Console.Write(object.M); static class E1 { extension(object) { public static string M() => throw null; } } static class E2 { extension(object) { public static string M => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,22): error CS9339: The extension resolution is ambiguous between the following members: 'E1.extension(object).M()' and 'E2.extension(object).M' // System.Console.Write(object.M); Diagnostic(ErrorCode.ERR_AmbigExtension, "object.M").WithArguments("E1.extension(object).M()", "E2.extension(object).M").WithLocation(1, 22)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.String E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "System.String E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Empty(model.GetMemberGroup(memberAccess)); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : public API, consider handling BoundBadExpression better } [Fact] public void PreferMoreSpecific_Static_MethodAndProperty_Generic() { var src = """ System.Console.Write(object.M); static class E1 { extension<T>(T) { public static string M() => throw null; } } static class E2 { extension<T>(T) { public static string M => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,22): error CS9339: The extension resolution is ambiguous between the following members: 'E1.extension<T>(T).M()' and 'E2.extension<object>(object).M' // System.Console.Write(object.M); Diagnostic(ErrorCode.ERR_AmbigExtension, "object.M").WithArguments("E1.extension<T>(T).M()", "E2.extension<object>(object).M").WithLocation(1, 22)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : public API, consider handling BoundBadExpression better AssertEx.SequenceEqual(["System.String E1.<G>$8048A6C8BE30A622530249B904B537EB<T>.M()", "System.String E2.<G>$8048A6C8BE30A622530249B904B537EB<T>.M { get; }"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Empty(model.GetMemberGroup(memberAccess)); } [Fact] public void PreferMoreSpecific_Static_MethodAndProperty_Invocation() { var src = """ System.Console.Write(object.M()); static class E1 { extension(object) { public static string M() => "ran"; } } static class E2 { extension(object) { public static string M => throw null; // not invocable } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("System.String E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); AssertEx.SequenceEqual(["System.String E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "System.String E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void GetCompatibleExtensions_TwoSubstitutions() { var src = """ C.M(); new C().M2(); interface I<T> { } class C : I<int>, I<string> { } static class E { extension<T>(I<T>) { public static void M() { } } public static void M2<T>(this I<T> i) { } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (1,3): error CS0411: The type arguments for method 'E.extension<T>(I<T>).M()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // C.M(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("E.extension<T>(I<T>).M()").WithLocation(1, 3), // (2,9): error CS0411: The type arguments for method 'E.M2<T>(I<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // new C().M2(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M2").WithArguments("E.M2<T>(I<T>)").WithLocation(2, 9)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.M"); Assert.Null(model.GetSymbolInfo(memberAccess1).Symbol); Assert.Equal([], model.GetSymbolInfo(memberAccess1).CandidateSymbols.ToTestDisplayStrings()); Assert.Empty(model.GetMemberGroup(memberAccess1)); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "new C().M2"); Assert.Null(model.GetSymbolInfo(memberAccess2).Symbol); Assert.Equal([], model.GetSymbolInfo(memberAccess2).CandidateSymbols.ToTestDisplayStrings()); Assert.Empty(model.GetMemberGroup(memberAccess2)); } [Theory, ClassData(typeof(ThreePermutationGenerator))] public void PreferMoreSpecific_Static_MethodAndMoreSpecificInvocablePropertyAndMoreSpecificMethod(int first, int second, int third) { string[] segments = [ """ static class E1 { extension(object) { public static string M() => throw null; } } """, """ static class E2 { extension(C) { public static System.Func<string> M => null; } } """, """ static class E3 { extension(C) { public static string M() => throw null; } } """]; var src = $$""" System.Console.Write(C.M()); class C { } {{segments[first]}} {{segments[second]}} {{segments[third]}} """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,22): error CS9339: The extension resolution is ambiguous between the following members: 'E3.extension(C).M()' and 'E2.extension(C).M' // System.Console.Write(C.M()); Diagnostic(ErrorCode.ERR_AmbigExtension, "C.M").WithArguments("E3.extension(C).M()", "E2.extension(C).M").WithLocation(1, 22)); } [Fact] public void AmbiguousCallOnInterface() { var src = """ I2.M(); interface I<T> { public static void M() { } } interface I2 : I<int>, I<string> { } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (1,4): error CS0121: The call is ambiguous between the following methods or properties: 'I<int>.M()' and 'I<string>.M()' // I2.M(); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("I<int>.M()", "I<string>.M()").WithLocation(1, 4)); } [Fact] public void AmbiguousCallOnInterface_Generic() { var src = """ I2.M<int>(); interface I<T> { public static void M<U>() { } } interface I2 : I<int>, I<string> { } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (1,4): error CS0121: The call is ambiguous between the following methods or properties: 'I<int>.M<U>()' and 'I<string>.M<U>()' // I2.M<int>(); Diagnostic(ErrorCode.ERR_AmbigCall, "M<int>").WithArguments("I<int>.M<U>()", "I<string>.M<U>()").WithLocation(1, 4)); } [Fact] public void OmittedTypeArguments() { var src = """ object.P<int>; object.P<>; static class E { extension(object) { public static int P => 42; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (1,1): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement // object.P<int>; Diagnostic(ErrorCode.ERR_IllegalStatement, "object.P<int>").WithLocation(1, 1), // (1,8): error CS0117: 'object' does not contain a definition for 'P' // object.P<int>; Diagnostic(ErrorCode.ERR_NoSuchMember, "P<int>").WithArguments("object", "P").WithLocation(1, 8), // (2,1): error CS8389: Omitting the type argument is not allowed in the current context // object.P<>; Diagnostic(ErrorCode.ERR_OmittedTypeArgument, "object.P<>").WithLocation(2, 1), // (2,1): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement // object.P<>; Diagnostic(ErrorCode.ERR_IllegalStatement, "object.P<>").WithLocation(2, 1), // (2,8): error CS0117: 'object' does not contain a definition for 'P' // object.P<>; Diagnostic(ErrorCode.ERR_NoSuchMember, "P<>").WithArguments("object", "P").WithLocation(2, 8)); } [Fact] public void ExtensionMemberLookup_PatternBased_ForEach_NoMethod() { var src = """ foreach (var x in new C()) { System.Console.Write(x); break; } class C { } class D { } static class E { extension(C c) { public D GetEnumerator() => new D(); } extension(D d) { public bool MoveNext() => true; public int Current => 42; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (1,19): error CS0117: 'D' does not contain a definition for 'Current' // foreach (var x in new C()) Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("D", "Current").WithLocation(1, 19), // (1,19): error CS0202: foreach requires that the return type 'D' of 'E.extension(C).GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property // foreach (var x in new C()) Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("D", "E.extension(C).GetEnumerator()").WithLocation(1, 19) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var loop = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single(); Assert.Null(model.GetForEachStatementInfo(loop).GetEnumeratorMethod); Assert.Null(model.GetForEachStatementInfo(loop).MoveNextMethod); Assert.Null(model.GetForEachStatementInfo(loop).CurrentProperty); } [Fact] public void ExtensionMemberLookup_PatternBased_ForEach_NoApplicableMethod() { var src = """ foreach (var x in new C()) { System.Console.Write(x); break; } class C { public void GetEnumerator(int notApplicable) { } // not applicable } class D { } static class E { extension(C c) { public D GetEnumerator() => new D(); } extension(D d) { public bool MoveNext() => true; public int Current => 42; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,19): error CS0117: 'D' does not contain a definition for 'Current' // foreach (var x in new C()) Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("D", "Current").WithLocation(1, 19), // (1,19): error CS0202: foreach requires that the return type 'D' of 'E.extension(C).GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property // foreach (var x in new C()) Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("D", "E.extension(C).GetEnumerator()").WithLocation(1, 19) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var loop = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single(); Assert.Null(model.GetForEachStatementInfo(loop).GetEnumeratorMethod); Assert.Null(model.GetForEachStatementInfo(loop).MoveNextMethod); Assert.Null(model.GetForEachStatementInfo(loop).CurrentProperty); } [Fact] public void ExtensionMemberLookup_PatternBased_ForEach_WrongArity() { var src = """ using System.Collections; foreach (var x in new C()) { } class C { } static class E { extension(C c) { public IEnumerator GetEnumerator<T>() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,19): error CS0411: The type arguments for method 'E.extension(C).GetEnumerator<T>()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // foreach (var x in new C()) { } Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "new C()").WithArguments("E.extension(C).GetEnumerator<T>()").WithLocation(3, 19), // (3,19): error CS1579: foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance or extension definition for 'GetEnumerator' // foreach (var x in new C()) { } Diagnostic(ErrorCode.ERR_ForEachMissingMember, "new C()").WithArguments("C", "GetEnumerator").WithLocation(3, 19)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var loop = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single(); Assert.Null(model.GetForEachStatementInfo(loop).GetEnumeratorMethod); } [Fact] public void ExtensionMemberLookup_PatternBased_ForEach_NonInvocable() { var src = """ using System.Collections; foreach (var x in new C()) { } class C { } static class E { extension(C c) { public IEnumerator GetEnumerator => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,19): error CS1579: foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance or extension definition for 'GetEnumerator' // foreach (var x in new C()) { } Diagnostic(ErrorCode.ERR_ForEachMissingMember, "new C()").WithArguments("C", "GetEnumerator").WithLocation(3, 19)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var loop = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single(); Assert.Null(model.GetForEachStatementInfo(loop).GetEnumeratorMethod); } [Fact] public void ExtensionMemberLookup_PatternBased_ForEach_DelegateTypeProperty() { var src = """ using System.Collections; foreach (var x in new C()) { } class C { } static class E { extension(C c) { public System.Func<IEnumerator> GetEnumerator => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,19): error CS1579: foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance or extension definition for 'GetEnumerator' // foreach (var x in new C()) { } Diagnostic(ErrorCode.ERR_ForEachMissingMember, "new C()").WithArguments("C", "GetEnumerator").WithLocation(3, 19)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var loop = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single(); Assert.Null(model.GetForEachStatementInfo(loop).GetEnumeratorMethod); src = """ using System.Collections; foreach (var x in new C()) { } class C { public System.Func<IEnumerator> GetEnumerator => throw null; } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,19): warning CS0280: 'C' does not implement the 'collection' pattern. 'C.GetEnumerator' has the wrong signature. // foreach (var x in new C()) { } Diagnostic(ErrorCode.WRN_PatternBadSignature, "new C()").WithArguments("C", "collection", "C.GetEnumerator").WithLocation(3, 19), // (3,19): error CS1579: foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance or extension definition for 'GetEnumerator' // foreach (var x in new C()) { } Diagnostic(ErrorCode.ERR_ForEachMissingMember, "new C()").WithArguments("C", "GetEnumerator").WithLocation(3, 19)); } [Fact] public void ExtensionMemberLookup_PatternBased_ForEach_GetEnumerator_DynamicTypeProperty() { var src = """ using System.Collections; foreach (var x in new C()) { } class C { } static class E { extension(C c) { public dynamic GetEnumerator => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,19): error CS1579: foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance or extension definition for 'GetEnumerator' // foreach (var x in new C()) { } Diagnostic(ErrorCode.ERR_ForEachMissingMember, "new C()").WithArguments("C", "GetEnumerator").WithLocation(3, 19)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var loop = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single(); Assert.Null(model.GetForEachStatementInfo(loop).GetEnumeratorMethod); src = """ foreach (var x in new C()) { } class C { public dynamic GetEnumerator => throw null; } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,19): warning CS0280: 'C' does not implement the 'collection' pattern. 'C.GetEnumerator' has the wrong signature. // foreach (var x in new C()) { } Diagnostic(ErrorCode.WRN_PatternBadSignature, "new C()").WithArguments("C", "collection", "C.GetEnumerator").WithLocation(1, 19), // (1,19): error CS1579: foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance or extension definition for 'GetEnumerator' // foreach (var x in new C()) { } Diagnostic(ErrorCode.ERR_ForEachMissingMember, "new C()").WithArguments("C", "GetEnumerator").WithLocation(1, 19)); } [Fact] public void ExtensionMemberLookup_PatternBased_ForEach_GetEnumerator_Generic() { var src = """ using System.Collections.Generic; foreach (var x in new C()) { System.Console.Write(x); } class C { } static class E { extension<T>(T t) { public IEnumerator<T> GetEnumerator() { yield return t; } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "C").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var loop = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single(); AssertEx.Equal("System.Collections.Generic.IEnumerator<C> E.<G>$8048A6C8BE30A622530249B904B537EB<C>.GetEnumerator()", model.GetForEachStatementInfo(loop).GetEnumeratorMethod.ToTestDisplayString()); } [Fact] public void ExtensionMemberLookup_PatternBased_AwaitForEach_GetAsyncEnumerator() { var src = """ using System.Collections.Generic; await foreach (var x in new C()) { System.Console.Write(x); } class C { } static class E { extension<T>(T t) { public async IAsyncEnumerator<T> GetAsyncEnumerator() { await System.Threading.Tasks.Task.Yield(); yield return t; } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(comp, expectedOutput: ExpectedOutput("C"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var loop = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single(); AssertEx.Equal("System.Collections.Generic.IAsyncEnumerator<C> E.<G>$8048A6C8BE30A622530249B904B537EB<C>.GetAsyncEnumerator()", model.GetForEachStatementInfo(loop).GetEnumeratorMethod.ToTestDisplayString()); } [Fact] public void ExtensionMemberLookup_PatternBased_Deconstruct_NoMethod() { var src = """ var (x, y) = new C(); System.Console.Write((x, y)); class C { } static class E { extension(C c) { public void Deconstruct(out int i, out int j) { i = 42; j = 43; } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var deconstruction = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().First(); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Deconstruct(out System.Int32 i, out System.Int32 j)", model.GetDeconstructionInfo(deconstruction).Method.ToTestDisplayString()); } [Fact] public void ExtensionMemberLookup_PatternBased_Deconstruct_Conversion_01() { var src = """ var (x, y) = new C(); System.Console.Write((x, y)); class C { } static class E { extension(object o) { public void Deconstruct(out int i, out int j) { i = 42; j = 43; } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78682")] public void ExtensionMemberLookup_PatternBased_Deconstruct_Conversion_02() { // array to Span var src = """ var (x, y) = new int[] { 42 }; System.Console.Write((x, y)); class C { } static class E { extension(System.Span<int> s) { public void Deconstruct(out int i, out int j) { i = 42; j = 43; } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(comp, expectedOutput: ExpectedOutput("(42, 43)"), verify: Verification.Skipped).VerifyDiagnostics(); src = """ var (x, y) = new int[] { 42 }; System.Console.Write((x, y)); static class E { public static void Deconstruct(this System.Span<int> s, out int i, out int j) { i = 42; j = 43; } } """; comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(comp, expectedOutput: ExpectedOutput("(42, 43)"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78682")] public void ExtensionMemberLookup_PatternBased_Deconstruct_Conversion_03() { // We check conversion during initial binding var src = """ var (x, y) = new int[] { 42 }; System.Console.Write((x, y)); class C { } static class E { extension(System.Span<int> s) { public void Deconstruct(out int i, out int j) => throw null; } } namespace System { public ref struct Span<T> { } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (1,1): error CS0656: Missing compiler required member 'Span<T>.op_Implicit' // var (x, y) = new int[] { 42 }; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "var (x, y) = new int[] { 42 }").WithArguments("System.Span<T>", "op_Implicit").WithLocation(1, 1), // (8,22): warning CS0436: The type 'Span<T>' in '' conflicts with the imported type 'Span<T>' in 'System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Using the type defined in ''. // extension(System.Span<int> s) Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Span<int>").WithArguments("", "System.Span<T>", "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Span<T>").WithLocation(8, 22)); } [Fact] public void ExtensionMemberLookup_PatternBased_Deconstruct_Generic() { var src = """ var (x, y) = new C(); System.Console.Write((x, y)); class C { } static class E { extension<T>(T t) { public void Deconstruct(out int i, out int j) { i = 42; j = 43; } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var deconstruction = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().First(); AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<C>.Deconstruct(out System.Int32 i, out System.Int32 j)", model.GetDeconstructionInfo(deconstruction).Method.ToTestDisplayString()); } [Fact] public void ExtensionMemberLookup_PatternBased_Deconstruct_FallbackToExtensionMethod() { // If the method from the extension type is not applicable, we fall back // to a Deconstruct extension method var src = """ var (x, y) = new C(); System.Console.Write((x, y)); public class C { } static class E { extension(C c) { public void Deconstruct(int inapplicable) => throw null; } } public static class E2 { public static void Deconstruct(this C c, out int i, out int j) { i = 42; j = 43; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var deconstruction = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().First(); AssertEx.Equal("void E2.Deconstruct(this C c, out System.Int32 i, out System.Int32 j)", model.GetDeconstructionInfo(deconstruction).Method.ToTestDisplayString()); } [Fact] public void ExtensionMemberLookup_PatternBased_Deconstruct_DelegateTypeProperty() { var src = """ var (x1, y1) = new C1(); var (x2, y2) = new C2(); class C1 { } class C2 { public D Deconstruct => (out int i, out int j) => { i = 42; j = 43; }; } delegate void D(out int i, out int j); static class E { extension(C1 c) { public D Deconstruct => (out int i, out int j) => { i = 42; j = 43; }; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (1,6): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x1'. // var (x1, y1) = new C1(); Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x1").WithArguments("x1").WithLocation(1, 6), // (1,10): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'y1'. // var (x1, y1) = new C1(); Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y1").WithArguments("y1").WithLocation(1, 10), // (1,16): error CS1061: 'C1' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'C1' could be found (are you missing a using directive or an assembly reference?) // var (x1, y1) = new C1(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "new C1()").WithArguments("C1", "Deconstruct").WithLocation(1, 16), // (1,16): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'C1', with 2 out parameters and a void return type. // var (x1, y1) = new C1(); Diagnostic(ErrorCode.ERR_MissingDeconstruct, "new C1()").WithArguments("C1", "2").WithLocation(1, 16), // (3,6): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x2'. // var (x2, y2) = new C2(); Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x2").WithArguments("x2").WithLocation(3, 6), // (3,10): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'y2'. // var (x2, y2) = new C2(); Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y2").WithArguments("y2").WithLocation(3, 10), // (3,16): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'C2', with 2 out parameters and a void return type. // var (x2, y2) = new C2(); Diagnostic(ErrorCode.ERR_MissingDeconstruct, "new C2()").WithArguments("C2", "2").WithLocation(3, 16) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var deconstruction = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().First(); Assert.Null(model.GetDeconstructionInfo(deconstruction).Method); } [Fact] public void ExtensionMemberLookup_PatternBased_Deconstruct_DynamicProperty() { var src = """ var (x, y) = new C(); class C { } static class E { extension(C c) { public dynamic Deconstruct => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,6): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x'. // var (x, y) = new C(); Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x").WithArguments("x").WithLocation(1, 6), // (1,9): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'y'. // var (x, y) = new C(); Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y").WithArguments("y").WithLocation(1, 9), // (1,14): error CS1061: 'C' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) // var (x, y) = new C(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "new C()").WithArguments("C", "Deconstruct").WithLocation(1, 14), // (1,14): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'C', with 2 out parameters and a void return type. // var (x, y) = new C(); Diagnostic(ErrorCode.ERR_MissingDeconstruct, "new C()").WithArguments("C", "2").WithLocation(1, 14) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var deconstruction = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().First(); Assert.Null(model.GetDeconstructionInfo(deconstruction).Method); src = """ var (x, y) = new C(); class C { public dynamic Deconstruct => throw null; } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,6): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x'. // var (x, y) = new C(); Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x").WithArguments("x").WithLocation(1, 6), // (1,9): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'y'. // var (x, y) = new C(); Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y").WithArguments("y").WithLocation(1, 9), // (1,14): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'C', with 2 out parameters and a void return type. // var (x, y) = new C(); Diagnostic(ErrorCode.ERR_MissingDeconstruct, "new C()").WithArguments("C", "2").WithLocation(1, 14)); } [Fact] public void ExtensionMemberLookup_PatternBased_Deconstruct_NoApplicableMethod() { var src = """ var (x, y) = new C(); System.Console.Write((x, y)); class C { public void Deconstruct() { } // not applicable } static class E { extension(C c) { public void Deconstruct(out int i, out int j) { i = 42; j = 43; } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var deconstruction = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().First(); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Deconstruct(out System.Int32 i, out System.Int32 j)", model.GetDeconstructionInfo(deconstruction).Method.ToTestDisplayString()); } [Fact] public void ExtensionMemberLookup_PatternBased_PositionalPattern() { var libSrc = """ public static class E { extension<T>(T t) { public void Deconstruct(out int i, out int j) { i = 42; j = 43; } } } """; var libRef = CreateCompilation(libSrc).EmitToImageReference(); var src = """ var c = new C(); if (c is var (x, y)) System.Console.Write((x, y)); class C { } """; var comp = CreateCompilation(src, references: [libRef]); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_DisposeAsync_NoMethod() { var src = """ using System.Threading.Tasks; /*<bind>*/ await using var x1 = new C1(); /*</bind>*/ await using var x2 = new C2(); class C1 { } class C2 { } static class E { extension(C1 c) { public Task DisposeAsync() => throw null; } public static Task DisposeAsync(this C2 c) => throw null; } """; var comp = CreateCompilation(src); var expectedDiagnostics = new[] { // (4,1): error CS8410: 'C1': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. // await using var x1 = new C1(); Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "await using var x1 = new C1();").WithArguments("C1").WithLocation(4, 1), // (7,1): error CS8410: 'C2': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. // await using var x2 = new C2(); Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "await using var x2 = new C2();").WithArguments("C2").WithLocation(7, 1) }; comp.VerifyDiagnostics(expectedDiagnostics); string expectedOperationTree = """ IUsingDeclarationOperation(IsAsynchronous: True) (OperationKind.UsingDeclaration, Type: null, IsInvalid) (Syntax: 'await using ... = new C1();') DeclarationGroup: IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsInvalid, IsImplicit) (Syntax: 'await using ... = new C1();') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'var x1 = new C1()') Declarators: IVariableDeclaratorOperation (Symbol: C1 x1) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: 'x1 = new C1()') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null, IsInvalid) (Syntax: '= new C1()') IObjectCreationOperation (Constructor: C1..ctor()) (OperationKind.ObjectCreation, Type: C1, IsInvalid) (Syntax: 'new C1()') Arguments(0) Initializer: null Initializer: null """; VerifyOperationTreeAndDiagnosticsForTest<LocalDeclarationStatementSyntax>(src, expectedOperationTree, expectedDiagnostics); } [Fact] public void TestPatternBasedDisposal_ExtensionMethod() { string source = @" public class C { public static async System.Threading.Tasks.Task<int> Main() { await using (var x = new C()) { } return 1; } } public static class Extensions { extension (C c) { public System.Threading.Tasks.ValueTask DisposeAsync() => throw null; } } "; // extension methods do not contribute to pattern-based disposal var comp = CreateCompilationWithTasksExtensions(new[] { source, IAsyncDisposableDefinition }, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // 0.cs(6,22): error CS8410: 'C': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. // await using (var x = new C()) Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "var x = new C()").WithArguments("C").WithLocation(6, 22) ); } [Fact] public void PatternBased_Dispose_Async_DelegateTypeProperty() { var src = """ using System.Threading.Tasks; await using var x = new C(); class C { public System.Func<Task> DisposeAsync => async () => { System.Console.Write("ran2"); await Task.Yield(); }; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,1): error CS8410: 'C': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. // await using var x = new C(); Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "await using var x = new C();").WithArguments("C").WithLocation(3, 1) ); } [Fact] public void ExtensionMemberLookup_PatternBased_Dispose_Async_DelegateTypeProperty() { var src = """ using System.Threading.Tasks; await using var x = new C(); class C { } static class E { extension(C c) { public System.Func<Task> DisposeAsync => async () => { await Task.Yield(); }; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,1): error CS8410: 'C': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. // await using var x = new C(); Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "await using var x = new C();").WithArguments("C").WithLocation(3, 1) ); } [Fact] public void ExtensionMemberLookup_PatternBased_Dispose_Async_NoApplicableMethod() { var src = """ using System.Threading.Tasks; /*<bind>*/ await using var x = new C(); /*</bind>*/ class C { public Task DisposeAsync(int notApplicable) => throw null; // not applicable } static class E { extension(C c) { public async Task DisposeAsync() { System.Console.Write("RAN"); await Task.Yield(); } } } """; DiagnosticDescription[] expectedDiagnostics = [ // (4,1): error CS8410: 'C': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. // await using var x = new C(); Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "await using var x = new C();").WithArguments("C").WithLocation(4, 1)]; var comp = CreateCompilation(src).VerifyEmitDiagnostics(expectedDiagnostics); string expectedOperationTree = """ IUsingDeclarationOperation(IsAsynchronous: True) (OperationKind.UsingDeclaration, Type: null, IsInvalid) (Syntax: 'await using ... = new C();') DeclarationGroup: IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsInvalid, IsImplicit) (Syntax: 'await using ... = new C();') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'var x = new C()') Declarators: IVariableDeclaratorOperation (Symbol: C x) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: 'x = new C()') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null, IsInvalid) (Syntax: '= new C()') IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C, IsInvalid) (Syntax: 'new C()') Arguments(0) Initializer: null Initializer: null """; VerifyOperationTreeAndDiagnosticsForTest<LocalDeclarationStatementSyntax>(src, expectedOperationTree, expectedDiagnostics); } [Fact] public void ExtensionMemberLookup_PatternBased_Dispose_RefStruct() { var src = """ using var x1 = new S1(); using var x2 = new S2(); ref struct S1 { } ref struct S2 { } static class E { extension(S1 s) { public void Dispose() { } } public static void Dispose(this S2 s) { } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (1,1): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'. // using var x1 = new S1(); Diagnostic(ErrorCode.ERR_NoConvToIDisp, "using var x1 = new S1();").WithArguments("S1").WithLocation(1, 1), // (2,1): error CS1674: 'S2': type used in a using statement must implement 'System.IDisposable'. // using var x2 = new S2(); Diagnostic(ErrorCode.ERR_NoConvToIDisp, "using var x2 = new S2();").WithArguments("S2").WithLocation(2, 1) ); } [Fact] public void ExtensionMemberLookup_PatternBased_Dispose_RefStruct_DelegateTypeProperty() { var src = """ using var x1 = new S1(); ref struct S1 { } static class E { extension(S1 s) { public System.Action Dispose => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (1,1): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'. // using var x1 = new S1(); Diagnostic(ErrorCode.ERR_NoConvToIDisp, "using var x1 = new S1();").WithArguments("S1").WithLocation(1, 1)); src = """ using var x1 = new S1(); ref struct S1 { public System.Action Dispose => throw null; } """; comp = CreateCompilation(src); comp.VerifyDiagnostics( // (1,1): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'. // using var x1 = new S1(); Diagnostic(ErrorCode.ERR_NoConvToIDisp, "using var x1 = new S1();").WithArguments("S1").WithLocation(1, 1)); } [Fact] public void ExtensionMemberLookup_PatternBased_Fixed_01() { var text = """ unsafe class C { public static void Main() { fixed (int* p = new Fixable()) { System.Console.WriteLine(p[1]); } } } class Fixable { } static class E { extension(Fixable f) { public ref int GetPinnableReference() { System.Console.Write("pin "); return ref (new int[] { 1, 2, 3 })[0]; } } } """; var comp = CreateCompilation(text, options: TestOptions.UnsafeReleaseExe); CompileAndVerify(comp, expectedOutput: "pin 2", verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_Fixed_Conversion_01() { var text = """ unsafe class C { public static void Main() { fixed (int* p = new Fixable()) { System.Console.WriteLine(p[1]); } } } class Fixable { } static class E { extension(object o) { public ref int GetPinnableReference() { System.Console.Write("pin "); return ref (new int[] { 1, 2, 3 })[0]; } } } """; var comp = CreateCompilation(text, options: TestOptions.UnsafeReleaseExe); CompileAndVerify(comp, expectedOutput: "pin 2", verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_Fixed_Conversion_02() { var text = """ unsafe class C { public static void Main() { fixed (int* p = (0, "")) { System.Console.WriteLine(p[1]); } } } static class E { extension((object, object) t) { public ref int GetPinnableReference() { System.Console.Write("pin "); return ref (new int[] { 1, 2, 3 })[0]; } } } """; var comp = CreateCompilation(text, options: TestOptions.UnsafeReleaseExe, targetFramework: TargetFramework.Net90); CompileAndVerify(comp, expectedOutput: ExpectedOutput("pin 2"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_Fixed_Conversion_03() { // We check conversion during initial binding var text = """ unsafe class C { public static void M() { System.ReadOnlySpan<string> x = default; fixed (long* p = x) { } } } static class E { extension(System.ReadOnlySpan<object> s) { public ref long GetPinnableReference() => throw null; } } namespace System { public ref struct ReadOnlySpan<T> { } } """; var comp = CreateCompilation(text, options: TestOptions.UnsafeDebugDll, targetFramework: TargetFramework.Net90); comp.VerifyDiagnostics( // (5,16): warning CS0436: The type 'ReadOnlySpan<T>' in '' conflicts with the imported type 'ReadOnlySpan<T>' in 'System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Using the type defined in ''. // System.ReadOnlySpan<string> x = default; Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "ReadOnlySpan<string>").WithArguments("", "System.ReadOnlySpan<T>", "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.ReadOnlySpan<T>").WithLocation(5, 16), // (6,26): error CS0656: Missing compiler required member 'ReadOnlySpan<T>.CastUp' // fixed (long* p = x) Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x").WithArguments("System.ReadOnlySpan<T>", "CastUp").WithLocation(6, 26), // (14,22): warning CS0436: The type 'ReadOnlySpan<T>' in '' conflicts with the imported type 'ReadOnlySpan<T>' in 'System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Using the type defined in ''. // extension(System.ReadOnlySpan<object> s) Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "ReadOnlySpan<object>").WithArguments("", "System.ReadOnlySpan<T>", "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.ReadOnlySpan<T>").WithLocation(14, 22)); } [Fact] public void ExtensionMemberLookup_PatternBased_Fixed_03_DelegateTypeProperty() { var text = @" unsafe class C { public static void Main() { fixed (int* p = new Fixable1()) { System.Console.WriteLine(p[1]); } fixed (int* p = new Fixable2()) { System.Console.WriteLine(p[1]); } } } class Fixable1 { } class Fixable2 { public MyDelegate GetPinnableReference => throw null; } delegate ref int MyDelegate(); static class E { extension(Fixable1 f) { public MyDelegate GetPinnableReference => throw null; } } "; var comp = CreateCompilation(text, options: TestOptions.UnsafeReleaseExe); comp.VerifyEmitDiagnostics( // (6,25): error CS8385: The given expression cannot be used in a fixed statement // fixed (int* p = new Fixable1()) Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable1()").WithLocation(6, 25), // (11,25): error CS8385: The given expression cannot be used in a fixed statement // fixed (int* p = new Fixable2()) Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable2()").WithLocation(11, 25) ); } [Fact] public void ExtensionMemberLookup_PatternBased_Fixed_04_DynamicTypeProperty() { var text = @" unsafe class C { public static void Main() { fixed (int* p = new Fixable1()) { } } } class Fixable1 { } delegate ref int MyDelegate(); static class E { extension(Fixable1 f) { public dynamic GetPinnableReference => throw null; } } "; var comp = CreateCompilation(text, options: TestOptions.UnsafeReleaseExe); comp.VerifyEmitDiagnostics( // (6,25): error CS8385: The given expression cannot be used in a fixed statement // fixed (int* p = new Fixable1()) Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable1()").WithLocation(6, 25)); text = @" unsafe class C { public static void Main() { fixed (int* p = new Fixable1()) { } } } class Fixable1 { public dynamic GetPinnableReference => throw null; } delegate ref int MyDelegate(); "; comp = CreateCompilation(text, options: TestOptions.UnsafeReleaseExe); comp.VerifyEmitDiagnostics( // (6,25): error CS8385: The given expression cannot be used in a fixed statement // fixed (int* p = new Fixable1()) Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable1()").WithLocation(6, 25)); } [Fact] public void ExtensionMemberLookup_PatternBased_Fixed_05() { var src = """ unsafe class C { public static void Main() { /*<bind>*/ fixed (int* p = new Fixable()) { System.Console.WriteLine(p[1]); } /*</bind>*/ } } class Fixable { public ref int GetPinnableReference(int notApplicable) => throw null; // not applicable } static class E { extension(Fixable f) { public ref int GetPinnableReference() { return ref (new int[] { 1, 2, 3 })[0]; } } } """; var comp = CreateCompilation(src, options: TestOptions.UnsafeReleaseExe); CompileAndVerify(comp, expectedOutput: "2", verify: Verification.Skipped).VerifyDiagnostics(); string expectedOperationTree = """ IFixedOperation (OperationKind.None, Type: null) (Syntax: 'fixed (int* ... }') Locals: Local_1: System.Int32* p Declaration: IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsImplicit) (Syntax: 'int* p = new Fixable()') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'int* p = new Fixable()') Declarators: IVariableDeclaratorOperation (Symbol: System.Int32* p) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'p = new Fixable()') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= new Fixable()') IOperation: (OperationKind.None, Type: System.Int32*, IsImplicit) (Syntax: 'new Fixable()') Children(1): IObjectCreationOperation (Constructor: Fixable..ctor()) (OperationKind.ObjectCreation, Type: Fixable) (Syntax: 'new Fixable()') Arguments(0) Initializer: null Initializer: null Body: IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'System.Cons ... Line(p[1]);') Expression: IInvocationOperation (void System.Console.WriteLine(System.Int32 value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'System.Cons ... eLine(p[1])') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'p[1]') IOperation: (OperationKind.None, Type: System.Int32) (Syntax: 'p[1]') Children(2): ILocalReferenceOperation: p (OperationKind.LocalReference, Type: System.Int32*) (Syntax: 'p') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) """; VerifyOperationTreeAndDiagnosticsForTest<FixedStatementSyntax>(src, expectedOperationTree, [], targetFramework: TargetFramework.Net70, compilationOptions: TestOptions.UnsafeReleaseExe); } [Fact] public void ExtensionMemberLookup_PatternBased_Fixed_06() { var text = @" unsafe class C { public static void Main() { fixed (int* p = new Fixable()) { } } } class Fixable { } static class E { extension(Fixable f) { public static ref int GetPinnableReference() => throw null; } } "; var comp = CreateCompilation(text, options: TestOptions.UnsafeReleaseExe); comp.VerifyEmitDiagnostics( // (6,25): error CS0176: Member 'E.extension(Fixable).GetPinnableReference()' cannot be accessed with an instance reference; qualify it with a type name instead // fixed (int* p = new Fixable()) Diagnostic(ErrorCode.ERR_ObjectProhibited, "new Fixable()").WithArguments("E.extension(Fixable).GetPinnableReference()").WithLocation(6, 25), // (6,25): error CS8385: The given expression cannot be used in a fixed statement // fixed (int* p = new Fixable()) Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable()").WithLocation(6, 25)); } [Fact] public void ExtensionMemberLookup_PatternBased_Await_ExtensionIsCompleted() { var text = @" using System; using System.Runtime.CompilerServices; int i = await new C(); System.Console.Write(i); class C { public D GetAwaiter() => new D(); } class D : INotifyCompletion { public int GetResult() => 42; public void OnCompleted(Action continuation) => throw null; } static class E { extension(D d) { public bool IsCompleted => true; } } "; var comp = CreateCompilation(text); comp.VerifyEmitDiagnostics( // (5,9): error CS0117: 'D' does not contain a definition for 'IsCompleted' // int i = await new C(); Diagnostic(ErrorCode.ERR_NoSuchMember, "await new C()").WithArguments("D", "IsCompleted").WithLocation(5, 9) ); } [Fact] public void ExtensionMemberLookup_PatternBased_Await_ExtensionGetAwaiter() { var text = @" using System; using System.Runtime.CompilerServices; /*<bind>*/ int i = await new C(); /*</bind>*/ System.Console.Write(i); class C { } class D : INotifyCompletion { public int GetResult() => 42; public void OnCompleted(Action continuation) => throw null; public bool IsCompleted => true; } static class E { extension(C c) { public D GetAwaiter() => new D(); } } "; var comp = CreateCompilation(text); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); string expectedOperationTree = """ IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'int i = await new C();') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'int i = await new C()') Declarators: IVariableDeclaratorOperation (Symbol: System.Int32 i) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'i = await new C()') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= await new C()') IAwaitOperation (OperationKind.Await, Type: System.Int32) (Syntax: 'await new C()') Expression: IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C()') Arguments(0) Initializer: null Initializer: null """; VerifyOperationTreeAndDiagnosticsForTest<LocalDeclarationStatementSyntax>(text, expectedOperationTree, [], targetFramework: TargetFramework.Net70); } [Fact] public void ExtensionMemberLookup_PatternBased_Await_ExtensionGetAwaiter_Conversion() { var text = @" using System; using System.Runtime.CompilerServices; int i = await new C(); System.Console.Write(i); class C { } class D : INotifyCompletion { public int GetResult() => 42; public void OnCompleted(Action continuation) => throw null; public bool IsCompleted => true; } static class E { extension(object o) { public D GetAwaiter() => new D(); } } "; var comp = CreateCompilation(text); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_Await_ExtensionGetAwaiter_DelegateTypeProperty() { var text = @" using System; using System.Runtime.CompilerServices; int i = await new C(); System.Console.Write(i); class C { } class D : INotifyCompletion { public int GetResult() => 42; public void OnCompleted(Action continuation) => throw null; public bool IsCompleted => true; } static class E { extension(C c) { public System.Func<D> GetAwaiter => () => new D(); } } "; var comp = CreateCompilation(text); comp.VerifyEmitDiagnostics( // (5,9): error CS1061: 'C' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) // int i = await new C(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "await new C()").WithArguments("C", "GetAwaiter").WithLocation(5, 9)); text = @" using System; using System.Runtime.CompilerServices; int i = await new C(); System.Console.Write(i); class C { public System.Func<D> GetAwaiter => () => new D(); } class D : INotifyCompletion { public int GetResult() => 42; public void OnCompleted(Action continuation) => throw null; public bool IsCompleted => true; } "; comp = CreateCompilation(text); comp.VerifyEmitDiagnostics( // (5,9): error CS0118: 'GetAwaiter' is a property but is used like a method // int i = await new C(); Diagnostic(ErrorCode.ERR_BadSKknown, "await new C()").WithArguments("GetAwaiter", "property", "method").WithLocation(5, 9)); } [Fact] public void ExtensionMemberLookup_PatternBased_Await_ExtensionGetAwaiter_DynamicTypeProperty() { var text = @" using System; using System.Runtime.CompilerServices; int i = await new C(); System.Console.Write(i); class C { } class D : INotifyCompletion { public int GetResult() => 42; public void OnCompleted(Action continuation) => throw null; public bool IsCompleted => true; } static class E { extension(C c) { public dynamic GetAwaiter => throw null; } } "; var comp = CreateCompilation(text); comp.VerifyEmitDiagnostics( // (5,9): error CS1061: 'C' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) // int i = await new C(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "await new C()").WithArguments("C", "GetAwaiter").WithLocation(5, 9)); text = @" using System; using System.Runtime.CompilerServices; int i = await new C(); System.Console.Write(i); class C { public dynamic GetAwaiter => throw null; } class D : INotifyCompletion { public int GetResult() => 42; public void OnCompleted(Action continuation) => throw null; public bool IsCompleted => true; } "; comp = CreateCompilation(text); comp.VerifyEmitDiagnostics( // (5,9): error CS0118: 'GetAwaiter' is a property but is used like a method // int i = await new C(); Diagnostic(ErrorCode.ERR_BadSKknown, "await new C()").WithArguments("GetAwaiter", "property", "method").WithLocation(5, 9)); } [Fact] public void ExtensionMemberLookup_PatternBased_Await_ExtensionGetResult() { var text = @" using System; using System.Runtime.CompilerServices; int i = await new C(); System.Console.Write(i); class C { public D GetAwaiter() => new D(); } class D : INotifyCompletion { public void OnCompleted(Action continuation) => throw null; public bool IsCompleted => true; } static class E { extension(D d) { public int GetResult() => 42; } } "; var comp = CreateCompilation(text); // The error is consistent with classic extension methods comp.VerifyEmitDiagnostics( // (5,9): error CS0117: 'D' does not contain a definition for 'GetResult' // int i = await new C(); Diagnostic(ErrorCode.ERR_NoSuchMember, "await new C()").WithArguments("D", "GetResult").WithLocation(5, 9) ); text = """ using System; using System.Runtime.CompilerServices; int i = await new C(); System.Console.Write(i); class C { public D GetAwaiter() => new D(); } class D : INotifyCompletion { public void OnCompleted(Action continuation) => throw null; public bool IsCompleted => true; } static class E { public static int GetResult(this D d) => 42; } """; comp = CreateCompilation(text); comp.VerifyEmitDiagnostics( // (4,9): error CS0117: 'D' does not contain a definition for 'GetResult' // int i = await new C(); Diagnostic(ErrorCode.ERR_NoSuchMember, "await new C()").WithArguments("D", "GetResult").WithLocation(4, 9) ); } [Fact] public void ExtensionMemberLookup_PatternBased_Await_ExtensionGetResult_DelegateTypeProperty() { var text = @" using System; using System.Runtime.CompilerServices; int i = await new C(); System.Console.Write(i); class C { public D GetAwaiter() => new D(); } class D : INotifyCompletion { public void OnCompleted(Action continuation) => throw null; public bool IsCompleted => true; } static class E { extension(D d) { public System.Func<int> GetResult => () => 42; } } "; var comp = CreateCompilation(text); comp.VerifyEmitDiagnostics( // (5,9): error CS0117: 'D' does not contain a definition for 'GetResult' // int i = await new C(); Diagnostic(ErrorCode.ERR_NoSuchMember, "await new C()").WithArguments("D", "GetResult").WithLocation(5, 9)); text = """ using System; using System.Runtime.CompilerServices; int i = await new C(); System.Console.Write(i); class C { public D GetAwaiter() => new D(); } class D : INotifyCompletion { public void OnCompleted(Action continuation) => throw null; public bool IsCompleted => true; public System.Func<int> GetResult => () => 42; } """; comp = CreateCompilation(text); comp.VerifyEmitDiagnostics( // (4,9): error CS0118: 'GetResult' is a property but is used like a method // int i = await new C(); Diagnostic(ErrorCode.ERR_BadSKknown, "await new C()").WithArguments("GetResult", "property", "method").WithLocation(4, 9)); } [Fact] public void ExtensionMemberLookup_PatternBased_Await_ExtensionGetResult_DynamicTypeProperty() { var text = @" using System; using System.Runtime.CompilerServices; int i = await new C(); System.Console.Write(i); class C { public D GetAwaiter() => new D(); } class D : INotifyCompletion { public void OnCompleted(Action continuation) => throw null; public bool IsCompleted => true; } static class E { extension(D d) { public dynamic GetResult => throw null; } } "; var comp = CreateCompilation(text); comp.VerifyEmitDiagnostics( // (5,9): error CS0117: 'D' does not contain a definition for 'GetResult' // int i = await new C(); Diagnostic(ErrorCode.ERR_NoSuchMember, "await new C()").WithArguments("D", "GetResult").WithLocation(5, 9)); text = """ using System; using System.Runtime.CompilerServices; int i = await new C(); System.Console.Write(i); class C { public D GetAwaiter() => new D(); } class D : INotifyCompletion { public void OnCompleted(Action continuation) => throw null; public bool IsCompleted => true; public dynamic GetResult => throw null; } """; comp = CreateCompilation(text); comp.VerifyEmitDiagnostics( // (4,9): error CS0118: 'GetResult' is a property but is used like a method // int i = await new C(); Diagnostic(ErrorCode.ERR_BadSKknown, "await new C()").WithArguments("GetResult", "property", "method").WithLocation(4, 9)); } [Fact] public void ExtensionMemberLookup_PatternBased_IndexIndexer_Length() { var src = """ var c = new C(); /*<bind>*/ _ = c[^1]; /*</bind>*/ class C { public int this[int i] { get { System.Console.Write(i); return 0; } } } static class E { extension(C c) { public int Length => 10; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("9"), verify: Verification.Skipped).VerifyDiagnostics(); string expectedOperationTree = """ ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: '_ = c[^1]') Left: IDiscardOperation (Symbol: System.Int32 _) (OperationKind.Discard, Type: System.Int32) (Syntax: '_') Right: IImplicitIndexerReferenceOperation (OperationKind.ImplicitIndexerReference, Type: System.Int32) (Syntax: 'c[^1]') Instance: ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C) (Syntax: 'c') Argument: IUnaryOperation (UnaryOperatorKind.Hat) (OperationKind.Unary, Type: System.Index) (Syntax: '^1') Operand: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') LengthSymbol: System.Int32 E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Length { get; } IndexerSymbol: System.Int32 C.this[System.Int32 i] { get; } """; VerifyOperationTreeAndDiagnosticsForTest<AssignmentExpressionSyntax>(src, expectedOperationTree, [], targetFramework: TargetFramework.Net70); } [Fact] public void ExtensionMemberLookup_PatternBased_IndexIndexer_Count() { var src = """ var c = new C(); _ = c[^1]; class C { public int this[int i] { get { System.Console.Write(i); return 0; } } } static class E { extension(C c) { public int Count => 10; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("9"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_IndexIndexer_IntIndexer() { var src = """ var c = new C(); System.Console.Write(c[^1]); class C { public int Length => 1; } static class E { extension(C c) { public int this[int i] => i; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics( // (13,20): error CS9327: Feature 'extension indexers' is not available in C# 14.0. Please use language version 15.0 or greater. // public int this[int i] => i; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "this").WithArguments("extension indexers", "15.0").WithLocation(13, 20)); comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("0"), verify: Verification.Skipped).VerifyDiagnostics(); src = """ var c = new C(); System.Console.Write(c[^1]); class C { public int Length => 1; public int this[int i] => i; } """; comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("0"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_IndexIndexer_RegularIndexer() { var src = """ var c = new C(); _ = c[^1]; class C { } static class E { extension(C c) { public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics( // (10,20): error CS9327: Feature 'extension indexers' is not available in C# 14.0. Please use language version 15.0 or greater. // public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "this").WithArguments("extension indexers", "15.0").WithLocation(10, 20)); comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_RangeIndexer_Slice() { var src = """ var c = new C(); /*<bind>*/ _ = c[1..^1]; /*</bind>*/ class C { public int Length => 10; } static class E { extension(C c) { public int Slice(int i, int j) { System.Console.Write($"{i},{j}"); return 0; } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("1,8"), verify: Verification.Skipped).VerifyDiagnostics(); string expectedOperationTree = """ ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: '_ = c[1..^1]') Left: IDiscardOperation (Symbol: System.Int32 _) (OperationKind.Discard, Type: System.Int32) (Syntax: '_') Right: IImplicitIndexerReferenceOperation (OperationKind.ImplicitIndexerReference, Type: System.Int32) (Syntax: 'c[1..^1]') Instance: ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C) (Syntax: 'c') Argument: IRangeOperation (OperationKind.Range, Type: System.Range) (Syntax: '1..^1') LeftOperand: IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: System.Index System.Index.op_Implicit(System.Int32 value)) (OperationKind.Conversion, Type: System.Index, IsImplicit) (Syntax: '1') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: System.Index System.Index.op_Implicit(System.Int32 value)) Operand: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') RightOperand: IUnaryOperation (UnaryOperatorKind.Hat) (OperationKind.Unary, Type: System.Index) (Syntax: '^1') Operand: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') LengthSymbol: System.Int32 C.Length { get; } IndexerSymbol: System.Int32 E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Slice(System.Int32 i, System.Int32 j) """; VerifyOperationTreeAndDiagnosticsForTest<AssignmentExpressionSyntax>(src, expectedOperationTree, [], targetFramework: TargetFramework.Net70); src = """ var c = new C(); _ = c[1..^1]; class C { public int Length => 10; public int Slice(int i, int j) { System.Console.Write($"{i},{j}"); return 0; } } """; comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("1,8"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_RangeIndexer_Length() { var src = """ var c = new C(); _ = c[1..^1]; class C { public int Slice(int i, int j) { System.Console.Write($"{i},{j}"); return 0; } } static class E { extension(C c) { public int Length => 10; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("1,8"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_RangeIndexer_RegularIndexer() { var src = """ var c = new C(); _ = c[1..^1]; class C { public int Length => throw null; } static class E { extension(C c) { public int this[System.Range r] => throw null; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics( // (13,20): error CS9327: Feature 'extension indexers' is not available in C# 14.0. Please use language version 15.0 or greater. // public int this[System.Range r] => throw null; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "this").WithArguments("extension indexers", "15.0").WithLocation(13, 20)); comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics(); src = """ var c = new C(); _ = c[1..^1]; class C { public int Length => throw null; public int this[System.Range r] => throw null; } """; comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_ListPattern_Length() { var src = """ _ = new C() is [1]; class C { public int this[int i] => throw null; } static class E { extension(C c) { public int Length => throw null; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_ListPattern_IntIndexer() { var src = """ System.Console.Write(new C() is [1]); class C { public int Length => 1; } static class E { extension(C c) { public int this[int i] { get { System.Console.Write(i); return 1; } } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics( // (12,20): error CS9327: Feature 'extension indexers' is not available in C# 14.0. Please use language version 15.0 or greater. // public int this[int i] Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "this").WithArguments("extension indexers", "15.0").WithLocation(12, 20)); comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("0True"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_ListPattern_RegularIndexer() { var src = """ _ = new C() is [.., 1]; class C { public int Length => 3; } static class E { extension(C c) { public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics( // (12,20): error CS9327: Feature 'extension indexers' is not available in C# 14.0. Please use language version 15.0 or greater. // public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "this").WithArguments("extension indexers", "15.0").WithLocation(12, 20)); comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_SpreadPattern_Length() { var src = """ if (new C() is [_, .. var x]) System.Console.Write(x); class C { public int this[System.Index i] => throw null; public int Slice(int i, int j) { System.Console.Write($"Slice({i},{j}) "); return 42; } } static class E { extension(C c) { public int Length { get { System.Console.Write("length "); return 2; } } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("length Slice(1,1) 42"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_SpreadPattern_Slice() { var src = """ if (new C() is [_, .. var x]) System.Console.Write(x); class C { public int this[System.Index i] => throw null; public int Length { get { System.Console.Write("length "); return 2; } } } static class E { extension(C c) { public int Slice(int i, int j) { System.Console.Write($"Slice({i},{j}) "); return 42; } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("length Slice(1,1) 42"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_PatternBased_SpreadPattern_RegularIndexer() { var src = """ _ = new C() is [_, .. var x]; class C { public int this[System.Index i] => throw null; public int Length => 3; } static class E { extension(C c) { public int this[System.Range r] { get { System.Console.WriteLine(r); return 0; } } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics( // (13,20): error CS9327: Feature 'extension indexers' is not available in C# 14.0. Please use language version 15.0 or greater. // public int this[System.Range r] { get { System.Console.WriteLine(r); return 0; } } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "this").WithArguments("extension indexers", "15.0").WithLocation(13, 20)); comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("1..^0"), verify: Verification.Skipped).VerifyDiagnostics(); src = """ _ = new C() is [_, .. var x]; class C { public int this[System.Index i] => throw null; public int this[System.Range r] => throw null; public int Length => throw null; } """; comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics(); } [Fact] public void ExtensionMemberLookup_Patterns() { var libSrc = """ public class C { } public static class E { extension(C c) { public int Property { get { System.Console.Write("property"); return 42; } } } } """; var libRef = CreateCompilation(libSrc).EmitToImageReference(); var src = """ var c = new C(); _ = c is { Property: 42 }; """; var comp = CreateCompilation(src, references: [libRef]); CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nameColon = GetSyntax<NameColonSyntax>(tree, "Property:"); AssertEx.Equal("System.Int32 E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Property { get; }", model.GetSymbolInfo(nameColon.Name).Symbol.ToTestDisplayString()); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics( // (2,12): error CS9260: Feature 'extensions' is not available in C# 13.0. Please use language version 14.0 or greater. // _ = c is { Property: 42 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion13, "Property").WithArguments("extensions", "14.0").WithLocation(2, 12)); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_Patterns_Conversion_01() { var src = """ var c = new C(); _ = c is { Property: 42 }; class C { } static class E { extension(object o) { public int Property { get { System.Console.Write("property"); return 42; } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_Patterns_Conversion_02() { // implicit span conversion: array to Span var src = """ int[] i = [42]; _ = i is { Property: 42 }; i.M(); class C { } static class E { extension(System.Span<int> s) { public int Property { get { System.Console.Write("property "); return 42; } } } public static void M(this System.Span<int> s) { System.Console.Write("method"); } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); var verify = CompileAndVerify(comp, expectedOutput: ExpectedOutput("property method"), verify: Verification.Skipped).VerifyDiagnostics(); verify.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 46 (0x2e) .maxstack 4 .locals init (int[] V_0) //i IL_0000: ldc.i4.1 IL_0001: newarr "int" IL_0006: dup IL_0007: ldc.i4.0 IL_0008: ldc.i4.s 42 IL_000a: stelem.i4 IL_000b: stloc.0 IL_000c: ldloc.0 IL_000d: brfalse.s IL_0020 IL_000f: ldloc.0 IL_0010: call "System.Span<int> System.Span<int>.op_Implicit(int[])" IL_0015: call "int E.get_Property(System.Span<int>)" IL_001a: ldc.i4.s 42 IL_001c: ceq IL_001e: br.s IL_0021 IL_0020: ldc.i4.0 IL_0021: pop IL_0022: ldloc.0 IL_0023: call "System.Span<int> System.Span<int>.op_Implicit(int[])" IL_0028: call "void E.M(System.Span<int>)" IL_002d: ret } """); } [Fact] public void ExtensionMemberLookup_Patterns_Conversion_03() { // implicit span conversion: array to Span var src = """ string[] i = [""]; _ = i is { Property: 42 }; i.M(); class C { } static class E { extension(System.Span<object> s) { public int Property { get { System.Console.Write("property "); return 42; } } } public static void M(this System.Span<object> s) { System.Console.Write("method"); } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (2,12): error CS1929: 'string[]' does not contain a definition for 'Property' and the best extension method overload 'E.extension(Span<object>).Property' requires a receiver of type 'System.Span<object>' // _ = i is { Property: 42 }; Diagnostic(ErrorCode.ERR_BadInstanceArgType, "Property").WithArguments("string[]", "Property", "E.extension(System.Span<object>).Property", "System.Span<object>").WithLocation(2, 12), // (3,1): error CS1929: 'string[]' does not contain a definition for 'M' and the best extension method overload 'E.M(Span<object>)' requires a receiver of type 'System.Span<object>' // i.M(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "i").WithArguments("string[]", "M", "E.M(System.Span<object>)", "System.Span<object>").WithLocation(3, 1)); } [Fact] public void ExtensionMemberLookup_Patterns_Conversion_04() { // implicit span conversion: Span to ReadOnlySpan var src = """ System.Span<string> i = [""]; _ = i is { Property: 42 }; i.M(); class C { } static class E { extension(System.ReadOnlySpan<object> s) { public int Property { get { System.Console.Write("property "); return 42; } } } public static void M(this System.ReadOnlySpan<object> s) { System.Console.Write("method"); } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); var verify = CompileAndVerify(comp, expectedOutput: ExpectedOutput("property method"), verify: Verification.Skipped).VerifyDiagnostics(); verify.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 46 (0x2e) .maxstack 2 .locals init (string V_0) IL_0000: ldstr "" IL_0005: stloc.0 IL_0006: ldloca.s V_0 IL_0008: newobj "System.Span<string>..ctor(ref string)" IL_000d: dup IL_000e: call "System.ReadOnlySpan<string> System.Span<string>.op_Implicit(System.Span<string>)" IL_0013: call "System.ReadOnlySpan<object> System.ReadOnlySpan<object>.CastUp<string>(System.ReadOnlySpan<string>)" IL_0018: call "int E.get_Property(System.ReadOnlySpan<object>)" IL_001d: pop IL_001e: call "System.ReadOnlySpan<string> System.Span<string>.op_Implicit(System.Span<string>)" IL_0023: call "System.ReadOnlySpan<object> System.ReadOnlySpan<object>.CastUp<string>(System.ReadOnlySpan<string>)" IL_0028: call "void E.M(System.ReadOnlySpan<object>)" IL_002d: ret } """); } [Fact] public void ExtensionMemberLookup_Patterns_Conversion_05() { // implicit span conversion: ReadOnlySpan to ReadOnlySpan var src = """ System.ReadOnlySpan<string> i = [""]; _ = i is { Property: 42 }; i.M(); class C { } static class E { extension(System.ReadOnlySpan<object> s) { public int Property { get { System.Console.Write("property "); return 42; } } } public static void M(this System.ReadOnlySpan<object> s) { System.Console.Write("method"); } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); var verify = CompileAndVerify(comp, expectedOutput: ExpectedOutput("property method"), verify: Verification.Skipped).VerifyDiagnostics(); verify.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 36 (0x24) .maxstack 2 .locals init (string V_0) IL_0000: ldstr "" IL_0005: stloc.0 IL_0006: ldloca.s V_0 IL_0008: newobj "System.ReadOnlySpan<string>..ctor(ref readonly string)" IL_000d: dup IL_000e: call "System.ReadOnlySpan<object> System.ReadOnlySpan<object>.CastUp<string>(System.ReadOnlySpan<string>)" IL_0013: call "int E.get_Property(System.ReadOnlySpan<object>)" IL_0018: pop IL_0019: call "System.ReadOnlySpan<object> System.ReadOnlySpan<object>.CastUp<string>(System.ReadOnlySpan<string>)" IL_001e: call "void E.M(System.ReadOnlySpan<object>)" IL_0023: ret } """); } [Fact] public void ExtensionMemberLookup_Patterns_Conversion_06() { // implicit span conversion: string to ReadOnlySpan var src = """ string s = ""; _ = s is { Property: 42 }; s.M(); class C { } static class E { extension(System.ReadOnlySpan<char> s) { public int Property { get { System.Console.Write("property "); return 42; } } } public static void M(this System.ReadOnlySpan<char> s) { System.Console.Write("method"); } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); var verify = CompileAndVerify(comp, expectedOutput: ExpectedOutput("property method"), verify: Verification.Skipped).VerifyDiagnostics(); verify.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 40 (0x28) .maxstack 2 .locals init (string V_0) //s IL_0000: ldstr "" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: brfalse.s IL_001a IL_0009: ldloc.0 IL_000a: call "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)" IL_000f: call "int E.get_Property(System.ReadOnlySpan<char>)" IL_0014: ldc.i4.s 42 IL_0016: ceq IL_0018: br.s IL_001b IL_001a: ldc.i4.0 IL_001b: pop IL_001c: ldloc.0 IL_001d: call "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)" IL_0022: call "void E.M(System.ReadOnlySpan<char>)" IL_0027: ret } """); var spanSrc = """ namespace System; public readonly ref struct ReadOnlySpan<T> { } """; comp = CreateCompilation([src, spanSrc]); comp.VerifyEmitDiagnostics( // (2,12): error CS0656: Missing compiler required member 'System.MemoryExtensions.AsSpan' // _ = s is { Property: 42 }; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "Property").WithArguments("System.MemoryExtensions", "AsSpan").WithLocation(2, 12), // (3,1): error CS0656: Missing compiler required member 'System.MemoryExtensions.AsSpan' // s.M(); Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "s").WithArguments("System.MemoryExtensions", "AsSpan").WithLocation(3, 1)); } [Fact] public void ExtensionMemberLookup_Patterns_Conversion_07() { // boxing var src = """ int i = 42; _ = i is { Property: 42 }; i.M(); class C { } static class E { extension(object o) { public int Property { get { System.Console.Write("property "); return 42; } } } public static void M(this object o) { System.Console.Write("method"); } } """; var comp = CreateCompilation(src); var verify = CompileAndVerify(comp, expectedOutput: "property method").VerifyDiagnostics(); verify.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 25 (0x19) .maxstack 2 IL_0000: ldc.i4.s 42 IL_0002: dup IL_0003: box "int" IL_0008: call "int E.get_Property(object)" IL_000d: pop IL_000e: box "int" IL_0013: call "void E.M(object)" IL_0018: ret } """); } [Fact] public void ExtensionMemberLookup_Patterns_Conversion_08() { // implicit tuple conversion var src = """ (int, string) t = (42, ""); _ = t is { Property: 42 }; t.M(); class C { } static class E { extension((object, object) t) { public int Property { get { System.Console.Write("property "); return 42; } } } public static void M(this (object, object) t) { System.Console.Write("method"); } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); var verify = CompileAndVerify(comp, expectedOutput: ExpectedOutput("property method"), verify: Verification.Skipped).VerifyDiagnostics(); verify.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 71 (0x47) .maxstack 3 .locals init (System.ValueTuple<int, string> V_0) IL_0000: ldc.i4.s 42 IL_0002: ldstr "" IL_0007: newobj "System.ValueTuple<int, string>..ctor(int, string)" IL_000c: dup IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: ldfld "int System.ValueTuple<int, string>.Item1" IL_0014: box "int" IL_0019: ldloc.0 IL_001a: ldfld "string System.ValueTuple<int, string>.Item2" IL_001f: newobj "System.ValueTuple<object, object>..ctor(object, object)" IL_0024: call "int E.get_Property(System.ValueTuple<object, object>)" IL_0029: pop IL_002a: stloc.0 IL_002b: ldloc.0 IL_002c: ldfld "int System.ValueTuple<int, string>.Item1" IL_0031: box "int" IL_0036: ldloc.0 IL_0037: ldfld "string System.ValueTuple<int, string>.Item2" IL_003c: newobj "System.ValueTuple<object, object>..ctor(object, object)" IL_0041: call "void E.M(System.ValueTuple<object, object>)" IL_0046: ret } """); } [Fact] public void ExtensionMemberLookup_Patterns_Conversion_09() { // We check conversion during initial binding var src = """ int[] i = []; _ = i is { Property: 42 }; static class E { extension(System.ReadOnlySpan<int> r) { public int Property => throw null; } } namespace System { public ref struct ReadOnlySpan<T> { } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (2,12): error CS0656: Missing compiler required member 'ReadOnlySpan<T>.op_Implicit' // _ = i is { Property: 42 }; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "Property").WithArguments("System.ReadOnlySpan<T>", "op_Implicit").WithLocation(2, 12), // (6,22): warning CS0436: The type 'ReadOnlySpan<T>' in '' conflicts with the imported type 'ReadOnlySpan<T>' in 'System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Using the type defined in ''. // extension(System.ReadOnlySpan<int> r) Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "ReadOnlySpan<int>").WithArguments("", "System.ReadOnlySpan<T>", "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.ReadOnlySpan<T>").WithLocation(6, 22)); } [Fact] public void ExtensionMemberLookup_Patterns_ExtendedPropertyPattern() { var src = """ var c = new C(); _ = c is { Property.Property2: 43 }; class C { } static class E1 { extension(C c) { public int Property { get { System.Console.Write("property "); return 42; } } } } static class E2 { extension(int i) { public int Property2 { get { System.Console.Write("property2"); return 43; } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "property property2").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var expressionColon = GetSyntax<ExpressionColonSyntax>(tree, "Property.Property2:"); AssertEx.Equal("System.Int32 E2.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.Property2 { get; }", model.GetSymbolInfo(expressionColon.Expression).Symbol.ToTestDisplayString()); } [Fact] public void ExtensionMemberLookup_Patterns_ExtendedPropertyPattern_Conversion() { var src = """ var c = new C(); _ = c is { Property.Property2: 43 }; class C { } static class E1 { extension(object o) { public int Property { get { System.Console.Write("property "); return 42; } } } } static class E2 { extension(int i) { public int Property2 { get { System.Console.Write("property2"); return 43; } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "property property2").VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_Patterns_ExtendedPropertyPattern_Conversion_02() { var src = """ var c = new C(); _ = c is { Property.Property2: 43 }; class C { } static class E1 { extension(C c) { public C Property { get { System.Console.Write("property "); return c; } } } } static class E2 { extension(object o) { public int Property2 { get { System.Console.Write("property2"); return 43; } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "property property2").VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_Patterns_ListPattern_NoInstanceLength() { var src = """ System.Console.Write(new C() is ["hi"]); class C { public string this[System.Index i] { get { System.Console.Write("indexer "); return "hi"; } } } static class E { extension(C c) { public int Length { get { System.Console.Write("length "); return 1; } } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); CompileAndVerify(comp, expectedOutput: ExpectedOutput("length indexer True"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_ObjectInitializer() { var libSrc = """ public class C { } public static class E { extension(C c) { public int Property { set { System.Console.Write("property"); } } } } """; var libRef = CreateCompilation(libSrc).EmitToImageReference(); var src = """ _ = new C() { Property = 42 }; """; var comp = CreateCompilation(src, references: [libRef]); CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntax<AssignmentExpressionSyntax>(tree, "Property = 42"); AssertEx.Equal("System.Int32 E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Property { set; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString()); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics( // (1,15): error CS9260: Feature 'extensions' is not available in C# 13.0. Please use language version 14.0 or greater. // _ = new C() { Property = 42 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion13, "Property").WithArguments("extensions", "14.0").WithLocation(1, 15)); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_ObjectInitializer_Conversion_01() { var src = """ _ = new C() { Property = 42 }; class C { } static class E { extension(object o) { public int Property { set { System.Console.Write("property"); } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_ObjectInitializer_Conversion_02() { var src = """ _ = new System.ReadOnlySpan<string>() { Property = 42 }; new System.ReadOnlySpan<string>().Property = 43; class C { } static class E { extension(System.ReadOnlySpan<object> s) { public int Property { set { } } } } """; // Tracked by https://github.com/dotnet/roslyn/issues/79451 : consider adjusting receiver requirements for extension members var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (1,41): error CS0131: The left-hand side of an assignment must be a variable, property or indexer // _ = new System.ReadOnlySpan<string>() { Property = 42 }; Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "Property").WithLocation(1, 41), // (3,1): error CS0131: The left-hand side of an assignment must be a variable, property or indexer // new System.ReadOnlySpan<string>().Property = 43; Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new System.ReadOnlySpan<string>().Property").WithLocation(3, 1)); src = """ new S().Property = 42; struct S { public int Property { set { } } } """; comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (1,1): error CS0131: The left-hand side of an assignment must be a variable, property or indexer // new S().Property = 42; Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S().Property").WithLocation(1, 1)); } [Fact] public void ExtensionMemberLookup_ObjectInitializer_Conversion_03() { // implicit tuple conversion var src = """ _ = new System.ValueTuple<int, string>() { Property = 42 }; static class E { extension((object, object) t) { public int Property { set { System.Console.Write("property"); } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,44): error CS0131: The left-hand side of an assignment must be a variable, property or indexer // _ = new System.ValueTuple<int, string>() { Property = 42 }; Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "Property").WithLocation(1, 44)); } [Fact] public void ExtensionMemberLookup_ObjectInitializer_Conversion_04() { // implicit span conversion from string var src = """ _ = new System.String('a', 10) { Property = 42 }; static class E { extension(System.ReadOnlySpan<char> s) { public int Property { set { System.Console.Write(value); } } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyDiagnostics( // (1,34): error CS0131: The left-hand side of an assignment must be a variable, property or indexer // _ = new System.String('a', 10) { Property = 42 }; Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "Property").WithLocation(1, 34)); } [Fact] public void ExtensionMemberLookup_With() { var libSrc = """ public struct S { } public static class E { extension(S s) { public int Property { set { System.Console.Write("property"); } } } } """; var libRef = CreateCompilation(libSrc).EmitToImageReference(); var src = """ _ = new S() with { Property = 42 }; """; var comp = CreateCompilation(src, references: [libRef]); CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntax<AssignmentExpressionSyntax>(tree, "Property = 42"); AssertEx.Equal("System.Int32 E.<G>$3B24C9A1A6673CA92CA71905DDEE0A6C.Property { set; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString()); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics( // (1,20): error CS9260: Feature 'extensions' is not available in C# 13.0. Please use language version 14.0 or greater. // _ = new S() with { Property = 42 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion13, "Property").WithArguments("extensions", "14.0").WithLocation(1, 20)); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics(); } [Fact] public void ExtensionMemberLookup_CollectionInitializer() { var src = """ using System.Collections; using System.Collections.Generic; /*<bind>*/ _ = new C() { 42 }; /*</bind>*/ class C : IEnumerable<int>, IEnumerable { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } static class E { extension(C c) { public void Add(int i) { System.Console.Write("add"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "add").VerifyDiagnostics(); string expectedOperationTree = """ ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() { 42 }') Left: IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') Right: IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { 42 }') Arguments(0) Initializer: IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C) (Syntax: '{ 42 }') Initializers(1): IInvocationOperation ( void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Add(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '42') Instance Receiver: IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'C') Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) """; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<AssignmentExpressionSyntax>(src, expectedOperationTree, expectedDiagnostics); } [Fact] public void ExtensionMemberLookup_CollectionInitializer_Conversion() { var src = """ using System.Collections; using System.Collections.Generic; /*<bind>*/ _ = new C() { 42 }; /*</bind>*/ class C : IEnumerable<int>, IEnumerable { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } static class E { extension(object o) { public void Add(int i) { System.Console.Write("add"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "add").VerifyDiagnostics(); string expectedOperationTree = """ ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() { 42 }') Left: IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') Right: IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { 42 }') Arguments(0) Initializer: IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C) (Syntax: '{ 42 }') Initializers(1): IInvocationOperation ( void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Add(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '42') Instance Receiver: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'C') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) Operand: IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'C') Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) """; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<AssignmentExpressionSyntax>(src, expectedOperationTree, expectedDiagnostics); } [Fact] public void ExtensionMemberLookup_CollectionInitializer_NoApplicableMethod() { var src = """ using System.Collections; using System.Collections.Generic; class Program { static void Main() { /*<bind>*/ _ = new C() { 42 }; /*</bind>*/ } } class C : IEnumerable<int>, IEnumerable { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; public void Add(string notApplicable) => throw null; } static class E { extension(object o) { public void Add(int i) { System.Console.Write("add"); } } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "add").VerifyDiagnostics(); string expectedOperationTree = """ ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() { 42 }') Left: IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') Right: IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { 42 }') Arguments(0) Initializer: IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C) (Syntax: '{ 42 }') Initializers(1): IInvocationOperation ( void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Add(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '42') Instance Receiver: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'C') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) Operand: IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'C') Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) """; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<AssignmentExpressionSyntax>(src, expectedOperationTree, expectedDiagnostics); VerifyFlowGraph(comp, comp.SyntaxTrees.Single().GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().First(), """ Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { CaptureIds: [0] Block[B1] - Block Predecessors: [B0] Statements (3) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'new C() { 42 }') Value: IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { 42 }') Arguments(0) Initializer: null IInvocationOperation ( void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Add(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '42') Instance Receiver: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'C') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) (ImplicitReference) Operand: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'new C() { 42 }') Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '_ = new C() { 42 };') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() { 42 }') Left: IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') Right: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'new C() { 42 }') Next (Regular) Block[B2] Leaving: {R1} } Block[B2] - Exit Predecessors: [B1] Statements (0) """); } [Fact] public void ExtensionMemberLookup_CollectionInitializer_NoApplicableMethod_ExpressionTree() { var src = """ using System.Collections; using System.Collections.Generic; try { System.Linq.Expressions.Expression<System.Func<C>> e = () => new C() { 42 }; System.Console.Write(e); } catch (System.ArgumentException ae) { System.Console.Write(ae.Message); } class C : IEnumerable<int>, IEnumerable { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; public void Add(string notApplicable) => throw null; } static class E { extension(object o) { public void Add(int i) { System.Console.Write("add"); } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (6,76): error CS8075: An extension Add method is not supported for a collection initializer in an expression lambda. // System.Linq.Expressions.Expression<System.Func<C>> e = () => new C() { 42 }; Diagnostic(ErrorCode.ERR_ExtensionCollectionElementInitializerInExpressionTree, "42").WithLocation(6, 76) ); src = """ using System.Collections; using System.Collections.Generic; try { System.Linq.Expressions.Expression<System.Func<C>> e = () => new C() { 42 }; System.Console.Write(e); } catch (System.ArgumentException ae) { System.Console.Write(ae.Message); } class C : IEnumerable<int>, IEnumerable { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; public void Add(string notApplicable) => throw null; } static class E { public static void Add(this object o, int i) { System.Console.Write("add"); } } """; comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (6,76): error CS8075: An extension Add method is not supported for a collection initializer in an expression lambda. // System.Linq.Expressions.Expression<System.Func<C>> e = () => new C() { 42 }; Diagnostic(ErrorCode.ERR_ExtensionCollectionElementInitializerInExpressionTree, "42").WithLocation(6, 76) ); } [Fact] public void ResolveAll_CollectionInitializer_DelegateTypeProperty() { var source = """ using System.Collections; using System.Collections.Generic; MyCollection c = new MyCollection() { 42 }; static class E { extension(MyCollection c) { public System.Action<int> Add => (int i) => { }; } } public class MyCollection : IEnumerable<int> { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (4,39): error CS1061: 'MyCollection' does not contain a definition for 'Add' and no accessible extension method 'Add' accepting a first argument of type 'MyCollection' could be found (are you missing a using directive or an assembly reference?) // MyCollection c = new MyCollection() { 42 }; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "42").WithArguments("MyCollection", "Add").WithLocation(4, 39)); source = """ using System.Collections; using System.Collections.Generic; MyCollection c = new MyCollection() { 42 }; public class MyCollection : IEnumerable<int> { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; public System.Action<int> Add => (int i) => { }; } """; comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (4,39): error CS0118: 'Add' is a property but is used like a method // MyCollection c = new MyCollection() { 42 }; Diagnostic(ErrorCode.ERR_BadSKknown, "42").WithArguments("Add", "property", "method").WithLocation(4, 39)); } [Fact] public void ResolveAll_CollectionInitializer_DynamicTypeProperty() { var source = """ using System.Collections; using System.Collections.Generic; MyCollection c = new MyCollection() { 42 }; static class E { extension(MyCollection c) { public dynamic Add => throw null; } } public class MyCollection : IEnumerable<int> { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (4,39): error CS1061: 'MyCollection' does not contain a definition for 'Add' and no accessible extension method 'Add' accepting a first argument of type 'MyCollection' could be found (are you missing a using directive or an assembly reference?) // MyCollection c = new MyCollection() { 42 }; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "42").WithArguments("MyCollection", "Add").WithLocation(4, 39)); source = """ using System.Collections; using System.Collections.Generic; MyCollection c = new MyCollection() { 42 }; public class MyCollection : IEnumerable<int> { IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; public dynamic Add => throw null; } """; comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (4,39): error CS0118: 'Add' is a property but is used like a method // MyCollection c = new MyCollection() { 42 }; Diagnostic(ErrorCode.ERR_BadSKknown, "42").WithArguments("Add", "property", "method").WithLocation(4, 39)); } [Fact] public void ExtensionMemberLookup_Query_NoMethod() { var src = """ /*<bind>*/ string query = from x in new C() select x; /*</bind>*/ System.Console.Write(query); class C { } static class E { extension(C c) { public string Select(System.Func<C, C> selector) => "hello"; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "hello").VerifyDiagnostics(); string expectedOperationTree = """ IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'string quer ... ) select x;') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'string quer ... () select x') Declarators: IVariableDeclaratorOperation (Symbol: System.String query) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'query = fro ... () select x') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= from x in ... () select x') ITranslatedQueryOperation (OperationKind.TranslatedQuery, Type: System.String) (Syntax: 'from x in n ... () select x') Expression: IInvocationOperation ( System.String E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Select(System.Func<C, C> selector)) (OperationKind.Invocation, Type: System.String, IsImplicit) (Syntax: 'select x') Instance Receiver: IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C()') Arguments(0) Initializer: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: selector) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'x') IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func<C, C>, IsImplicit) (Syntax: 'x') Target: IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null, IsImplicit) (Syntax: 'x') IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: 'x') IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'x') ReturnedValue: IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: C) (Syntax: 'x') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Initializer: null """; VerifyOperationTreeAndDiagnosticsForTest<LocalDeclarationStatementSyntax>(src, expectedOperationTree, DiagnosticDescription.None); } [Fact] public void ExtensionMemberLookup_Query_NoApplicableMethod() { var src = """ /*<bind>*/ string query = from x in new C() select x; /*</bind>*/ System.Console.Write(query); class C { public string Select(int notApplicable) => throw null; // not applicable } static class E { extension(C c) { public string Select(System.Func<C, C> selector) => "hello"; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "hello").VerifyDiagnostics(); string expectedOperationTree = """ IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'string quer ... ) select x;') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'string quer ... () select x') Declarators: IVariableDeclaratorOperation (Symbol: System.String query) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'query = fro ... () select x') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= from x in ... () select x') ITranslatedQueryOperation (OperationKind.TranslatedQuery, Type: System.String) (Syntax: 'from x in n ... () select x') Expression: IInvocationOperation ( System.String E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Select(System.Func<C, C> selector)) (OperationKind.Invocation, Type: System.String, IsImplicit) (Syntax: 'select x') Instance Receiver: IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C()') Arguments(0) Initializer: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: selector) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'x') IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func<C, C>, IsImplicit) (Syntax: 'x') Target: IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null, IsImplicit) (Syntax: 'x') IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: 'x') IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'x') ReturnedValue: IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: C) (Syntax: 'x') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Initializer: null """; VerifyOperationTreeAndDiagnosticsForTest<LocalDeclarationStatementSyntax>(src, expectedOperationTree, []); } [Fact] public void ExtensionMemberLookup_Invocation_ZeroArityMatchesAny() { var source = $$""" object.Method(""); object.Method<string>(""); static class E { extension(object) { public static void Method(int i) => throw null; public static void Method<T>(T t) { System.Console.Write("Method "); } public static void Method<T1, T2>(T1 t1, T2 t2) => throw null; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "Method Method").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, """object.Method("")"""); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Method<System.String>(System.String t)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); Assert.Empty(model.GetMemberGroup(invocation)); } [Fact] public void ExtensionMemberLookup_Invocation_ZeroArityMatchesAny_FailedOverloadResolution() { var source = $$""" object.Method(); static class E { extension(object) { public static void Method(int i) => throw null; public static void Method<T>(T t) { System.Console.Write("Method "); } public static void Method<T1, T2>(T1 t1, T2 t2) => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,8): error CS1501: No overload for method 'Method' takes 0 arguments // object.Method(); Diagnostic(ErrorCode.ERR_BadArgCount, "Method").WithArguments("Method", "0").WithLocation(1, 8)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "object.Method()"); Assert.Null(model.GetSymbolInfo(invocation).Symbol); Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); } [Fact] public void StaticPropertyAccess_ZeroArityMatchesAny() { var source = """ int i = object.P; static class E1 { extension(object) { public static int P => 42; } } static class E2 { extension(object) { public static void P<T>() => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,9): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(object).P<T>()' and 'E1.extension(object).P' // int i = object.P; Diagnostic(ErrorCode.ERR_AmbigExtension, "object.P").WithArguments("E2.extension(object).P<T>()", "E1.extension(object).P").WithLocation(1, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.P"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.Int32 E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.P { get; }", "void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.P<T>()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void StaticPropertyAccess_NonZeroArity() { var source = """ int i = object.P<int>; static class E1 { extension(object) { public static int P => 42; } } static class E2 { extension(object) { public static void P<T>() => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,16): error CS0428: Cannot convert method group 'P' to non-delegate type 'int'. Did you intend to invoke the method? // int i = object.P<int>; Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "P<int>").WithArguments("P", "int").WithLocation(1, 16)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.P<int>"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.P<System.Int32>()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void StaticMethodAccess_NonZeroArity() { var source = """ object.M<int>(); static class E1 { extension(object) { public static void M() { } public static void M<T1, T2>() { } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,8): error CS0117: 'object' does not contain a definition for 'M' // object.M<int>(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M<int>").WithArguments("object", "M").WithLocation(1, 8)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M<int>"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Empty(model.GetSymbolInfo(memberAccess).CandidateSymbols); Assert.Empty(model.GetMemberGroup(memberAccess)); } [Fact] public void AddressOf_TypeReceiver() { var src = """ unsafe class C { static void Main() { delegate*<string, object, void> ptr = &C.M; ptr("ran", null); } } static class E { extension(C) { public static void M(string s, object o) { System.Console.Write(s); } } } """; var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: "ran", verify: Verification.Fails with { ILVerifyMessage = "[Main]: ImportCalli not implemented" }); verifier.VerifyIL("C.Main", """ { // Code size 24 (0x18) .maxstack 3 .locals init (delegate*<string, object, void> V_0, //ptr delegate*<string, object, void> V_1) IL_0000: nop IL_0001: ldftn "void E.M(string, object)" IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: stloc.1 IL_000a: ldstr "ran" IL_000f: ldnull IL_0010: ldloc.1 IL_0011: calli "delegate*<string, object, void>" IL_0016: nop IL_0017: ret } """); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.M"); AssertEx.Equal("void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.String s, System.Object o)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void AddressOf_InstanceReceiver() { var src = """ unsafe class C { static void Main() { C c = new C(); delegate*<string, object, void> ptr = &c.M; ptr("ran", null); delegate*<string, object, void> ptr2 = &c.M2; } } static class E { extension(C c) { public void M(string s, object o) { System.Console.Write(s); } } public static void M2(this C c, string s, object o) { System.Console.Write(s); } } """; var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe); comp.VerifyEmitDiagnostics( // (6,48): error CS8759: Cannot create a function pointer for 'E.extension(C).M(string, object)' because it is not a static method // delegate*<string, object, void> ptr = &c.M; Diagnostic(ErrorCode.ERR_FuncPtrMethMustBeStatic, "c.M").WithArguments("E.extension(C).M(string, object)").WithLocation(6, 48), // (9,48): error CS8788: Cannot use an extension method with a receiver as the target of a '&' operator. // delegate*<string, object, void> ptr2 = &c.M2; Diagnostic(ErrorCode.ERR_CannotUseReducedExtensionMethodInAddressOf, "&c.M2").WithLocation(9, 48)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "c.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); } [Fact] public void AddressOf_AmbiguousBestMethod() { var src = """ unsafe class C { static void M1() { delegate*<string, string, void> ptr = &C.M; } } static class E { extension(C) { public static void M(string s, object o) {} public static void M(object o, string s) {} } } """; var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugDll); comp.VerifyEmitDiagnostics( // (5,48): error CS0121: The call is ambiguous between the following methods or properties: 'E.extension(C).M(string, object)' and 'E.extension(C).M(object, string)' // delegate*<string, string, void> ptr = &C.M; Diagnostic(ErrorCode.ERR_AmbigCall, "C.M").WithArguments("E.extension(C).M(string, object)", "E.extension(C).M(object, string)").WithLocation(5, 48)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.String s, System.Object o)", "void E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.M(System.Object o, System.String s)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void AddressOf_TypeReceiver_UnmanagedCallersOnly_01() { var src = """ unsafe class C { static void Main() { delegate*<void> ptr = &C.M; delegate*<void> ptr2 = &E.M; } } static class E { extension(C) { [System.Runtime.InteropServices.UnmanagedCallersOnly] public static void M() { } } } """; var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (5,32): error CS8786: Calling convention of 'E.extension(C).M()' is not compatible with 'Default'. // delegate*<void> ptr = &C.M; Diagnostic(ErrorCode.ERR_WrongFuncPtrCallingConvention, "C.M").WithArguments("E.extension(C).M()", "Default").WithLocation(5, 32), // (6,33): error CS8786: Calling convention of 'E.M()' is not compatible with 'Default'. // delegate*<void> ptr2 = &E.M; Diagnostic(ErrorCode.ERR_WrongFuncPtrCallingConvention, "E.M").WithArguments("E.M()", "Default").WithLocation(6, 33)); } [Fact] public void AddressOf_TypeReceiver_UnmanagedCallersOnly_02() { var src = """ unsafe class C { static void Main() { delegate* unmanaged<void> ptr = &C.M; delegate* unmanaged<void> ptr2 = &E.M; } } static class E { extension(C) { [System.Runtime.InteropServices.UnmanagedCallersOnly] public static void M() { } } } """; var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugExe, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); } [Fact] public void TwoExtensions_MethodAndProperty() { var src = """ System.Console.Write(object.M()); static class E1 { extension(object) { public static string M() => throw null; } } static class E2 { extension(object) { public static System.Func<string> M => null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,22): error CS9339: The extension resolution is ambiguous between the following members: 'E1.extension(object).M()' and 'E2.extension(object).M' // System.Console.Write(object.M()); Diagnostic(ErrorCode.ERR_AmbigExtension, "object.M").WithArguments("E1.extension(object).M()", "E2.extension(object).M").WithLocation(1, 22)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.String E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "System.Func<System.String> E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Empty(model.GetMemberGroup(memberAccess)); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : public API, consider handling BoundBadExpression better } [Fact] public void Nameof_Static_Method() { var src = """ System.Console.Write(nameof(C.Method)); class C { } static class E { extension(C) { public static string Method() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,29): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. // System.Console.Write(nameof(C.Method)); Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "C.Method").WithLocation(1, 29)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.Method"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.String E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Method()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void Nameof_Instance_Method() { var src = """ C c = null; _ = nameof(c.Method); class C { } static class E { extension(C c) { public string Method() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,12): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. // _ = nameof(c.Method); Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "c.Method").WithLocation(2, 12)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "c.Method"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); } [Fact] public void Nameof_Static_Property() { var src = """ System.Console.Write(nameof(C.Property)); class C { } static class E { extension(C) { public static string Property => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,29): error CS9316: Extension members are not allowed as an argument to 'nameof'. // System.Console.Write(nameof(C.Property)); Diagnostic(ErrorCode.ERR_NameofExtensionMember, "C.Property").WithLocation(1, 29)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.Property"); AssertEx.Equal("System.String E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void Nameof_Static_WrongArityMethod() { var src = """ System.Console.Write(nameof(C.Method)); class C { } static class E { extension(C) { public static string Method<T>() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,29): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. // System.Console.Write(nameof(C.Method)); Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "C.Method").WithLocation(1, 29)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.Method"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.String E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Method<T>()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void Nameof_Instance_Property_01() { var src = """ C c = null; System.Console.Write(nameof(c.Property)); class C { } static class E { extension(C c) { public string Property => "Property"; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,29): error CS9316: Extension members are not allowed as an argument to 'nameof'. // System.Console.Write(nameof(c.Property)); Diagnostic(ErrorCode.ERR_NameofExtensionMember, "c.Property").WithLocation(2, 29)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "c.Property"); AssertEx.Equal("System.String E.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void Nameof_Instance_Property_02() { var src = """ C c = null; System.Console.Write(nameof(c.Property.Property)); // 1 System.Console.Write(nameof(c.Property.ToString)); class C { } static class E { extension(C c) { public C Property => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,29): error CS9316: Extension members are not allowed as an argument to 'nameof'. // System.Console.Write(nameof(c.Property.Property)); // 1 Diagnostic(ErrorCode.ERR_NameofExtensionMember, "c.Property.Property").WithLocation(2, 29)); } [Fact] public void Nameof_Instance_Property_Generic_01() { var src = """ I<string> i = null; System.Console.Write(nameof(i.Property)); interface I<T> { } static class E { extension<T>(I<T> i) { public string Property => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,29): error CS9316: Extension members are not allowed as an argument to 'nameof'. // System.Console.Write(nameof(i.Property)); Diagnostic(ErrorCode.ERR_NameofExtensionMember, "i.Property").WithLocation(2, 29)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "i.Property"); AssertEx.Equal("System.String E.<G>$74EBC78B2187AB07A25EEFC1322000B0<System.String>.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void Nameof_Static_Property_Generic_01() { var src = """ System.Console.Write(nameof(C.Property)); class C : I<string> { } interface I<T> { } static class E { extension<T>(I<T> i) { public static string Property => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,29): error CS9316: Extension members are not allowed as an argument to 'nameof'. // System.Console.Write(nameof(C.Property)); Diagnostic(ErrorCode.ERR_NameofExtensionMember, "C.Property").WithLocation(1, 29)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.Property"); AssertEx.Equal("System.String E.<G>$74EBC78B2187AB07A25EEFC1322000B0<System.String>.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void Nameof_Static_Property_Generic_02() { var src = """ System.Console.Write(nameof(C.Property)); class C : I<string>, I<int> { } interface I<T> { } static class E { extension<T>(I<T> i) { public static string Property => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,29): error CS1061: 'C' does not contain a definition for 'Property' and no accessible extension method 'Property' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) // System.Console.Write(nameof(C.Property)); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "C.Property").WithArguments("C", "Property").WithLocation(1, 29)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.Property"); AssertEx.Equal("System.String E.<G>$74EBC78B2187AB07A25EEFC1322000B0<T>.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void Nameof_Static_Property_Generic_03() { var src = """ System.Console.Write(nameof(I<string>.Property)); interface I<T> { } static class E { extension<T>(I<T> i) { public static string Property => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,29): error CS9316: Extension members are not allowed as an argument to 'nameof'. // System.Console.Write(nameof(I<string>.Property)); Diagnostic(ErrorCode.ERR_NameofExtensionMember, "I<string>.Property").WithLocation(1, 29)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "I<string>.Property"); AssertEx.Equal("System.String E.<G>$74EBC78B2187AB07A25EEFC1322000B0<System.String>.Property { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void Nameof_Overloads_01() { var src = """ System.Console.Write($"{nameof(object.M)} "); static class E { extension(object) { public static void M() { } public static void M(int i) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,32): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. // System.Console.Write($"{nameof(object.M)} "); Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "object.M").WithLocation(1, 32)); } [Fact] public void Nameof_Overloads_02() { var src = """ System.Console.Write($"{nameof(object.M)} "); static class E1 { extension<T>(T) where T : class { public static void M() { } } } static class E2 { extension<T>(T) where T : struct { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,32): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. // System.Console.Write($"{nameof(object.M)} "); Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "object.M").WithLocation(1, 32)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void E1.<G>$66F77D1E46F965A5B22D4932892FA78B<System.Object>.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); AssertEx.SequenceEqual(["void E1.<G>$66F77D1E46F965A5B22D4932892FA78B<System.Object>.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void Nameof_SimpleName() { var src = """ class C { void M() { _ = nameof(Method); _ = nameof(Property); } } static class E { extension(object) { public static void Method() { } public static int Property => 0; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,20): error CS0103: The name 'Method' does not exist in the current context // _ = nameof(Method); Diagnostic(ErrorCode.ERR_NameNotInContext, "Method").WithArguments("Method").WithLocation(5, 20), // (6,20): error CS0103: The name 'Property' does not exist in the current context // _ = nameof(Property); Diagnostic(ErrorCode.ERR_NameNotInContext, "Property").WithArguments("Property").WithLocation(6, 20)); } [Fact] public void Nameof_NoParameter() { var src = """ class C { void M() { System.Console.Write(nameof()); } } static class E { extension(C c) { public string nameof() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,30): error CS0103: The name 'nameof' does not exist in the current context // System.Console.Write(nameof()); Diagnostic(ErrorCode.ERR_NameNotInContext, "nameof").WithArguments("nameof").WithLocation(5, 30)); } [Fact] public void Nameof_SingleParameter() { var src = """ class C { public static void Main() { string x = ""; System.Console.Write(nameof(x)); } } static class E { extension(C c) { public string nameof(string s) => throw null; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "x").VerifyDiagnostics(); } [Fact] public void StaticMethodInvocation_TypeParameter_InNameof() { var source = """ public static class C { static void M<T>() { _ = nameof(T.Method); } extension<T>(T) { public static void Method() { } } } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // 0.cs(5,20): error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter // _ = nameof(T.Method); Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(5, 20)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "T.Method"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Empty(model.GetMemberGroup(memberAccess)); } [Fact] public void SymbolInfoForMethodGroup03() { var source = """ public class A { } static class E { extension(A a) { public string Extension() { return null; } } public static string Extension2(this A a) { return null; } } public class Program { public static void Main(string[] args) { A a = null; _ = nameof(a.Extension); _ = nameof(a.Extension2); } } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (17,20): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. // _ = nameof(a.Extension); Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "a.Extension").WithLocation(17, 20), // (18,20): error CS8093: Extension method groups are not allowed as an argument to 'nameof'. // _ = nameof(a.Extension2); Diagnostic(ErrorCode.ERR_NameofExtensionMethod, "a.Extension2").WithLocation(18, 20)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "a.Extension"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.Equal(["System.String E.<G>$43BB1C51423008731091E2D86C21895C.Extension()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "a.Extension2"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Equal(["System.String A.Extension2()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void StaticMethodInvocation_PartialStaticClass() { var source = """ object.M(); object.M2(); public static partial class C { extension(object) { public static void M() { System.Console.Write("ran "); } } } public static partial class C { extension(object) { public static void M2() { System.Console.Write("ran2"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran ran2", symbolValidator: (m) => { var container = m.GlobalNamespace.GetTypeMember("C"); var extension = container.GetTypeMembers().Single(); AssertEx.Equal("System.Object", extension.ExtensionParameter.ToTestDisplayString()); AssertEx.Equal("<M>$C43E2675C7BBF9284AF22FB8A9BF0280", extension.MetadataName); var methods = extension.GetMembers(); AssertEx.Equal("C.extension(object).M()", methods[0].ToDisplayString()); AssertEx.Equal([], methods[0].GetAttributes()); AssertEx.Equal("C.extension(object).M2()", methods[1].ToDisplayString()); AssertEx.Equal([], methods[1].GetAttributes()); }). VerifyDiagnostics(). VerifyTypeIL("C", """ .class public auto ansi abstract sealed beforefieldinit C extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20b1 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$C43E2675C7BBF9284AF22FB8A9BF0280'::'<Extension>$' } // end of class <M>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method public hidebysig static void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 43 34 33 45 32 36 37 35 43 37 42 42 46 39 32 38 34 41 46 32 32 46 42 38 41 39 42 46 30 32 38 30 00 00 ) // Method begins at RVA 0x20aa // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M .method public hidebysig static void M2 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 43 34 33 45 32 36 37 35 43 37 42 42 46 39 32 38 34 41 46 32 32 46 42 38 41 39 42 46 30 32 38 30 00 00 ) // Method begins at RVA 0x20aa // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M2 } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method public hidebysig static void M () cil managed { // Method begins at RVA 0x2092 // Code size 11 (0xb) .maxstack 8 IL_0000: ldstr "ran " IL_0005: call void [mscorlib]System.Console::Write(string) IL_000a: ret } // end of method C::M .method public hidebysig static void M2 () cil managed { // Method begins at RVA 0x209e // Code size 11 (0xb) .maxstack 8 IL_0000: ldstr "ran2" IL_0005: call void [mscorlib]System.Console::Write(string) IL_000a: ret } // end of method C::M2 } // end of class C """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var source2 = """ object.M(); object.M2(); """; var comp2 = CreateCompilation(source2, references: [comp.EmitToImageReference()]); CompileAndVerify(comp2, expectedOutput: "ran ran2"); } [Fact] public void StaticMethodInvocation_TupleTypeReceiver() { var src = """ (string, string).M(); (int a, int b).M(); """; // Tracked by https://github.com/dotnet/roslyn/issues/78961 : consider parsing this var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (1,2): error CS1525: Invalid expression term 'string' // (string, string).M(); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string").WithLocation(1, 2), // (1,10): error CS1525: Invalid expression term 'string' // (string, string).M(); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string").WithLocation(1, 10), // (2,2): error CS8185: A declaration is not allowed in this context. // (int a, int b).M(); Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "int a").WithLocation(2, 2), // (2,2): error CS0165: Use of unassigned local variable 'a' // (int a, int b).M(); Diagnostic(ErrorCode.ERR_UseDefViolation, "int a").WithArguments("a").WithLocation(2, 2), // (2,9): error CS8185: A declaration is not allowed in this context. // (int a, int b).M(); Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "int b").WithLocation(2, 9), // (2,9): error CS0165: Use of unassigned local variable 'b' // (int a, int b).M(); Diagnostic(ErrorCode.ERR_UseDefViolation, "int b").WithArguments("b").WithLocation(2, 9), // (2,16): error CS1061: '(int a, int b)' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type '(int a, int b)' could be found (are you missing a using directive or an assembly reference?) // (int a, int b).M(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("(int a, int b)", "M").WithLocation(2, 16)); } [Fact] public void StaticMethodInvocation_TupleTypeReceiver_02() { var src = """ ((string, string)).M(); ((int a, int b)).M(); """; // Tracked by https://github.com/dotnet/roslyn/issues/78961 : consider parsing this var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (1,3): error CS1525: Invalid expression term 'string' // ((string, string)).M(); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string").WithLocation(1, 3), // (1,11): error CS1525: Invalid expression term 'string' // ((string, string)).M(); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string").WithLocation(1, 11), // (2,3): error CS8185: A declaration is not allowed in this context. // ((int a, int b)).M(); Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "int a").WithLocation(2, 3), // (2,3): error CS0165: Use of unassigned local variable 'a' // ((int a, int b)).M(); Diagnostic(ErrorCode.ERR_UseDefViolation, "int a").WithArguments("a").WithLocation(2, 3), // (2,10): error CS8185: A declaration is not allowed in this context. // ((int a, int b)).M(); Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "int b").WithLocation(2, 10), // (2,10): error CS0165: Use of unassigned local variable 'b' // ((int a, int b)).M(); Diagnostic(ErrorCode.ERR_UseDefViolation, "int b").WithArguments("b").WithLocation(2, 10), // (2,18): error CS1061: '(int a, int b)' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type '(int a, int b)' could be found (are you missing a using directive or an assembly reference?) // ((int a, int b)).M(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("(int a, int b)", "M").WithLocation(2, 18)); } [Fact] public void StaticMethodInvocation_PointerTypeReceiver() { var src = """ unsafe class C { void M() { int*.M(); delegate*<void>.M(); } } """; // Tracked by https://github.com/dotnet/roslyn/issues/78961 : consider parsing this var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (5,13): error CS1001: Identifier expected // int*.M(); Diagnostic(ErrorCode.ERR_IdentifierExpected, ".").WithLocation(5, 13), // (5,13): error CS1003: Syntax error, ',' expected // int*.M(); Diagnostic(ErrorCode.ERR_SyntaxError, ".").WithArguments(",").WithLocation(5, 13), // (5,14): error CS1002: ; expected // int*.M(); Diagnostic(ErrorCode.ERR_SemicolonExpected, "M").WithLocation(5, 14), // (6,17): error CS1514: { expected // delegate*<void>.M(); Diagnostic(ErrorCode.ERR_LbraceExpected, "*").WithLocation(6, 17), // (6,17): warning CS8848: Operator '*' cannot be used here due to precedence. Use parentheses to disambiguate. // delegate*<void>.M(); Diagnostic(ErrorCode.WRN_PrecedenceInversion, "*").WithArguments("*").WithLocation(6, 17), // (6,18): error CS1525: Invalid expression term '<' // delegate*<void>.M(); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<").WithArguments("<").WithLocation(6, 18), // (6,19): error CS1525: Invalid expression term 'void' // delegate*<void>.M(); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "void").WithArguments("void").WithLocation(6, 19), // (6,24): error CS1525: Invalid expression term '.' // delegate*<void>.M(); Diagnostic(ErrorCode.ERR_InvalidExprTerm, ".").WithArguments(".").WithLocation(6, 24)); } [Fact] public void StaticMethodInvocation_DynamicTypeReceiver() { var src = """ dynamic.M(); """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (1,1): error CS0103: The name 'dynamic' does not exist in the current context // dynamic.M(); Diagnostic(ErrorCode.ERR_NameNotInContext, "dynamic").WithArguments("dynamic").WithLocation(1, 1)); } [Fact] public void DisplayString_Constraint() { var source = """ static class E { extension<T>(T) where T : struct { } } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); var format = new SymbolDisplayFormat(genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints); AssertEx.Equal("E.extension<T>(T) where T : struct", symbol.ToDisplayString(format)); } [Fact] public void DisplayString_Modifier() { var source = """ static class E { extension(ref readonly int i) { } } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extension); var format = new SymbolDisplayFormat(parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeModifiers); AssertEx.Equal("E.extension(ref readonly Int32)", symbol.ToDisplayString(format)); } [Fact] public void NameConflict_01_EnclosingStaticTypeNameWithExtensionTypeParameterName() { var src = """ static class Extensions { extension<Extensions>(Extensions) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void NameConflict_02_EnclosingStaticTypeNameWithReceiverParameterName() { var src = """ static class Extensions { extension(int Extensions) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void NameConflict_03_ExtensionTypeParameterNameWithReceiverParameterName() { var src = """ static class Extensions { #line 7 extension<T>(T[] T) { void M1(){} } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (7,22): error CS9287: 'T': a receiver parameter cannot have the same name as an extension container type parameter // extension<T>(T[] T) Diagnostic(ErrorCode.ERR_ReceiverParameterSameNameAsTypeParameter, "T").WithArguments("T").WithLocation(7, 22) ); } [Fact] public void NameConflict_04_ExtensionTypeParameterNameWithMemberParameterName() { var src = """ static class Extensions { extension<T>(T[] p) { #line 14 void M2(int T){} static void M3(int T){} int this[int T] => 0; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (14,21): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter // void M2(int T){} Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(14, 21), // (15,28): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter // static void M3(int T){} Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(15, 28), // (16,22): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter // int this[int T] => 0; Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(16, 22) ); } [Theory] [CombinatorialData] public void NameConflict_05_ExtensionTypeParameterNameWithSetterValueParameter(bool isStatic) { var src = @" static class Extensions { extension<value>(value[] p) { " + (isStatic ? "static" : "") + @" int P11 {set{}} " + (isStatic ? "static" : "") + @" int P12 => 0; } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (4,15): warning CS8981: The type name 'value' only contains lower-cased ascii characters. Such names may become reserved for the language. // extension<value>(value[] p) Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "value").WithArguments("value").WithLocation(4, 15), // (7,18): error CS9294: 'value': an automatically-generated parameter name conflicts with an extension type parameter name // int P11 {set{}} Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionTypeParameter, "set").WithLocation(7, 18) ); } [Fact] public void NameConflict_06_ExtensionTypeParameterNameWithSetterValueParameter() { var src = @" static class Extensions { extension<value>(value[] p) { int this[int i] {set{}} int this[long i] => 0; } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (4,15): warning CS8981: The type name 'value' only contains lower-cased ascii characters. Such names may become reserved for the language. // extension<value>(value[] p) Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "value").WithArguments("value").WithLocation(4, 15), // (6,26): error CS9294: 'value': an automatically-generated parameter name conflicts with an extension type parameter name // int this[int i] {set{}} Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionTypeParameter, "set").WithLocation(6, 26) ); } [Theory] [CombinatorialData] public void NameConflict_07_ExtensionTypeParameterNameWithLocalFunctionParameterName(bool isStatic1, bool isStatic2) { var modifier1 = isStatic1 ? "static " : ""; var modifier2 = isStatic2 ? "static " : ""; var src = @" #pragma warning disable CS8321 // The local function 'local' is declared but never used static class Extensions { extension<T>(T[] p) { " + modifier1 + @"void M4() { " + modifier2 + @"int local(int T) { return T; } } " + modifier1 + @"int P7 { set { " + modifier2 + @"int local(int T) { return T; } } } } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Theory] [CombinatorialData] public void NameConflict_08_ExtensionTypeParameterNameWithLambdaParameterName(bool isStatic1, bool isStatic2) { var modifier1 = isStatic1 ? "static " : ""; var modifier2 = isStatic2 ? "static " : ""; var src = @" static class Extensions { extension<T>(T[] p) { " + modifier1 + @"void M4() { System.Func<int, int> l = " + modifier2 + @"(int T) => { return T; }; } " + modifier1 + @"int P7 { set { System.Func<int, int> l = " + modifier2 + @"(int T) => { return T; }; } } } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Theory] [CombinatorialData] public void NameConflict_09_ExtensionTypeParameterNameWithLocalName(bool isStatic) { var modifier = isStatic ? "static " : ""; var src = @" static class Extensions { extension<T>(T[] p) { " + modifier + @"int M4() { #line 19 int T = 0; return T; } " + modifier + @"int M5() { int T() => 0; return T(); } " + modifier + @"int P7 { get { int T = 0; return T; } } " + modifier + @"int P8 { get { int T() => 0; return T(); } } } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (19,17): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter // int T = 0; Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(19, 17), // (24,17): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter // int T() => 0; Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(24, 17), // (31,21): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter // int T = 0; Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(31, 21), // (39,21): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter // int T() => 0; Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(39, 21) ); } [Theory] [CombinatorialData] public void NameConflict_10_ExtensionTypeParameterNameWithLocalNameInLocalFunction(bool isStatic1, bool isStatic2) { var modifier1 = isStatic1 ? "static " : ""; var modifier2 = isStatic2 ? "static " : ""; var src = @" #pragma warning disable CS8321 // The local function 'local' is declared but never used static class Extensions { extension<T>(T[] p) { " + modifier1 + @"void M4() { " + modifier2 + @"int local() { int T = 0; return T; } } " + modifier1 + @"void M5() { " + modifier2 + @"int local() { int T() => 0; return T(); } } " + modifier1 + @"int P7 { set { " + modifier2 + @"int local() { int T = 0; return T; } } } " + modifier1 + @"int P8 { set { " + modifier2 + @"int local() { int T() => 0; return T(); } } } } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Theory] [CombinatorialData] public void NameConflict_11_ExtensionTypeParameterNameWithLocalNameInLambda(bool isStatic1, bool isStatic2) { var modifier1 = isStatic1 ? "static " : ""; var modifier2 = isStatic2 ? "static " : ""; var src = @" static class Extensions { extension<T>(T[] p) { " + modifier1 + @"void M4() { System.Func<int> l = " + modifier2 + @"() => { int T = 0; return T; }; } " + modifier1 + @"void M5() { System.Func<int> l = " + modifier2 + @"() => { int T() => 0; return T(); }; } " + modifier1 + @"int P7 { set { System.Func<int> l = " + modifier2 + @"() => { int T = 0; return T; }; } } " + modifier1 + @"int P8 { set { System.Func<int> l = " + modifier2 + @"() => { int T() => 0; return T(); }; } } } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void NameConflict_12_ExtensionTypeParameterNameWithAnotherExtensionTypeParameterName() { var src = """ static class Extensions { #line 55 extension<T, T>(T[] p) {} } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (55,18): error CS0692: Duplicate type parameter 'T' // extension<T, T>(T[] p) Diagnostic(ErrorCode.ERR_DuplicateTypeParameter, "T").WithArguments("T").WithLocation(55, 18), // (55,21): error CS0229: Ambiguity between 'T' and 'T' // extension<T, T>(T[] p) Diagnostic(ErrorCode.ERR_AmbigMember, "T").WithArguments("T", "T").WithLocation(55, 21) ); } [Theory] [CombinatorialData] public void NameConflict_13_ExtensionTypeParameterNameWithMemberTypeParameterName(bool isStatic) { var modifier = isStatic ? "static" : ""; var src = @" static class Extensions { extension<T>(T[] p) { " + modifier + @" #line 60 void M9<T>(){} " + modifier + @" #line 61 void M10<T, T>(){} } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (60,17): error CS9289: Type parameter 'T' has the same name as an extension container type parameter // void M9<T>(){} Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(60, 17), // (61,18): error CS9289: Type parameter 'T' has the same name as an extension container type parameter // void M10<T, T>(){} Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(61, 18), // (61,21): error CS9289: Type parameter 'T' has the same name as an extension container type parameter // void M10<T, T>(){} Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(61, 21) ); } [Theory] [CombinatorialData] public void NameConflict_14_ExtensionTypeParameterNameWithLocalFunctionTypeParameterName(bool isStatic1, bool isStatic2) { var modifier1 = isStatic1 ? "static " : ""; var modifier2 = isStatic2 ? "static" : ""; var src = @" #pragma warning disable CS8321 // The local function 'local' is declared but never used static class Extensions { extension<T>(T[] p) { " + modifier1 + @"void M4() { " + modifier2 + @" T local<T>(T p1) { return p1; } } " + modifier1 + @"void M5() { void local2() { " + modifier2 + @" T local<T>(T p1) { return p1; } } } " + modifier1 + @"int P7 { set { " + modifier2 + @" T local<T>(T p1) { return p1; } } } " + modifier1 + @"int P8 { set { void local2() { " + modifier2 + @" T local<T>(T p1) { return p1; } } } } } } "; var comp = CreateCompilation(src); // Tracked by https://github.com/dotnet/roslyn/issues/78830 : diagnostic quality, we might need to add a new warning if we don't want to refer to extension as a type in diagnostics comp.VerifyEmitDiagnostics( // (11,21): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions.extension<T>(T[])' // T local<T>(T p1) Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions.extension<T>(T[])").WithLocation(11, 21), // (21,25): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions.extension<T>(T[])' // T local<T>(T p1) Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions.extension<T>(T[])").WithLocation(21, 25), // (32,25): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions.extension<T>(T[])' // T local<T>(T p1) Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions.extension<T>(T[])").WithLocation(32, 25), // (45,29): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions.extension<T>(T[])' // T local<T>(T p1) Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions.extension<T>(T[])").WithLocation(45, 29) ); } [Fact] public void NameConflict_15_ExtensionTypeParameterNameWithMemberName() { var src = """ static class Extensions { extension<T>(C1<T> p) { int T() { return T; } } extension<T>(C2<T> p) { int T => T; } extension<T>(C3<T> p) { [System.Runtime.CompilerServices.IndexerName("T")] int this[int x] => T; } extension<T>(C4<T> p) { static int T() { return T; } } extension<T>(C5<T> p) { static int T => T; } extension<get_P>(C6<get_P> p) { int P => 0; } extension<get_Indexer>(C7<get_Indexer> p) { [System.Runtime.CompilerServices.IndexerName("Indexer")] int this[int x] => 0; } extension<get_Item>(C8<get_Item> p) { int this[int x] => 0; } } class C1<T> {} class C2<T> {} class C3<T> {} class C4<T> {} class C5<T> {} class C6<T> {} class C7<T> {} class C8<T> {} """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,20): error CS0119: 'T' is a type, which is not valid in the given context // return T; Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(7, 20), // (13,18): error CS0119: 'T' is a type, which is not valid in the given context // int T => T; Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(13, 18), // (19,13): error CS0102: The type 'Extensions' already contains a definition for 'T' // int this[int x] => T; Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "this").WithArguments("Extensions", "T").WithLocation(19, 13), // (19,28): error CS0119: 'T' is a type, which is not valid in the given context // int this[int x] => T; Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(19, 28), // (26,20): error CS0119: 'T' is a type, which is not valid in the given context // return T; Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(26, 20), // (32,25): error CS0119: 'T' is a type, which is not valid in the given context // static int T => T; Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(32, 25) ); } [Fact] public void NameConflict_16_ReceiverParameterNameWithMemberName() { var src = """ static class Extensions { extension(int M1) { void M1() { int x = M1; x++; } } extension(long P1) { int P1 { get { P1 = long.MaxValue; return 0; } } } extension(byte Indexer) { [System.Runtime.CompilerServices.IndexerName("Indexer")] int this[int y] { get { byte x = Indexer; x++; return 0; } } } extension(short M1) { static void M1() { short x = M1; x++; } } extension(string P1) { static int P1 { get { P1 = "val"; return 0; } } } extension(int[] get_P) { int P => 0; } extension(long[] get_Indexer) { [System.Runtime.CompilerServices.IndexerName("Indexer")] int this[int x] => 0; } extension(byte[] get_Item) { int this[int x] => 0; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (42,23): error CS9347: Static members cannot access the value of extension parameter 'M1'. // short x = M1; Diagnostic(ErrorCode.ERR_ExtensionParameterInStaticContext, "M1").WithArguments("M1").WithLocation(42, 23), // (53,17): error CS9347: Static members cannot access the value of extension parameter 'P1'. // P1 = "val"; Diagnostic(ErrorCode.ERR_ExtensionParameterInStaticContext, "P1").WithArguments("P1").WithLocation(53, 17) ); } [Theory] [CombinatorialData] public void NameConflict_17_ReceiverParameterNameWithMemberTypeParameterName(bool isStatic) { var modifier = isStatic ? "static" : ""; var src = @" static class Extensions { extension(int T) { " + modifier + @" #line 5 void M1<T>(){} } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,17): error CS9292: Type parameter 'T' has the same name as an extension parameter // void M1<T>(){} Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionParameter, "T").WithArguments("T").WithLocation(5, 17) ); } [Theory] [CombinatorialData] public void NameConflict_18_ReceiverParameterNameWithLocalFunctionTypeParameterName(bool isStatic1, bool isStatic2) { var modifier1 = isStatic1 ? "static " : ""; var modifier2 = isStatic2 ? "static" : ""; var src = @" #pragma warning disable CS8321 // The local function 'local' is declared but never used static class Extensions { extension(int T) { " + modifier1 + @"void M4() { " + modifier2 + @" T local<T>(T p1) { return p1; } } " + modifier1 + @"void M5() { void local2() { " + modifier2 + @" T local<T>(T p1) { return p1; } } } " + modifier1 + @"int P7 { set { " + modifier2 + @" T local<T>(T p1) { return p1; } } } " + modifier1 + @"int P8 { set { void local2() { " + modifier2 + @" T local<T>(T p1) { return p1; } } } } } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void NameConflict_19_ReceiverParameterNameWithMemberParameterName() { var src = """ static class Extensions { extension(int p) { void M2(int p){} static void M3(int p){} int this[int p] => 0; void M3(int p2, int p2) {} } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,21): error CS9290: 'p': a parameter, local variable, or local function cannot have the same name as an extension parameter // void M2(int p){} Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "p").WithArguments("p").WithLocation(5, 21), // (6,28): error CS9290: 'p': a parameter, local variable, or local function cannot have the same name as an extension parameter // static void M3(int p){} Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "p").WithArguments("p").WithLocation(6, 28), // (7,22): error CS9290: 'p': a parameter, local variable, or local function cannot have the same name as an extension parameter // int this[int p] => 0; Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "p").WithArguments("p").WithLocation(7, 22), // (8,29): error CS0100: The parameter name 'p2' is a duplicate // void M3(int p2, int p2) {} Diagnostic(ErrorCode.ERR_DuplicateParamName, "p2").WithArguments("p2").WithLocation(8, 29) ); } [Fact] public void NameConflict_20_ReceiverParameterNameWithSetterValueParameter() { var src = """ static class Extensions { extension(int value) { int P1 {get=>0;} int P2 {set{}} int this[int x] {get=>0;} int this[long x] {set{}} int this[long x, int value] {set{}} static int P6 {get=>0;} static int P7 {set{}} } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (6,17): error CS9291: 'value': an automatically-generated parameter name conflicts with an extension parameter name // int P2 {set{}} Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, "set").WithLocation(6, 17), // (8,27): error CS9291: 'value': an automatically-generated parameter name conflicts with an extension parameter name // int this[long x] {set{}} Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, "set").WithLocation(8, 27), // (9,30): error CS9290: 'value': a parameter, local variable, or local function cannot have the same name as an extension parameter // int this[long x, int value] {set{}} Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "value").WithArguments("value").WithLocation(9, 30), // (9,30): error CS0316: The parameter name 'value' conflicts with an automatically-generated parameter name // int this[long x, int value] {set{}} Diagnostic(ErrorCode.ERR_DuplicateGeneratedName, "value").WithArguments("value").WithLocation(9, 30), // (9,38): error CS9291: 'value': an automatically-generated parameter name conflicts with an extension parameter name // int this[long x, int value] {set{}} Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, "set").WithLocation(9, 38), // (11,24): error CS9291: 'value': an automatically-generated parameter name conflicts with an extension parameter name // static int P7 {set{}} Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, "set").WithLocation(11, 24) ); } [Theory] [CombinatorialData] public void NameConflict_21_ReceiverParameterNameWithLocalFunctionParameterName(bool isStatic1, bool isStatic2) { var modifier1 = isStatic1 ? "static " : ""; var modifier2 = isStatic2 ? "static " : ""; var src = @" #pragma warning disable CS8321 // The local function 'local' is declared but never used static class Extensions { extension(string p) { " + modifier1 + @"void M4() { " + modifier2 + @"int local(int p) { return p; } } " + modifier1 + @"int P7 { set { " + modifier2 + @"int local(int p) { return p; } } } } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Theory] [CombinatorialData] public void NameConflict_22_ReceiverParameterNameWithLambdaParameterName(bool isStatic1, bool isStatic2) { var modifier1 = isStatic1 ? "static " : ""; var modifier2 = isStatic2 ? "static " : ""; var src = @" static class Extensions { extension(string p) { " + modifier1 + @"void M4() { System.Func<int, int> l = " + modifier2 + @"(int p) => { return p; }; } " + modifier1 + @"int P7 { set { System.Func<int, int> l = " + modifier2 + @"(int p) => { return p; }; } } } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Theory] [CombinatorialData] public void NameConflict_23_ReceiverParameterNameWithLocalName(bool isStatic) { var modifier = isStatic ? "static " : ""; var src = @" static class Extensions { extension(int p) { " + modifier + @"int M4() { #line 7 int p = 0; return p; } " + modifier + @"int M5() { int p() => 0; return p(); } " + modifier + @"int P7 { get { int p = 0; return p; } } " + modifier + @"int P8 { get { int p() => 0; return p(); } } } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (7,17): error CS0136: A local or parameter named 'p' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // int p = 0; Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "p").WithArguments("p").WithLocation(7, 17), // (12,17): error CS0136: A local or parameter named 'p' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // int p() => 0; Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "p").WithArguments("p").WithLocation(12, 17), // (19,21): error CS0136: A local or parameter named 'p' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // int p = 0; Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "p").WithArguments("p").WithLocation(19, 21), // (27,21): error CS0136: A local or parameter named 'p' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // int p() => 0; Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "p").WithArguments("p").WithLocation(27, 21) ); } [Theory] [CombinatorialData] public void NameConflict_24_ReceiverParameterNameWithLocalNameInLocalFunction(bool isStatic1, bool isStatic2) { var modifier1 = isStatic1 ? "static " : ""; var modifier2 = isStatic2 ? "static " : ""; var src = @" #pragma warning disable CS8321 // The local function 'local' is declared but never used static class Extensions { extension(string p) { " + modifier1 + @"void M4() { " + modifier2 + @"int local() { int p = 0; return p; } } " + modifier1 + @"void M5() { " + modifier2 + @"int local() { int p() => 0; return p(); } } " + modifier1 + @"int P7 { set { " + modifier2 + @"int local() { int p = 0; return p; } } } " + modifier1 + @"int P8 { set { " + modifier2 + @"int local() { int p() => 0; return p(); } } } } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Theory] [CombinatorialData] public void NameConflict_25_ReceiverParameterNameWithLocalNameInLambda(bool isStatic1, bool isStatic2) { var modifier1 = isStatic1 ? "static " : ""; var modifier2 = isStatic2 ? "static " : ""; var src = @" static class Extensions { extension(string p) { " + modifier1 + @"void M4() { System.Func<int> l = " + modifier2 + @"() => { int p = 0; return p; }; } " + modifier1 + @"void M5() { System.Func<int> l = " + modifier2 + @"() => { int p() => 0; return p(); }; } " + modifier1 + @"int P7 { set { System.Func<int> l = " + modifier2 + @"() => { int p = 0; return p; }; } } " + modifier1 + @"int P8 { set { System.Func<int> l = " + modifier2 + @"() => { int p() => 0; return p(); }; } } } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void NameConflict_26_ExampleFromSpec() { var src = @" using System.Linq; public static class E { extension<T>(T[] ts) { public bool M1(T t) => ts.Contains(t); // `T` and `ts` are in scope public static bool M2(T t) => ts.Contains(t); // Error: Cannot refer to `ts` from static context public void M3(int T, string ts) { } // Error: Cannot reuse names `T` and `ts` public void M4<T, ts>(string s) { } // Error: Cannot reuse names `T` and `ts` } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (9,39): error CS9347: Static members cannot access the value of extension parameter 'ts'. // public static bool M2(T t) => ts.Contains(t); // Error: Cannot refer to `ts` from static context Diagnostic(ErrorCode.ERR_ExtensionParameterInStaticContext, "ts").WithArguments("ts").WithLocation(9, 39), // (10,28): error CS9288: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter // public void M3(int T, string ts) { } // Error: Cannot reuse names `T` and `ts` Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(10, 28), // (10,38): error CS9290: 'ts': a parameter, local variable, or local function cannot have the same name as an extension parameter // public void M3(int T, string ts) { } // Error: Cannot reuse names `T` and `ts` Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "ts").WithArguments("ts").WithLocation(10, 38), // (11,24): error CS9289: Type parameter 'T' has the same name as an extension container type parameter // public void M4<T, ts>(string s) { } // Error: Cannot reuse names `T` and `ts` Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(11, 24), // (11,27): warning CS8981: The type name 'ts' only contains lower-cased ascii characters. Such names may become reserved for the language. // public void M4<T, ts>(string s) { } // Error: Cannot reuse names `T` and `ts` Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "ts").WithArguments("ts").WithLocation(11, 27), // (11,27): error CS9292: Type parameter 'ts' has the same name as an extension parameter // public void M4<T, ts>(string s) { } // Error: Cannot reuse names `T` and `ts` Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionParameter, "ts").WithArguments("ts").WithLocation(11, 27) ); } [Fact] public void NameConflict_27_ExampleFromSpec() { var src = @" public static class E { extension<T>(T[] ts) { public int T() { return M(ts); } // Generated static method M<T>(T[]) is found public string M() { return T(ts); } // Error: T is a type parameter } } class CTest { static int M<T>(T[] ts) { return T(ts); } static int T<U>(U[] ts) => 0; } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (6,33): error CS0029: Cannot implicitly convert type 'string' to 'int' // public int T() { return M(ts); } // Generated static method M<T>(T[]) is found Diagnostic(ErrorCode.ERR_NoImplicitConv, "M(ts)").WithArguments("string", "int").WithLocation(6, 33), // (7,36): error CS0119: 'T' is a type, which is not valid in the given context // public string M() { return T(ts); } // Error: T is a type parameter Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(7, 36), // (15,16): error CS0119: 'T' is a type, which is not valid in the given context // return T(ts); Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(15, 16) ); } [Fact] public void NameConflict_28_ExampleFromSpec() { var src = @" public static class E { extension(int P) { public int P() { return M(P); } // Generated static method M<T>(T[]) is found public string M() { return P(P); } // Error: P is a parameter } } class CTest { static int M(int P) { return P(P); } static int P(int P) => 0; } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (6,33): error CS0029: Cannot implicitly convert type 'string' to 'int' // public int P() { return M(P); } // Generated static method M<T>(T[]) is found Diagnostic(ErrorCode.ERR_NoImplicitConv, "M(P)").WithArguments("string", "int").WithLocation(6, 33), // (7,36): error CS0149: Method name expected // public string M() { return P(P); } // Error: P is a parameter Diagnostic(ErrorCode.ERR_MethodNameExpected, "P").WithLocation(7, 36), // (15,16): error CS0149: Method name expected // return P(P); Diagnostic(ErrorCode.ERR_MethodNameExpected, "P").WithLocation(15, 16) ); } [Fact] public void NameConflict_29_WithStaticTypeTypeParameter() { var src = @" public static class E<T> { extension(int p) { public void M1<T>() {} } extension<T>(T[] p) { public void M2<T>() {} } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (4,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension(int p) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(4, 5), // (6,24): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'E<T>' // public void M1<T>() {} Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "E<T>").WithLocation(6, 24), // (9,5): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension<T>(T[] p) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(9, 5), // (9,15): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'E<T>' // extension<T>(T[] p) Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "E<T>").WithLocation(9, 15), // (11,24): error CS9289: Type parameter 'T' has the same name as an extension container type parameter // public void M2<T>() {} Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(11, 24) ); } [Fact] public void ReceiverParameterScope_01_InStaticMember() { var src = """ static class Extensions { extension(int p) { static int P1 { get => p; } static int M2() { return p; } } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,32): error CS9347: Static members cannot access the value of extension parameter 'p'. // static int P1 { get => p; } Diagnostic(ErrorCode.ERR_ExtensionParameterInStaticContext, "p").WithArguments("p").WithLocation(5, 32), // (8,20): error CS9347: Static members cannot access the value of extension parameter 'p'. // return p; Diagnostic(ErrorCode.ERR_ExtensionParameterInStaticContext, "p").WithArguments("p").WithLocation(8, 20) ); } [Fact] public void ReceiverParameterScope_02_InStaticMember() { var src = """ static class Extensions { extension(int p) { static int P1 { get { int local() => p; return local(); } } static int M2() { int local() => p; return local(); } } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (9,32): error CS9347: Static members cannot access the value of extension parameter 'p'. // int local() => p; Diagnostic(ErrorCode.ERR_ExtensionParameterInStaticContext, "p").WithArguments("p").WithLocation(9, 32), // (15,28): error CS9347: Static members cannot access the value of extension parameter 'p'. // int local() => p; Diagnostic(ErrorCode.ERR_ExtensionParameterInStaticContext, "p").WithArguments("p").WithLocation(15, 28) ); } [Fact] public void ReceiverParameterScope_03_InStaticMember() { var src = """ static class Extensions { extension(int p) { static string P1 { get => nameof(p); } static string M2() { return nameof(p); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void ReceiverParameterScope_04_InStaticLocalFunction() { var src = """ static class Extensions { extension(int p) { int P1 { get { static int local() => p; return local(); } } int M2() { static int local() => p; return local(); } } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (9,39): error CS8421: A static local function cannot contain a reference to 'p'. // static int local() => p; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "p").WithArguments("p").WithLocation(9, 39), // (15,35): error CS8421: A static local function cannot contain a reference to 'p'. // static int local() => p; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "p").WithArguments("p").WithLocation(15, 35) ); } [Theory] [CombinatorialData] public void ReceiverParameterScope_05_InAttribute(bool isStatic) { var modifier = isStatic ? "static " : ""; var src = @" static class Extensions { extension(int p) { [MyAttr(nameof(p))] " + modifier + @"int P1 { get => 0; } [MyAttr(nameof(p))] " + modifier + @"int M2() { return 0; } } } class MyAttr : System.Attribute { public MyAttr(string s) {} } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Theory] [CombinatorialData] public void ReceiverParameterScope_06_InAttribute(bool isStatic) { var modifier = isStatic ? "static " : ""; var src = @" static class Extensions { extension(int p) { [MyAttr(p)] " + modifier + @"int P1 { get => 0; } [MyAttr(p)] " + modifier + @"int M2() { return 0; } } } class MyAttr : System.Attribute { public MyAttr(int p) {} } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,17): error CS9293: Cannot use extension parameter 'int p' in this context. // [MyAttr(p)] Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(6, 17), // (6,17): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [MyAttr(p)] Diagnostic(ErrorCode.ERR_BadAttributeArgument, "p").WithLocation(6, 17), // (9,17): error CS9293: Cannot use extension parameter 'int p' in this context. // [MyAttr(p)] Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(9, 17), // (9,17): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [MyAttr(p)] Diagnostic(ErrorCode.ERR_BadAttributeArgument, "p").WithLocation(9, 17) ); } [Fact] public void ReceiverParameterScope_07_InAttribute() { var src = @" static class Extensions { extension(int p) { [MyAttr(nameof(p))] int this[int y] { get { return 0; } } } } class MyAttr : System.Attribute { public MyAttr(string p) {} } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void ReceiverParameterScope_08_InAttribute() { var src = @" static class Extensions { extension(string p) { [System.Runtime.CompilerServices.IndexerName(p)] int this[int y] { get { return 0; } } } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (6,54): error CS9293: Cannot use extension parameter 'string p' in this context. // [System.Runtime.CompilerServices.IndexerName(p)] Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("string p").WithLocation(6, 54), // (6,54): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [System.Runtime.CompilerServices.IndexerName(p)] Diagnostic(ErrorCode.ERR_BadAttributeArgument, "p").WithLocation(6, 54) ); } [Theory] [CombinatorialData] public void ReceiverParameterScope_09_InDefaultValue(bool isStatic) { var modifier = isStatic ? "static " : ""; var src = @" static class Extensions { extension(int p) { " + modifier + @"int M2(string x = nameof(p)) { return 0; } } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Theory] [CombinatorialData] public void ReceiverParameterScope_10_InDefaultValue(bool isStatic) { var modifier = isStatic ? "static" : ""; var src = @" static class Extensions { extension(int p) { " + modifier + @" #line 6 int M2(int x = p) { return 0; } } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,24): error CS9293: Cannot use extension parameter 'int p' in this context. // int M2(int x = p) Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(6, 24), // (6,24): error CS1736: Default parameter value for 'x' must be a compile-time constant // int M2(int x = p) Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "p").WithArguments("x").WithLocation(6, 24) ); } [Theory] [CombinatorialData] public void ReceiverParameterScope_11_InNestedType(bool isStatic) { var modifier = isStatic ? "static" : ""; var src = @" static class Extensions { extension(int p) { class Nested { " + modifier + @" int M2() { return p; } " + modifier + @" string M3() { return nameof(p); } } } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,15): error CS9282: This member is not allowed in an extension block // class Nested Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Nested").WithLocation(6, 15), // (11,24): error CS9293: Cannot use extension parameter 'int p' in this context. // return p; Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(11, 24) ); } [Fact] public void CycleInAttribute_01() { var src = @" static class Extensions { const string Str = ""val""; extension(string p) { [System.Runtime.CompilerServices.IndexerName(Str)] int this[int y] { get { return 0; } } } } "; var comp = CreateCompilation(src); // Tracked by https://github.com/dotnet/roslyn/issues/78829 : indexers, We do not allow complex forms of IndexerName attribute due to a possible binding cycle comp.VerifyEmitDiagnostics( // (7,54): error CS8078: An expression is too long or complex to compile // [System.Runtime.CompilerServices.IndexerName(Str)] Diagnostic(ErrorCode.ERR_InsufficientStack, "Str").WithLocation(7, 54)); } [Fact] public void MemberNameAndSignatureConflict_01() { var src = """ static class Extensions { extension(object receiver) { public void M1() {} } extension(object receiver) { public void M1() {} } extension(int receiver) { public void M2() {} } extension(ref int receiver) { public void M2() {} } extension(in int receiver) { public void M3() {} } extension(ref int receiver) { public void M3() {} } extension(ref readonly int receiver) { public void M4() {} } extension(ref int receiver) { public void M4() {} } extension(ref readonly int receiver) { public void M5() {} } extension(in int receiver) { public void M5() {} } static public void M6(this int receiver) {} static public void M6(this ref int receiver) {} static public void M7(this in int receiver) {} static public void M7(this ref int receiver) {} static public void M8(this ref readonly int receiver) {} static public void M8(this ref int receiver) {} static public void M9(this ref readonly int receiver) {} static public void M9(this in int receiver) {} extension(object receiver) { public void M10() {} public void M10() {} } extension(object receiver1) { public void M13() {} } extension(object receiver2) { public void M13() {} } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (10,21): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types // public void M1() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(10, 21), // (20,21): error CS0111: Type 'Extensions' already defines a member called 'M2' with the same parameter types // public void M2() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M2").WithArguments("M2", "Extensions").WithLocation(20, 21), // (30,21): error CS0111: Type 'Extensions' already defines a member called 'M3' with the same parameter types // public void M3() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M3").WithArguments("M3", "Extensions").WithLocation(30, 21), // (40,21): error CS0111: Type 'Extensions' already defines a member called 'M4' with the same parameter types // public void M4() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M4").WithArguments("M4", "Extensions").WithLocation(40, 21), // (50,21): error CS0111: Type 'Extensions' already defines a member called 'M5' with the same parameter types // public void M5() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M5").WithArguments("M5", "Extensions").WithLocation(50, 21), // (59,24): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref' and 'in' // static public void M7(this ref int receiver) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M7").WithArguments("Extensions", "method", "ref", "in").WithLocation(59, 24), // (63,24): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref' and 'ref readonly' // static public void M8(this ref int receiver) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M8").WithArguments("Extensions", "method", "ref", "ref readonly").WithLocation(63, 24), // (67,24): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref readonly' // static public void M9(this in int receiver) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M9").WithArguments("Extensions", "method", "in", "ref readonly").WithLocation(67, 24), // (72,21): error CS0111: Type 'Extensions' already defines a member called 'M10' with the same parameter types // public void M10() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M10").WithArguments("M10", "Extensions").WithLocation(72, 21), // (82,21): error CS0111: Type 'Extensions' already defines a member called 'M13' with the same parameter types // public void M13() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M13").WithArguments("M13", "Extensions").WithLocation(82, 21) ); comp = CreateCompilation(""" static class Extensions { static void Main() { int i = 0; i.M11(); "".M11(); ((long)i).M12(i); ((long)i).M12(ref i); } extension(int receiver) { public void M11() {} } extension(string receiver) { public void M11() {} } extension(long receiver) { public void M12(int x) {} } extension(long receiver) { public void M12(ref int x) {} } } """); CompileAndVerify(comp).VerifyDiagnostics(); } [Fact] public void MemberNameAndSignatureConflict_02() { var src = """ static class Extensions { extension(object receiver) { static public void M1() {} } extension(object receiver) { static public void M1() {} } extension(object receiver) { static public void M2(ref int x) {} } extension(object receiver) { static public void M2(ref readonly int x) {} } extension(object receiver) { static public void M3(in int x) {} } extension(object receiver) { static public void M3(ref readonly int x) {} } extension(object receiver) { static public void M4(ref int x) {} } extension(object receiver) { static public void M4(in int x) {} } extension(object receiver) { static public void M5() {} static public void M5() {} } extension(int receiver) { static public void M6() {} } extension(string receiver) { static public void M6() {} } extension(int receiver) { static public int M7() => 0; } extension(long receiver) { static public long M7() => 0; } extension(int receiver) { public static void M8() {} } extension(ref int receiver) { public static void M8() {} } extension(int receiver) { public void M9() {} } extension(int receiver) { public static void M9(int x) {} } extension(ref int receiver) { public void M10() {} } extension(int receiver) { public static void M10(in int x) {} } extension(int receiver) { public void M11() {} public static void M11(int x) {} } extension(ref int receiver) { public void M12() {} public static void M12(in int x) {} } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (10,28): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types // static public void M1() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(10, 28), // (20,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref readonly' and 'ref' // static public void M2(ref readonly int x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M2").WithArguments("Extensions", "method", "ref readonly", "ref").WithLocation(20, 28), // (30,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref readonly' and 'in' // static public void M3(ref readonly int x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M3").WithArguments("Extensions", "method", "ref readonly", "in").WithLocation(30, 28), // (40,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' // static public void M4(in int x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M4").WithArguments("Extensions", "method", "in", "ref").WithLocation(40, 28), // (46,28): error CS0111: Type 'Extensions' already defines a member called 'M5' with the same parameter types // static public void M5() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M5").WithArguments("M5", "Extensions").WithLocation(46, 28), // (56,28): error CS0111: Type 'Extensions' already defines a member called 'M6' with the same parameter types // static public void M6() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M6").WithArguments("M6", "Extensions").WithLocation(56, 28), // (66,28): error CS0111: Type 'Extensions' already defines a member called 'M7' with the same parameter types // static public long M7() => 0; Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M7").WithArguments("M7", "Extensions").WithLocation(66, 28), // (76,28): error CS0111: Type 'Extensions' already defines a member called 'M8' with the same parameter types // public static void M8() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M8").WithArguments("M8", "Extensions").WithLocation(76, 28), // (86,28): error CS0111: Type 'Extensions' already defines a member called 'M9' with the same parameter types // public static void M9(int x) {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M9").WithArguments("M9", "Extensions").WithLocation(86, 28), // (96,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' // public static void M10(in int x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M10").WithArguments("Extensions", "method", "in", "ref").WithLocation(96, 28), // (102,28): error CS0111: Type 'Extensions' already defines a member called 'M11' with the same parameter types // public static void M11(int x) {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M11").WithArguments("M11", "Extensions").WithLocation(102, 28), // (108,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' // public static void M12(in int x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M12").WithArguments("Extensions", "method", "in", "ref").WithLocation(108, 28) ); comp = CreateCompilation(""" static class Extensions { static void Main() { int i = 0; i.M13(); int.M13(ref i); M13(i); M13(ref i); i.M14(); int.M14(i); M14(ref i); M14(i); } extension(int receiver) { public void M13() => System.Console.Write(1); } extension(int receiver) { public static void M13(ref int x) => System.Console.Write(2); } extension(ref int receiver) { public void M14() => System.Console.Write(3); } extension(int receiver) { public static void M14(int x) => System.Console.Write(4); } } """, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "12123434").VerifyDiagnostics(); } [Fact] public void MemberNameAndSignatureConflict_03() { var src = """ static class Extensions { extension(object receiver) { public int P1 => 1; } extension(object receiver) { public int P1 => 4; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (10,20): error CS0102: The type 'Extensions' already contains a definition for 'P1' // public int P1 => 4; Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P1").WithArguments("Extensions", "P1").WithLocation(10, 20) ); } [Fact] public void MemberNameAndSignatureConflict_04() { var src = """ static class Extensions { extension(object receiver) { static public int P1 => 1; } extension(object receiver) { static public int P1 => 4; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (10,27): error CS0102: The type 'Extensions' already contains a definition for 'P1' // static public int P1 => 4; Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P1").WithArguments("Extensions", "P1").WithLocation(10, 27) ); } [Fact] public void MemberNameAndSignatureConflict_05() { var src = """ static class Extensions { extension(object receiver) { public int P1 => 1; public int get_P2() => 2; } extension(object receiver) { public int get_P1() => 3; public int P2 => 4; } } static class Extensions2 { extension(object receiver) { public int P3 => 1; public int get_P4() => 2; public int get_P3() => 3; public int P4 => 4; } } static class Extensions3 { extension(object receiver) { public int P1 => 1; public int set_P2(int x) => 2; } extension(object receiver) { public int set_P1(int y) => 3; public int P2 => 4; } } static class Extensions4 { extension(object receiver) { public int P3 => 1; public int set_P4(int z) => 2; public int set_P3(int z) => 3; public int P4 => 4; } } static class Extensions5 { extension(object receiver) { public int this[int x] => 1; public int get_Item(long y) => 2; } extension(object receiver) { public int get_Item(int a) => 3; public int this[long b] => 4; } } static class Extensions6 { extension(object receiver) { [System.Runtime.CompilerServices.IndexerName("Indexer")] public int this[int x] => 1; } extension(object receiver) { public int get_Indexer(int a) => 3; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,26): error CS0082: Type 'Extensions' already reserves a member called 'get_P1' with the same parameter types // public int P1 => 1; Diagnostic(ErrorCode.ERR_MemberReserved, "1").WithArguments("get_P1", "Extensions").WithLocation(5, 26), // (12,26): error CS0082: Type 'Extensions' already reserves a member called 'get_P2' with the same parameter types // public int P2 => 4; Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_P2", "Extensions").WithLocation(12, 26), // (20,26): error CS0082: Type 'Extensions2' already reserves a member called 'get_P3' with the same parameter types // public int P3 => 1; Diagnostic(ErrorCode.ERR_MemberReserved, "1").WithArguments("get_P3", "Extensions2").WithLocation(20, 26), // (23,26): error CS0082: Type 'Extensions2' already reserves a member called 'get_P4' with the same parameter types // public int P4 => 4; Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_P4", "Extensions2").WithLocation(23, 26), // (31,20): error CS0082: Type 'Extensions3' already reserves a member called 'set_P1' with the same parameter types // public int P1 => 1; Diagnostic(ErrorCode.ERR_MemberReserved, "P1").WithArguments("set_P1", "Extensions3").WithLocation(31, 20), // (38,20): error CS0082: Type 'Extensions3' already reserves a member called 'set_P2' with the same parameter types // public int P2 => 4; Diagnostic(ErrorCode.ERR_MemberReserved, "P2").WithArguments("set_P2", "Extensions3").WithLocation(38, 20), // (46,20): error CS0082: Type 'Extensions4' already reserves a member called 'set_P3' with the same parameter types // public int P3 => 1; Diagnostic(ErrorCode.ERR_MemberReserved, "P3").WithArguments("set_P3", "Extensions4").WithLocation(46, 20), // (49,20): error CS0082: Type 'Extensions4' already reserves a member called 'set_P4' with the same parameter types // public int P4 => 4; Diagnostic(ErrorCode.ERR_MemberReserved, "P4").WithArguments("set_P4", "Extensions4").WithLocation(49, 20), // (57,35): error CS0082: Type 'Extensions5' already reserves a member called 'get_Item' with the same parameter types // public int this[int x] => 1; Diagnostic(ErrorCode.ERR_MemberReserved, "1").WithArguments("get_Item", "Extensions5").WithLocation(57, 35), // (64,36): error CS0082: Type 'Extensions5' already reserves a member called 'get_Item' with the same parameter types // public int this[long b] => 4; Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_Item", "Extensions5").WithLocation(64, 36), // (73,35): error CS0082: Type 'Extensions6' already reserves a member called 'get_Indexer' with the same parameter types // public int this[int x] => 1; Diagnostic(ErrorCode.ERR_MemberReserved, "1").WithArguments("get_Indexer", "Extensions6").WithLocation(73, 35) ); } [Fact] public void MemberNameAndSignatureConflict_06() { var src = """ static class Extensions1 { extension(object receiver) { public int P1 => 1; } extension(object receiver) { public int P1 {set{}} } } static class Extensions2 { extension(object receiver1) { public int this[int x] => 1; } extension(object receiver2) { public int this[int y] {set{}} } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (10,20): error CS0102: The type 'Extensions1' already contains a definition for 'P1' // public int P1 {set{}} Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P1").WithArguments("Extensions1", "P1").WithLocation(10, 20), // (23,20): error CS0111: Type 'Extensions2' already defines a member called 'this' with the same parameter types // public int this[int y] {set{}} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "this").WithArguments("this", "Extensions2").WithLocation(23, 20) ); } [Fact] public void MemberNameAndSignatureConflict_07() { var src = """ static class Extensions { extension(object receiver) { public void M(){} } extension(__arglist) { public void M(object x){} } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (8,15): error CS1669: __arglist is not valid in this context // extension(__arglist) Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(8, 15) ); } [Fact] public void MemberNameAndSignatureConflict_08() { var src = """ static class Extensions { extension(object receiver) { public void M1() {} } public static void M1(object receiver) {} extension(int receiver) { public void M2() {} } public static void M2(ref int receiver) {} extension(in int receiver) { public void M3() {} } public static void M3(ref int receiver) {} extension(ref readonly int receiver) { public void M4() {} } public static void M4(ref int receiver) {} extension(ref readonly int receiver) { public void M5() {} } public static void M5(in int receiver) {} extension(object receiver1) { public void M13() {} } public static void M13(object receiver2) {} } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,21): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types // public void M1() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(5, 21), // Tracked by https://github.com/dotnet/roslyn/issues/78830 : diagnostic quality, the error might be somewhat confusing in this scenario because there are no parameters and we complain about ref-ness of the receiver. // (19,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' // public void M3() {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M3").WithArguments("Extensions", "method", "in", "ref").WithLocation(19, 21), // (26,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref readonly' and 'ref' // public void M4() {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M4").WithArguments("Extensions", "method", "ref readonly", "ref").WithLocation(26, 21), // (33,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref readonly' and 'in' // public void M5() {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M5").WithArguments("Extensions", "method", "ref readonly", "in").WithLocation(33, 21), // (40,21): error CS0111: Type 'Extensions' already defines a member called 'M13' with the same parameter types // public void M13() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M13").WithArguments("M13", "Extensions").WithLocation(40, 21) ); comp = CreateCompilation(""" static class Extensions { static void Main() { 1.M2(); } extension(int receiver) { public void M2() {} } public static void M2(this ref int receiver) {} } """); comp.VerifyDiagnostics( // (5,11): error CS0121: The call is ambiguous between the following methods or properties: 'Extensions.extension(int).M2()' and 'Extensions.M2(ref int)' // 1.M2(); Diagnostic(ErrorCode.ERR_AmbigCall, "M2").WithArguments("Extensions.extension(int).M2()", "Extensions.M2(ref int)").WithLocation(5, 11) ); comp = CreateCompilation(""" static class Extensions { static void Main() { int i = 0; 1.M2(); M2(i); M2(ref i); ((long)i).M12(i); ((long)i).M12(ref i); } extension(int receiver) { public void M2() {} } public static void M2(ref int receiver) {} extension(long receiver) { public void M12(int x) {} } public static void M12(this long receiver, ref int x) {} } """); CompileAndVerify(comp).VerifyDiagnostics(); } [Fact] public void MemberNameAndSignatureConflict_09() { var src = """ static class Extensions { public static void M1(object receiver) {} extension(object receiver) { public void M1() {} } public static void M2(ref int receiver) {} extension(int receiver) { public void M2() {} } public static void M3(ref int receiver) {} extension(in int receiver) { public void M3() {} } public static void M4(ref int receiver) {} extension(ref readonly int receiver) { public void M4() {} } public static void M5(in int receiver) {} extension(ref readonly int receiver) { public void M5() {} } public static void M13(object receiver2) {} extension(object receiver1) { public void M13() {} } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (7,21): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types // public void M1() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(7, 21), // Tracked by https://github.com/dotnet/roslyn/issues/78830 : diagnostic quality, the error might be somewhat confusing in this scenario because there are no parameters and we complain about ref-ness of the receiver. // (21,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' // public void M3() {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M3").WithArguments("Extensions", "method", "in", "ref").WithLocation(21, 21), // (28,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref readonly' and 'ref' // public void M4() {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M4").WithArguments("Extensions", "method", "ref readonly", "ref").WithLocation(28, 21), // (35,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref readonly' and 'in' // public void M5() {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M5").WithArguments("Extensions", "method", "ref readonly", "in").WithLocation(35, 21), // (42,21): error CS0111: Type 'Extensions' already defines a member called 'M13' with the same parameter types // public void M13() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M13").WithArguments("M13", "Extensions").WithLocation(42, 21) ); comp = CreateCompilation(""" static class Extensions { static void Main() { 1.M2(); } public static void M2(this ref int receiver) {} extension(int receiver) { public void M2() {} } } """); comp.VerifyDiagnostics( // (5,11): error CS0121: The call is ambiguous between the following methods or properties: 'Extensions.extension(int).M2()' and 'Extensions.M2(ref int)' // 1.M2(); Diagnostic(ErrorCode.ERR_AmbigCall, "M2").WithArguments("Extensions.extension(int).M2()", "Extensions.M2(ref int)").WithLocation(5, 11) ); } [Fact] public void MemberNameAndSignatureConflict_10() { var src = """ static class Extensions { extension(object receiver) { static public void M1() {} } static public void M1() {} extension(object receiver) { static public void M2(ref int x) {} } static public void M2(ref readonly int x) {} extension(object receiver) { static public void M3(in int x) {} } static public void M3(ref readonly int x) {} extension(object receiver) { static public void M4(ref int x) {} } static public void M4(in int x) {} extension(int receiver) { static public int M7() => 0; } static public long M7() => 0; public static void M9(int receiver) {} extension(int receiver) { public static void M9(int x) {} } public static void M10(ref int receiver) {} extension(int receiver) { public static void M10(in int x) {} } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,28): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types // static public void M1() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(5, 28), // (12,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref' and 'ref readonly' // static public void M2(ref int x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M2").WithArguments("Extensions", "method", "ref", "ref readonly").WithLocation(12, 28), // (19,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref readonly' // static public void M3(in int x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M3").WithArguments("Extensions", "method", "in", "ref readonly").WithLocation(19, 28), // (26,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref' and 'in' // static public void M4(ref int x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M4").WithArguments("Extensions", "method", "ref", "in").WithLocation(26, 28), // (34,27): error CS0111: Type 'Extensions' already defines a member called 'M7' with the same parameter types // static public int M7() => 0; Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M7").WithArguments("M7", "Extensions").WithLocation(34, 27), // (44,28): error CS0111: Type 'Extensions' already defines a member called 'M9' with the same parameter types // public static void M9(int x) {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M9").WithArguments("M9", "Extensions").WithLocation(44, 28), // (51,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' // public static void M10(in int x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M10").WithArguments("Extensions", "method", "in", "ref").WithLocation(51, 28) ); comp = CreateCompilation(""" static class Extensions { static void Main() { int i = 0; i.M13(); int.M13(ref i); M13(i); M13(ref i); i.M14(); int.M14(i); M14(ref i); M14(i); } public static void M13(this int receiver) => System.Console.Write(1); extension(int receiver) { public static void M13(ref int x) => System.Console.Write(2); } public static void M14(this ref int receiver) => System.Console.Write(3); extension(int receiver) { public static void M14(int x) => System.Console.Write(4); } } """, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "12123434").VerifyDiagnostics(); } [Fact] public void MemberNameAndSignatureConflict_11() { var src = """ static class Extensions { static public void M1() {} extension(object receiver) { static public void M1() {} } static public void M2(ref readonly int x) {} extension(object receiver) { static public void M2(ref int x) {} } static public void M3(ref readonly int x) {} extension(object receiver) { static public void M3(in int x) {} } static public void M4(in int x) {} extension(object receiver) { static public void M4(ref int x) {} } static public long M7() => 0; extension(int receiver) { static public int M7() => 0; } extension(int receiver) { public static void M9(int x) {} } public static void M9(int receiver) {} extension(int receiver) { public static void M10(in int x) {} } public static void M10(ref int receiver) {} } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (7,28): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types // static public void M1() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(7, 28), // (14,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref' and 'ref readonly' // static public void M2(ref int x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M2").WithArguments("Extensions", "method", "ref", "ref readonly").WithLocation(14, 28), // (21,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref readonly' // static public void M3(in int x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M3").WithArguments("Extensions", "method", "in", "ref readonly").WithLocation(21, 28), // (28,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'ref' and 'in' // static public void M4(ref int x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M4").WithArguments("Extensions", "method", "ref", "in").WithLocation(28, 28), // (35,27): error CS0111: Type 'Extensions' already defines a member called 'M7' with the same parameter types // static public int M7() => 0; Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M7").WithArguments("M7", "Extensions").WithLocation(35, 27), // (40,28): error CS0111: Type 'Extensions' already defines a member called 'M9' with the same parameter types // public static void M9(int x) {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M9").WithArguments("M9", "Extensions").WithLocation(40, 28), // (47,28): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' // public static void M10(in int x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M10").WithArguments("Extensions", "method", "in", "ref").WithLocation(47, 28) ); } [Fact] public void MemberNameAndSignatureConflict_12() { var src = """ static class Extensions { extension(object receiver) { public int P1 => 1; } public static int get_P1(object receiver) => 4; public static int get_P2(object receiver) => 4; extension(object receiver) { public int P2 => 1; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,26): error CS0111: Type 'Extensions' already defines a member called 'get_P1' with the same parameter types // public int P1 => 1; Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "1").WithArguments("get_P1", "Extensions").WithLocation(5, 26), // (14,26): error CS0111: Type 'Extensions' already defines a member called 'get_P2' with the same parameter types // public int P2 => 1; Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "1").WithArguments("get_P2", "Extensions").WithLocation(14, 26) ); } [Fact] public void MemberNameAndSignatureConflict_13() { var src = """ static class Extensions { extension(object receiver) { static public int P1 => 1; } public static int P1 => 4; public static int P2 => 4; extension(object receiver) { static public int P2 => 1; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (8,29): error CS0082: Type 'Extensions' already reserves a member called 'get_P1' with the same parameter types // public static int P1 => 4; Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_P1", "Extensions").WithLocation(8, 29), // (10,29): error CS0082: Type 'Extensions' already reserves a member called 'get_P2' with the same parameter types // public static int P2 => 4; Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_P2", "Extensions").WithLocation(10, 29) ); } [Fact] public void MemberNameAndSignatureConflict_14() { var src = """ static class Extensions { extension(object receiver) { static public int get_P1() => 1; } public static int P1 => 4; public static int P2 => 4; extension(object receiver) { static public int get_P2() => 1; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (8,29): error CS0082: Type 'Extensions' already reserves a member called 'get_P1' with the same parameter types // public static int P1 => 4; Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_P1", "Extensions").WithLocation(8, 29), // (10,29): error CS0082: Type 'Extensions' already reserves a member called 'get_P2' with the same parameter types // public static int P2 => 4; Diagnostic(ErrorCode.ERR_MemberReserved, "4").WithArguments("get_P2", "Extensions").WithLocation(10, 29) ); } [Fact] public void MemberNameAndSignatureConflict_15() { var src = """ static class Extensions { extension(object receiver) { public int P1 => 1; } public static int set_P1(object receiver, int x) => 4; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void MemberNameAndSignatureConflict_16() { var src = """ static class Extensions { extension(object receiver) { static public int P1 => 1; } public static int P1 {set{}} static public int get_P2() => 1; public static int P2 {set{}} } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (8,23): error CS0082: Type 'Extensions' already reserves a member called 'get_P1' with the same parameter types // public static int P1 {set{}} Diagnostic(ErrorCode.ERR_MemberReserved, "P1").WithArguments("get_P1", "Extensions").WithLocation(8, 23), // (11,23): error CS0082: Type 'Extensions' already reserves a member called 'get_P2' with the same parameter types // public static int P2 {set{}} Diagnostic(ErrorCode.ERR_MemberReserved, "P2").WithArguments("get_P2", "Extensions").WithLocation(11, 23) ); } [Fact] public void MemberNameAndSignatureConflict_17() { var src = """ static class Extensions { extension(object receiver) { static public int set_P1(int x) => 1; } public static int P1 => 4; static public int set_P2(int x) => 1; public static int P2 => 4; } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (8,23): error CS0082: Type 'Extensions' already reserves a member called 'set_P1' with the same parameter types // public static int P1 => 4; Diagnostic(ErrorCode.ERR_MemberReserved, "P1").WithArguments("set_P1", "Extensions").WithLocation(8, 23), // (11,23): error CS0082: Type 'Extensions' already reserves a member called 'set_P2' with the same parameter types // public static int P2 => 4; Diagnostic(ErrorCode.ERR_MemberReserved, "P2").WithArguments("set_P2", "Extensions").WithLocation(11, 23) ); } [Fact] public void MemberNameAndSignatureConflict_18() { var src = """ public static class Extensions { extension(object receiver) { static public void M1(int x) {} } public static int M1 => 4; extension(object receiver) { static public void M2(int x) {} } public static int M2 = 4; extension(object receiver) { static public void M3(int x) {} } #pragma warning disable CS0067 // The event 'Extensions.M3' is never used public static event System.Action M3; } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,28): error CS0102: The type 'Extensions' already contains a definition for 'M1' // static public void M1(int x) {} Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "M1").WithArguments("Extensions", "M1").WithLocation(5, 28), // (12,28): error CS0102: The type 'Extensions' already contains a definition for 'M2' // static public void M2(int x) {} Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "M2").WithArguments("Extensions", "M2").WithLocation(12, 28), // (19,28): error CS0102: The type 'Extensions' already contains a definition for 'M3' // static public void M3(int x) {} Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "M3").WithArguments("Extensions", "M3").WithLocation(19, 28) ); } [Fact] public void MemberNameAndSignatureConflict_19() { var src = """ public static class Extensions { public static int M1 => 4; extension(object receiver) { static public void M1(int x) {} } public static int M2 = 4; extension(object receiver) { static public void M2(int x) {} } #pragma warning disable CS0067 // The event 'Extensions.M3' is never used public static event System.Action M3; extension(object receiver) { static public void M3(int x) {} } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (7,28): error CS0102: The type 'Extensions' already contains a definition for 'M1' // static public void M1(int x) {} Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "M1").WithArguments("Extensions", "M1").WithLocation(7, 28), // (14,28): error CS0102: The type 'Extensions' already contains a definition for 'M2' // static public void M2(int x) {} Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "M2").WithArguments("Extensions", "M2").WithLocation(14, 28), // (22,28): error CS0102: The type 'Extensions' already contains a definition for 'M3' // static public void M3(int x) {} Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "M3").WithArguments("Extensions", "M3").WithLocation(22, 28) ); } [Fact] public void MemberNameAndSignatureConflict_20_ReceiverType_TupleNameDifference() { var src = """ public static class Extensions { extension((int a, int b) receiver) { void M1() {} } extension((int c, int d)) { static void M1() {} } extension(int receiver) { void M1() {} } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (10,21): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types // static void M1() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(10, 21) ); } [Fact] public void MemberNameAndSignatureConflict_21_ReceiverType_NativeIntDifference() { var src = """ public static class Extensions { extension(System.IntPtr receiver) { void M1() {} } extension(nint) { static void M1() {} } extension(int receiver) { void M1() {} } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyDiagnostics( // (10,21): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types // static void M1() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(10, 21) ); } [Fact] public void MemberNameAndSignatureConflict_22_ReceiverType_NullabilityDifference() { var src = """ #nullable enable public static class Extensions { extension(string[]) { static void M1() {} } extension(string?[] receiver) { void M1() {} } extension(int receiver) { void M1() {} } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (12,14): error CS0111: Type 'Extensions' already defines a member called 'M1' with the same parameter types // void M1() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions").WithLocation(12, 14) ); } [Fact] public void MemberNameAndSignatureConflict_23_Receiver_TypeDifference() { var src = """ public static class Extensions { extension(int receiver) { void M1() {} } extension(long) { static void M1() {} } } """; var comp = CreateCompilation(src); CompileAndVerify(comp).VerifyDiagnostics(); } [Theory] [CombinatorialData] public void MemberNameAndSignatureConflict_24_Genericity(bool insertAtTheBeginning) { var insert = """ extension<S>(S[]) { static void M1(int z) {} } """; var src = @" public static class Extensions { " + (insertAtTheBeginning ? insert : "") + @" extension<T>(T[]) where T : class { static void M1(T x) {} } " + (!insertAtTheBeginning ? insert : "") + @" extension<U>(U[] receiver) where U : struct { #line 17 void M1(U y) {} void M2(U y) {} static void M2(U x) {} } extension(int[] receiver) { void M1(int a) {} } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (19,21): error CS0111: Type 'Extensions' already defines a member called 'M2' with the same parameter types // static void M2(U x) {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M2").WithArguments("M2", "Extensions").WithLocation(19, 21) ); } [Fact] public void MemberNameAndSignatureConflict_25_Genericity_DifferentArity() { var src = """ public static class Extensions1 { extension<T1>(T1) { static void M1(T1 x) {} } extension<T1, U1>(T1) { static void M1(T1 x) {} } } public static class Extensions2 { extension<T2, U2>(T2) { static void M1(T2 x) {} } extension<T2>(T2) { static void M1(T2 x) {} } } public static class Extensions3 { extension<T3, U3>(T3) { static void M1(T3 x) {} } extension<T3>(T3) { static void M1<U3>(T3 x) {} } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (37,21): error CS0111: Type 'Extensions3' already defines a member called 'M1' with the same parameter types // static void M1<U3>(T3 x) {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions3").WithLocation(37, 21)); } [Fact] public void MemberNameAndSignatureConflict_26_Genericity() { var src = """ public static class Extensions1 { extension<T, S>(C<T, S>) { static void M1() {} } extension<T, S>(C<S, T>) { static void M1() {} } } class C<T, S> {} """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (10,21): error CS0111: Type 'Extensions1' already defines a member called 'M1' with the same parameter types // static void M1() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "Extensions1").WithLocation(10, 21) ); } [Fact] public void MemberNameAndSignatureConflict_27_Genericity() { var src = """ public static class Extensions1 { extension<T, S>(C<T, S> c) { internal void M1() {} } extension<T, S>(C<S, T> c) { internal void M1() {} } } class C<T, S> {} """; var comp = CreateCompilation(src); CompileAndVerify(comp).VerifyDiagnostics().VerifyTypeIL("Extensions1", """ .class public auto ansi abstract sealed beforefieldinit Extensions1 extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$373395272A45479DE48E8BB1CCB2C42B`2'<$T0, $T1> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$80D5112A03B26C94C628316C4DA793B2'<T, S> extends [mscorlib]System.Object { // Methods .method assembly hidebysig specialname static void '<Extension>$' ( class C`2<!T, !S> c ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$80D5112A03B26C94C628316C4DA793B2'::'<Extension>$' } // end of class <M>$80D5112A03B26C94C628316C4DA793B2 // Methods .method assembly hidebysig instance void M1 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 38 30 44 35 31 31 32 41 30 33 42 32 36 43 39 34 43 36 32 38 33 31 36 43 34 44 41 37 39 33 42 32 00 00 ) // Method begins at RVA 0x2088 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$373395272A45479DE48E8BB1CCB2C42B`2'::M1 } // end of class <G>$373395272A45479DE48E8BB1CCB2C42B`2 .class nested public auto ansi sealed specialname '<G>$6D4255504AB27A230E5AB4858D9E46EB`2'<$T0, $T1> extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$2237E852D2E9F48E0CC6BF2FD528DA2A'<T, S> extends [mscorlib]System.Object { // Methods .method assembly hidebysig specialname static void '<Extension>$' ( class C`2<!S, !T> c ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$2237E852D2E9F48E0CC6BF2FD528DA2A'::'<Extension>$' } // end of class <M>$2237E852D2E9F48E0CC6BF2FD528DA2A // Methods .method assembly hidebysig instance void M1 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 32 32 33 37 45 38 35 32 44 32 45 39 46 34 38 45 30 43 43 36 42 46 32 46 44 35 32 38 44 41 32 41 00 00 ) // Method begins at RVA 0x2088 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$6D4255504AB27A230E5AB4858D9E46EB`2'::M1 } // end of class <G>$6D4255504AB27A230E5AB4858D9E46EB`2 // Methods .method assembly hidebysig static void M1<T, S> ( class C`2<!!T, !!S> c ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method Extensions1::M1 .method assembly hidebysig static void M1<T, S> ( class C`2<!!S, !!T> c ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x207e // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method Extensions1::M1 } // end of class Extensions1 """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } [Theory] [CombinatorialData] public void MemberNameAndSignatureConflict_28_Genericity(bool insertAtTheBeginning) { var insert = """ extension<S>(S[]) { static void M1(ref int z) {} } """; var src = @" public static class Extensions { " + (insertAtTheBeginning ? insert : "") + @" extension<T>(T[]) { static void M1(ref T x) {} } " + (!insertAtTheBeginning ? insert : "") + @" extension<U>(U[] receiver) { #line 17 void M1(in U y) {} void M2(ref U y) {} static void M2(in U x) {} } extension(int[] receiver) { void M1(ref int a) {} } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (17,14): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' // void M1(in U y) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M1").WithArguments("Extensions", "method", "in", "ref").WithLocation(17, 14), // (19,21): error CS0663: 'Extensions' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' // static void M2(in U x) {} Diagnostic(ErrorCode.ERR_OverloadRefKind, "M2").WithArguments("Extensions", "method", "in", "ref").WithLocation(19, 21) ); } [Theory] [CombinatorialData] public void MemberNameAndSignatureConflict_29_Indexers(bool insertAtTheBeginning) { var insert = """ extension<S>(S[] s) { static void M1(int z) {} } """; var src = @" public static class Extensions { " + (insertAtTheBeginning ? insert : "") + @" extension<T>(T[] t) { #line 8 int this[T x] => default; } " + (!insertAtTheBeginning ? insert : "") + @" extension<U>(U[] receiver) { void Item(U x) {} } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (8,13): error CS0102: The type 'Extensions' already contains a definition for 'Item' // int this[T x] => default; Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "this").WithArguments("Extensions", "Item").WithLocation(8, 13) ); } [Theory] [CombinatorialData] public void MemberNameAndSignatureConflict_30_Indexers(bool insertAtTheBeginning) { var insert = """ extension<S>(S[]) { static void M1(int z) {} } """; var src = @" public static class Extensions { " + (insertAtTheBeginning ? insert : "") + @" extension<T>(T[] t) { #line 8 int this[T x] => default; } " + (!insertAtTheBeginning ? insert : "") + @" extension<U>(U[] receiver) { #line 18 int this[U x] { set{}} } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (18,13): error CS0111: Type 'Extensions' already defines a member called 'this' with the same parameter types // int this[U x] { set{}} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "this").WithArguments("this", "Extensions").WithLocation(18, 13) ); } [Theory] [CombinatorialData] public void MemberNameAndSignatureConflict_31_Indexers(bool insertAtTheBeginning) { var insert = """ extension<S>(S[]) { static void M1(int z) {} } """; var src = @" public static class Extensions { " + (insertAtTheBeginning ? insert : "") + @" extension<T>(T[] t) { #line 8 int this[T x] => default; } " + (!insertAtTheBeginning ? insert : "") + @" extension<U>(U[] receiver) { #line 18 [System.Runtime.CompilerServices.IndexerName(""NotItem"")] int this[int x] { set{}} } } "; var comp = CreateCompilation(src); // Tracked by https://github.com/dotnet/roslyn/issues/78830 : diagnostic quality, the "within a type" part of the message might be somewhat misleading comp.VerifyDiagnostics( // (19,13): error CS0668: Two indexers have different names; the IndexerName attribute must be used with the same name on every indexer within a type // int this[int x] { set{}} Diagnostic(ErrorCode.ERR_InconsistentIndexerNames, "this").WithLocation(19, 13) ); } [Theory] [CombinatorialData] public void MemberNameAndSignatureConflict_32_Properties(bool insertAtTheBeginning) { var insert = """ extension<S>(S[]) { static void M1(int z) {} } """; var src = @" public static class Extensions { " + (insertAtTheBeginning ? insert : "") + @" extension<T>(T[] t) { T P => default; } " + (!insertAtTheBeginning ? insert : "") + @" extension<U>(U[] receiver) { #line 18 void P(U x) {} } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (18,14): error CS0102: The type 'Extensions' already contains a definition for 'P' // void P(U x) {} Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P").WithArguments("Extensions", "P").WithLocation(18, 14) ); } [Theory] [CombinatorialData] public void MemberNameAndSignatureConflict_33_Properties(bool insertAtTheBeginning) { var insert = """ extension<S>(S[]) { static void M1(int z) {} } """; var src = @" public static class Extensions { " + (insertAtTheBeginning ? insert : "") + @" extension<T>(T[] t) { #line 8 T P => default; } " + (!insertAtTheBeginning ? insert : "") + @" extension<U>(U[] receiver) { static void set_P(U x) {} } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (8,11): error CS0082: Type 'Extensions' already reserves a member called 'set_P' with the same parameter types // T P => default; Diagnostic(ErrorCode.ERR_MemberReserved, "P").WithArguments("set_P", "Extensions").WithLocation(8, 11) ); } [Theory] [CombinatorialData] public void MemberNameAndSignatureConflict_34_Properties(bool insertAtTheBeginning) { var insert = """ extension<S>(S[]) { static void M1(int z) {} } """; var src = @" public static class Extensions { " + (insertAtTheBeginning ? insert : "") + @" extension<T>(T[] t) { #line 8 T P => default; } " + (!insertAtTheBeginning ? insert : "") + @" extension<U>(U[] receiver) { U[] get_P => null; } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (8,16): error CS0102: The type 'Extensions' already contains a definition for 'get_P' // T P => default; Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "default").WithArguments("Extensions", "get_P").WithLocation(8, 16) ); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79043")] public void MemberNameAndSignatureConflict_35() { var src = """ new object().M(); int i = 42; i.M(); public static class C { extension<T>(T inst) where T : class { public void M() { System.Console.Write("ran1 "); } } extension<T>(ref T inst) where T : struct { public void M() { System.Console.Write("ran2"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran1 ran2").VerifyDiagnostics(); } [Fact] public void MethodInvocation_01() { var source = """ new object().M(); static class E1 { extension(object o) { public void M() { } } } static class E2 { public static void M(this object o) { } } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (1,14): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(object).M()' and 'E2.M(object)' // new object().M(); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E1.extension(object).M()", "E2.M(object)").WithLocation(1, 14)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.SequenceEqual(["void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "void System.Object.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void MethodInvocation_02() { var source = """ new object().M(42); static class E1 { extension(object o) { public void M(int i) { System.Console.Write("ran"); } } } static class E2 { public static void M(this object o, string s) => throw null; } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.Equal("void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_03() { var source = """ new object().M(""); static class E1 { extension(object o) { public void M(int i) => throw null; } } static class E2 { public static void M(this object o, string s) { System.Console.Write("ran"); } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M"); AssertEx.Equal("void System.Object.M(System.String s)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_04() { var source = """ 42.M(); static class E1 { extension(int i) { public void M() { System.Console.Write("ran"); } } } static class E2 { public static void M(this int? i) => throw null; } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M"); AssertEx.Equal("void E1.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_05() { var source = """ 42.M(); static class E1 { extension(int? i) { public void M() => throw null; } } static class E2 { public static void M(this int i) { System.Console.Write("ran"); } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M"); AssertEx.Equal("void System.Int32.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_06() { var src = """ object.M(); public static class E { extension(object) { public static void M<T>() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,8): error CS0411: The type arguments for method 'E.extension(object).M<T>()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // object.M(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("E.extension(object).M<T>()").WithLocation(1, 8)); } [Fact] public void MethodInvocation_RemoveLowerPriorityMembers_01() { var source = """ 42.M(43); static class E1 { extension(int i) { public void M(int j) => throw null; [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public void M(long l) { System.Console.Write("ran"); } } } """; var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M"); AssertEx.Equal("void E1.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M(System.Int64 l)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_RemoveLowerPriorityMembers_02() { var libSrc = """ public static class E1 { extension(int i) { [System.Runtime.CompilerServices.OverloadResolutionPriority(0)] public void M(int j) => throw null; } extension(int i) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public void M(long l) { System.Console.Write("ran"); } } } """; var source = """ 42.M(43); """; var comp = CreateCompilation([source, libSrc, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran", symbolValidator: verify).VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M"); AssertEx.Equal("void E1.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M(System.Int64 l)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); var libComp = CreateCompilation([libSrc, OverloadResolutionPriorityAttributeDefinition]); var comp2 = CreateCompilation(source, references: [libComp.EmitToImageReference()]); CompileAndVerify(comp2, expectedOutput: "ran").VerifyDiagnostics(); source = """ E1.M(42, 43); """; var comp3 = CreateCompilation([source, libSrc, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp3, expectedOutput: "ran", symbolValidator: verify).VerifyDiagnostics(); static void verify(ModuleSymbol m) { var implementations = m.ContainingAssembly.GetTypeByMetadataName("E1").GetMembers().OfType<MethodSymbol>().ToArray(); AssertEx.Equal("void E1.M(this System.Int32 i, System.Int32 j)", implementations[0].ToTestDisplayString()); AssertEx.Equal("System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(0)", implementations[0].GetAttributes().Single().ToString()); AssertEx.Equal("void E1.M(this System.Int32 i, System.Int64 l)", implementations[1].ToTestDisplayString()); AssertEx.Equal("System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(1)", implementations[1].GetAttributes().Single().ToString()); } } [Fact] public void MethodInvocation_RemoveLowerPriorityMembers_03() { var source = """ 42.M(43); static class E1 { extension(int i) { public void M(int j) => throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public static void M(this int i, long l) { System.Console.Write("ran"); } } """; var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M"); AssertEx.Equal("void System.Int32.M(System.Int64 l)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_RemoveLowerPriorityMembers_04() { var source = """ 42.M(43); static class E1 { public static void M(this int i, int j) => throw null; extension(int i) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public void M(long l) { System.Console.Write("ran"); } } } """; var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M"); AssertEx.Equal("void E1.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M(System.Int64 l)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_RemoveLowerPriorityMembers_05() { var source = """ 42.M(43); static class E1 { extension(int i) { public void M(int j) { System.Console.Write("ran"); } } } static class E2 { extension(int i) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public void M(long l) => throw null; } } """; var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M"); AssertEx.Equal("void E1.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M(System.Int32 j)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_RemoveLowerPriorityMembers_06() { var source = """ 42.M(43); static class E1 { public static void M(this int i, int j) { System.Console.Write("ran"); } } static class E2 { extension(int i) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public void M(long l) => throw null; } } """; var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M"); AssertEx.Equal("void System.Int32.M(System.Int32 j)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_RemoveLowerPriorityMembers_07() { var source = """ string s = ""; s.M(); static class E1 { extension(object o) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public void M() { System.Console.Write("ran"); } } extension(string s) { public void M() => throw null; } } """; var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.M"); AssertEx.Equal("void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_RemoveLowerPriorityMembers_08() { var source = """ string s = "ran"; System.Console.Write(s.ToString()); static class E { extension(object o) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public string ToString() => throw null; } } """; var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void MethodInvocation_RemoveLowerPriorityMembers_09() { var libSrc = """ public static class E { extension(int i) { public void M() => throw null; } extension(long l) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public void M() { System.Console.Write("ran"); } } } """; var source = """ E.M(43); """; var comp = CreateCompilation([source, libSrc, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var libComp = CreateCompilation([libSrc, OverloadResolutionPriorityAttributeDefinition]); var comp2 = CreateCompilation([source], references: [libComp.EmitToImageReference()]); CompileAndVerify(comp2, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void MethodInvocation_RemoveLowerPriorityMembers_10() { var libSrc = """ public static class E { extension(int) { [System.Runtime.CompilerServices.OverloadResolutionPriority(0)] public static void M(int j) => throw null; } extension(int) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public static void M(long l) { System.Console.Write("ran"); } } } """; var source = """ int.M(43); """; var comp = CreateCompilation([source, libSrc, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran", symbolValidator: verify).VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.M"); AssertEx.Equal("void E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M(System.Int64 l)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); var libComp = CreateCompilation([libSrc, OverloadResolutionPriorityAttributeDefinition]); var comp2 = CreateCompilation(source, references: [libComp.EmitToImageReference()]); CompileAndVerify(comp2, expectedOutput: "ran").VerifyDiagnostics(); static void verify(ModuleSymbol m) { var implementations = m.ContainingAssembly.GetTypeByMetadataName("E").GetMembers().OfType<MethodSymbol>().ToArray(); AssertEx.Equal("void E.M(System.Int32 j)", implementations[0].ToTestDisplayString()); AssertEx.Equal("System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(0)", implementations[0].GetAttributes().Single().ToString()); AssertEx.Equal("void E.M(System.Int64 l)", implementations[1].ToTestDisplayString()); AssertEx.Equal("System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(1)", implementations[1].GetAttributes().Single().ToString()); } } [Fact] public void PropertyAccess_RemoveLowerPriorityMembers_01() { var source = """ string s = ""; _ = s.P; static class E { extension(object o) { public long P => throw null; } extension(string s) { public int P { get { System.Console.Write("ran"); return 0; } } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.P"); AssertEx.Equal("System.Int32 E.<G>$34505F560D9EACF86A87F3ED1F85E448.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PropertyAccess_RemoveLowerPriorityMembers_02() { var libSrc = """ public static class E { extension(object o) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public int P { get { System.Console.Write("ran"); return 0; } } } extension(string s) { public long P => throw null; } } """; var source = """ string s = ""; _ = s.P; """; var comp = CreateCompilation([source, libSrc, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.P"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); var libComp = CreateCompilation([libSrc, OverloadResolutionPriorityAttributeDefinition]); var comp2 = CreateCompilation([source], references: [libComp.EmitToImageReference()]); CompileAndVerify(comp2, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void PropertyAccess_RemoveLowerPriorityMembers_03() { var source = """ string s = ""; _ = s.P; static class E1 { extension(object o) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public long P => throw null; } } static class E2 { extension(string s) { public int P { get { System.Console.Write("ran"); return 0; } } } } """; var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.P"); AssertEx.Equal("System.Int32 E2.<G>$34505F560D9EACF86A87F3ED1F85E448.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PropertyAccess_RemoveLowerPriorityMembers_04() { var source = """ static class E { extension(object o) { public int P { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] get => throw null; [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] set => throw null; } } } """; var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); comp.VerifyEmitDiagnostics( // (7,14): error CS9262: Cannot use 'OverloadResolutionPriorityAttribute' on this member. // [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] Diagnostic(ErrorCode.ERR_CannotApplyOverloadResolutionPriorityToMember, "System.Runtime.CompilerServices.OverloadResolutionPriority(1)").WithLocation(7, 14), // (9,14): error CS9262: Cannot use 'OverloadResolutionPriorityAttribute' on this member. // [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] Diagnostic(ErrorCode.ERR_CannotApplyOverloadResolutionPriorityToMember, "System.Runtime.CompilerServices.OverloadResolutionPriority(1)").WithLocation(9, 14)); } [Fact] public void PropertyAccess_RemoveLowerPriorityMembers_05() { var libSrc = """ public static class E { extension(object o) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public int P { get { System.Console.Write("ran"); return 0; } } } extension(string s) { public long P => throw null; } } """; var source = """ E.get_P(""); """; var comp = CreateCompilation([source, libSrc, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran", symbolValidator: verify).VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "E.get_P"); AssertEx.Equal("System.Int32 E.get_P(System.Object o)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); var libComp = CreateCompilation([libSrc, OverloadResolutionPriorityAttributeDefinition]); var comp2 = CreateCompilation([source], references: [libComp.EmitToImageReference()]); CompileAndVerify(comp2, expectedOutput: "ran").VerifyDiagnostics(); static void verify(ModuleSymbol m) { var implementations = m.ContainingAssembly.GetTypeByMetadataName("E").GetMembers().OfType<MethodSymbol>().ToArray(); AssertEx.Equal("System.Int32 E.get_P(System.Object o)", implementations[0].ToTestDisplayString()); AssertEx.Equal("System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(1)", implementations[0].GetAttributes().Single().ToString()); AssertEx.Equal("System.Int64 E.get_P(System.String s)", implementations[1].ToTestDisplayString()); Assert.Empty(implementations[1].GetAttributes()); } } [Fact] public void PropertyAccess_RemoveLowerPriorityMembers_06() { var libSrc = """ public static class E { extension(object o) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public int P { set { System.Console.Write("ran"); } } } extension(string s) { [System.Runtime.CompilerServices.OverloadResolutionPriority(0)] public int P { set => throw null; } } } """; var source = """ E.set_P("", 0); """; var comp = CreateCompilation([source, libSrc, OverloadResolutionPriorityAttributeDefinition]); CompileAndVerify(comp, expectedOutput: "ran", symbolValidator: verify).VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "E.set_P"); AssertEx.Equal("void E.set_P(System.Object o, System.Int32 value)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); var libComp = CreateCompilation([libSrc, OverloadResolutionPriorityAttributeDefinition]); var comp2 = CreateCompilation([source], references: [libComp.EmitToImageReference()]); CompileAndVerify(comp2, expectedOutput: "ran").VerifyDiagnostics(); static void verify(ModuleSymbol m) { var implementations = m.ContainingAssembly.GetTypeByMetadataName("E").GetMembers().OfType<MethodSymbol>().ToArray(); AssertEx.Equal("void E.set_P(System.Object o, System.Int32 value)", implementations[0].ToTestDisplayString()); AssertEx.Equal("System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(1)", implementations[0].GetAttributes().Single().ToString()); AssertEx.Equal("void E.set_P(System.String s, System.Int32 value)", implementations[1].ToTestDisplayString()); AssertEx.Equal("System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(0)", implementations[1].GetAttributes().Single().ToString()); } } [Fact] public void PropertyAccess_RemoveLowerPriorityMembers_07() { var source = """ public static class E { extension(object o) { public static int P => 0; } extension(string s) { public static int P => 0; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (9,32): error CS0111: Type 'E' already defines a member called 'get_P' with the same parameter types // public static int P => 0; Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "0").WithArguments("get_P", "E").WithLocation(9, 32)); } [Fact] public void PropertyAccess_RemoveLowerPriorityMembers_08() { var source = """ static class E { extension(object o) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] public int P => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,42): error CS0234: The type or namespace name 'OverloadResolutionPriorityAttribute' does not exist in the namespace 'System.Runtime.CompilerServices' (are you missing an assembly reference?) // [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "OverloadResolutionPriority").WithArguments("OverloadResolutionPriorityAttribute", "System.Runtime.CompilerServices").WithLocation(5, 42), // (5,42): error CS0234: The type or namespace name 'OverloadResolutionPriority' does not exist in the namespace 'System.Runtime.CompilerServices' (are you missing an assembly reference?) // [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "OverloadResolutionPriority").WithArguments("OverloadResolutionPriority", "System.Runtime.CompilerServices").WithLocation(5, 42)); } [Fact] public void PropertyAccess_RemoveLowerPriorityMembers_09() { var source = """ public static class E { extension(object o) { [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] [System.Runtime.CompilerServices.OverloadResolutionPriority(2)] public int P { set { } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property, AllowMultiple = true, Inherited = false)] public sealed class OverloadResolutionPriorityAttribute(int priority) : Attribute { public int Priority => priority; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, symbolValidator: verify).VerifyDiagnostics(); static void verify(ModuleSymbol m) { var implementation = m.ContainingAssembly.GetTypeByMetadataName("E").GetMembers().OfType<MethodSymbol>().Single(); AssertEx.SetEqual([ "System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(1)", "System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(2)"], implementation.GetAttributes().ToStrings()); } } [Fact] public void MethodInvocation_RemoveStaticInstanceMismatches_01() { var src = """ using N; 42.M(); static class E1 { extension(object o) { public static void M() => throw null; // skipped } } namespace N { static class E2 { extension(object o) { public void M() { System.Console.Write("ran"); } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M"); AssertEx.Equal("void N.E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_RemoveStaticInstanceMismatches_02() { var src = """ using N; 42.M(); static class E1 { extension(object o) { public void M() { System.Console.Write("ran"); } } } namespace N { static class E2 { extension(object o) { public void M() => throw null; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): hidden CS8019: Unnecessary using directive. // using N; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N;").WithLocation(1, 1)); CompileAndVerify(comp, expectedOutput: "ran"); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M"); AssertEx.Equal("void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_RemoveStaticInstanceMismatches_03() { var src = """ using N; int.M(); static class E1 { extension(object o) { public void M() => throw null; } } namespace N { static class E2 { extension(object o) { public static void M() { System.Console.Write("ran"); } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.M"); AssertEx.Equal("void N.E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_RemoveStaticInstanceMismatches_ColorColor_01() { var src = """ using N; Color.M2(null); class Color { public static void M2(Color Color) { Color.M(); } } static class E1 { extension(Color) { public static void M() { System.Console.Write("ran"); } } } namespace N { static class E2 { extension(Color c) { public void M() => throw null; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): hidden CS8019: Unnecessary using directive. // using N; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N;").WithLocation(1, 1)); CompileAndVerify(comp, expectedOutput: "ran"); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.M"); AssertEx.Equal("void E1.<G>$2404CFB602D7DEE90BDDEF217EC37C58.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(memberAccess.Expression).Symbol.Kind); } [Fact] public void MethodInvocation_RemoveStaticInstanceMismatches_ColorColor_02() { var src = """ using N; Color.M2(new Color()); class Color { public static void M2(Color Color) { Color.M(); } } static class E1 { extension(Color c) { public void M() { System.Console.Write("ran"); } } } namespace N { static class E2 { extension(Color) { public static void M() => throw null; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): hidden CS8019: Unnecessary using directive. // using N; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N;").WithLocation(1, 1)); CompileAndVerify(comp, expectedOutput: "ran"); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.M"); AssertEx.Equal("void E1.<G>$2404CFB602D7DEE90BDDEF217EC37C58.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal(SymbolKind.Parameter, model.GetSymbolInfo(memberAccess.Expression).Symbol.Kind); } [Fact] public void MethodInvocation_RemoveInaccessibleTypeArguments() { var src = """ int.M(new A.C()); static class E1 { extension(int) { public static void M<T>(I<T> x) { } } } interface I<T> { } class A { private class B { } public class C : I<B> { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,5): error CS0122: 'E1.extension(int).M<A.B>(I<A.B>)' is inaccessible due to its protection level // int.M(new A.C()); Diagnostic(ErrorCode.ERR_BadAccess, "M").WithArguments("E1.extension(int).M<A.B>(I<A.B>)").WithLocation(1, 5)); } [Fact] public void MethodInvocation_RemoveLessDerivedMembers() { var src = """ "".M(""); static class E { extension(object o) { public void M(string s) { } } extension(string s) { public void M(object o) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,4): error CS0121: The call is ambiguous between the following methods or properties: 'E.extension(object).M(string)' and 'E.extension(string).M(object)' // "".M(""); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E.extension(object).M(string)", "E.extension(string).M(object)").WithLocation(1, 4)); } [Fact] public void MethodInvocation_RemoveWorseMembers_01() { var src = """ I<C2> i = null; i.M(); static class E1 { extension(I<C1> i) { public void M() { } } } static class E2 { extension(I<object> i) { public void M() { } } } interface I<out T> { } class C1 { } class C2 : C1 { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "i.M"); AssertEx.Equal("void E1.<G>$04E653405309F31558CF576D60A83155.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_RemoveWorseMembers_02() { var src = """ I<C2>.M(); static class E1 { extension(I<C1>) { public static void M() { } } } static class E2 { extension(I<object>) { public static void M() { } } } interface I<out T> { } class C1 { } class C2 : C1 { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "I<C2>.M"); AssertEx.Equal("void E1.<G>$04E653405309F31558CF576D60A83155.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_RemoveWorseMembers_03() { var src = """ 42.M(); static class E1 { extension<T>(T t) { public void M() { } } } static class E2 { extension(int i) { public void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M"); AssertEx.Equal("void E2.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_RemoveWorseMembers_04() { var src = """ int.M(); static class E1 { extension<T>(T) { public static void M() { } } } static class E2 { extension(int) { public static void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.M"); AssertEx.Equal("void E2.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_RemoveWorseMembers_05() { // by-value vs. in, instance method var src = """ 42.M(); static class E1 { extension(int i) { public void M() { } } } static class E2 { extension(in int i) { public void M() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M"); AssertEx.Equal("void E1.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79171")] public void MethodInvocation_RemoveWorseMembers_06() { // by-value vs. in, static method var src = """ int.M(); static class E1 { extension(int) { public static void M() { } } } static class E2 { extension(in int i) { public static void M() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,5): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(int).M()' and 'E2.extension(in int).M()' // int.M(); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E1.extension(int).M()", "E2.extension(in int).M()").WithLocation(1, 5)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); } [Fact] public void MethodInvocation_RemoveWorseMembers_07() { var src = """ int.M(42); static class E1 { extension(int) { public static void M<T>(T t) { } } } static class E2 { extension<T>(T t) { public static void M(int i) => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,5): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension(int).M<T>(T)' and 'E2.extension<int>(int).M(int)' // int.M(42); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E1.extension(int).M<T>(T)", "E2.extension<int>(int).M(int)").WithLocation(1, 5)); } [Fact] public void MethodInvocation_RemoveWorseMembers_08() { var src = """ int.M(42); 0.M2(42); static class E1 { extension<T>(T t) { public static void M<U>(U u) => throw null; public void M2<U>(U u) => throw null; } } static class E2 { extension<T>(T t) { public static void M(int i) { System.Console.Write("ran "); } public void M2(int i) { System.Console.Write("ran2"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran ran2").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.M"); AssertEx.Equal("void E2.<G>$8048A6C8BE30A622530249B904B537EB<System.Int32>.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79171")] public void MethodInvocation_RemoveWorseMembers_09() { // by-value vs. in, static method, instance receiver var src = """ 42.M(); static class E1 { extension(int) { public static void M() { } } } static class E2 { extension(in int i) { public static void M() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS0176: Member 'E1.extension(int).M()' cannot be accessed with an instance reference; qualify it with a type name instead // 42.M(); Diagnostic(ErrorCode.ERR_ObjectProhibited, "42.M").WithArguments("E1.extension(int).M()").WithLocation(1, 1)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79171")] public void MethodInvocation_RemoveWorseMembers_10() { var src = """ int.M(); static class E1 { extension(int) { public static void M() => throw null; } } static class E2 { extension(params int[]) { public static void M() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (12,15): error CS1670: params is not valid in this context // extension(params int[]) Diagnostic(ErrorCode.ERR_IllegalParams, "params").WithLocation(12, 15)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.M"); AssertEx.Equal("void E1.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void MethodInvocation_ByValueArgumentForRefReadonlyParameter_01() { var src = """ int.M(42); static class E { extension(int) { public static void M(ref readonly int i) { System.Console.Write(i); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,7): warning CS9193: Argument 1 should be a variable because it is passed to a 'ref readonly' parameter // int.M(42); Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "42").WithArguments("1").WithLocation(1, 7)); CompileAndVerify(comp, expectedOutput: "42"); } [Fact] public void MethodInvocation_ByValueArgumentForRefReadonlyParameter_02() { var src = """ int i = 42; int.M(i); static class E { extension(int) { public static void M(ref readonly int i) { System.Console.Write(i); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,7): warning CS9192: Argument 1 should be passed with 'ref' or 'in' keyword // int.M(i); Diagnostic(ErrorCode.WRN_ArgExpectedRefOrIn, "i").WithArguments("1").WithLocation(2, 7)); CompileAndVerify(comp, expectedOutput: "42"); } [Fact] public void MethodInvocation_ByValueArgumentForRefReadonlyParameter_03() { var src = """ var f = (ref readonly int i) => int.M(i); int i = 42; f(ref i); static class E { extension(int) { public static void M(ref readonly int i) { System.Console.Write(i); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,39): warning CS9195: Argument 1 should be passed with the 'in' keyword // var f = (ref readonly int i) => int.M(i); Diagnostic(ErrorCode.WRN_ArgExpectedIn, "i").WithArguments("1").WithLocation(1, 39)); CompileAndVerify(comp, expectedOutput: "42"); } [Fact] public void MethodInvocation_RefArgumentForInParameter() { var src = """ int i = 42; int.M(ref i); static class E { extension(int) { public static void M(in int i) { System.Console.Write(i); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,11): warning CS9191: The 'ref' modifier for argument 1 corresponding to 'in' parameter is equivalent to 'in'. Consider using 'in' instead. // int.M(ref i); Diagnostic(ErrorCode.WRN_BadArgRef, "i").WithArguments("1").WithLocation(2, 11)); CompileAndVerify(comp, expectedOutput: "42"); } [Fact] public void MethodInvocation_ByValueReceiverForRefReadonlyParameter_01() { var src = """ 42.M(); static class E { extension(ref readonly int i) { public void M() { System.Console.Write(42); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): warning CS9193: Argument 0 should be a variable because it is passed to a 'ref readonly' parameter // 42.M(); Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "42").WithArguments("0").WithLocation(1, 1)); CompileAndVerify(comp, expectedOutput: "42"); } [Fact] public void MethodInvocation_ByValueReceiverForRefReadonlyParameter_02() { var src = """ int i = 42; i.M(); static class E { extension(ref readonly int i) { public void M() { System.Console.Write(i); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); } [Fact] public void MethodInvocation_ByValueReceiverForRefReadonlyParameter_03() { var src = """ var f = (ref readonly int i) => i.M(); int i = 42; f(ref i); static class E { extension(ref readonly int i) { public void M() { System.Console.Write(i); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); } [Fact] public void MethodInvocation_Params() { var src = """ int.M(42, 43); static class E { extension(int) { public static void M(params int[] i) { System.Console.Write((i[0], i[1])); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); } [Fact] public void MethodInvocation_Params_02() { var src = """ int.M([42, 43]); static class E { extension(int) { public static void M(params int[] i) { System.Console.Write((i[0], i[1])); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); } [Fact] public void MethodInvocation_Params_03() { var src = """ int.M([42, 43]); static class E { extension(int) { public static void M(params long[] l) { System.Console.Write((l[0], l[1])); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "(42, 43)").VerifyDiagnostics(); } [Fact] public void MethodInvocation_DefaultValue() { var src = """ int.M(); static class E { extension(int) { public static void M(int i = 42) { System.Console.Write(i); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); } [Fact] public void MethodInvocation_DefaultValue_02() { var src = """ 42.M(); static class E { extension(int i = 0) { public void M(int j = 1) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,15): error CS9284: The receiver parameter of an extension cannot have a default value // extension(int i = 0) Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, "int i = 0").WithLocation(5, 15)); } [Fact] public void MethodInvocation_InaccessibleTypeArguments() { var src = """ new A.C().M(); new A.C().M2(); static class E1 { extension<T>(I<T> i) { public void M() { } } public static void M2<T>(this I<T> i) { } } interface I<T> { } class A { private class B { } public class C : I<B> { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,11): error CS0122: 'E1.extension<A.B>(I<A.B>).M()' is inaccessible due to its protection level // new A.C().M(); Diagnostic(ErrorCode.ERR_BadAccess, "M").WithArguments("E1.extension<A.B>(I<A.B>).M()").WithLocation(1, 11), // (2,11): error CS0122: 'E1.M2<A.B>(I<A.B>)' is inaccessible due to its protection level // new A.C().M2(); Diagnostic(ErrorCode.ERR_BadAccess, "M2").WithArguments("E1.M2<A.B>(I<A.B>)").WithLocation(2, 11)); } [Fact] public void PropertyAccess_InaccessibleTypeArguments() { var src = """ _ = new A.C().P; static class E1 { extension<T>(I<T> i) { public int P => 0; } } interface I<T> { } class A { private class B { } public class C : I<B> { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,5): error CS0122: 'E1.extension<A.B>(I<A.B>).P' is inaccessible due to its protection level // _ = new A.C().P; Diagnostic(ErrorCode.ERR_BadAccess, "new A.C().P").WithArguments("E1.extension<A.B>(I<A.B>).P").WithLocation(1, 5)); } [Fact] public void MethodInvocation_ReceiverConversion() { var src = """ 42.M(); static class E { extension(object o) { public void M() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var literal = GetSyntax<LiteralExpressionSyntax>(tree, "42"); AssertEx.Equal("System.Int32", model.GetTypeInfo(literal).Type.ToTestDisplayString()); AssertEx.Equal("System.Object", model.GetTypeInfo(literal).ConvertedType.ToTestDisplayString()); } [Fact] public void MethodInvocation_ReceiverConversion_ColorColor() { var src = """ Color.M2(new Color(42)); class Color(int i) : Base(i) { public static void M2(Color Color) { Color.M(); } } class Base(int i) { public int value = i; } static class E { extension(Base b) { public void M() { System.Console.Write(b.value); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var color = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.M").Expression; AssertEx.Equal("Color", model.GetTypeInfo(color).Type.ToTestDisplayString()); AssertEx.Equal("Base", model.GetTypeInfo(color).ConvertedType.ToTestDisplayString()); } [Fact] public void PropertyAccess_ReceiverConversion_01() { var src = """ _ = 42.P; static class E { extension(object o) { public int P => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var literal = GetSyntax<LiteralExpressionSyntax>(tree, "42"); AssertEx.Equal("System.Int32", model.GetTypeInfo(literal).Type.ToTestDisplayString()); AssertEx.Equal("System.Object", model.GetTypeInfo(literal).ConvertedType.ToTestDisplayString()); } [Fact] public void PropertyAccess_ReceiverConversion_02() { // tuple names mismatch var src = """ (int a, int b) t = (1, 2); _ = t.P; static class E { extension((int c, int d) t) { public int P { get => throw null!; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void PropertyAccess_ReceiverConversion_ColorColor() { var src = """ Color.M2(new Color(42)); class Color(int i) : Base(i) { public static void M2(Color Color) { _ = Color.P; } } class Base(int i) { public int value = i; } static class E { extension(Base b) { public int P { get { System.Console.Write(b.value); return 0; } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var color = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.P").Expression; AssertEx.Equal("Color", model.GetTypeInfo(color).Type.ToTestDisplayString()); AssertEx.Equal("Base", model.GetTypeInfo(color).ConvertedType.ToTestDisplayString()); } [Fact] public void MethodInvocation_BrokenConstraint_01() { var src = """ 42.M("", null); static class E { extension(object o) { public void M<T>(T t, C<T> c) where T : struct => throw null; } } class C<U> where U : struct { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,4): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.extension(object).M<T>(T, C<T>)' // 42.M("", null); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M").WithArguments("E.extension(object).M<T>(T, C<T>)", "T", "string").WithLocation(1, 4)); } [Fact] public void MethodInvocation_BrokenConstraint_02() { var src = """ 42.M(null, ""); static class E { extension(object o) { public void M<T>(C<T> c, T t) where T : struct => throw null; } } class C<U> where U : struct { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,4): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.extension(object).M<T>(C<T>, T)' // 42.M(null, ""); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M").WithArguments("E.extension(object).M<T>(C<T>, T)", "T", "string").WithLocation(1, 4)); } [Fact] public void MethodInvocation_ExtraRef() { var src = """ int i = 0; int.M(ref i); static class E { extension(int) { public static void M(int i) => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,11): error CS1615: Argument 2 may not be passed with the 'ref' keyword // int.M(ref i); Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("2", "ref").WithLocation(2, 11)); } [Fact] public void SingleCandidate_Extension() { string src = """ public class C { static void Main() { dynamic d = 1; var result = new C().Test("name", d); System.Console.Write(result); } } static class Extensions { extension(C c) { public int Test(string name, object value) => 123; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp); comp.VerifyDiagnostics( // (6,22): error CS1973: 'C' has no applicable method named 'Test' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. // var result = new C().Test("name", d); Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, @"new C().Test(""name"", d)").WithArguments("C", "Test").WithLocation(6, 22)); } [Fact] public void ArgList_Error() { string source = """ dynamic d = 1; object.M(d); static class Extensions { extension(object) { public static int M(__arglist) => 123; } } """; CreateCompilation(source, targetFramework: TargetFramework.Net90).VerifyDiagnostics( // (2,10): error CS1503: Argument 2: cannot convert from 'dynamic' to '__arglist' // object.M(d); Diagnostic(ErrorCode.ERR_BadArgType, "d").WithArguments("2", "dynamic", "__arglist").WithLocation(2, 10)); } [Fact] public void ArgList() { string source = """ int i = 1; object.M(__arglist(i)); static class Extensions { extension(object) { public static void M(__arglist) { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); } [Fact] public void MethodInvocation_ReceiverWithTupleDifferences() { string source = """ C<(int, int other)>.M(); static class Extensions { extension(C<(int a, int b)>) { public static void M() { System.Console.Write("ran"); } } } class C<T> { } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void PropertyAccess_RemoveStaticInstanceMismatches_InstanceReceiver() { var source = """ System.Console.Write(42.P); static class E1 { extension(int i) { public int P => 43; } } static class E2 { extension(int) { public static int P => throw null; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "43").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.P"); AssertEx.Equal("System.Int32 E1.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void PropertyAccess_RemoveStaticInstanceMismatches_StaticReceiver() { var source = """ System.Console.Write(int.P); static class E1 { extension(int i) { public int P => throw null; } } static class E2 { extension(int) { public static int P => 42; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.P"); AssertEx.Equal("System.Int32 E2.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void PropertyAccess_RemoveStaticInstanceMismatches_ColorColor_01() { var source = """ class Color { static void M(Color Color) { _ = Color.P; } } static class E1 { extension(Color c) { public int P => 0; } } static class E2 { extension(Color) { public static int P => 0; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,13): error CS9339: The extension resolution is ambiguous between the following members: 'E1.extension(Color).P' and 'E2.extension(Color).P' // _ = Color.P; Diagnostic(ErrorCode.ERR_AmbigExtension, "Color.P").WithArguments("E1.extension(Color).P", "E2.extension(Color).P").WithLocation(5, 13)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.P"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.Int32 E1.<G>$2404CFB602D7DEE90BDDEF217EC37C58.P { get; }", "System.Int32 E2.<G>$2404CFB602D7DEE90BDDEF217EC37C58.P { get; }"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void PropertyAccess_RemoveStaticInstanceMismatches_ColorColor_02() { var source = """ Color.M(new Color()); class Color { public static void M(Color Color) { _ = Color.P; } } static class E1 { extension(Color c) { public int P { get { System.Console.Write("ran"); return 0; } } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.P"); AssertEx.Equal("System.Int32 E1.<G>$2404CFB602D7DEE90BDDEF217EC37C58.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.Equal("Color Color", model.GetSymbolInfo(memberAccess.Expression).Symbol.ToTestDisplayString()); Assert.Equal(SymbolKind.Parameter, model.GetSymbolInfo(memberAccess.Expression).Symbol.Kind); } [Fact] public void PropertyAccess_RemoveStaticInstanceMismatches_ColorColor_03() { var source = """ Color.M(null); class Color { public static void M(Color Color) { _ = Color.P; } } static class E1 { extension(Color c) { public static int P { get { System.Console.Write("ran"); return 0; } } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "Color.P"); AssertEx.Equal("System.Int32 E1.<G>$2404CFB602D7DEE90BDDEF217EC37C58.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.Equal("Color", model.GetSymbolInfo(memberAccess.Expression).Symbol.ToTestDisplayString()); Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(memberAccess.Expression).Symbol.Kind); } [Fact] public void RefOmittedComCall() { // For COM import type, omitting the ref is allowed string source = @" using System; using System.Runtime.InteropServices; short x = 123; C c = new C(); c.M(x); c.I(123); [ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] class C { } static class E { extension(C c) { public void M(ref short p) { } public void M(sbyte p) { } public void I(ref int p) { } } } "; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); } [Fact] public void RefOmittedComCall_02() { string source = @" using System; using System.Runtime.InteropServices; C c = default; c.M(); c.M2(); [ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] class C { } static class E { extension(ref C c) { public void M() { } } public static void M2(this ref C c) { } } "; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,3): error CS1061: 'C' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) // c.M(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("C", "M").WithLocation(6, 3), // (7,3): error CS1061: 'C' does not contain a definition for 'M2' and no accessible extension method 'M2' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) // c.M2(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M2").WithArguments("C", "M2").WithLocation(7, 3), // (14,19): error CS9300: The 'ref' receiver parameter of an extension block must be a value type or a generic type constrained to struct. // extension(ref C c) Diagnostic(ErrorCode.ERR_RefExtensionParameterMustBeValueTypeOrConstrainedToOne, "C").WithLocation(14, 19), // (18,24): error CS8337: The first parameter of a 'ref' extension method 'M2' must be a value type or a generic type constrained to struct. // public static void M2(this ref C c) { } Diagnostic(ErrorCode.ERR_RefExtensionMustBeValueTypeOrConstrainedToOne, "M2").WithArguments("M2").WithLocation(18, 24)); } [Fact] public void RefOmittedComCall_03() { string source = @" using System; using System.Runtime.InteropServices; C c = default; c.M(); c.M2(); [ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] struct C { } static class E { extension(ref C c) { public void M() { } } public static void M2(this ref C c) { } } "; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (9,2): error CS0592: Attribute 'ComImport' is not valid on this declaration type. It is only valid on 'class, interface' declarations. // [ComImport, Guid("1234C65D-1234-447A-B786-64682CBEF136")] Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "ComImport").WithArguments("ComImport", "class, interface").WithLocation(9, 2)); } [Fact] public void RefOmittedComCall_04() { // For COM import type, omitting the ref is allowed (even in static scenarios) string source = @" using System; using System.Runtime.InteropServices; short x = 42; short y = 43; C.M(x.ToString(), y.ToString()); [ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] class C { } static class E { extension(C) { public static void M(ref string p, ref string p2) { } } } "; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 32 (0x20) .maxstack 2 .locals init (short V_0, //x short V_1, //y string V_2, string V_3) IL_0000: ldc.i4.s 42 IL_0002: stloc.0 IL_0003: ldc.i4.s 43 IL_0005: stloc.1 IL_0006: ldloca.s V_0 IL_0008: call "string short.ToString()" IL_000d: stloc.2 IL_000e: ldloca.s V_2 IL_0010: ldloca.s V_1 IL_0012: call "string short.ToString()" IL_0017: stloc.3 IL_0018: ldloca.s V_3 IL_001a: call "void E.M(ref string, ref string)" IL_001f: ret } """); source = """ using System; using System.Runtime.InteropServices; short x = 42; C.M(x.ToString()); [ComImport, Guid("1234C65D-1234-447A-B786-64682CBEF136")] class C { public extern static void M(ref string p); } """; comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify); verifier.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 19 (0x13) .maxstack 1 .locals init (short V_0, //x string V_1) IL_0000: ldc.i4.s 42 IL_0002: stloc.0 IL_0003: ldloca.s V_0 IL_0005: call "string short.ToString()" IL_000a: stloc.1 IL_000b: ldloca.s V_1 IL_000d: call "void C.M(ref string)" IL_0012: ret } """); } [Fact] public void RefOmittedComCall_05() { string source = @" using System; using System.Runtime.InteropServices; short x = 42; C.M(x.ToString()); [ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] class C { } static class E { extension(C) { public static void M(string p) { } } } "; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyIL("<top-level-statements-entry-point>", """ { // Code size 16 (0x10) .maxstack 1 .locals init (short V_0) //x IL_0000: ldc.i4.s 42 IL_0002: stloc.0 IL_0003: ldloca.s V_0 IL_0005: call "string short.ToString()" IL_000a: call "void E.M(string)" IL_000f: ret } """); } [Fact] public void Nullability_Method_01() { string source = """ #nullable enable string? s = null; s.M(); static class E { extension<T>(T t) { public void M() { System.Console.Write(t is null); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "True").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.M"); AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<System.String?>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void Nullability_Method_02() { string source = """ #nullable enable string s = ""; s.M(null); static class E { extension<T>(T t) { public void M(T t2) { System.Console.Write(t2 is null); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "True").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.M"); AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<System.String?>.M(System.String? t2)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); } [Fact] public void Nullability_Method_03() { var src = """ #nullable enable object oNotNull = new object(); oNotNull.M(out object x1, null).ToString(); // 1 oNotNull.M(out object x2, oNotNull).ToString(); x1.ToString(); x2.ToString(); static class E { extension<T>(T t1) { public T M<U>(out U u, T t2) => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,1): warning CS8602: Dereference of a possibly null reference. // oNotNull.M(out object x1, null).ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "oNotNull.M(out object x1, null)").WithLocation(5, 1)); } [Fact] public void Nullability_Method_04() { var src = """ #nullable enable object oNotNull = new object(); "".M(oNotNull, null).ToString(); // 1 "".M(null, oNotNull).ToString(); // 2 "".M(oNotNull, oNotNull).ToString(); static class E { extension<T>(T t) { public U M<U>(U u1, U u2) => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,1): warning CS8602: Dereference of a possibly null reference. // "".M(oNotNull, null).ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, @""""".M(oNotNull, null)").WithLocation(5, 1), // (6,1): warning CS8602: Dereference of a possibly null reference. // "".M(null, oNotNull).ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, @""""".M(null, oNotNull)").WithLocation(6, 1)); } [Fact] public void PropertyAccess_RemoveWorseMembers_01() { string source = """ string s = ""; System.Console.Write(s.P); static class E { extension(string s) { public int P => 42; } extension(object o) { public int P => throw null; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.P"); AssertEx.Equal("System.Int32 E.<G>$34505F560D9EACF86A87F3ED1F85E448.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void PropertyAccess_RemoveWorseMembers_02() { string source = """ System.Console.Write(string.P); static class E1 { extension(string s) { public static int P => 42; } } static class E2 { extension(object o) { public static int P => throw null; } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "string.P"); AssertEx.Equal("System.Int32 E1.<G>$34505F560D9EACF86A87F3ED1F85E448.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void PropertyAccess_RemoveWorseMembers_03() { var src = """ I<string> i = null; System.Console.Write(i.P); interface I<out T> { } static class E { extension(I<string> i) { public int P => 42; } extension(I<object> i) { public int P => throw null; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "i.P"); AssertEx.Equal("E.extension(I<string>).P", model.GetSymbolInfo(memberAccess).Symbol.ToDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void PropertyAccess_RemoveWorseMembers_04() { var src = """ I<string> i = null; System.Console.Write(i.P); interface I<out T> { } static class E { extension(I<object> i) { public int P => throw null; } extension(I<string> i) { public int P => 42; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "i.P"); AssertEx.Equal("E.extension(I<string>).P", model.GetSymbolInfo(memberAccess).Symbol.ToDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79171")] public void PropertyAccess_RemoveWorseMembers_05() { var src = """ System.Console.Write(42.P); static class E1 { extension(int i) { public int P => 42; } } static class E2 { extension(in int i) { public int P => throw null; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.P"); AssertEx.Equal("System.Int32 E1.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void PropertyAccess_RemoveWorseMembers_06() { var src = """ System.Console.Write(int.P); static class E1 { extension(int i) { public static int P => 42; } } static class E2 { extension(in int i) { public static int P => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,22): error CS9339: The extension resolution is ambiguous between the following members: 'E1.extension(int).P' and 'E2.extension(in int).P' // System.Console.Write(int.P); Diagnostic(ErrorCode.ERR_AmbigExtension, "int.P").WithArguments("E1.extension(int).P", "E2.extension(in int).P").WithLocation(1, 22)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.P"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.Equal([ "System.Int32 E1.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.P { get; }", "System.Int32 E2.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.P { get; }" ], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void PropertyAccess_RemoveWorseMembers_07() { var src = """ System.Console.Write(int.P); static class E1 { extension(int i) { public static int P => 42; } } static class E2 { extension<T>(T t) { public static int P => throw null; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.P"); AssertEx.Equal("System.Int32 E1.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void PropertyAccess_RemoveWorseMembers_08() { // In COM import scenarios, better conversion from expression considers ref kind, // but we can't cause such a difference with static extension members string src = @" using System; using System.Runtime.InteropServices; [ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] struct S { } static class E1 { extension(in S s) { public static int P => 42; } } static class E2 { extension(S) { public static int P => throw null; } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (5,2): error CS0592: Attribute 'ComImport' is not valid on this declaration type. It is only valid on 'class, interface' declarations. // [ComImport, Guid("1234C65D-1234-447A-B786-64682CBEF136")] Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "ComImport").WithArguments("ComImport", "class, interface").WithLocation(5, 2)); } [Fact] public void PropertyAccess_RemoveWorseMembers_09() { // In COM import scenarios, better conversion from expression considers ref kind, // but we can't cause such a difference with static extension members string src = @" using System; using System.Runtime.InteropServices; class C { void M<T>() where T : struct, I { _ = T.P; } } [ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] interface I { } static class E1 { extension<T>(ref T t) where T : struct, I { public static int P => 42; } } static class E2 { extension<T>(T t) where T : struct, I { public static int P => throw null; } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (9,13): error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter // _ = T.P; Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(9, 13)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "T.P"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void PropertyAccess_RemoveWorseMembers_10() { // In COM import scenarios, better conversion from expression considers ref kind, // but we can't cause such a difference with static extension members string src = @" using System; using System.Runtime.InteropServices; class C { void M<T>(T t) where T : struct, I { _ = t.P; // Note: T is not COM import type... } } [ComImport, Guid(""1234C65D-1234-447A-B786-64682CBEF136"")] interface I { } static class E1 { extension<T>(ref T t) where T : struct, I { public static int P => 42; } } static class E2 { extension<T>(T t) where T : struct, I { public static int P => throw null; } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (9,13): error CS0176: Member 'E1.extension<T>(ref T).P' cannot be accessed with an instance reference; qualify it with a type name instead // _ = t.P; // Note: T is not COM import type... Diagnostic(ErrorCode.ERR_ObjectProhibited, "t").WithArguments("E1.extension<T>(ref T).P").WithLocation(9, 13)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "t.P"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Equal([ "System.Int32 E1.<G>$650CAC53424D6B2378EC6C39C3E99C6C<T>.P { get; }", "System.Int32 E2.<G>$650CAC53424D6B2378EC6C39C3E99C6C<T>.P { get; }" ], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void PropertyOrMethod_RemoveWorseMembers_01() { var src = """ string s = null; s.M(); static class E { extension(string s) { public System.Action M => throw null; } extension(object o) { public string M() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,1): error CS9339: The extension resolution is ambiguous between the following members: 'E.extension(object).M()' and 'E.extension(string).M' // s.M(); Diagnostic(ErrorCode.ERR_AmbigExtension, "s.M").WithArguments("E.extension(object).M()", "E.extension(string).M").WithLocation(2, 1)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.Action E.<G>$34505F560D9EACF86A87F3ED1F85E448.M { get; }", "System.String E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void PropertyOrMethod_RemoveWorseMembers_02() { var src = """ string.M(); static class E { extension(object) { public static System.Action M => throw null; } extension(string) { public static string M() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS9339: The extension resolution is ambiguous between the following members: 'E.extension(string).M()' and 'E.extension(object).M' // string.M(); Diagnostic(ErrorCode.ERR_AmbigExtension, "string.M").WithArguments("E.extension(string).M()", "E.extension(object).M").WithLocation(1, 1)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "string.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.Action E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", "System.String E.<G>$34505F560D9EACF86A87F3ED1F85E448.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void PropertyOrMethod_RemoveWorseMembers_03() { var src = """ I<string> i = null; i.M(); interface I<out T> { } static class E { extension(I<string> i) { public System.Action M => throw null; } extension(I<object> i) { public string M() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,1): error CS9339: The extension resolution is ambiguous between the following members: 'E.extension(I<object>).M()' and 'E.extension(I<string>).M' // i.M(); Diagnostic(ErrorCode.ERR_AmbigExtension, "i.M").WithArguments("E.extension(I<object>).M()", "E.extension(I<string>).M").WithLocation(2, 1)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "i.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.Action E.<G>$B5F2BFAFBDD4469288FE06B785D143CD.M { get; }", "System.String E.<G>$2B406085AC5EBECC11B16BCD2A24DF4E.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void PropertyOrMethod_RemoveWorseMembers_04() { var src = """ I<string> i = null; i.M(); interface I<out T> { } static class E1 { extension(I<object> i) { public System.Action M => throw null; } } static class E2 { extension(I<string> i) { public string M() => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,1): error CS9339: The extension resolution is ambiguous between the following members: 'E2.extension(I<string>).M()' and 'E1.extension(I<object>).M' // i.M(); Diagnostic(ErrorCode.ERR_AmbigExtension, "i.M").WithArguments("E2.extension(I<string>).M()", "E1.extension(I<object>).M").WithLocation(2, 1)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "i.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["System.Action E1.<G>$2B406085AC5EBECC11B16BCD2A24DF4E.M { get; }", "System.String E2.<G>$B5F2BFAFBDD4469288FE06B785D143CD.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Empty(model.GetMemberGroup(memberAccess)); } [Fact] public void Dynamic_01() { var src = """ dynamic d = new object(); object.M(d); new object().M(d); static class E { extension<U>(U) { public static int M<T>(T t) => throw null; } public static int M2<U, T>(this U u, T t) => throw null; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,1): error CS1973: 'object' has no applicable method named 'M' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. // object.M(d); Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, "object.M(d)").WithArguments("object", "M").WithLocation(2, 1), // (3,1): error CS0176: Member 'E.extension<U>(U).M<T>(T)' cannot be accessed with an instance reference; qualify it with a type name instead // new object().M(d); Diagnostic(ErrorCode.ERR_ObjectProhibited, "new object().M").WithArguments("E.extension<U>(U).M<T>(T)").WithLocation(3, 1)); } [Fact] public void Dynamic_02() { var src = """ dynamic d = new object(); object.M(d); new object().M2(d); static class E { extension(object) { public static int M<T>(T t) => throw null; } public static int M2<T>(this object o, T t) => throw null; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,1): error CS1973: 'object' has no applicable method named 'M' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. // object.M(d); Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, "object.M(d)").WithArguments("object", "M").WithLocation(2, 1), // (3,1): error CS1973: 'object' has no applicable method named 'M2' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. // new object().M2(d); Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, "new object().M2(d)").WithArguments("object", "M2").WithLocation(3, 1)); } [Fact] public void Dynamic_03() { var src = """ dynamic d = new object(); object.M(d); new object().M2(d); static class E { extension<U>(U) { public static int M(object o) => throw null; } public static int M2<U>(this U u, object o) => throw null; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,1): error CS1973: 'object' has no applicable method named 'M' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. // object.M(d); Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, "object.M(d)").WithArguments("object", "M").WithLocation(2, 1), // (3,1): error CS1973: 'object' has no applicable method named 'M2' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. // new object().M2(d); Diagnostic(ErrorCode.ERR_BadArgTypeDynamicExtension, "new object().M2(d)").WithArguments("object", "M2").WithLocation(3, 1)); } [Fact] public void Dynamic_04() { var src = """ int i = 42; i.M(i); i.M2(i); static class E { extension(object o) { public void M(dynamic d) { System.Console.Write(d); } } public static void M2(this object o, dynamic d) { } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(comp, expectedOutput: ExpectedOutput("42"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void Dynamic_05() { var src = """ try { dynamic d = 42; _ = d.P; } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException e) { System.Console.Write(e.Message); } static class E { extension(object o) { public int P => 0; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: ExpectedOutput("'int' does not contain a definition for 'P'"), verify: Verification.FailsPEVerify); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "d.P"); var dynamicType = model.GetTypeInfo(memberAccess.Expression).Type; Assert.True(dynamicType.IsDynamic()); AssertEqualAndNoDuplicates(["System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.P { get; }"], model.LookupSymbols(position: 0, dynamicType, name: "P", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.P { get; }"], model.LookupSymbols(position: 0, dynamicType, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); } [Fact] public void Dynamic_06() { var src = """ try { dynamic d = 42; d.M(); } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException e) { System.Console.Write(e.Message); } static class E { extension(object o) { public void M() { } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: ExpectedOutput("'int' does not contain a definition for 'M'"), verify: Verification.FailsPEVerify); } [Fact] public void Dynamic_07() { var src = """ object.M(); static class E { extension(object o) { public static void M() { dynamic d = 42; M2(d); } } static void M2(int i) { System.Console.Write(i); } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(comp, expectedOutput: ExpectedOutput("42"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2(d)"); Assert.Equal("void E.M2(System.Int32 i)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); } [Fact] public void ResolveExtension_01() { var src = """ using N; System.Console.Write(object.M()); static class E1 { extension(string) // inapplicable { public static System.Action M => null; } } namespace N { static class E2 { extension(object) { public static int M() => 42; } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: ExpectedOutput("42")).VerifyDiagnostics(); } [Fact] public void ResolveExtension_02() { var src = """ using N; object.M(); static class E1 { extension(string) // inapplicable { public static System.Action M => null; } } namespace N { static class E2 { extension(object) { public static System.Action M => () => { System.Console.Write("ran"); }; } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: ExpectedOutput("ran")).VerifyDiagnostics(); } [Fact] public void ResolveExtension_03() { var src = """ using N; new object().M(); static class E1 { public static void M(this string s) { } // inapplicable } namespace N { static class E2 { extension(object o) { public System.Action M => () => { System.Console.Write("ran"); }; } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: ExpectedOutput("ran")).VerifyDiagnostics(); } [Fact] public void ResolveExtension_04() { var src = """ using N; new object().M(); static class E1 { public static void M(this string s) { } // inapplicable } namespace N { static class E2 { extension(object o) { public void M() { System.Console.Write("ran"); } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: ExpectedOutput("ran")).VerifyDiagnostics(); } [Fact] public void ResolveExtension_05() { var src = """ using N; new object().M(); static class E1 { extension(string s) // inapplicable { public void M() { } } } namespace N { static class E2 { extension(object o) { public System.Action M => () => { System.Console.Write("ran"); }; } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: ExpectedOutput("ran")).VerifyDiagnostics(); } [Fact] public void ResolveExtension_06() { var src = """ using N; new object().M(); static class E1 { extension(string s) // inapplicable { public void M() { } } } namespace N { static class E2 { extension(object o) { public void M() { System.Console.Write("ran"); } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: ExpectedOutput("ran")).VerifyDiagnostics(); } [Fact] public void PropertyAccess_ByValueReceiverForRefReadonlyParameter_01() { var src = """ _ = 42.P; static class E { extension(ref readonly int i) { public int P { get { System.Console.Write(i); return 0; } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,5): warning CS9193: Argument 0 should be a variable because it is passed to a 'ref readonly' parameter // _ = 42.P; Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "42").WithArguments("0").WithLocation(1, 5)); CompileAndVerify(comp, expectedOutput: "42"); } [Fact] public void PropertyAccess_ByValueReceiverForRefReadonlyParameter_02() { var src = """ int i = 42; _ = i.P; static class E { extension(ref readonly int i) { public int P { get { System.Console.Write(i); return 0; } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); } [Fact] public void PropertyAccess_ByValueReceiverForRefReadonlyParameter_03() { var src = """ var f = (ref readonly int i) => i.P; int i = 42; f(ref i); static class E { extension(ref readonly int i) { public int P { get { System.Console.Write(i); return 0; } } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); } [Fact] public void PropertyAccess_AmbiguityWithNoArguments() { var src = """ int x = new object().M; public static class E1 { extension(object o) { public int M => 42; } } public static class E2 { public static void M(this object o) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,9): error CS9339: The extension resolution is ambiguous between the following members: 'E2.M(object)' and 'E1.extension(object).M' // int x = new object().M; Diagnostic(ErrorCode.ERR_AmbigExtension, "new object().M").WithArguments("E2.M(object)", "E1.extension(object).M").WithLocation(1, 9)); } [Fact] public void ConstAccess() { var src = """ _ = int.Const; static class E { extension(int) { public const int Const = 42; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,9): error CS0117: 'int' does not contain a definition for 'Const' // _ = int.Const; Diagnostic(ErrorCode.ERR_NoSuchMember, "Const").WithArguments("int", "Const").WithLocation(1, 9), // (7,26): error CS9282: This member is not allowed in an extension block // public const int Const = 42; Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Const").WithLocation(7, 26)); } [Fact] public void ParamsReceiver_01() { // extension(params int[] i) // Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading) var ilSrc = """ .class public auto ansi abstract sealed beforefieldinit E extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi sealed specialname '<Extension>$C598AEF9A11D80BC24BD328BD05F52D9' extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi abstract sealed specialname '<Marker>$1C2558E27345F208D185AA996666DFDA' extends System.Object { .method public hidebysig specialname static void '<Extension>$' ( int32[] i ) cil managed { .param [1] .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00) IL_0000: ret } } .method public hidebysig instance void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 31 43 32 35 35 38 45 32 37 33 34 35 46 32 30 38 44 31 38 35 41 41 39 39 36 36 36 36 44 46 44 41 00 00 ) IL_0000: ldnull IL_0001: throw } } .method public hidebysig static void M ( int32[] i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .param [1] .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00) IL_0000: ldstr "ran" IL_0005: call void [mscorlib]System.Console::Write(string) IL_000a: ret } } """ + ExtensionMarkerAttributeIL; var src = """ int[] i = null; i.M(); """; var comp = CreateCompilationWithIL(src, ilSrc); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: "ran"); src = """ int i = 0; i.M(); """; comp = CreateCompilationWithIL(src, ilSrc); comp.VerifyEmitDiagnostics( // (2,1): error CS1929: 'int' does not contain a definition for 'M' and the best extension method overload 'E.extension(params int[]).M()' requires a receiver of type 'params int[]' // i.M(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "i").WithArguments("int", "M", "E.extension(params int[]).M()", "params int[]").WithLocation(2, 1)); src = """ int i = 0; i.M(2); """; comp = CreateCompilationWithIL(src, ilSrc); comp.VerifyEmitDiagnostics( // (2,3): error CS1501: No overload for method 'M' takes 1 arguments // i.M(2); Diagnostic(ErrorCode.ERR_BadArgCount, "M").WithArguments("M", "1").WithLocation(2, 3)); } [Fact] public void ParamsReceiver_02() { // extension(params int[] i) // Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading) var ilSrc = """ .class public auto ansi abstract sealed beforefieldinit E extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi sealed specialname '<Extension>$C598AEF9A11D80BC24BD328BD05F52D9' extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi abstract sealed specialname '<Marker>$1C2558E27345F208D185AA996666DFDA' extends System.Object { .method public hidebysig specialname static void '<Extension>$' ( int32[] i ) cil managed { .param [1] .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00) IL_0000: ret } } .method public hidebysig specialname instance int32 get_P () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 31 43 32 35 35 38 45 32 37 33 34 35 46 32 30 38 44 31 38 35 41 41 39 39 36 36 36 36 44 46 44 41 00 00 ) IL_0000: ldnull IL_0001: throw } .property instance int32 P() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 31 43 32 35 35 38 45 32 37 33 34 35 46 32 30 38 44 31 38 35 41 41 39 39 36 36 36 36 44 46 44 41 00 00 ) .get instance int32 E/'<Extension>$C598AEF9A11D80BC24BD328BD05F52D9'::get_P() } } .method public hidebysig static int32 get_P ( int32[] i ) cil managed { .param [1] .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00) IL_0000: ldstr "ran" IL_0005: call void [mscorlib]System.Console::Write(string) IL_000a: ldc.i4.0 IL_000b: ret } } """ + ExtensionMarkerAttributeIL; var src = """ int[] i = null; _ = i.P; """; var comp = CreateCompilationWithIL(src, ilSrc); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); src = """ int i = 0; _ = i.P; """; comp = CreateCompilationWithIL(src, ilSrc); comp.VerifyEmitDiagnostics( // (2,5): error CS1929: 'int' does not contain a definition for 'P' and the best extension method overload 'E.extension(params int[]).P' requires a receiver of type 'params int[]' // _ = i.P; Diagnostic(ErrorCode.ERR_BadInstanceArgType, "i").WithArguments("int", "P", "E.extension(params int[]).P", "params int[]").WithLocation(2, 5)); src = """ int i = 0; _ = i.P(1); """; comp = CreateCompilationWithIL(src, ilSrc); comp.VerifyEmitDiagnostics( // (2,7): error CS1061: 'int' does not contain a definition for 'P' and no accessible extension method 'P' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) // _ = i.P(1); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "P").WithArguments("int", "P").WithLocation(2, 7)); } [Fact] public void ExplicitTypeArguments_01() { var src = """ string s = "ran"; s.M<object>(); static class E { extension<T>(T t) { public void M() { System.Console.Write(t); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "s.M<object>()"); AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.M<object>"); AssertEx.SequenceEqual(["void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ExplicitTypeArguments_02() { var src = """ 42.M<object>(); static class E { extension<T>(T t) where T : struct { public void M() { System.Console.Write(t); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,4): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.extension<T>(T)' // 42.M<object>(); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M<object>").WithArguments("E.extension<T>(T)", "T", "object").WithLocation(1, 4)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "42.M<object>()"); Assert.Null(model.GetSymbolInfo(invocation).Symbol); Assert.Equal([], model.GetMemberGroup(invocation).ToTestDisplayStrings()); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M<object>"); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ExplicitTypeArguments_03() { var src = """ string s = "ran"; _ = s.P<object>; static class E { extension<T>(T t) { public int P => 0; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,7): error CS1061: 'string' does not contain a definition for 'P' and no accessible extension method 'P' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) // _ = s.P<object>; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "P<object>").WithArguments("string", "P").WithLocation(2, 7)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.P<object>"); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ExplicitTypeArguments_04() { var src = """ string s = "ran"; s.M<string>(); static class E { extension<T>(T t) { public void M() => throw null; } extension(string s) { public void M<T>() { System.Console.Write(s); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.M<string>"); AssertEx.SequenceEqual(["void E.<G>$8048A6C8BE30A622530249B904B537EB<System.String>.M()", "void E.<G>$34505F560D9EACF86A87F3ED1F85E448.M<System.String>()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ExplicitTypeArguments_05() { var src = """ string s = null; s.M<string>(); static class E { extension<T>(T t) { public void M<U>() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,3): error CS1061: 'string' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) // s.M<string>(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M<string>").WithArguments("string", "M").WithLocation(2, 3)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.M<string>"); AssertEx.Empty(model.GetMemberGroup(memberAccess)); src = """ string s = null; s.M<string>(); static class E { public static void M<T, U>(this T t) { } } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,3): error CS1061: 'string' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) // s.M<string>(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M<string>").WithArguments("string", "M").WithLocation(2, 3)); tree = comp.SyntaxTrees.First(); model = comp.GetSemanticModel(tree); memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.M<string>"); AssertEx.Empty(model.GetMemberGroup(memberAccess)); } [Fact] public void ExplicitTypeArguments_06() { var src = """ C<string, string>.M<string>(); class C<T1, T2> { } static class E { extension<T, U>(C<T, U> t) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,19): error CS0117: 'C<string, string>' does not contain a definition for 'M' // C<string, string>.M<string>(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M<string>").WithArguments("C<string, string>", "M").WithLocation(1, 19)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C<string, string>.M<string>"); AssertEx.Empty(model.GetMemberGroup(memberAccess)); } [Fact] public void ExplicitTypeArguments_07() { var src = """ string.M<object, long>(42); static class E { extension<T>(T t) { public static void M<U>(U u) { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "string.M<object, long>(42)"); AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M<System.Int64>(System.Int64 u)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "string.M<object, long>"); AssertEx.SequenceEqual(["void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M<System.Int64>(System.Int64 u)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ExplicitTypeArguments_08() { var src = """ object.M<string, long>(42); static class E { extension<T>(T t) { public static void M<U>(U u) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS1929: 'object' does not contain a definition for 'M' and the best extension method overload 'E.extension<string>(string).M<long>(long)' requires a receiver of type 'string' // object.M<string, long>(42); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "object").WithArguments("object", "M", "E.extension<string>(string).M<long>(long)", "string").WithLocation(1, 1)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M<string, long>"); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ExplicitTypeArguments_09() { var src = """ 42.M<object>(42); 42.M2<object>(42); 42.M3<object>(42); static class E { extension(int i) { public void M<T>(T t) where T : struct { } } extension<T>(T t) where T : struct { public void M2(int i) { } } public static void M3<T>(this int i, T t) where T : struct { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,4): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.extension(int).M<T>(T)' // 42.M<object>(42); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M<object>").WithArguments("E.extension(int).M<T>(T)", "T", "object").WithLocation(1, 4), // (2,4): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.extension<T>(T)' // 42.M2<object>(42); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M2<object>").WithArguments("E.extension<T>(T)", "T", "object").WithLocation(2, 4), // (3,4): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'E.M3<T>(int, T)' // 42.M3<object>(42); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M3<object>").WithArguments("E.M3<T>(int, T)", "T", "object").WithLocation(3, 4)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M<object>"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M2<object>"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M3<object>"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void ExplicitTypeArguments_10() { var src = """ string s = ""; s.P<object> = 42; static class E { extension<T>(T t) { public int P { get => 0; set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (2,3): error CS1061: 'string' does not contain a definition for 'P' and no accessible extension method 'P' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) // s.P<object> = 42; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "P<object>").WithArguments("string", "P").WithLocation(2, 3)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "s.P<object>"); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void GetDeclaredSymbol_01() { var src = """ static class E { extension(int i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var extensionParameter = tree.GetRoot().DescendantNodes().OfType<ParameterSyntax>().Single(); var symbol = model.GetDeclaredSymbol(extensionParameter); Assert.Equal(SymbolKind.Parameter, symbol.Kind); Assert.Equal("System.Int32 i", symbol.ToTestDisplayString()); Assert.Equal("E", model.GetEnclosingSymbol(extensionParameter.SpanStart).ToTestDisplayString()); src = """ static class E { static void M(int i2) { } } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); tree = comp.SyntaxTrees.Single(); model = comp.GetSemanticModel(tree); var parameter = tree.GetRoot().DescendantNodes().OfType<ParameterSyntax>().Single(); symbol = model.GetDeclaredSymbol(parameter); Assert.Equal(SymbolKind.Parameter, symbol.Kind); Assert.Equal("System.Int32 i2", symbol.ToTestDisplayString()); Assert.Equal("E", model.GetEnclosingSymbol(parameter.SpanStart).ToTestDisplayString()); } readonly string[] _objectMembers = [ "System.String System.Object.ToString()", "System.Boolean System.Object.Equals(System.Object obj)", "System.Boolean System.Object.Equals(System.Object objA, System.Object objB)", "System.Int32 System.Object.GetHashCode()", "System.Type System.Object.GetType()", "System.Boolean System.Object.ReferenceEquals(System.Object objA, System.Object objB)"]; [Fact] public void LookupSymbols_Simple() { var src = """ object.M(); _ = object.Property; public static class E { extension(object) { public static void M() => throw null; public static int Property => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "object.M()"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); var property = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.Property"); AssertEx.Equal("System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; }", model.GetSymbolInfo(property).Symbol.ToTestDisplayString()); var e = ((Compilation)comp).GlobalNamespace.GetTypeMember("E"); AssertEqualAndNoDuplicates(["void E.M()"], model.LookupSymbols(position: 0, e, name: "M").ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["void E.M()", "void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.LookupSymbols(position: 0, e, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, e, name: "Property").ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; }"], model.LookupSymbols(position: 0, e, name: "Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["System.Int32 E.get_Property()"], model.LookupSymbols(position: 0, e, name: "get_Property").ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["System.Int32 E.get_Property()"], model.LookupSymbols(position: 0, e, name: "get_Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "M").ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "Property").ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; }"], model.LookupSymbols(position: 0, o, name: "Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; }", .. _objectMembers], model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); Assert.Equal([ "System.Boolean System.Object.Equals(System.Object objA, System.Object objB)", "System.Boolean System.Object.ReferenceEquals(System.Object objA, System.Object objB)"], model.LookupStaticMembers(position: 0, o, name: null).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : public API, should we include extension static members? Assert.Empty(model.LookupNamespacesAndTypes(position: 0, o, name: null)); } [Fact] public void LookupSymbols_Inapplicable() { var src = """ object.M(); _ = object.Property; public static class E { extension(string) { public static void M() => throw null; public static int Property => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,1): error CS1929: 'object' does not contain a definition for 'M' and the best extension method overload 'E.extension(string).M()' requires a receiver of type 'string' // object.M(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "object").WithArguments("object", "M", "E.extension(string).M()", "string").WithLocation(1, 1), // (2,5): error CS1929: 'object' does not contain a definition for 'Property' and the best extension method overload 'E.extension(string).Property' requires a receiver of type 'string' // _ = object.Property; Diagnostic(ErrorCode.ERR_BadInstanceArgType, "object").WithArguments("object", "Property", "E.extension(string).Property", "string").WithLocation(2, 5)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "M").ToTestDisplayStrings()); AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "Property").ToTestDisplayStrings()); AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(_objectMembers, model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); } [Fact] public void LookupSymbols_Substituted_01() { var src = """ string.M(); _ = string.Property; public static class E { extension<T>(T) { public static void M() => throw null; public static int Property => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "M").ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "Property").ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.Property { get; }"], model.LookupSymbols(position: 0, o, name: "Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M()", "System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.Property { get; }", .. _objectMembers], model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); var s = ((Compilation)comp).GetSpecialType(SpecialType.System_String); AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, s, name: "M").ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["void E.<G>$8048A6C8BE30A622530249B904B537EB<System.String>.M()"], model.LookupSymbols(position: 0, s, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, s, name: "Property").ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<System.String>.Property { get; }"], model.LookupSymbols(position: 0, s, name: "Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); } [Fact] public void LookupSymbols_Substituted_02() { var src = """ string.M(42); public static class E { extension<T>(T) { public static void M<U>(U u) => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var s = ((Compilation)comp).GetSpecialType(SpecialType.System_String); AssertEqualAndNoDuplicates(["void E.<G>$8048A6C8BE30A622530249B904B537EB<System.String>.M<U>(U u)"], model.LookupSymbols(position: 0, s, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); } [Fact] public void LookupSymbols_StaticAndInstance() { var src = """ public static class E1 { extension(object o) { public static void M() => throw null; public static int Property => throw null; } } public static class E2 { extension(object o) { public void M() => throw null; public int Property => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); AssertEqualAndNoDuplicates(["void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["System.Int32 E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; }", "System.Int32 E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; }"], model.LookupSymbols(position: 0, o, name: "Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates([ "void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "System.Int32 E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; }", "void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "System.Int32 E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.Property { get; }", .. _objectMembers], model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); } [Fact] public void LookupSymbols_MethodAndProperty() { var src = """ public static class E1 { extension(object) { public static void MP() => throw null; } } public static class E2 { extension(object o) { public int MP => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); AssertEqualAndNoDuplicates(["void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.MP()", "System.Int32 E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.MP { get; }"], model.LookupSymbols(position: 0, o, name: "MP", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["void E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.MP()", "System.Int32 E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.MP { get; }", .. _objectMembers], model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); } [Fact] public void LookupSymbols_ClassicAndNew() { var src = """ public static class E { extension(object o) { public static void M() => throw null; public void M(string s) => throw null; } public static void M(this object o, int i) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); AssertEqualAndNoDuplicates(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M(System.String s)", "void System.Object.M(System.Int32 i)"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M(System.String s)", "void System.Object.M(System.Int32 i)", .. _objectMembers], model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); } [Fact] public void LookupSymbols_NestedType() { var src = """ public static class E { extension(object) { static class Nested { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,22): error CS9282: This member is not allowed in an extension block // static class Nested { } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Nested").WithLocation(6, 22)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "Nested", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates([.. _objectMembers], model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); Assert.Empty(model.LookupNamespacesAndTypes(position: 0, o, name: null)); } [Fact] public void LookupSymbols_ExtensionParameter() { var src = """ public static class E { extension(object o) { } } """; var comp = CreateCompilation(src); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var extension = tree.GetRoot().DescendantNodes().OfType<ExtensionBlockDeclarationSyntax>().Single(); int position = extension.OpenBraceToken.EndPosition; AssertEqualAndNoDuplicates(["System.Object o"], model.LookupSymbols(position, null, name: "o").ToTestDisplayStrings()); AssertEx.Equal("System.Object o", model.LookupSymbols(position, null, name: null).OfType<IParameterSymbol>().Single().ToTestDisplayString()); Assert.Empty(model.LookupNamespacesAndTypes(position, null, name: "o")); position = extension.OpenBraceToken.Position; Assert.Empty(model.LookupSymbols(position, null, name: "o")); Assert.Empty(model.LookupSymbols(position, null, name: null).OfType<IParameterSymbol>()); } [Fact] public void LookupSymbols_InField() { var src = """ class C { object field = null; } public static class E { extension(object o) { public void M() { } } } """; var comp = CreateCompilation(src); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); int position = GetSyntax<LiteralExpressionSyntax>(tree, "null").EndPosition - 1; var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); Assert.Empty(model.LookupSymbols(position, o, name: "M")); Assert.Empty(model.LookupNamespacesAndTypes(position, o, name: "M")); } [Fact] public void LookupSymbols_UsedImports() { var src = """ // here using N; namespace N { public static class E { extension(object) { public static void M() => throw null; } } } """; var comp = CreateCompilation(src); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); AssertEqualAndNoDuplicates(["void N.E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); model.GetDiagnostics().Verify( // (3,1): hidden CS8019: Unnecessary using directive. // using N; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N;").WithLocation(3, 1)); } [Fact] public void LookupSymbols_WasNotFullyInferred() { var src = """ public static class E { extension<T, U>(T t) { public void M() => throw null; public int Property => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,20): error CS9295: The type parameter `U` is not referenced by either the extension parameter or a parameter of this member // public int Property => throw null; Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "Property").WithArguments("U").WithLocation(7, 20)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); AssertEqualAndNoDuplicates(["void E.<G>$B7F0343159FB3A22D67EC9801612841A<System.Object, U>.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["System.Int32 E.<G>$B7F0343159FB3A22D67EC9801612841A<System.Object, U>.Property { get; }"], model.LookupSymbols(position: 0, o, name: "Property", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates([ "void E.<G>$B7F0343159FB3A22D67EC9801612841A<System.Object, U>.M()", "System.Int32 E.<G>$B7F0343159FB3A22D67EC9801612841A<System.Object, U>.Property { get; }", .. _objectMembers ], model.LookupSymbols(position: 0, o, name: null, includeReducedExtensionMethods: true).ToTestDisplayStrings()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/26549")] public void LookupSymbols_FromBaseInterface_01() { var src = """ public static class E { extension<T>(I<T> i) { public void M(T t) => throw null; } } public interface I<T> { } public class C : I<int> { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var c = ((Compilation)comp).GlobalNamespace.GetTypeMember("C"); AssertEqualAndNoDuplicates(["void E.<G>$74EBC78B2187AB07A25EEFC1322000B0<System.Int32>.M(System.Int32 t)"], model.LookupSymbols(position: 0, c, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); var extension = comp.GlobalNamespace.GetTypeMember("E").GetTypeMembers().Single(); var method = extension.GetMember<MethodSymbol>("M").GetPublicSymbol(); AssertEx.Equal("void E.<G>$74EBC78B2187AB07A25EEFC1322000B0<System.Int32>.M(System.Int32 t)", method.ReduceExtensionMember(c).ToTestDisplayString()); var extensionMethod = comp.GlobalNamespace.GetTypeMember("E").GetMember<MethodSymbol>("M").GetPublicSymbol(); AssertEx.Equal("void I<System.Int32>.M<System.Int32>(System.Int32 t)", extensionMethod.ReduceExtensionMethod(c).ToTestDisplayString()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/26549")] public void LookupSymbols_FromBaseInterface_02() { var src = """ public static class E { extension<T>(I<T> i) { public void M(T t) => throw null; } } public interface I<T> { } public class C : I<int>, I<double> { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var c = ((Compilation)comp).GlobalNamespace.GetTypeMember("C"); Assert.Empty(model.LookupSymbols(position: 0, c, name: "M", includeReducedExtensionMethods: true)); var extension = comp.GlobalNamespace.GetTypeMember("E").GetTypeMembers().Single(); var method = extension.GetMember<MethodSymbol>("M").GetPublicSymbol(); Assert.Null(method.ReduceExtensionMember(c)); var extensionMethod = comp.GlobalNamespace.GetTypeMember("E").GetMember<MethodSymbol>("M").GetPublicSymbol(); Assert.Null(extensionMethod.ReduceExtensionMethod(c)); } [Fact] public void GetMemberGroup_01() { var src = """ object.M<int>(); new object().M2<int>(); static class E { extension(object) { public static void M<U>() where U : class { } } public static void M2<U>(this object o) where U : class { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,8): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'U' in the generic type or method 'E.extension(object).M<U>()' // object.M<int>(); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M<int>").WithArguments("E.extension(object).M<U>()", "U", "int").WithLocation(1, 8), // (2,14): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'U' in the generic type or method 'E.M2<U>(object)' // new object().M2<int>(); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M2<int>").WithArguments("E.M2<U>(object)", "U", "int").WithLocation(2, 14)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M<int>"); Assert.Equal([], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M2<int>"); Assert.Equal([], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); } [Fact] public void GetMemberGroup_02() { var src = """ object.M(42); new object().M2(42); static class E { extension(object) { public static void M<U>(U u) where U : class { } } public static void M2<U>(this object o, U u) where U : class { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,8): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'U' in the generic type or method 'E.extension(object).M<U>(U)' // object.M(42); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M").WithArguments("E.extension(object).M<U>(U)", "U", "int").WithLocation(1, 8), // (2,14): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'U' in the generic type or method 'E.M2<U>(object, U)' // new object().M2(42); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M2").WithArguments("E.M2<U>(object, U)", "U", "int").WithLocation(2, 14)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M<U>(U u)"], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "new object().M2"); AssertEx.SequenceEqual(["void System.Object.M2<U>(U u)"], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); } [Fact] public void GetMemberGroup_03() { var src = """ int.M<int>(); 42.M2<int>(); static class E { extension<T>(T) where T : class { public static void M() { } } public static void M2<T>(this T t) where T : class { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,5): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'E.extension<T>(T)' // int.M<int>(); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M<int>").WithArguments("E.extension<T>(T)", "T", "int").WithLocation(1, 5), // (2,4): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'E.M2<T>(T)' // 42.M2<int>(); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M2<int>").WithArguments("E.M2<T>(T)", "T", "int").WithLocation(2, 4)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.M<int>"); Assert.Equal([], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M2<int>"); Assert.Equal([], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); } [Fact] public void GetMemberGroup_04() { var src = """ int.M(); 42.M2(); static class E { extension<T>(T) where T : class { public static void M() { } } public static void M2<T>(this T t) where T : class { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,5): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'E.extension<T>(T)' // int.M(); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M").WithArguments("E.extension<T>(T)", "T", "int").WithLocation(1, 5), // (2,4): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'E.M2<T>(T)' // 42.M2(); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M2").WithArguments("E.M2<T>(T)", "T", "int").WithLocation(2, 4)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "int.M"); Assert.Equal([], model.GetMemberGroup(memberAccess1).ToTestDisplayStrings()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "42.M2"); Assert.Equal([], model.GetMemberGroup(memberAccess2).ToTestDisplayStrings()); } [Fact] public void GetMemberGroup_05() { var src = """ object.M(); static class E { extension(object) { public static void M() { } public static void M(int i) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void GetMemberGroup_06() { var src = """ _ = object.P; static class E { extension(object) { public static int P => 0; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.P"); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : handle GetMemberGroup on a property access } [Fact] public void GetMemberGroup_07() { var src = """ object.M(); static class E1 { extension(object) { public static int M => 0; } } static class E2 { extension(object) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.SequenceEqual(["System.Int32 E1.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M { get; }", "void E2.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void GetMemberGroup_08() { var src = """ string.M(); static class E1 { extension<T>(T) { public static int M => 0; } } static class E2 { extension<T>(T) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "string.M"); AssertEx.Equal("void E2.<G>$8048A6C8BE30A622530249B904B537EB<System.String>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["System.Int32 E1.<G>$8048A6C8BE30A622530249B904B537EB<System.String>.M { get; }", "void E2.<G>$8048A6C8BE30A622530249B904B537EB<System.String>.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "string.M()"); AssertEx.Equal("void E2.<G>$8048A6C8BE30A622530249B904B537EB<System.String>.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); } [Fact] public void GetMemberGroup_09() { var src = """ string.M(); static class E1 { extension<T>(T) { public static void M() { } } } static class E2 { extension<T>(T) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,8): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension<string>(string).M()' and 'E2.extension<string>(string).M()' // string.M(); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E1.extension<string>(string).M()", "E2.extension<string>(string).M()").WithLocation(1, 8)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "string.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void E1.<G>$8048A6C8BE30A622530249B904B537EB<System.String>.M()", "void E2.<G>$8048A6C8BE30A622530249B904B537EB<System.String>.M()"], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); AssertEx.SequenceEqual(["void E1.<G>$8048A6C8BE30A622530249B904B537EB<System.String>.M()", "void E2.<G>$8048A6C8BE30A622530249B904B537EB<System.String>.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void GetMemberGroup_10() { var src = """ System.Action a = new System.Action(object.M); static class E { extension(object) { public static void M() { } public static void M(int i) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()", "void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void GetMemberGroup_11() { var src = """ System.Action a = new System.Action(object.M); static class E { extension<T>(T) { public static void M() { } public static void M(int i) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); AssertEx.SequenceEqual(["void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M()", "void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void GetMemberGroup_12() { var src = """ System.Action a = (System.Action)object.M; static class E { extension<T>(T) { public static void M() { } public static void M(int i) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.M"); AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); AssertEx.SequenceEqual(["void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M()", "void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); var cast = GetSyntax<CastExpressionSyntax>(tree, "(System.Action)object.M"); AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Object>.M()", model.GetSymbolInfo(cast).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(cast).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal([], model.GetMemberGroup(cast).ToTestDisplayStrings()); } [Fact] public void ToBadExpression_01() { var source = """ class A { void F() { } } class C { static void M(A a) { a.F(); M(a.F); } static void M(System.Action a) { } } static class E1 { static void F<T>(this T t) { } } static class E2 { extension<T>(T) { static void F() { } } } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,11): error CS0122: 'A.F()' is inaccessible due to its protection level // a.F(); Diagnostic(ErrorCode.ERR_BadAccess, "F").WithArguments("A.F()").WithLocation(10, 11), // (11,13): error CS0122: 'A.F()' is inaccessible due to its protection level // M(a.F); Diagnostic(ErrorCode.ERR_BadAccess, "F").WithArguments("A.F()").WithLocation(11, 13)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "a.F").ToArray(); Assert.Null(model.GetSymbolInfo(memberAccess[0]).Symbol); AssertEqualAndNoDuplicates(["void A.F()"], model.GetSymbolInfo(memberAccess[0]).CandidateSymbols.ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["void A.F()", "void E2.<G>$8048A6C8BE30A622530249B904B537EB<A>.F()", "void A.F<A>()"], model.GetMemberGroup(memberAccess[0]).ToTestDisplayStrings()); Assert.Null(model.GetSymbolInfo(memberAccess[1]).Symbol); AssertEqualAndNoDuplicates(["void A.F()", "void E2.<G>$8048A6C8BE30A622530249B904B537EB<A>.F()", "void A.F<A>()"], model.GetSymbolInfo(memberAccess[1]).CandidateSymbols.ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["void A.F()", "void E2.<G>$8048A6C8BE30A622530249B904B537EB<A>.F()", "void A.F<A>()"], model.GetMemberGroup(memberAccess[1]).ToTestDisplayStrings()); } [Fact] public void PropertyAccess_NotAmbiguousWithInapplicableMethod() { var src = """ int i = object.P; System.Console.Write(i); static class E1 { extension<T>(T) where T : struct { public static void P() { } } } static class E2 { extension<T>(T) where T : class { public static int P => 42; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "object.P"); AssertEx.Equal("System.Int32 E2.<G>$66F77D1E46F965A5B22D4932892FA78B<System.Object>.P { get; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); Assert.Equal([], model.GetSymbolInfo(memberAccess).CandidateSymbols.ToTestDisplayStrings()); Assert.Equal([], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); // Tracked by https://github.com/dotnet/roslyn/issues/78957 : handle GetMemberGroup on a property access } [Fact] public void GetSymbolInfo_GenericMethodInGenericType_01() { var src = """ class C<T> { public static void M<T2>(T2 x) { } public static void M(int x) { } } class D { public void Test() { C<int>.M<int>(1); } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var genericName = GetSyntax<GenericNameSyntax>(tree, "M<int>"); AssertEx.Equal("void C<System.Int32>.M<System.Int32>(System.Int32 x)", model.GetSymbolInfo(genericName).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void C<System.Int32>.M<System.Int32>(System.Int32 x)"], model.GetMemberGroup(genericName).ToTestDisplayStrings()); } [Fact] public void GetSymbolInfo_GenericMethodInGenericType_02() { var src = """ class C<T> { public static void M<T2>(T2 x) where T2 : class { } } class D { public void Test() { C<int>.M<int>(1); } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (10,16): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T2' in the generic type or method 'C<int>.M<T2>(T2)' // C<int>.M<int>(1); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M<int>").WithArguments("C<int>.M<T2>(T2)", "T2", "int").WithLocation(10, 16)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var genericName = GetSyntax<GenericNameSyntax>(tree, "M<int>"); Assert.Null(model.GetSymbolInfo(genericName).Symbol); Assert.Equal([], model.GetMemberGroup(genericName).ToTestDisplayStrings()); } [Fact] public void GetSymbolInfo_GenericMethodInGenericType_03() { var src = """ class C<T> { public static void M<T2>(T2 x) where T2 : class { } } class D { public void Test() { C<int>.M(1); } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (10,16): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T2' in the generic type or method 'C<int>.M<T2>(T2)' // C<int>.M(1); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M").WithArguments("C<int>.M<T2>(T2)", "T2", "int").WithLocation(10, 16)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C<int>.M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); AssertEx.SequenceEqual(["void C<System.Int32>.M<T2>(T2 x)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] public void GetSymbolInfo_04() { var src = """ class C { private static void M<T>() { M<T>(); } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var genericName = GetSyntax<InvocationExpressionSyntax>(tree, "M<T>()").Expression; AssertEx.Equal("void C.M<T>()", model.GetSymbolInfo(genericName).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void C.M<T>()"], model.GetMemberGroup(genericName).ToTestDisplayStrings()); } [Fact] public void GetSymbolInfo_05() { var src = """ public static class E { extension<T>(T t) { static void M() { T.M<T>(); T.M(); E.M<T>(); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,13): error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter // T.M<T>(); Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(7, 13), // (8,13): error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter // T.M(); Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(8, 13)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var expr = GetSyntax<InvocationExpressionSyntax>(tree, "T.M<T>()").Expression; Assert.Null(model.GetSymbolInfo(expr).Symbol); Assert.Equal([], model.GetMemberGroup(expr).ToTestDisplayStrings()); expr = GetSyntax<InvocationExpressionSyntax>(tree, "T.M()").Expression; Assert.Null(model.GetSymbolInfo(expr).Symbol); Assert.Equal([], model.GetMemberGroup(expr).ToTestDisplayStrings()); expr = GetSyntax<InvocationExpressionSyntax>(tree, "E.M<T>()").Expression; AssertEx.Equal("void E.M<T>()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.M<T>()"], model.GetMemberGroup(expr).ToTestDisplayStrings()); } [Fact] public void GetSymbolInfo_06() { var src = """ public static class E { extension<T>(T t) { void M() { t.M<T>(); t.M(); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var expr = GetSyntax<InvocationExpressionSyntax>(tree, "t.M<T>()").Expression; AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M()"], model.GetMemberGroup(expr).ToTestDisplayStrings()); expr = GetSyntax<InvocationExpressionSyntax>(tree, "t.M()").Expression; AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M()"], model.GetMemberGroup(expr).ToTestDisplayStrings()); } [Fact] public void GetSymbolInfo_07() { var src = """ public static class E { extension<T>(T t) { void M<U>(U u) { t.M<T, U>(u); t.M(u); t.M(42); 42.M(u); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var extensionParameterSyntax = tree.GetRoot().DescendantNodes().OfType<ParameterSyntax>().First(); IParameterSymbol extensionParameter = model.GetDeclaredSymbol(extensionParameterSyntax); AssertEx.Equal("T t", extensionParameter.ToTestDisplayString()); var t = extensionParameter.Type; var expr = GetSyntax<InvocationExpressionSyntax>(tree, "t.M<T, U>(u)").Expression; AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M<U>(U u)", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M<U>(U u)"], model.GetMemberGroup(expr).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M<U>(U u)"], model.LookupSymbols(position: expr.SpanStart, t, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); expr = GetSyntax<InvocationExpressionSyntax>(tree, "t.M(u)").Expression; AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M<U>(U u)", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M<U>(U u)"], model.GetMemberGroup(expr).ToTestDisplayStrings()); expr = GetSyntax<InvocationExpressionSyntax>(tree, "t.M(42)").Expression; AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M<System.Int32>(System.Int32 u)", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M<U>(U u)"], model.GetMemberGroup(expr).ToTestDisplayStrings()); expr = GetSyntax<InvocationExpressionSyntax>(tree, "42.M(u)").Expression; AssertEx.Equal("void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Int32>.M<U>(U u)", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void E.<G>$8048A6C8BE30A622530249B904B537EB<System.Int32>.M<U>(U u)"], model.GetMemberGroup(expr).ToTestDisplayStrings()); } [Fact] public void GetSymbolInfo_08() { var src = """ public static class E { public static void M<T>(this T t) { t.M<T>(); t.M(); } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var extensionParameterSyntax = tree.GetRoot().DescendantNodes().OfType<ParameterSyntax>().First(); IParameterSymbol extensionParameter = model.GetDeclaredSymbol(extensionParameterSyntax); AssertEx.Equal("T t", extensionParameter.ToTestDisplayString()); var t = extensionParameter.Type; var expr = GetSyntax<InvocationExpressionSyntax>(tree, "t.M<T>()").Expression; AssertEx.Equal("void T.M<T>()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void T.M<T>()"], model.GetMemberGroup(expr).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["void T.M<T>()"], model.LookupSymbols(position: expr.SpanStart, t, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); expr = GetSyntax<InvocationExpressionSyntax>(tree, "t.M()").Expression; AssertEx.Equal("void T.M<T>()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString()); AssertEx.SequenceEqual(["void T.M<T>()"], model.GetMemberGroup(expr).ToTestDisplayStrings()); } [Fact] public void LangVer_01() { var libSrc = """ public static class E { extension(object o) { public void M() { } public static void M2() { } public int P => 0; public static int P2 => 0; } } """; var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.Regular14); libComp.VerifyEmitDiagnostics(); var libRef = libComp.EmitToImageReference(); var srcCompat = """ new object().M(); System.Action a = new object().M; var x = new object().M; E.M(new object()); E.M2(); E.get_P(new object()); E.get_P2(); """; var comp = CreateCompilation(srcCompat, references: [libRef], parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics(); comp = CreateCompilation(srcCompat, references: [libRef], parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics(); comp = CreateCompilation(srcCompat, references: [libRef]); comp.VerifyEmitDiagnostics(); var src = """ object.M2(); System.Action a = object.M2; var x = object.M2; _ = object.P2; """; comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular12); comp.VerifyEmitDiagnostics( // (1,1): error CS9202: Feature 'extensions' is not available in C# 12.0. Please use language version 14.0 or greater. // object.M2(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "object.M2()").WithArguments("extensions", "14.0").WithLocation(1, 1), // (2,19): error CS9202: Feature 'extensions' is not available in C# 12.0. Please use language version 14.0 or greater. // System.Action a = object.M2; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "object.M2").WithArguments("extensions", "14.0").WithLocation(2, 19), // (3,9): error CS9202: Feature 'extensions' is not available in C# 12.0. Please use language version 14.0 or greater. // var x = object.M2; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "object.M2").WithArguments("extensions", "14.0").WithLocation(3, 9), // (5,5): error CS9202: Feature 'extensions' is not available in C# 12.0. Please use language version 14.0 or greater. // _ = object.P2; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "object.P2").WithArguments("extensions", "14.0").WithLocation(5, 5)); verifySymbolInfo(comp); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics( // (1,1): error CS9260: Feature 'extensions' is not available in C# 13.0. Please use language version 14.0 or greater. // object.M2(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion13, "object.M2()").WithArguments("extensions", "14.0").WithLocation(1, 1), // (2,19): error CS9260: Feature 'extensions' is not available in C# 13.0. Please use language version 14.0 or greater. // System.Action a = object.M2; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion13, "object.M2").WithArguments("extensions", "14.0").WithLocation(2, 19), // (3,9): error CS9260: Feature 'extensions' is not available in C# 13.0. Please use language version 14.0 or greater. // var x = object.M2; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion13, "object.M2").WithArguments("extensions", "14.0").WithLocation(3, 9), // (5,5): error CS9260: Feature 'extensions' is not available in C# 13.0. Please use language version 14.0 or greater. // _ = object.P2; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion13, "object.P2").WithArguments("extensions", "14.0").WithLocation(5, 5)); verifySymbolInfo(comp); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics(); verifySymbolInfo(comp); comp = CreateCompilation(src, references: [libRef]); comp.VerifyEmitDiagnostics(); verifySymbolInfo(comp); src = """ _ = new object().P; """; comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics( // (1,5): error CS9260: Feature 'extensions' is not available in C# 13.0. Please use language version 14.0 or greater. // _ = new object().P; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion13, "new object().P").WithArguments("extensions", "14.0").WithLocation(1, 5)); verifySymbolInfo(comp); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics(); verifySymbolInfo(comp); comp = CreateCompilation(src, references: [libRef]); comp.VerifyEmitDiagnostics(); verifySymbolInfo(comp); static void verifySymbolInfo(CSharpCompilation comp) { var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object); AssertEqualAndNoDuplicates(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M2()"], model.LookupSymbols(position: 0, o, name: "M2", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.P { get; }"], model.LookupSymbols(position: 0, o, name: "P", includeReducedExtensionMethods: true).ToTestDisplayStrings()); AssertEqualAndNoDuplicates(["System.Int32 E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.P2 { get; }"], model.LookupSymbols(position: 0, o, name: "P2", includeReducedExtensionMethods: true).ToTestDisplayStrings()); } } [Fact] public void LangVer_02() { var libSrc = """ public static class E { extension(object o) { public System.Collections.IEnumerator GetEnumerator() => throw null; } } """; var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.Regular14); libComp.VerifyEmitDiagnostics(); var libRef = libComp.EmitToImageReference(); var src = """ foreach (var x in new object()) { } """; var comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics(); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics(); comp = CreateCompilation(src, references: [libRef]); comp.VerifyEmitDiagnostics(); } [Fact] public void LangVer_03() { var libSrc = """ public static class E { extension(object o) { public void Add(object o2) { } } } """; var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.Regular14); libComp.VerifyEmitDiagnostics(); var libRef = libComp.EmitToImageReference(); var src = """ using System.Collections; using System.Collections.Generic; MyCollection c = [new object()]; public class MyCollection : IEnumerable<object> { IEnumerator<object> IEnumerable<object>.GetEnumerator() => throw null!; IEnumerator IEnumerable.GetEnumerator() => throw null!; } """; var comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics(); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics(); comp = CreateCompilation(src, references: [libRef]); comp.VerifyEmitDiagnostics(); } [Fact] public void LangVer_04() { var libSrc = """ namespace N; public static class E { extension(int i) { public System.Action Member => () => System.Console.Write("property"); } } """; var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.Regular14); libComp.VerifyEmitDiagnostics(); var libRef = libComp.EmitToImageReference(); var src = """ namespace N { class D { public static void Main() { 42.Member(); } } } static class Classic { public static void Member(this int i) { System.Console.Write("classic"); } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "classic").VerifyDiagnostics(); comp = CreateCompilation(src, references: [libRef], options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics(); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics(); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics( // (7,13): error CS9260: Feature 'extensions' is not available in C# 13.0. Please use language version 14.0 or greater. // 42.Member(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion13, "42.Member").WithArguments("extensions", "14.0").WithLocation(7, 13)); } [Fact] public void LangVer_05() { // Function type with a type argument violating constraint var libSrc = """ public static class E { extension(object o) { public void M<T>() where T : class { } } } """; var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.Regular14); var libRef = libComp.EmitToImageReference(expectedWarnings: null); var src = """ var x = new object().M<int>; """; DiagnosticDescription[] cannotInferDelegateType = [ // (1,9): error CS8917: The delegate type could not be inferred. // var x = new object().M<int>; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new object().M<int>").WithLocation(1, 9)]; var comp = CreateCompilation(src, references: [libRef]); comp.VerifyDiagnostics(cannotInferDelegateType); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics(cannotInferDelegateType); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); comp.VerifyDiagnostics(cannotInferDelegateType); // Note: in older LangVer, new extension methods are subject to more stringent check than classic extension methods comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular12); comp.VerifyDiagnostics(cannotInferDelegateType); src = """ var x = new object().M<int>; public static class E { public static void M<T>(this object o) where T : class { } } """; comp = CreateCompilation(src); comp.VerifyDiagnostics(cannotInferDelegateType); comp = CreateCompilation(src, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics(cannotInferDelegateType); comp = CreateCompilation(src, parseOptions: TestOptions.Regular13); comp.VerifyDiagnostics(cannotInferDelegateType); comp = CreateCompilation(src, parseOptions: TestOptions.Regular12); comp.VerifyDiagnostics( // (1,9): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'E.M<T>(object)' // var x = new object().M<int>; Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "new object().M<int>").WithArguments("E.M<T>(object)", "T", "int").WithLocation(1, 9)); } [Fact] public void LangVer_06() { // Function type with a type argument violating constraint, in outer scope var libSrc = """ namespace N { public static class E1 { extension(object o) { public void M<T>() where T : class { } } } } """; var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.Regular14); var libRef = libComp.EmitToImageReference(expectedWarnings: null); var src = """ using N; var x = new object().M<int>; x(); public static class E2 { public static void M<T>(this object o) { System.Console.Write("ran"); } } """; DiagnosticDescription[] unnecessaryDirective = [ // (1,1): hidden CS8019: Unnecessary using directive. // using N; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N;").WithLocation(1, 1)]; var comp = CreateCompilation(src, references: [libRef]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(unnecessaryDirective); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(unnecessaryDirective); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(unnecessaryDirective); if (!CompilationExtensions.EnableVerifyUsedAssemblies) // Tracked by https://github.com/dotnet/roslyn/issues/78968 { // Note: in older LangVer, we look at all scopes to determine the unique signature comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular12); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); //var used = comp.GetUsedAssemblyReferences(); //Assert.Contains(libRef, used); } src = """ var x = new object().M<int>; x(); namespace N { public static class E1 { public static void M<T>(this object o) where T : class { } } } public static class E2 { public static void M<T>(this object o) { System.Console.Write("ran"); } } """; comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(src, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(src, parseOptions: TestOptions.Regular13); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(src, parseOptions: TestOptions.Regular12); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void LangVer_07() { // Function type with a type argument violating constraint, in same scope var libSrc = """ public static class E1 { extension(object o) { public void M<T>() where T : class { } } } """; var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.Regular14); var libRef = libComp.EmitToImageReference(expectedWarnings: null); var src = """ var x = new object().M<int>; x(); public static class E2 { public static void M<T>(this object o) { System.Console.Write("ran"); } } """; var comp = CreateCompilation(src, references: [libRef]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular12); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); src = """ var x = new object().M<int>; x(); public static class E1 { public static void M<T>(this object o) where T : class { } } public static class E2 { public static void M<T>(this object o) { System.Console.Write("ran"); } } """; comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(src, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(src, parseOptions: TestOptions.Regular13); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(src, parseOptions: TestOptions.Regular12); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void LangVer_08() { // Function type with a type argument violating constraint, in same scope, different signatures var libSrc = """ public static class E1 { extension(object o) { public void M<T>(int i) where T : class { } } } """; var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.Regular14); var libRef = libComp.EmitToImageReference(expectedWarnings: null); var src = """ var x = new object().M<int>; x(); public static class E2 { public static void M<T>(this object o) { System.Console.Write("ran"); } } """; var comp = CreateCompilation(src, references: [libRef]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); // Note: in older LangVer, we look at all scopes to determine the unique signature, but we apply stricter standards to new extension methods comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular12); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); src = """ var x = new object().M<int>; x(); public static class E1 { public static void M<T>(this object o, int i) where T : class { } } public static class E2 { public static void M<T>(this object o) { System.Console.Write("ran"); } } """; comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(src, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(src, parseOptions: TestOptions.Regular13); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); // Note: in older LangVer, classic extension methods candidates with broken constraints are still considered for unique signature comp = CreateCompilation(src, parseOptions: TestOptions.Regular12); comp.VerifyDiagnostics( // (1,9): error CS8917: The delegate type could not be inferred. // var x = new object().M<int>; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new object().M<int>").WithLocation(1, 9)); } [Fact] public void LangVer_09() { // Function type with static/instance mismatch var libSrc = """ public static class E { extension(object o) { public void M() { } } } """; var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.Regular14); var libRef = libComp.EmitToImageReference(expectedWarnings: null); var src = """ var x = object.M; x(); """; DiagnosticDescription[] expected = [ // (1,9): error CS8917: The delegate type could not be inferred. // var x = object.M; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "object.M").WithLocation(1, 9)]; var comp = CreateCompilation(src, references: [libRef]); comp.VerifyDiagnostics(expected); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics(expected); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); comp.VerifyDiagnostics(expected); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular12); comp.VerifyDiagnostics(expected); } [Fact] public void LangVer_10() { // Function type with static/instance mismatch var libSrc = """ public static class E { extension(object) { public static void M() { } } } """; var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.Regular14); var libRef = libComp.EmitToImageReference(expectedWarnings: null); var src = """ var x = new object().M; """; DiagnosticDescription[] expected = [ // (1,9): error CS8917: The delegate type could not be inferred. // var x = new object().M; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new object().M").WithLocation(1, 9)]; var comp = CreateCompilation(src, references: [libRef]); comp.VerifyDiagnostics(expected); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics(expected); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); comp.VerifyDiagnostics(expected); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular12); comp.VerifyDiagnostics(expected); } [Fact] public void LangVer_11() { // Function type with static/instance mismatch var src = """ var x = object.M; public static class E { public static void M(this object o) { } } """; DiagnosticDescription[] expected = [ // (1,9): error CS8917: The delegate type could not be inferred. // var x = object.M; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "object.M").WithLocation(1, 9)]; var comp = CreateCompilation(src); comp.VerifyDiagnostics(expected); comp = CreateCompilation(src, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics(expected); comp = CreateCompilation(src, parseOptions: TestOptions.Regular13); comp.VerifyDiagnostics(expected); comp = CreateCompilation(src, parseOptions: TestOptions.Regular12); comp.VerifyDiagnostics(expected); } [Fact] public void LangVer_12() { // Function type with an extension property in outer scope var libSrc = """ namespace N { public static class E1 { extension(object o) { public int M => 0; } } } """; var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.Regular14); var libRef = libComp.EmitToImageReference(expectedWarnings: null); var src = """ using N; var x = new object().M; x(); public static class E2 { public static void M(this object o) { System.Console.Write("ran"); } } """; DiagnosticDescription[] unnecessaryDirective = [ // (1,1): hidden CS8019: Unnecessary using directive. // using N; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N;").WithLocation(1, 1)]; var comp = CreateCompilation(src, references: [libRef]); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(unnecessaryDirective); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(unnecessaryDirective); comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(unnecessaryDirective); if (!CompilationExtensions.EnableVerifyUsedAssemblies) // Tracked by https://github.com/dotnet/roslyn/issues/78968 { comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular12); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); //var used = comp.GetUsedAssemblyReferences(); //Assert.Contains(libRef, used); } } [Fact] public void This_01() { var src = """ static class E { extension(object o) { public void M() { var x = this; this.ToString(); local(); void local() { var y = this; } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,21): error CS0027: Keyword 'this' is not available in the current context // var x = this; Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(7, 21), // (8,13): error CS0027: Keyword 'this' is not available in the current context // this.ToString(); Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13), // (13,25): error CS0027: Keyword 'this' is not available in the current context // var y = this; Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(13, 25)); } [Fact] public void This_02() { var src = """ static class E { extension(object o) { public void M() { M2(); this.M2(); M2(new object()); } public void M2() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)' // M2(); Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13), // (8,13): error CS0027: Keyword 'this' is not available in the current context // this.M2(); Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()"); Assert.Null(model.GetSymbolInfo(invocation).Symbol); invocation = GetSyntax<InvocationExpressionSyntax>(tree, "this.M2()"); AssertEx.Equal("void E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); var symbolInfo = model.GetSymbolInfo(GetSyntax<ThisExpressionSyntax>(tree, "this")); Assert.Null(symbolInfo.Symbol); Assert.Equal(CandidateReason.NotReferencable, symbolInfo.CandidateReason); Assert.True(symbolInfo.CandidateSymbols is [IParameterSymbol { Name: "this", ContainingSymbol: INamedTypeSymbol { IsExtension: true } }]); invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2(new object())"); AssertEx.Equal("void E.M2(this System.Object o)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); } [Fact] public void This_03() { var src = """ static class E { extension(object o) { public static void M() { M2(); } public void M2() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)' // M2(); Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13)); } [Fact] public void This_04() { var src = """ static class E { extension(object o) { public void M() { M2(); } public static void M2() { } } } """; var comp = CreateCompilation(src); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()"); AssertEx.Equal("void E.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString()); CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify).VerifyDiagnostics(); void verify(ModuleSymbol m) { var type = m.GlobalNamespace.GetMember<NamedTypeSymbol>("E"); var method = type.GetTypeMember("").GetMember<MethodSymbol>("M"); Assert.Null(method.ThisParameter); } } [Fact] public void ReceiverParameter_Access_01() { var src = """ static class E { extension(object o) { public void M() { o.M2(); } public void M2() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void ReceiverParameter_Access_02() { var src = """ static class E { extension(object o) { public void M() { o.M2(); } public static void M2() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,13): error CS0176: Member 'E.extension(object).M2()' cannot be accessed with an instance reference; qualify it with a type name instead // o.M2(); Diagnostic(ErrorCode.ERR_ObjectProhibited, "o.M2").WithArguments("E.extension(object).M2()").WithLocation(7, 13)); } [Fact] public void ReceiverParameter_Access_03() { var src = """ static class E { extension(object o) { public static void M() { o.M2(); } public void M2() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,13): error CS9347: Static members cannot access the value of extension parameter 'o'. // o.M2(); Diagnostic(ErrorCode.ERR_ExtensionParameterInStaticContext, "o").WithArguments("o").WithLocation(7, 13)); } [Fact] public void ReceiverParameter_Access_04() { var src = """ static class E { extension(object o) { public void M() { local(); void local() { o.M2(); } } public void M2() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void ReceiverParameter_Access_05() { var src = """ static class E { extension(object o, object o2) { public void M() { o2.ToString(); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,25): error CS9285: An extension container can have only one receiver parameter // extension(object o, object o2) Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "object o2").WithLocation(3, 25), // (7,13): error CS0103: The name 'o2' does not exist in the current context // o2.ToString(); Diagnostic(ErrorCode.ERR_NameNotInContext, "o2").WithArguments("o2").WithLocation(7, 13)); } [Fact] public void ReceiverParameter_Access_06() { var src = """ static class E { extension(System.Span<int> s) { public async void M() { s.ToString(); await System.Threading.Tasks.Task.Yield(); s.ToString(); } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (5,27): error CS4012: Parameters of type 'Span<int>' cannot be declared in async methods or async lambda expressions. // public async void M() Diagnostic(ErrorCode.ERR_BadSpecialByRefParameter, "M").WithArguments("System.Span<int>").WithLocation(5, 27)); } [Fact] public void ReceiverParameter_TypeParametersMustBeUsed() { var src = """ int i = C.P; class C { } static class E { extension<T, U>(C) { static int P => 0; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,11): error CS0117: 'C' does not contain a definition for 'P' // int i = C.P; Diagnostic(ErrorCode.ERR_NoSuchMember, "P").WithArguments("C", "P").WithLocation(1, 11), // (9,20): error CS9295: The type parameter `T` is not referenced by either the extension parameter or a parameter of this member // static int P => 0; Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "P").WithArguments("T").WithLocation(9, 20), // (9,20): error CS9295: The type parameter `U` is not referenced by either the extension parameter or a parameter of this member // static int P => 0; Diagnostic(ErrorCode.ERR_UnderspecifiedExtension, "P").WithArguments("U").WithLocation(9, 20)); } public partial class RegionAnalysisTests : FlowTestBase { [Fact] public void RegionAnalysis_01() { var analysisResults = CompileAndAnalyzeDataFlowExpression(""" static class E { extension(int i) { public void M(int i2) { _ = /*<bind>*/i + i2/*</bind>*/; } } } """); VerifyDataFlowAnalysis(""" VariablesDeclared: AlwaysAssigned: Captured: CapturedInside: CapturedOutside: DataFlowsIn: i, i2 DataFlowsOut: DefinitelyAssignedOnEntry: i, i2 DefinitelyAssignedOnExit: i, i2 ReadInside: i, i2 ReadOutside: WrittenInside: WrittenOutside: i, i2 """, analysisResults); } [Fact] public void RegionAnalysis_02() { var analysisResults = CompileAndAnalyzeDataFlowExpression(""" static class E { extension(int i) { public void M(int i2) { /*<bind>*/this.ToString()/*</bind>*/; } } } """); VerifyDataFlowAnalysis(""" VariablesDeclared: AlwaysAssigned: Captured: CapturedInside: CapturedOutside: DataFlowsIn: DataFlowsOut: DefinitelyAssignedOnEntry: i, i2 DefinitelyAssignedOnExit: i, i2 ReadInside: ReadOutside: WrittenInside: WrittenOutside: i, i2 """, analysisResults); } [Fact] public void RegionAnalysis_03() { var analysisResults = CompileAndAnalyzeDataFlowExpression(""" static class E { extension(int i) { public void M(int i2) { int i3 = 0; /*<bind>*/ System.Action<int> = () => i + i2 + i3; /*</bind>*/ } } } """); VerifyDataFlowAnalysis(""" VariablesDeclared: AlwaysAssigned: Captured: i, i2, i3 CapturedInside: i, i2, i3 CapturedOutside: DataFlowsIn: i, i2, i3 DataFlowsOut: DefinitelyAssignedOnEntry: i, i2, i3 DefinitelyAssignedOnExit: i, i2, i3 ReadInside: i, i2, i3 ReadOutside: WrittenInside: WrittenOutside: i, i2, i3 """, analysisResults); } [Fact] public void RegionAnalysis_04() { var analysisResults = CompileAndAnalyzeDataFlowExpression(""" static class E { extension(ref int i) { public void M(ref int i2) { _ = /*<bind>*/i + i2/*</bind>*/; } } } """); VerifyDataFlowAnalysis(""" VariablesDeclared: AlwaysAssigned: Captured: CapturedInside: CapturedOutside: DataFlowsIn: i, i2 DataFlowsOut: DefinitelyAssignedOnEntry: i, i2 DefinitelyAssignedOnExit: i, i2 ReadInside: i, i2 ReadOutside: i, i2 WrittenInside: WrittenOutside: i, i2 """, analysisResults); } [Fact] public void RegionAnalysis_05() { var analysisResults = CompileAndAnalyzeDataFlowExpression(""" static class E { extension(out int i) { public void M(out int i2) { /*<bind>*/i = i2 = 0;/*</bind>*/ } } } """); VerifyDataFlowAnalysis(""" VariablesDeclared: AlwaysAssigned: i, i2 Captured: CapturedInside: CapturedOutside: DataFlowsIn: DataFlowsOut: i, i2 DefinitelyAssignedOnEntry: DefinitelyAssignedOnExit: i, i2 ReadInside: ReadOutside: i, i2 WrittenInside: i, i2 WrittenOutside: """, analysisResults); } [Fact] public void RegionAnalysis_06() { var analysisResults = CompileAndAnalyzeDataFlowExpression(""" static class E { extension(int i) { public void M(int i2) { /*<bind>*/i = i2 = 0;/*</bind>*/ } } } """); VerifyDataFlowAnalysis(""" VariablesDeclared: AlwaysAssigned: i, i2 Captured: CapturedInside: CapturedOutside: DataFlowsIn: DataFlowsOut: DefinitelyAssignedOnEntry: i, i2 DefinitelyAssignedOnExit: i, i2 ReadInside: ReadOutside: WrittenInside: i, i2 WrittenOutside: i, i2 """, analysisResults); } [Fact] public void RegionAnalysis_07() { var analysisResults = CompileAndAnalyzeDataFlowExpression(""" static class E { extension(ref int i) { public void M(ref int i2) { /*<bind>*/i = ref i2;/*</bind>*/ } } } """); VerifyDataFlowAnalysis(""" VariablesDeclared: AlwaysAssigned: i Captured: CapturedInside: CapturedOutside: DataFlowsIn: i2 DataFlowsOut: i, i2 DefinitelyAssignedOnEntry: i, i2 DefinitelyAssignedOnExit: i, i2 ReadInside: i2 ReadOutside: i, i2 WrittenInside: i, i2 WrittenOutside: i, i2 """, analysisResults); } [Fact] public void RegionAnalysis_08() { var analysisResults = CompileAndAnalyzeDataFlowExpression(""" static class E { extension(int i) { public void M(int i2) { void local(int i3) { _ = /*<bind>*/i + i2 + i3/*</bind>*/; } } } } """); VerifyDataFlowAnalysis(""" VariablesDeclared: AlwaysAssigned: Captured: i, i2 CapturedInside: i, i2 CapturedOutside: DataFlowsIn: i3 DataFlowsOut: DefinitelyAssignedOnEntry: i, i2, i3 DefinitelyAssignedOnExit: i, i2, i3 ReadInside: i, i2, i3 ReadOutside: WrittenInside: WrittenOutside: i, i2, i3 """, analysisResults); } [Fact] public void RegionAnalysis_09() { var analysisResults = CompileAndAnalyzeDataFlowExpression(""" static class E { extension(out int i) { public void M(out int i2) { void local(out int i3) { /*<bind>*/i = i2 = i3 = 0;/*</bind>*/ } } } } """); VerifyDataFlowAnalysis(""" VariablesDeclared: AlwaysAssigned: i, i2, i3 Captured: i, i2 CapturedInside: i, i2 CapturedOutside: DataFlowsIn: DataFlowsOut: i, i2, i3 DefinitelyAssignedOnEntry: DefinitelyAssignedOnExit: i, i2, i3 ReadInside: ReadOutside: i, i2, i3 WrittenInside: i, i2, i3 WrittenOutside: """, analysisResults); } [Fact] public void RegionAnalysis_10() { // in indexer var analysisResults = CompileAndAnalyzeDataFlowExpression(""" static class E { extension(int i) { public int this[int i2] { get { _ = /*<bind>*/i + i2/*</bind>*/; return 0; } } } } """); VerifyDataFlowAnalysis(""" VariablesDeclared: AlwaysAssigned: Captured: CapturedInside: CapturedOutside: DataFlowsIn: i, i2 DataFlowsOut: DefinitelyAssignedOnEntry: i, i2 DefinitelyAssignedOnExit: i, i2 ReadInside: i, i2 ReadOutside: WrittenInside: WrittenOutside: i, i2 """, analysisResults); } } [Fact] public void Base_01() { var src = """ static class E { extension(object o) { public void M() { base.ToString(); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,13): error CS1512: Keyword 'base' is not available in the current context // base.ToString(); Diagnostic(ErrorCode.ERR_BaseInBadContext, "base").WithLocation(7, 13)); } [Fact] public void FunctionType_TypeReceiver_01() { var src = """ var x = int.M; x(); public static class E { extension<T>(T t) { public static void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, "var x = int.M"); AssertEx.Equal("System.Action", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); } [Fact] public void FunctionType_TypeReceiver_02() { var src = """ var x = int.M; public static class E { extension<T>(T t) { public void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,9): error CS8917: The delegate type could not be inferred. // var x = int.M; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "int.M").WithLocation(1, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, "var x = int.M"); Assert.True(model.GetTypeInfo(localDeclaration.Type).Type.IsErrorType()); } [Fact] public void FunctionType_TypeReceiver_03() { var src = """ var x = int.M; public static class E { public static void M<T>(this T t) { } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,9): error CS8917: The delegate type could not be inferred. // var x = int.M; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "int.M").WithLocation(1, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, "var x = int.M"); Assert.True(model.GetTypeInfo(localDeclaration.Type).Type.IsErrorType()); } [Fact] public void FunctionType_InstanceReceiver_01() { var src = """ var x = 42.M; public static class E { extension<T>(T t) { public void M() { System.Console.Write(t); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,9): error CS1113: Extension method 'E.extension<int>(int).M()' defined on value type 'int' cannot be used to create delegates // var x = 42.M; Diagnostic(ErrorCode.ERR_ValueTypeExtDelegate, "42.M").WithArguments("E.extension<int>(int).M()", "int").WithLocation(1, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, "var x = 42.M"); AssertEx.Equal("System.Action", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); } [Fact] public void FunctionType_InstanceReceiver_02() { var src = """ var x = "ran".M; x(); public static class E { extension<T>(T t) { public void M() { System.Console.Write(t); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, """var x = "ran".M"""); AssertEx.Equal("System.Action", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); } [Fact] public void FunctionType_InstanceReceiver_03() { var src = """ var x = 42.M; public static class E { extension<T>(T t) { public static void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,9): error CS8917: The delegate type could not be inferred. // var x = 42.M; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "42.M").WithLocation(1, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, "var x = 42.M"); Assert.True(model.GetTypeInfo(localDeclaration.Type).Type.IsErrorType()); } [Fact] public void FunctionType_InstanceReceiver_04() { var src = """ var x = 42.M; public static class E { extension(int i) { public void M<T>() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,9): error CS8917: The delegate type could not be inferred. // var x = 42.M; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "42.M").WithLocation(1, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, "var x = 42.M"); Assert.True(model.GetTypeInfo(localDeclaration.Type).Type.IsErrorType()); } [Fact] public void FunctionType_InstanceReceiver_05() { var src = """ var x = "ran".M<object>; x(); public static class E { extension(string s) { public void M<T>() { System.Console.Write(s); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, """var x = "ran".M<object>"""); AssertEx.Equal("System.Action", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); } [Fact] public void FunctionType_InstanceReceiver_06() { var src = """ var x = "ran".M; x(); public static class E { extension(string s) { public void M() { System.Console.Write(s); } public void M<T>(T t) { } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, """var x = "ran".M"""); AssertEx.Equal("System.Action", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); } [Fact] public void FunctionType_InstanceReceiver_07() { var src = """ namespace N { public class C { public static void Main() { var x = "".M; System.Console.Write(x); } } public static class E1 { extension(string s) { public void M<T>() { } } } } public static class E2 { extension(string s) { public int M => 42; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // (7,21): error CS8917: The delegate type could not be inferred. // var x = "".M; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, @""""".M").WithLocation(7, 21)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, """var x = "".M"""); Assert.True(model.GetTypeInfo(localDeclaration.Type).Type.IsErrorType()); } [Fact] public void FunctionType_InstanceReceiver_08() { var src = """ namespace N { public class C { public static void Main() { var x = "ran".M; x(42); } } public static class E1 { extension(string s) { public void M<T>() { } } } } public static class E2 { extension(string s) { public void M(int i) { System.Console.Write((s, i)); } } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "(ran, 42)").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, """var x = "ran".M"""); AssertEx.Equal("System.Action<System.Int32>", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); } [Fact] public void FunctionType_InstanceReceiver_09() { var src = """ var x = "ran".M; public static class E1 { extension(string s) { public void M() { } } } public static class E2 { extension(string s) { public void M(int i) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,9): error CS8917: The delegate type could not be inferred. // var x = "ran".M; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, @"""ran"".M").WithLocation(1, 9)); } [Fact] public void FunctionType_InstanceReceiver_10() { var src = """ System.Delegate x = "ran".M; x.DynamicInvoke(); id("ran".M)(); T id<T>(T t) => t; public static class E { extension(string s) { public void M() { System.Console.Write("ran "); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran ran").VerifyDiagnostics(); } [Fact] public void FunctionType_InstanceReceiver_11() { var src = """ using N; var x = "ran".M; public static class E1 { extension<T>(T t) where T : struct { public void M<U>() { } } } namespace N { public static class E2 { extension<T>(T t) { public void M() { } } } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79309")] public void FunctionType_InstanceReceiver_12() { // static non-extension method vs. extension property var src = """ var x = new C().M; public static class E { extension(C c) { public int M => 42; } } public class C { public static int M() => throw null; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,9): error CS8917: The delegate type could not be inferred. // var x = new C().M; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new C().M").WithLocation(1, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, "var x = new C().M"); Assert.Equal("?", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); // without non-extension method src = """ var x = new C().M; System.Console.Write(x); public static class E { extension(C c) { public int M => 42; } } public class C { } """; comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics(); tree = comp.SyntaxTrees.First(); model = comp.GetSemanticModel(tree); localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, "var x = new C().M"); Assert.Equal("System.Int32", model.GetTypeInfo(localDeclaration.Type).Type.ToTestDisplayString()); // analogous non-extension scenario src = """ var x = new C().M; System.Console.Write(x); public class Base { public int M => 42; } public class C : Base { public static new int M() => throw null; } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,9): error CS8917: The delegate type could not be inferred. // var x = new C().M; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new C().M").WithLocation(1, 9)); } [Fact] public void FunctionType_InstanceReceiver_13() { var src = """ var x = 42.M; public static class E { extension<T, U>(T t) { public void M(U u) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (1,9): error CS8917: The delegate type could not be inferred. // var x = 42.M; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "42.M").WithLocation(1, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var localDeclaration = GetSyntax<VariableDeclarationSyntax>(tree, "var x = 42.M"); Assert.True(model.GetTypeInfo(localDeclaration.Type).Type.IsErrorType()); } [Fact] public void FunctionType_ColorColorReceiver_01() { var src = """ Color.M2(new Color()); public class Color { public static void M2(Color Color) { var x = Color.M; x(); } } public static class E { extension<T>(T t) { public void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void FunctionType_ColorColorReceiver_02() { var src = """ Color.M2(null); public class Color { public static void M2(Color Color) { var x = Color.M; x(); } } public static class E { extension<T>(T) { public static void M() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void FunctionType_ColorColorReceiver_03() { var src = """ Color.M2(new Color()); public class Color { public static void M2(Color Color) { var x = Color.M; x(); } public void M() { System.Console.Write("ran"); } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void FunctionType_ColorColorReceiver_04() { var src = """ Color.M2(null); public class Color { public static void M2(Color Color) { var x = Color.M; x(); } public static void M() { System.Console.Write("ran"); } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void FunctionType_ColorColorReceiver_05() { var src = """ public class Color { public static void M2(Color Color) { var x = Color.M; } } public static class E1 { extension<T>(T) { public static void M() { } } } public static class E2 { extension<T>(T t) { public void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,17): error CS0121: The call is ambiguous between the following methods or properties: 'E1.extension<Color>(Color).M()' and 'E2.extension<Color>(Color).M()' // var x = Color.M; Diagnostic(ErrorCode.ERR_AmbigCall, "Color.M").WithArguments("E1.extension<Color>(Color).M()", "E2.extension<Color>(Color).M()").WithLocation(5, 17)); } [Fact] public void Params_ExtensionScopes_01() { var source = """ static class E1 { extension(N.C c) { public void M(int[] x) => System.Console.Write(3); } } namespace N { static class E2 { extension(C c) { public void M(params int[] x) => System.Console.Write(2); } } class C { public void M(params int[] x) => System.Console.Write(1); public static void Main() { var d = new C().M; System.Console.WriteLine(d.GetType()); d(); } } } """; var expectedOutput = """ <>f__AnonymousDelegate0`1[System.Int32] 1 """; CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); static void validateSymbols(ModuleSymbol module) { var m = module.GlobalNamespace.GetMember<MethodSymbol>("<>f__AnonymousDelegate0.Invoke"); AssertEx.Equal("void <>f__AnonymousDelegate0<T1>.Invoke(params T1[] arg)", m.ToTestDisplayString()); } } [Fact] public void Params_ExtensionScopes_02() { var source = """ static class E1 { extension(N.C c) { public void M(params int[] x) => System.Console.Write(3); } } namespace N { static class E2 { extension(C c) { public void M(params int[] x) => System.Console.Write(2); } } class C { public void M(params int[] x) => System.Console.Write(1); public static void Main() { var d = new C().M; System.Console.WriteLine(d.GetType()); d(); } } } """; var expectedOutput = """ <>f__AnonymousDelegate0`1[System.Int32] 1 """; CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); static void validateSymbols(ModuleSymbol module) { var m = module.GlobalNamespace.GetMember<MethodSymbol>("<>f__AnonymousDelegate0.Invoke"); AssertEx.Equal("void <>f__AnonymousDelegate0<T1>.Invoke(params T1[] arg)", m.ToTestDisplayString()); } } [Fact] public void Params_ExtensionScopes_07() { var source = """ static class E1 { extension(N.C c) { public void M(params int[] x) => System.Console.Write(1); } } namespace N { static class E2 { extension(C c) { public void M(int[] x) => System.Console.Write(2); } } class C { public static void Main() { var d = new C().M; System.Console.WriteLine(d.GetType()); d(default); } } } """; var expectedOutput = """ System.Action`1[System.Int32[]] 2 """; CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); } [Fact] public void Params_ExtensionScopes_08() { var source = """ static class E1 { extension(N.C c) { public void M(int[] x) => System.Console.Write(1); } } namespace N { static class E2 { extension(C c) { public void M(params int[] x) => System.Console.Write(2); } } class C { public static void Main() { var d = new C().M; System.Console.WriteLine(d.GetType()); d(); } } } """; var expectedOutput = """ <>f__AnonymousDelegate0`1[System.Int32] 2 """; CreateCompilation(source).VerifyDiagnostics(); CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); static void validateSymbols(ModuleSymbol module) { var m = module.GlobalNamespace.GetMember<MethodSymbol>("<>f__AnonymousDelegate0.Invoke"); AssertEx.Equal("void <>f__AnonymousDelegate0<T1>.Invoke(params T1[] arg)", m.ToTestDisplayString()); } } [Fact] public void ImplementsIEnumerableT_21_AddIsNotAnExtension() { var src = """ using System.Collections; using System.Collections.Generic; class MyCollection : IEnumerable<long> { IEnumerator<long> IEnumerable<long>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } static class Ext { extension(MyCollection c) { public void Add(long l) {} } } class Program { static void Main() { Test(); Test(1); Test(2, 3); } #line 24 static void Test(params MyCollection a) { } static void Test2() { Test([2, 3]); } } """; var comp = CreateCompilation(src, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (24,22): error CS9227: 'MyCollection' does not contain a definition for a suitable instance 'Add' method // static void Test(params MyCollection a) Diagnostic(ErrorCode.ERR_ParamsCollectionExtensionAddMethod, "params MyCollection a").WithArguments("MyCollection").WithLocation(24, 22) ); } [Fact] public void TestGetEnumeratorPatternViaExtensionWithOptionalParameter() { var source = @" using System; public class C { public static void Main() /*<bind>*/ { foreach (var i in new C()) { Console.Write(i); } } /*</bind>*/ public sealed class Enumerator { public Enumerator(int start) => Current = start; public int Current { get; private set; } public bool MoveNext() => Current++ != 3; } } public static class Extensions { extension(C self) { public C.Enumerator GetEnumerator(int x = 1) => new C.Enumerator(x); } }"; var verifier = CompileAndVerify(source, expectedOutput: "23"); VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>((CSharpCompilation)verifier.Compilation, @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { CaptureIds: [0] Block[B1] - Block Predecessors: [B0] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'new C()') Value: IInvocationOperation ( C.Enumerator Extensions.<G>$9794DAFCCB9E752B29BFD6350ADA77F2.GetEnumerator([System.Int32 x = 1])) (OperationKind.Invocation, Type: C.Enumerator, IsImplicit) (Syntax: 'new C()') Instance Receiver: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: C, IsImplicit) (Syntax: 'new C()') Conversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) (Identity) Operand: IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C()') Arguments(0) Initializer: null Arguments(1): IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: x) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'new C()') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsImplicit) (Syntax: 'new C()') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Next (Regular) Block[B2] Block[B2] - Block Predecessors: [B1] [B3] Statements (0) Jump if False (Regular) to Block[B4] IInvocationOperation ( System.Boolean C.Enumerator.MoveNext()) (OperationKind.Invocation, Type: System.Boolean, IsImplicit) (Syntax: 'new C()') Instance Receiver: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C.Enumerator, IsImplicit) (Syntax: 'new C()') Arguments(0) Leaving: {R1} Next (Regular) Block[B3] Entering: {R2} .locals {R2} { Locals: [System.Int32 i] Block[B3] - Block Predecessors: [B2] Statements (2) ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: null, IsImplicit) (Syntax: 'var') Left: ILocalReferenceOperation: i (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Int32, IsImplicit) (Syntax: 'var') Right: IPropertyReferenceOperation: System.Int32 C.Enumerator.Current { get; private set; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'var') Instance Receiver: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C.Enumerator, IsImplicit) (Syntax: 'new C()') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(i);') Expression: IInvocationOperation (void System.Console.Write(System.Int32 value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(i)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'i') ILocalReferenceOperation: i (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Next (Regular) Block[B2] Leaving: {R2} } } Block[B4] - Exit Predecessors: [B2] Statements (0) ", []); } [Fact] public void TestGetEnumeratorPatternViaExtensionWithOptionalParameter_02() { var source = @" using System; public struct C { public static void Main() /*<bind>*/ { foreach (var i in new C()) { Console.Write(i); } } /*</bind>*/ public sealed class Enumerator { public Enumerator(int start) => Current = start; public int Current { get; private set; } public bool MoveNext() => Current++ != 3; } } public static class Extensions { extension(object self) { public C.Enumerator GetEnumerator(int x = 1) => new C.Enumerator(x); } }"; var verifier = CompileAndVerify(source, expectedOutput: "23"); VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>((CSharpCompilation)verifier.Compilation, @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { CaptureIds: [0] Block[B1] - Block Predecessors: [B0] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'new C()') Value: IInvocationOperation ( C.Enumerator Extensions.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.GetEnumerator([System.Int32 x = 1])) (OperationKind.Invocation, Type: C.Enumerator, IsImplicit) (Syntax: 'new C()') Instance Receiver: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'new C()') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) (Boxing) Operand: IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C()') Arguments(0) Initializer: null Arguments(1): IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: x) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'new C()') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsImplicit) (Syntax: 'new C()') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Next (Regular) Block[B2] Block[B2] - Block Predecessors: [B1] [B3] Statements (0) Jump if False (Regular) to Block[B4] IInvocationOperation ( System.Boolean C.Enumerator.MoveNext()) (OperationKind.Invocation, Type: System.Boolean, IsImplicit) (Syntax: 'new C()') Instance Receiver: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C.Enumerator, IsImplicit) (Syntax: 'new C()') Arguments(0) Leaving: {R1} Next (Regular) Block[B3] Entering: {R2} .locals {R2} { Locals: [System.Int32 i] Block[B3] - Block Predecessors: [B2] Statements (2) ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: null, IsImplicit) (Syntax: 'var') Left: ILocalReferenceOperation: i (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Int32, IsImplicit) (Syntax: 'var') Right: IPropertyReferenceOperation: System.Int32 C.Enumerator.Current { get; private set; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'var') Instance Receiver: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C.Enumerator, IsImplicit) (Syntax: 'new C()') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(i);') Expression: IInvocationOperation (void System.Console.Write(System.Int32 value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(i)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'i') ILocalReferenceOperation: i (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Next (Regular) Block[B2] Leaving: {R2} } } Block[B4] - Exit Predecessors: [B2] Statements (0) ", []); } [Fact] public void TestMoveNextPatternViaExtensions_OnInstanceGetEnumerator() { var source = @" using System; public class C { public static void Main() { foreach (var i in new C()) { Console.Write(i); } } public sealed class Enumerator { public int Current { get; private set; } } public C.Enumerator GetEnumerator() => new C.Enumerator(); } public static class Extensions { extension(C.Enumerator e) { public bool MoveNext() => false; } }"; CreateCompilation(source) .VerifyDiagnostics( // (7,27): error CS0117: 'C.Enumerator' does not contain a definition for 'MoveNext' // foreach (var i in new C()) Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("C.Enumerator", "MoveNext").WithLocation(7, 27), // (7,27): error CS0202: foreach requires that the return type 'C.Enumerator' of 'C.GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property // foreach (var i in new C()) Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetEnumerator()").WithLocation(7, 27) ); source = """ using System; public class C { public static void Main() { foreach (var i in new C()) { Console.Write(i); } } public sealed class Enumerator { public int Current { get; private set; } } public C.Enumerator GetEnumerator() => new C.Enumerator(); } public static class Extensions { public static bool MoveNext(this C.Enumerator e) => false; } """; CreateCompilation(source) .VerifyDiagnostics( // (6,27): error CS0117: 'C.Enumerator' does not contain a definition for 'MoveNext' // foreach (var i in new C()) Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("C.Enumerator", "MoveNext").WithLocation(6, 27), // (6,27): error CS0202: foreach requires that the return type 'C.Enumerator' of 'C.GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property // foreach (var i in new C()) Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetEnumerator()").WithLocation(6, 27) ); } [Fact] public void TestMoveNextPatternViaExtensions_DelegateTypeProperty() { var src = """ using System; foreach (var i in new C()) { Console.Write(i); } public class C { public sealed class Enumerator { public int Current { get; private set; } } public C.Enumerator GetEnumerator() => new C.Enumerator(); } public static class Extensions { extension(C.Enumerator e) { public System.Func<bool> MoveNext => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (3,19): error CS0117: 'C.Enumerator' does not contain a definition for 'MoveNext' // foreach (var i in new C()) Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("C.Enumerator", "MoveNext").WithLocation(3, 19), // (3,19): error CS0202: foreach requires that the return type 'C.Enumerator' of 'C.GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property // foreach (var i in new C()) Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetEnumerator()").WithLocation(3, 19)); src = """ using System; foreach (var i in new C()) { Console.Write(i); } public class C { public sealed class Enumerator { public int Current { get; private set; } public System.Func<bool> MoveNext => throw null; } public C.Enumerator GetEnumerator() => new C.Enumerator(); } """; comp = CreateCompilation(src); comp.VerifyDiagnostics( // (3,19): error CS0202: foreach requires that the return type 'C.Enumerator' of 'C.GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property // foreach (var i in new C()) Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetEnumerator()").WithLocation(3, 19)); } [Fact] public void TestMoveNextPatternViaExtensions_DynamicTypeProperty() { var src = """ using System; foreach (var i in new C()) { Console.Write(i); } public class C { public sealed class Enumerator { public int Current { get; private set; } } public C.Enumerator GetEnumerator() => new C.Enumerator(); } public static class Extensions { extension(C.Enumerator e) { public System.Func<bool> MoveNext => throw null; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (3,19): error CS0117: 'C.Enumerator' does not contain a definition for 'MoveNext' // foreach (var i in new C()) Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("C.Enumerator", "MoveNext").WithLocation(3, 19), // (3,19): error CS0202: foreach requires that the return type 'C.Enumerator' of 'C.GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property // foreach (var i in new C()) Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetEnumerator()").WithLocation(3, 19)); src = """ using System; foreach (var i in new C()) { Console.Write(i); } public class C { public sealed class Enumerator { public int Current { get; private set; } public System.Func<bool> MoveNext => throw null; } public C.Enumerator GetEnumerator() => new C.Enumerator(); } """; comp = CreateCompilation(src); comp.VerifyDiagnostics( // (3,19): error CS0202: foreach requires that the return type 'C.Enumerator' of 'C.GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property // foreach (var i in new C()) Diagnostic(ErrorCode.ERR_BadGetEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetEnumerator()").WithLocation(3, 19)); } [Fact] public void TestMoveNextAsyncPatternViaExtensions_01() { var src = """ await foreach (var i in new C()) { } public class C { public sealed class Enumerator { public int Current { get; private set; } } public C.Enumerator GetAsyncEnumerator() => new C.Enumerator(); } public static class E { extension(C.Enumerator e) { public System.Threading.Tasks.Task<bool> MoveNextAsync() => throw null; } } """; CreateCompilation(src).VerifyEmitDiagnostics( // (1,25): error CS0117: 'C.Enumerator' does not contain a definition for 'MoveNextAsync' // await foreach (var i in new C()) Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("C.Enumerator", "MoveNextAsync").WithLocation(1, 25), // (1,25): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'C.GetAsyncEnumerator()' must have a suitable public 'MoveNextAsync' method and public 'Current' property // await foreach (var i in new C()) Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetAsyncEnumerator()").WithLocation(1, 25)); src = """ await foreach (var i in new C()) { } public class C { public sealed class Enumerator { public int Current { get; private set; } } public C.Enumerator GetAsyncEnumerator() => new C.Enumerator(); } public static class E { public static System.Threading.Tasks.Task<bool> MoveNextAsync(this C.Enumerator e) => throw null; } """; CreateCompilation(src).VerifyEmitDiagnostics( // (1,25): error CS0117: 'C.Enumerator' does not contain a definition for 'MoveNextAsync' // await foreach (var i in new C()) Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("C.Enumerator", "MoveNextAsync").WithLocation(1, 25), // (1,25): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'C.GetAsyncEnumerator()' must have a suitable public 'MoveNextAsync' method and public 'Current' property // await foreach (var i in new C()) Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetAsyncEnumerator()").WithLocation(1, 25)); src = """ await foreach (var i in new C()) { } public class C { public sealed class Enumerator { public int Current { get; private set; } public System.Threading.Tasks.Task<bool> MoveNextAsync() => throw null; } public C.Enumerator GetAsyncEnumerator() => new C.Enumerator(); } """; CreateCompilation(src).VerifyEmitDiagnostics(); } [Fact] public void TestGetEnumeratorPatternViaRefExtensionOnNonAssignableVariable() { var source = @" using System; public struct C { public static void Main() { foreach (var i in new C()) { Console.Write(i); } } public struct Enumerator { public int Current { get; private set; } public bool MoveNext() => Current++ != 3; } } public static class Extensions { extension(ref C self) { public C.Enumerator GetEnumerator() => new C.Enumerator(); } }"; CreateCompilation(source) .VerifyDiagnostics( // (7,27): error CS1510: A ref or out value must be an assignable variable // foreach (var i in new C()) Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new C()").WithLocation(7, 27)); } [Fact] public void TestGetEnumeratorPatternViaRefExtensionOnNonAssignableVariable_In() { var src = """ using System; public struct C { public static void Main() { foreach (var i in new C()) { Console.Write(i); } } public struct Enumerator { public int Current { get; private set; } public bool MoveNext() => Current++ != 3; } } public static class Extensions { extension(in C self) { public C.Enumerator GetEnumerator() => new C.Enumerator(); } } """; CreateCompilation(src).VerifyEmitDiagnostics(); src = """ using System; public struct C { public static void Main() { foreach (var i in new C()) { Console.Write(i); } } public struct Enumerator { public int Current { get; private set; } public bool MoveNext() => Current++ != 3; } } public static class Extensions { public static C.Enumerator GetEnumerator(this in C self) => new C.Enumerator(); } """; CreateCompilation(src).VerifyEmitDiagnostics(); } [Fact] public void TestGetEnumeratorPatternViaRefExtensionOnNonAssignableVariable_RefReadonly() { var src = """ using System; public struct C { public static void Main() { foreach (var i in new C()) { Console.Write(i); } } public struct Enumerator { public int Current { get; private set; } public bool MoveNext() => Current++ != 3; } } public static class Extensions { extension(ref readonly C self) { public C.Enumerator GetEnumerator() => new C.Enumerator(); } } """; CreateCompilation(src).VerifyEmitDiagnostics(); src = """ using System; public struct C { public static void Main() { foreach (var i in new C()) { Console.Write(i); } } public struct Enumerator { public int Current { get; private set; } public bool MoveNext() => Current++ != 3; } } public static class Extensions { public static C.Enumerator GetEnumerator(this ref readonly C self) => new C.Enumerator(); } """; CreateCompilation(src).VerifyEmitDiagnostics(); } [Fact] public void ExpressionTrees_01_InstanceMethod() { var src = """ using System; using System.Linq.Expressions; public static class Extensions { extension(object o) { public string M(string s) => o + s; } } class Program { static void Main() { var e = Test(); System.Console.Write(e.Compile().Invoke("1", "2")); System.Console.Write(": "); System.Console.Write(e); } static Expression<Func<object, string, string>> Test() { return (o, s) => o.M(s); } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: @"12: (o, s) => o.M(s)").VerifyDiagnostics(); } [Fact] public void ExpressionTrees_02_StaticMethod() { var src = """ using System; using System.Linq.Expressions; public static class Extensions { extension(object o) { public static string M(string s) => s; } } class Program { static void Main() { var e = Test(); System.Console.Write(e.Compile().Invoke("1")); System.Console.Write(": "); System.Console.Write(e); } static Expression<Func<string, string>> Test() { return (s) => object.M(s); } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: @"1: s => M(s)").VerifyDiagnostics(); } [Fact] public void ExpressionTrees_03_InstanceIndexer() { var src = """ using System; using System.Linq.Expressions; public static class Extensions { extension(object o) { public string this[string s] => o + s; } } class Program { static Expression<Func<object, string, string>> Test() { return (o, s) => o[s]; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (16,26): error CS9296: An expression tree may not contain an extension property or indexer access // return (o, s) => o[s]; Diagnostic(ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess, "o[s]").WithLocation(16, 26)); } [Fact] public void ExpressionTrees_04_InstanceProperty() { var src = """ using System; using System.Linq.Expressions; public static class Extensions { extension(object o) { public string P => (string)o; } } class Program { static void Main() { var e = Test(); System.Console.Write(e.Compile().Invoke("1")); System.Console.Write(": "); System.Console.Write(e); } static Expression<Func<object, string>> Test() { return (o) => o.P; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (24,23): error CS9296: An expression tree may not contain an extension property access // return (o) => o.P; Diagnostic(ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess, "o.P").WithLocation(24, 23) ); } [Fact] public void ExpressionTrees_05_InstanceProperty() { var src = """ using System; using System.Linq.Expressions; public static class Extensions { extension(object o) { public string P { get => (string)o; set {}} } } class Program { static void Main() { var e = Test(); System.Console.Write(e.Compile().Invoke("1")); System.Console.Write(": "); System.Console.Write(e); } static Expression<Func<string, object>> Test() { return (s) => new object() { P = s }; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (24,38): error CS9296: An expression tree may not contain an extension property access // return (s) => new object() { P = s }; Diagnostic(ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess, "P").WithLocation(24, 38) ); } [Fact] public void ExpressionTrees_06_InstanceProperty() { var src = """ using System; using System.Linq.Expressions; public static class Extensions { extension(object o) { public C P { get => default; } } } public class C { public string F; } class Program { static Expression<Func<string, object>> Test() { return (s) => new object() { P = { F = s } }; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (21,38): error CS9296: An expression tree may not contain an extension property access // return (s) => new object() { P = { F = s } }; Diagnostic(ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess, "P").WithLocation(21, 38) ); } [Fact] public void ExpressionTrees_07_InstanceProperty() { var src = """ using System; using System.Linq.Expressions; public static class Extensions { extension(object o) { public string P { get => default; } } } class Program { static void Main() { } static Expression<Func<object, bool>> Test() { return (o) => o is object { P: "s" }; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (20,23): error CS8122: An expression tree may not contain an 'is' pattern-matching operator. // return (o) => o is object { P: "s" }; Diagnostic(ErrorCode.ERR_ExpressionTreeContainsIsMatch, @"o is object { P: ""s"" }").WithLocation(20, 23) ); } [Fact] public void ExpressionTrees_08_StaticProperty() { var src = """ using System; using System.Linq.Expressions; public static class Extensions { extension(object o) { public static string P => "o"; } } class Program { static void Main() { var e = Test(); System.Console.Write(e.Compile().Invoke()); System.Console.Write(": "); System.Console.Write(e); } static Expression<Func<string>> Test() { return () => object.P; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (24,22): error CS9296: An expression tree may not contain an extension property access // return () => object.P; Diagnostic(ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess, "object.P").WithLocation(24, 22) ); } [Fact] public void ExpressionTrees_09_DelegateCreation_InstanceMethod() { var src = """ using System; using System.Linq.Expressions; public static class Extensions { extension(object o) { public string M(string s) => o + s; } } class Program { static void Main() { var e = Test(); System.Console.Write(e.Compile().Invoke("1").Invoke("2")); System.Console.Write(": "); System.Console.Write(e); } static Expression<Func<object, Func<string, string>>> Test() { return (o) => o.M; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: @"12: o => Convert(System.String M(System.Object, System.String).CreateDelegate(System.Func`2[System.String,System.String], o)" + (ExecutionConditionUtil.IsMonoOrCoreClr ? ", Func`2)" : ")")).VerifyDiagnostics(); } [Fact] public void ExpressionTrees_10_DelegateCreation_StaticMethod() { var src = """ using System; using System.Linq.Expressions; public static class Extensions { extension(object o) { public static string M(string s) => s; } } class Program { static void Main() { var e = Test(); System.Console.Write(e.Compile().Invoke().Invoke("1")); System.Console.Write(": "); System.Console.Write(e); } static Expression<Func<Func<string, string>>> Test() { return () => object.M; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: @"1: () => Convert(System.String M(System.String).CreateDelegate(System.Func`2[System.String,System.String], null)" + (ExecutionConditionUtil.IsMonoOrCoreClr ? ", Func`2)" : ")")).VerifyDiagnostics(); } [Fact] public void ExpressionTrees_11_InstanceIndexer() { var src = """ using System; using System.Linq.Expressions; Expression<Func<object>> e = () => new object() { [""] = "" }; public static class Extensions { extension(object o) { public string this[string s] { set { } } } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (4,51): error CS8074: An expression tree lambda may not contain a dictionary initializer. // Expression<Func<object>> e = () => new object() { [""] = "" }; Diagnostic(ErrorCode.ERR_DictionaryInitializerInExpressionTree, @"[""""]").WithLocation(4, 51), // (4,51): error CS9296: An expression tree may not contain an extension property or indexer access // Expression<Func<object>> e = () => new object() { [""] = "" }; Diagnostic(ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess, @"[""""]").WithLocation(4, 51)); } [Fact] public void ExpressionTrees_11() { // target-typed object creation with nested initializer var src = """ using System; using System.Linq.Expressions; public static class Extensions { extension(object o) { public C P { get => default; } } } public class C { public string F; } class Program { static Expression<Func<string, object>> Test() { return (s) => new() { P = { F = s } }; } } """; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (21,31): error CS9296: An expression tree may not contain an extension property access // return (s) => new() { P = { F = s } }; Diagnostic(ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess, "P").WithLocation(21, 31) ); } [Fact] public void ReceiverParameterValidation_Async_01() { string source = """ unsafe static class E { extension(int* i) { public static async void M() => throw null; public async void M2() => throw null; } } """; var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll); comp.VerifyEmitDiagnostics( // (3,15): error CS1103: The receiver parameter of an extension cannot be of type 'int*' // extension(int* i) Diagnostic(ErrorCode.ERR_BadTypeforThis, "int*").WithArguments("int*").WithLocation(3, 15) ); } [Fact] public void ReceiverParameterValidation_Async_02() { string source = """ static class E { extension(ref int i) { public static async void M() { await System.Threading.Tasks.Task.Yield(); } public async void M2() { await System.Threading.Tasks.Task.Yield(); } } } """; var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll); comp.VerifyEmitDiagnostics( // (6,27): error CS1988: Async methods cannot have ref, in or out parameters // public async void M2() { await System.Threading.Tasks.Task.Yield(); } Diagnostic(ErrorCode.ERR_BadAsyncArgType, "M2").WithLocation(6, 27)); } [Fact] public void ReceiverParameterValidation_Async_03() { string source = """ static class E { extension(System.Span<int> i) { public static async void M() { await System.Threading.Tasks.Task.Yield(); } } extension(System.Span<int> i) { public async void M2() { await System.Threading.Tasks.Task.Yield(); } } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (9,27): error CS4012: Parameters of type 'Span<int>' cannot be declared in async methods or async lambda expressions. // public async void M2() { await System.Threading.Tasks.Task.Yield(); } Diagnostic(ErrorCode.ERR_BadSpecialByRefParameter, "M2").WithArguments("System.Span<int>").WithLocation(9, 27)); } [Fact] public void ReceiverParameterValidation_Iterator_01() { string source = """ static class E { extension(ref int i) { public static System.Collections.Generic.IEnumerator<int> M() { yield return 0; } } extension(ref int i) { public System.Collections.Generic.IEnumerator<int> M2() { yield return 0; } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (9,60): error CS1623: Iterators cannot have ref, in or out parameters // public System.Collections.Generic.IEnumerator<int> M2() { yield return 0; } Diagnostic(ErrorCode.ERR_BadIteratorArgType, "M2").WithLocation(9, 60)); } [Fact] public void ReceiverParameterValidation_Iterator_02() { string source = """ unsafe static class E { extension(int* i) { public static System.Collections.Generic.IEnumerator<int> M() { yield return 0; } } extension(int* i) { public System.Collections.Generic.IEnumerator<int> M2() { yield return 0; } } } """; var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll); comp.VerifyEmitDiagnostics( // (3,15): error CS1103: The receiver parameter of an extension cannot be of type 'int*' // extension(int* i) Diagnostic(ErrorCode.ERR_BadTypeforThis, "int*").WithArguments("int*").WithLocation(3, 15), // (7,15): error CS1103: The receiver parameter of an extension cannot be of type 'int*' // extension(int* i) Diagnostic(ErrorCode.ERR_BadTypeforThis, "int*").WithArguments("int*").WithLocation(7, 15)); } [Fact] public void ReceiverParameterValidation_CancellationTokenParameter_Static() { string source = """ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; static class C { extension([EnumeratorCancellation] CancellationToken token1) { static async System.Collections.Generic.IAsyncEnumerable<int> Iter(int value, [EnumeratorCancellation] CancellationToken token2) { _ = token2.IsCancellationRequested; yield return value++; await Task.Yield(); } } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); comp.VerifyDiagnostics( // (7,16): warning CS8424: The EnumeratorCancellationAttribute applied to parameter 'token1' will have no effect. The attribute is only effective on a parameter of type CancellationToken in an async-iterator method returning IAsyncEnumerable // extension([EnumeratorCancellation] CancellationToken token1) Diagnostic(ErrorCode.WRN_UnconsumedEnumeratorCancellationAttributeUsage, "EnumeratorCancellation").WithArguments("token1").WithLocation(7, 16)); var verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify); verifier.VerifyIL("C.<Iter>d__1.System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)", """ { // Code size 188 (0xbc) .maxstack 3 .locals init (C.<Iter>d__1 V_0, System.Threading.CancellationToken V_1) IL_0000: ldarg.0 IL_0001: ldfld "int C.<Iter>d__1.<>1__state" IL_0006: ldc.i4.s -2 IL_0008: bne.un.s IL_0035 IL_000a: ldarg.0 IL_000b: ldfld "int C.<Iter>d__1.<>l__initialThreadId" IL_0010: call "int System.Environment.CurrentManagedThreadId.get" IL_0015: bne.un.s IL_0035 IL_0017: ldarg.0 IL_0018: ldc.i4.s -3 IL_001a: stfld "int C.<Iter>d__1.<>1__state" IL_001f: ldarg.0 IL_0020: call "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create()" IL_0025: stfld "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.<Iter>d__1.<>t__builder" IL_002a: ldarg.0 IL_002b: ldc.i4.0 IL_002c: stfld "bool C.<Iter>d__1.<>w__disposeMode" IL_0031: ldarg.0 IL_0032: stloc.0 IL_0033: br.s IL_003d IL_0035: ldc.i4.s -3 IL_0037: newobj "C.<Iter>d__1..ctor(int)" IL_003c: stloc.0 IL_003d: ldloc.0 IL_003e: ldarg.0 IL_003f: ldfld "int C.<Iter>d__1.<>3__value" IL_0044: stfld "int C.<Iter>d__1.value" IL_0049: ldarg.0 IL_004a: ldflda "System.Threading.CancellationToken C.<Iter>d__1.<>3__token2" IL_004f: ldloca.s V_1 IL_0051: initobj "System.Threading.CancellationToken" IL_0057: ldloc.1 IL_0058: call "bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)" IL_005d: brfalse.s IL_0068 IL_005f: ldloc.0 IL_0060: ldarg.1 IL_0061: stfld "System.Threading.CancellationToken C.<Iter>d__1.token2" IL_0066: br.s IL_00ba IL_0068: ldarga.s V_1 IL_006a: ldarg.0 IL_006b: ldfld "System.Threading.CancellationToken C.<Iter>d__1.<>3__token2" IL_0070: call "bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)" IL_0075: brtrue.s IL_0089 IL_0077: ldarga.s V_1 IL_0079: ldloca.s V_1 IL_007b: initobj "System.Threading.CancellationToken" IL_0081: ldloc.1 IL_0082: call "bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)" IL_0087: brfalse.s IL_0097 IL_0089: ldloc.0 IL_008a: ldarg.0 IL_008b: ldfld "System.Threading.CancellationToken C.<Iter>d__1.<>3__token2" IL_0090: stfld "System.Threading.CancellationToken C.<Iter>d__1.token2" IL_0095: br.s IL_00ba IL_0097: ldarg.0 IL_0098: ldarg.0 IL_0099: ldfld "System.Threading.CancellationToken C.<Iter>d__1.<>3__token2" IL_009e: ldarg.1 IL_009f: call "System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)" IL_00a4: stfld "System.Threading.CancellationTokenSource C.<Iter>d__1.<>x__combinedTokens" IL_00a9: ldloc.0 IL_00aa: ldarg.0 IL_00ab: ldfld "System.Threading.CancellationTokenSource C.<Iter>d__1.<>x__combinedTokens" IL_00b0: callvirt "System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get" IL_00b5: stfld "System.Threading.CancellationToken C.<Iter>d__1.token2" IL_00ba: ldloc.0 IL_00bb: ret } """); } [Fact] public void ReceiverParameterValidation_CancellationTokenParameter_Static_FirstParameter() { string source = """ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; static class C { extension(int) { static async System.Collections.Generic.IAsyncEnumerable<int> Iter([EnumeratorCancellation] CancellationToken token) { _ = token.IsCancellationRequested; yield return 0; await Task.Yield(); } } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify); verifier.VerifyIL("C.<Iter>d__1.System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)", """ { // Code size 176 (0xb0) .maxstack 3 .locals init (C.<Iter>d__1 V_0, System.Threading.CancellationToken V_1) IL_0000: ldarg.0 IL_0001: ldfld "int C.<Iter>d__1.<>1__state" IL_0006: ldc.i4.s -2 IL_0008: bne.un.s IL_0035 IL_000a: ldarg.0 IL_000b: ldfld "int C.<Iter>d__1.<>l__initialThreadId" IL_0010: call "int System.Environment.CurrentManagedThreadId.get" IL_0015: bne.un.s IL_0035 IL_0017: ldarg.0 IL_0018: ldc.i4.s -3 IL_001a: stfld "int C.<Iter>d__1.<>1__state" IL_001f: ldarg.0 IL_0020: call "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create()" IL_0025: stfld "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.<Iter>d__1.<>t__builder" IL_002a: ldarg.0 IL_002b: ldc.i4.0 IL_002c: stfld "bool C.<Iter>d__1.<>w__disposeMode" IL_0031: ldarg.0 IL_0032: stloc.0 IL_0033: br.s IL_003d IL_0035: ldc.i4.s -3 IL_0037: newobj "C.<Iter>d__1..ctor(int)" IL_003c: stloc.0 IL_003d: ldarg.0 IL_003e: ldflda "System.Threading.CancellationToken C.<Iter>d__1.<>3__token" IL_0043: ldloca.s V_1 IL_0045: initobj "System.Threading.CancellationToken" IL_004b: ldloc.1 IL_004c: call "bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)" IL_0051: brfalse.s IL_005c IL_0053: ldloc.0 IL_0054: ldarg.1 IL_0055: stfld "System.Threading.CancellationToken C.<Iter>d__1.token" IL_005a: br.s IL_00ae IL_005c: ldarga.s V_1 IL_005e: ldarg.0 IL_005f: ldfld "System.Threading.CancellationToken C.<Iter>d__1.<>3__token" IL_0064: call "bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)" IL_0069: brtrue.s IL_007d IL_006b: ldarga.s V_1 IL_006d: ldloca.s V_1 IL_006f: initobj "System.Threading.CancellationToken" IL_0075: ldloc.1 IL_0076: call "bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)" IL_007b: brfalse.s IL_008b IL_007d: ldloc.0 IL_007e: ldarg.0 IL_007f: ldfld "System.Threading.CancellationToken C.<Iter>d__1.<>3__token" IL_0084: stfld "System.Threading.CancellationToken C.<Iter>d__1.token" IL_0089: br.s IL_00ae IL_008b: ldarg.0 IL_008c: ldarg.0 IL_008d: ldfld "System.Threading.CancellationToken C.<Iter>d__1.<>3__token" IL_0092: ldarg.1 IL_0093: call "System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)" IL_0098: stfld "System.Threading.CancellationTokenSource C.<Iter>d__1.<>x__combinedTokens" IL_009d: ldloc.0 IL_009e: ldarg.0 IL_009f: ldfld "System.Threading.CancellationTokenSource C.<Iter>d__1.<>x__combinedTokens" IL_00a4: callvirt "System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get" IL_00a9: stfld "System.Threading.CancellationToken C.<Iter>d__1.token" IL_00ae: ldloc.0 IL_00af: ret } """); } [Fact] public void ReceiverParameterValidation_CancellationTokenParameter_Instance() { string source = """ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; static class C { extension([EnumeratorCancellation] CancellationToken token1) { async System.Collections.Generic.IAsyncEnumerable<int> Iter(int value) { _ = token1.IsCancellationRequested; yield return value++; await Task.Yield(); } } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); comp.VerifyDiagnostics( // (7,16): warning CS8424: The EnumeratorCancellationAttribute applied to parameter 'token1' will have no effect. The attribute is only effective on a parameter of type CancellationToken in an async-iterator method returning IAsyncEnumerable // extension([EnumeratorCancellation] CancellationToken token1) Diagnostic(ErrorCode.WRN_UnconsumedEnumeratorCancellationAttributeUsage, "EnumeratorCancellation").WithArguments("token1").WithLocation(7, 16)); var verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify); verifier.VerifyIL("C.<Iter>d__1.System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)", """ { // Code size 87 (0x57) .maxstack 2 .locals init (C.<Iter>d__1 V_0) IL_0000: ldarg.0 IL_0001: ldfld "int C.<Iter>d__1.<>1__state" IL_0006: ldc.i4.s -2 IL_0008: bne.un.s IL_0035 IL_000a: ldarg.0 IL_000b: ldfld "int C.<Iter>d__1.<>l__initialThreadId" IL_0010: call "int System.Environment.CurrentManagedThreadId.get" IL_0015: bne.un.s IL_0035 IL_0017: ldarg.0 IL_0018: ldc.i4.s -3 IL_001a: stfld "int C.<Iter>d__1.<>1__state" IL_001f: ldarg.0 IL_0020: call "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create()" IL_0025: stfld "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.<Iter>d__1.<>t__builder" IL_002a: ldarg.0 IL_002b: ldc.i4.0 IL_002c: stfld "bool C.<Iter>d__1.<>w__disposeMode" IL_0031: ldarg.0 IL_0032: stloc.0 IL_0033: br.s IL_003d IL_0035: ldc.i4.s -3 IL_0037: newobj "C.<Iter>d__1..ctor(int)" IL_003c: stloc.0 IL_003d: ldloc.0 IL_003e: ldarg.0 IL_003f: ldfld "System.Threading.CancellationToken C.<Iter>d__1.<>3__token1" IL_0044: stfld "System.Threading.CancellationToken C.<Iter>d__1.token1" IL_0049: ldloc.0 IL_004a: ldarg.0 IL_004b: ldfld "int C.<Iter>d__1.<>3__value" IL_0050: stfld "int C.<Iter>d__1.value" IL_0055: ldloc.0 IL_0056: ret } """); } [Fact] public void ReceiverParameterValidation_CancellationTokenParameter_Instance_Multiple() { string source = """ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; static class C { extension([EnumeratorCancellation] CancellationToken token1) { async System.Collections.Generic.IAsyncEnumerable<int> Iter(int value, [EnumeratorCancellation] CancellationToken token2) { _ = token1.IsCancellationRequested; _ = token2.IsCancellationRequested; yield return value++; await Task.Yield(); } } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); comp.VerifyDiagnostics( // (7,16): warning CS8424: The EnumeratorCancellationAttribute applied to parameter 'token1' will have no effect. The attribute is only effective on a parameter of type CancellationToken in an async-iterator method returning IAsyncEnumerable // extension([EnumeratorCancellation] CancellationToken token1) Diagnostic(ErrorCode.WRN_UnconsumedEnumeratorCancellationAttributeUsage, "EnumeratorCancellation").WithArguments("token1").WithLocation(7, 16)); var verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify); verifier.VerifyIL("C.<Iter>d__1.System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)", """ { // Code size 200 (0xc8) .maxstack 3 .locals init (C.<Iter>d__1 V_0, System.Threading.CancellationToken V_1) IL_0000: ldarg.0 IL_0001: ldfld "int C.<Iter>d__1.<>1__state" IL_0006: ldc.i4.s -2 IL_0008: bne.un.s IL_0035 IL_000a: ldarg.0 IL_000b: ldfld "int C.<Iter>d__1.<>l__initialThreadId" IL_0010: call "int System.Environment.CurrentManagedThreadId.get" IL_0015: bne.un.s IL_0035 IL_0017: ldarg.0 IL_0018: ldc.i4.s -3 IL_001a: stfld "int C.<Iter>d__1.<>1__state" IL_001f: ldarg.0 IL_0020: call "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create()" IL_0025: stfld "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.<Iter>d__1.<>t__builder" IL_002a: ldarg.0 IL_002b: ldc.i4.0 IL_002c: stfld "bool C.<Iter>d__1.<>w__disposeMode" IL_0031: ldarg.0 IL_0032: stloc.0 IL_0033: br.s IL_003d IL_0035: ldc.i4.s -3 IL_0037: newobj "C.<Iter>d__1..ctor(int)" IL_003c: stloc.0 IL_003d: ldloc.0 IL_003e: ldarg.0 IL_003f: ldfld "System.Threading.CancellationToken C.<Iter>d__1.<>3__token1" IL_0044: stfld "System.Threading.CancellationToken C.<Iter>d__1.token1" IL_0049: ldloc.0 IL_004a: ldarg.0 IL_004b: ldfld "int C.<Iter>d__1.<>3__value" IL_0050: stfld "int C.<Iter>d__1.value" IL_0055: ldarg.0 IL_0056: ldflda "System.Threading.CancellationToken C.<Iter>d__1.<>3__token2" IL_005b: ldloca.s V_1 IL_005d: initobj "System.Threading.CancellationToken" IL_0063: ldloc.1 IL_0064: call "bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)" IL_0069: brfalse.s IL_0074 IL_006b: ldloc.0 IL_006c: ldarg.1 IL_006d: stfld "System.Threading.CancellationToken C.<Iter>d__1.token2" IL_0072: br.s IL_00c6 IL_0074: ldarga.s V_1 IL_0076: ldarg.0 IL_0077: ldfld "System.Threading.CancellationToken C.<Iter>d__1.<>3__token2" IL_007c: call "bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)" IL_0081: brtrue.s IL_0095 IL_0083: ldarga.s V_1 IL_0085: ldloca.s V_1 IL_0087: initobj "System.Threading.CancellationToken" IL_008d: ldloc.1 IL_008e: call "bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)" IL_0093: brfalse.s IL_00a3 IL_0095: ldloc.0 IL_0096: ldarg.0 IL_0097: ldfld "System.Threading.CancellationToken C.<Iter>d__1.<>3__token2" IL_009c: stfld "System.Threading.CancellationToken C.<Iter>d__1.token2" IL_00a1: br.s IL_00c6 IL_00a3: ldarg.0 IL_00a4: ldarg.0 IL_00a5: ldfld "System.Threading.CancellationToken C.<Iter>d__1.<>3__token2" IL_00aa: ldarg.1 IL_00ab: call "System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)" IL_00b0: stfld "System.Threading.CancellationTokenSource C.<Iter>d__1.<>x__combinedTokens" IL_00b5: ldloc.0 IL_00b6: ldarg.0 IL_00b7: ldfld "System.Threading.CancellationTokenSource C.<Iter>d__1.<>x__combinedTokens" IL_00bc: callvirt "System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get" IL_00c1: stfld "System.Threading.CancellationToken C.<Iter>d__1.token2" IL_00c6: ldloc.0 IL_00c7: ret } """); } [Fact] public void ReceiverParameterValidation_UnnamedReceiverParameter() { string source = """ static class E { extension(int i) { public void M1() { } public static void M2() { } public int P1 => 0; public static int P2 => 0; } extension(int) { public void M3() { } // 1 public static void M4() { } public int P3 => 0; // 2 public static int P4 => 0; public int this[int j] => 0; // 3 } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (12,21): error CS9303: 'M3': cannot declare instance members in an extension block with an unnamed receiver parameter // public void M3() { } // 1 Diagnostic(ErrorCode.ERR_InstanceMemberWithUnnamedExtensionsParameter, "M3").WithArguments("M3").WithLocation(12, 21), // (14,20): error CS9303: 'P3': cannot declare instance members in an extension block with an unnamed receiver parameter // public int P3 => 0; // 2 Diagnostic(ErrorCode.ERR_InstanceMemberWithUnnamedExtensionsParameter, "P3").WithArguments("P3").WithLocation(14, 20), // (16,20): error CS9303: 'this[]': cannot declare instance members in an extension block with an unnamed receiver parameter // public int this[int j] => 0; // 3 Diagnostic(ErrorCode.ERR_InstanceMemberWithUnnamedExtensionsParameter, "this").WithArguments("this[]").WithLocation(16, 20)); } [Fact] public void ReceiverParameterValidation_UnnamedReceiverParameter_Ref() { string source = """ static class E { extension(ref int) { } extension(ref string) { } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (3,19): error CS9305: Cannot use modifiers on the unnamed receiver parameter of extension block // extension(ref int) Diagnostic(ErrorCode.ERR_ModifierOnUnnamedReceiverParameter, "int").WithLocation(3, 19), // (6,19): error CS9300: The 'ref' receiver parameter of an extension block must be a value type or a generic type constrained to struct. // extension(ref string) Diagnostic(ErrorCode.ERR_RefExtensionParameterMustBeValueTypeOrConstrainedToOne, "string").WithLocation(6, 19), // (6,19): error CS9305: Cannot use modifiers on the unnamed receiver parameter of extension block // extension(ref string) Diagnostic(ErrorCode.ERR_ModifierOnUnnamedReceiverParameter, "string").WithLocation(6, 19)); } [Fact] public void ReceiverParameterValidation_UnnamedReceiverParameter_Out() { string source = """ static class E { extension(out int) { } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (3,15): error CS8328: The parameter modifier 'out' cannot be used with 'extension' // extension(out int) Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15), // (3,19): error CS9305: Cannot use modifiers on the unnamed receiver parameter of extension block // extension(out int) Diagnostic(ErrorCode.ERR_ModifierOnUnnamedReceiverParameter, "int").WithLocation(3, 19)); } [Fact] public void ReceiverParameterValidation_UnnamedReceiverParameter_Scoped() { // Tracked by https://github.com/dotnet/roslyn/issues/78961 : This should probably parse (but still error) string source = """ static class E { extension(scoped RS) { } } ref struct RS { } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (3,15): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?) // extension(scoped RS) Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(3, 15)); } [Fact] public void ReceiverParameterValidation_UnnamedReceiverParameter_FromMetadata() { // extension(int) // { // public void M3() { } // public static void M4() { } // public int P3 => 0; // public static int P4 => 0; // } // Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading) var ilSrc = """ .class public auto ansi abstract sealed beforefieldinit E extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi abstract sealed specialname '<Marker>$F4B4FFE41AB49E80A4ECF390CF6EB372' extends System.Object { .method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) IL_0000: ret } } .method public hidebysig instance void M3 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) IL_0000: ldnull IL_0001: throw } .method public hidebysig static void M4 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) IL_0000: ldnull IL_0001: throw } .method public hidebysig specialname instance int32 get_P3 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) IL_0000: ldnull IL_0001: throw } .method public hidebysig specialname static int32 get_P4 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) IL_0000: ldnull IL_0001: throw } .property instance int32 P3() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) .get instance int32 E/'<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P3() } .property int32 P4() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) .get int32 E/'<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P4() } } .method public hidebysig static void M3 ( int32 '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) IL_0000: ret } .method public hidebysig static void M4 () cil managed { IL_0000: ret } .method public hidebysig static int32 get_P3 ( int32 '' ) cil managed { IL_0000: ldc.i4.0 IL_0001: ret } .method public hidebysig static int32 get_P4 () cil managed { IL_0000: ldc.i4.0 IL_0001: ret } } """ + ExtensionMarkerAttributeIL; string source = """ 42.M3(); int.M4(); _ = 42.P3; _ = int.P4; """; var comp = CreateCompilationWithIL(source, ilSrc); comp.VerifyEmitDiagnostics(); } [Fact] public void AsyncInSecurityCriticalClass() { var source = """ using System.Security; using System.Threading.Tasks; [SecurityCritical] public static class C { extension(int i) { public async void M() { await Task.Factory.StartNew(() => { }); } } } """; CreateCompilation(source).VerifyDiagnostics( // (9,27): error CS4031: Async methods are not allowed in an Interface, Class, or Structure which has the 'SecurityCritical' or 'SecuritySafeCritical' attribute. // public async void M() Diagnostic(ErrorCode.ERR_SecurityCriticalOrSecuritySafeCriticalOnAsyncInClassOrStruct, "M").WithLocation(9, 27)); } [Fact] public void Validation_Modifiers_Virtual() { string source = """ static class E { extension(int i) { public virtual void M() { } public virtual int P { get => 0; set { } } public virtual int this[int j] { get => 0; set { } } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,29): error CS0106: The modifier 'virtual' is not valid for this item // public virtual void M() { } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("virtual").WithLocation(5, 29), // (6,28): error CS0106: The modifier 'virtual' is not valid for this item // public virtual int P { get => 0; set { } } Diagnostic(ErrorCode.ERR_BadMemberFlag, "P").WithArguments("virtual").WithLocation(6, 28), // (7,28): error CS0106: The modifier 'virtual' is not valid for this item // public virtual int this[int j] { get => 0; set { } } Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("virtual").WithLocation(7, 28)); } [Fact] public void Validation_Modifiers_Abstract() { string source = """ static class E { extension(int i) { public abstract void M(); public abstract int P { get; } public abstract int P2 { set; } public abstract int this[int j] { get; } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,30): error CS0106: The modifier 'abstract' is not valid for this item // public abstract void M(); Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("abstract").WithLocation(5, 30), // (5,30): error CS0501: 'E.extension(int).M()' must declare a body because it is not marked abstract, extern, or partial // public abstract void M(); Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M").WithArguments("E.extension(int).M()").WithLocation(5, 30), // (6,29): error CS0106: The modifier 'abstract' is not valid for this item // public abstract int P { get; } Diagnostic(ErrorCode.ERR_BadMemberFlag, "P").WithArguments("abstract").WithLocation(6, 29), // (6,29): error CS9282: This member is not allowed in an extension block // public abstract int P { get; } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "P").WithLocation(6, 29), // (7,29): error CS0106: The modifier 'abstract' is not valid for this item // public abstract int P2 { set; } Diagnostic(ErrorCode.ERR_BadMemberFlag, "P2").WithArguments("abstract").WithLocation(7, 29), // (7,29): error CS9282: This member is not allowed in an extension block // public abstract int P2 { set; } Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "P2").WithLocation(7, 29), // (7,34): error CS8051: Auto-implemented properties must have get accessors. // public abstract int P2 { set; } Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithLocation(7, 34), // (8,29): error CS0106: The modifier 'abstract' is not valid for this item // public abstract int this[int j] { get; } Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("abstract").WithLocation(8, 29), // (8,43): error CS0501: 'E.extension(int).this[int].get' must declare a body because it is not marked abstract, extern, or partial // public abstract int this[int j] { get; } Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("E.extension(int).this[int].get").WithLocation(8, 43)); } [Fact] public void Validation_Modifiers_New() { string source = """ static class E { extension(int i) { public new string ToString() => ""; public new int P { get => 0; } public new int this[int j] { get => 0; } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,27): error CS0106: The modifier 'new' is not valid for this item // public new string ToString() => ""; Diagnostic(ErrorCode.ERR_BadMemberFlag, "ToString").WithArguments("new").WithLocation(5, 27), // (6,24): error CS0106: The modifier 'new' is not valid for this item // public new int P { get => 0; } Diagnostic(ErrorCode.ERR_BadMemberFlag, "P").WithArguments("new").WithLocation(6, 24), // (7,24): error CS0106: The modifier 'new' is not valid for this item // public new int this[int j] { get => 0; } Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("new").WithLocation(7, 24)); } [Fact] public void Validation_Modifiers_Override() { string source = """ static class E { extension(int i) { public override string ToString() => ""; public override int P { get => 0; } public override int this[int j] { get => 0; } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,32): error CS0106: The modifier 'override' is not valid for this item // public override string ToString() => ""; Diagnostic(ErrorCode.ERR_BadMemberFlag, "ToString").WithArguments("override").WithLocation(5, 32), // (6,29): error CS0106: The modifier 'override' is not valid for this item // public override int P { get => 0; } Diagnostic(ErrorCode.ERR_BadMemberFlag, "P").WithArguments("override").WithLocation(6, 29), // (7,29): error CS0106: The modifier 'override' is not valid for this item // public override int this[int j] { get => 0; } Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("override").WithLocation(7, 29)); } [Fact] public void Validation_Modifiers_Partial() { string source = """ static class E { extension(int i) { partial void M(); partial void M() { } partial int P { get; set; } partial int P { get => 0; set { } } partial int this[int j] { get; } partial int this[int j] { get => 0; } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,22): error CS0751: A partial member must be declared within a partial type // partial void M(); Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "M").WithLocation(5, 22), // (6,22): error CS0751: A partial member must be declared within a partial type // partial void M() { } Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "M").WithLocation(6, 22), // (7,21): error CS0751: A partial member must be declared within a partial type // partial int P { get; set; } Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "P").WithLocation(7, 21), // (9,21): error CS0751: A partial member must be declared within a partial type // partial int this[int j] { get; } Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "this").WithLocation(9, 21)); } [Fact] public void Validation_Modifiers_Sealed() { string source = """ static class E { extension(int i) { sealed void M() { } sealed int P { get => 0; set { } } sealed int this[int j] { get => 0; } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,21): error CS0106: The modifier 'sealed' is not valid for this item // sealed void M() { } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("sealed").WithLocation(5, 21), // (6,20): error CS0106: The modifier 'sealed' is not valid for this item // sealed int P { get => 0; set { } } Diagnostic(ErrorCode.ERR_BadMemberFlag, "P").WithArguments("sealed").WithLocation(6, 20), // (7,20): error CS0106: The modifier 'sealed' is not valid for this item // sealed int this[int j] { get => 0; } Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("sealed").WithLocation(7, 20)); } [Fact] public void Validation_Modifiers_Readonly() { string source = """ static class E { extension(int i) { readonly void M() { } readonly int P { get => 0; set { } } int P2 { readonly get => 0; readonly set { } } readonly int this[int j] { get => 0; } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,23): error CS0106: The modifier 'readonly' is not valid for this item // readonly void M() { } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("readonly").WithLocation(5, 23), // (6,22): error CS0106: The modifier 'readonly' is not valid for this item // readonly int P { get => 0; set { } } Diagnostic(ErrorCode.ERR_BadMemberFlag, "P").WithArguments("readonly").WithLocation(6, 22), // (7,27): error CS0106: The modifier 'readonly' is not valid for this item // int P2 { readonly get => 0; readonly set { } } Diagnostic(ErrorCode.ERR_BadMemberFlag, "get").WithArguments("readonly").WithLocation(7, 27), // (7,46): error CS0106: The modifier 'readonly' is not valid for this item // int P2 { readonly get => 0; readonly set { } } Diagnostic(ErrorCode.ERR_BadMemberFlag, "set").WithArguments("readonly").WithLocation(7, 46), // (8,22): error CS0106: The modifier 'readonly' is not valid for this item // readonly int this[int j] { get => 0; } Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("readonly").WithLocation(8, 22)); } [Fact] public void Validation_Modifiers_Required() { string source = """ static class E { extension(int i) { required void M() { } required int P { get => 0; set { } } required int this[int j] { get => 0; } } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (5,23): error CS0106: The modifier 'required' is not valid for this item // required void M() { } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("required").WithLocation(5, 23), // (6,22): error CS0106: The modifier 'required' is not valid for this item // required int P { get => 0; set { } } Diagnostic(ErrorCode.ERR_BadMemberFlag, "P").WithArguments("required").WithLocation(6, 22), // (7,22): error CS0106: The modifier 'required' is not valid for this item // required int this[int j] { get => 0; } Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("required").WithLocation(7, 22)); } [Fact] public void Extern_01() { string source = """ static class E { extension(int i) { extern void M() { } extern int P { get => 0; set { } } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,21): error CS0179: 'E.extension(int).M()' cannot be extern and declare a body // extern void M() { } Diagnostic(ErrorCode.ERR_ExternHasBody, "M").WithArguments("E.extension(int).M()").WithLocation(5, 21), // (6,24): error CS0179: 'E.extension(int).P.get' cannot be extern and declare a body // extern int P { get => 0; set { } } Diagnostic(ErrorCode.ERR_ExternHasBody, "get").WithArguments("E.extension(int).P.get").WithLocation(6, 24), // (6,34): error CS0179: 'E.extension(int).P.set' cannot be extern and declare a body // extern int P { get => 0; set { } } Diagnostic(ErrorCode.ERR_ExternHasBody, "set").WithArguments("E.extension(int).P.set").WithLocation(6, 34)); } [Fact] public void Extern_02() { var source = """ using System.Runtime.InteropServices; static class E { extension(int) { [DllImport("something.dll")] static extern void M(); static extern int P { [DllImport("something.dll")] get; [DllImport("something.dll")] set; } } } """; var verifier = CompileAndVerify(source).VerifyDiagnostics(); // Note: skeleton methods have "throw" bodies and lack pinvokeimpl/preservesig. Implementation methods have pinvokeimpl/preservesig and no body. verifier.VerifyTypeIL("E", """ .class private auto ansi abstract sealed beforefieldinit E extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2085 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::'<Extension>$' } // end of class <M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69 // Methods .method private hidebysig static void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 42 41 34 31 43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39 30 36 32 46 35 39 45 44 34 44 36 39 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::M .method private hidebysig specialname static int32 get_P () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 42 41 34 31 43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39 30 36 32 46 35 39 45 44 34 44 36 39 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P .method private hidebysig specialname static void set_P ( int32 'value' ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 42 41 34 31 43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39 30 36 32 46 35 39 45 44 34 44 36 39 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P // Properties .property int32 P() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 42 41 34 31 43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39 30 36 32 46 35 39 45 44 34 44 36 39 00 00 ) .get int32 E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P() .set void E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P(int32) } } // end of class <G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69 // Methods .method private hidebysig static pinvokeimpl("something.dll" winapi) void M () cil managed preservesig { } // end of method E::M .method private hidebysig static pinvokeimpl("something.dll" winapi) int32 get_P () cil managed preservesig { } // end of method E::get_P .method private hidebysig static pinvokeimpl("something.dll" winapi) void set_P ( int32 'value' ) cil managed preservesig { } // end of method E::set_P } // end of class E """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } [Fact] public void Extern_03() { var source = """ using System.Runtime.InteropServices; static class E { extension(int i) { [DllImport("something.dll")] extern void M(); extern int P { [DllImport("something.dll")] get; [DllImport("something.dll")] set; } } } """; var comp = CreateCompilation(source); var verifier = CompileAndVerify(source).VerifyDiagnostics(); verifier.VerifyTypeIL("E", """ .class private auto ansi abstract sealed beforefieldinit E extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$F4B4FFE41AB49E80A4ECF390CF6EB372' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2085 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$F4B4FFE41AB49E80A4ECF390CF6EB372'::'<Extension>$' } // end of class <M>$F4B4FFE41AB49E80A4ECF390CF6EB372 // Methods .method private hidebysig instance void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::M .method private hidebysig specialname instance int32 get_P () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P .method private hidebysig specialname instance void set_P ( int32 'value' ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P // Properties .property instance int32 P() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) .get instance int32 E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P() .set instance void E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P(int32) } } // end of class <G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69 // Methods .method private hidebysig static pinvokeimpl("something.dll" winapi) void M ( int32 i ) cil managed preservesig { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) } // end of method E::M .method private hidebysig static pinvokeimpl("something.dll" winapi) int32 get_P ( int32 i ) cil managed preservesig { } // end of method E::get_P .method private hidebysig static pinvokeimpl("something.dll" winapi) void set_P ( int32 i, int32 'value' ) cil managed preservesig { } // end of method E::set_P } // end of class E """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); source = """ using System.Runtime.InteropServices; static class E { [DllImport("something.dll")] static extern void M(this int i); } """; comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); } [Fact] public void Extern_04() { var source = """ using System.Runtime.InteropServices; static class E { extension(int) { [DllImport("something.dll", EntryPoint = "Method1")] static extern void M(); static extern int P { [DllImport("something.dll", EntryPoint = "Method2")] get; [DllImport("something.dll", EntryPoint = "Method3")] set; } } } """; var verifier = CompileAndVerify(source).VerifyDiagnostics(); verifier.VerifyTypeIL("E", """ .class private auto ansi abstract sealed beforefieldinit E extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2085 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::'<Extension>$' } // end of class <M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69 // Methods .method private hidebysig static void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 42 41 34 31 43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39 30 36 32 46 35 39 45 44 34 44 36 39 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::M .method private hidebysig specialname static int32 get_P () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 42 41 34 31 43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39 30 36 32 46 35 39 45 44 34 44 36 39 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P .method private hidebysig specialname static void set_P ( int32 'value' ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 42 41 34 31 43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39 30 36 32 46 35 39 45 44 34 44 36 39 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P // Properties .property int32 P() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 42 41 34 31 43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39 30 36 32 46 35 39 45 44 34 44 36 39 00 00 ) .get int32 E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P() .set void E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P(int32) } } // end of class <G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69 // Methods .method private hidebysig static pinvokeimpl("something.dll" as "Method1" winapi) void M () cil managed preservesig { } // end of method E::M .method private hidebysig static pinvokeimpl("something.dll" as "Method2" winapi) int32 get_P () cil managed preservesig { } // end of method E::get_P .method private hidebysig static pinvokeimpl("something.dll" as "Method3" winapi) void set_P ( int32 'value' ) cil managed preservesig { } // end of method E::set_P } // end of class E """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } [Fact] public void Extern_05() { var source = """ static class E { extension(int i) { extern void M(); extern int P { get; set; } } } """; var verifier = CompileAndVerify(source, verify: Verification.FailsPEVerify with { PEVerifyMessage = """ Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. Type load failed. """ }); verifier.VerifyDiagnostics( // (5,21): warning CS0626: Method, operator, or accessor 'E.extension(int).M()' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. // extern void M(); Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "M").WithArguments("E.extension(int).M()").WithLocation(5, 21), // (6,24): warning CS0626: Method, operator, or accessor 'E.extension(int).P.get' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. // extern int P { get; set; } Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "get").WithArguments("E.extension(int).P.get").WithLocation(6, 24), // (6,29): warning CS0626: Method, operator, or accessor 'E.extension(int).P.set' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. // extern int P { get; set; } Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "set").WithArguments("E.extension(int).P.set").WithLocation(6, 29)); verifier.VerifyTypeIL("E", """ .class private auto ansi abstract sealed beforefieldinit E extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$F4B4FFE41AB49E80A4ECF390CF6EB372' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2085 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$F4B4FFE41AB49E80A4ECF390CF6EB372'::'<Extension>$' } // end of class <M>$F4B4FFE41AB49E80A4ECF390CF6EB372 // Methods .method private hidebysig instance void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::M .method private hidebysig specialname instance int32 get_P () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P .method private hidebysig specialname instance void set_P ( int32 'value' ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P // Properties .property instance int32 P() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) .get instance int32 E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P() .set instance void E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P(int32) } } // end of class <G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69 // Methods .method private hidebysig static void M ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) } // end of method E::M .method private hidebysig static int32 get_P ( int32 i ) cil managed { } // end of method E::get_P .method private hidebysig static void set_P ( int32 i, int32 'value' ) cil managed { } // end of method E::set_P } // end of class E """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); source = """ class C { extern void M(); } """; verifier = CompileAndVerify(source, verify: Verification.FailsPEVerify with { PEVerifyMessage = """ Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. Type load failed. """ }); verifier.VerifyDiagnostics( // (3,17): warning CS0626: Method, operator, or accessor 'C.M()' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. // extern void M(); Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "M").WithArguments("C.M()").WithLocation(3, 17)); verifier.VerifyTypeIL("C", """ .class private auto ansi beforefieldinit C extends [mscorlib]System.Object { // Methods .method private hidebysig instance void M () cil managed { } // end of method C::M .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x2067 // 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 } // end of class C """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } [Fact] public void Extern_06() { var source = """ static class E { extension(int i) { static extern void M(); static extern int P { get; set; } } } """; var verifier = CompileAndVerify(source, verify: Verification.FailsPEVerify with { PEVerifyMessage = """ Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. Error: Method marked Abstract, Runtime, InternalCall or Imported must have zero RVA, and vice versa. Type load failed. """ }); verifier.VerifyDiagnostics( // (5,28): warning CS0626: Method, operator, or accessor 'E.extension(int).M()' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. // static extern void M(); Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "M").WithArguments("E.extension(int).M()").WithLocation(5, 28), // (6,31): warning CS0626: Method, operator, or accessor 'E.extension(int).P.get' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. // static extern int P { get; set; } Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "get").WithArguments("E.extension(int).P.get").WithLocation(6, 31), // (6,36): warning CS0626: Method, operator, or accessor 'E.extension(int).P.set' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. // static extern int P { get; set; } Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "set").WithArguments("E.extension(int).P.set").WithLocation(6, 36)); verifier.VerifyTypeIL("E", """ .class private auto ansi abstract sealed beforefieldinit E extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$F4B4FFE41AB49E80A4ECF390CF6EB372' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2085 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$F4B4FFE41AB49E80A4ECF390CF6EB372'::'<Extension>$' } // end of class <M>$F4B4FFE41AB49E80A4ECF390CF6EB372 // Methods .method private hidebysig static void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::M .method private hidebysig specialname static int32 get_P () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P .method private hidebysig specialname static void set_P ( int32 'value' ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P // Properties .property int32 P() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) .get int32 E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P() .set void E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P(int32) } } // end of class <G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69 // Methods .method private hidebysig static void M () cil managed { } // end of method E::M .method private hidebysig static int32 get_P () cil managed { } // end of method E::get_P .method private hidebysig static void set_P ( int32 'value' ) cil managed { } // end of method E::set_P } // end of class E """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } [Fact] public void Extern_07() { var source = """ static class E { extension(int i) { extern int this[int j] { get => 0; } } } """; CreateCompilation(source).VerifyEmitDiagnostics( // (5,34): error CS0179: 'E.extension(int).this[int].get' cannot be extern and declare a body // extern int this[int j] { get => 0; } Diagnostic(ErrorCode.ERR_ExternHasBody, "get").WithArguments("E.extension(int).this[int].get").WithLocation(5, 34)); } [Fact] public void Extern_08() { var source = """ static class E { extension(int i) { [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] static extern void M(); static extern int P { [method: System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] get; [method: System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] set; } } } """; var comp = CreateCompilation(source); // Note: skeleton methods have "throw" bodies and lack internalcall. Implementation methods have internalcall and no body. var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyTypeIL("E", """ .class private auto ansi abstract sealed beforefieldinit E extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$F4B4FFE41AB49E80A4ECF390CF6EB372' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2085 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$F4B4FFE41AB49E80A4ECF390CF6EB372'::'<Extension>$' } // end of class <M>$F4B4FFE41AB49E80A4ECF390CF6EB372 // Methods .method private hidebysig static void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::M .method private hidebysig specialname static int32 get_P () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P .method private hidebysig specialname static void set_P ( int32 'value' ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P // Properties .property int32 P() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) .get int32 E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P() .set void E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P(int32) } } // end of class <G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69 // Methods .method private hidebysig static void M () cil managed internalcall { } // end of method E::M .method private hidebysig static int32 get_P () cil managed internalcall { } // end of method E::get_P .method private hidebysig static void set_P ( int32 'value' ) cil managed internalcall { } // end of method E::set_P } // end of class E """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } [Fact] public void Extern_09() { var source = """ static class E { extension(int i) { [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] extern void M(); extern int P { [method: System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] get; [method: System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] set; } } } """; var comp = CreateCompilation(source); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyTypeIL("E", """ .class private auto ansi abstract sealed beforefieldinit E extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$F4B4FFE41AB49E80A4ECF390CF6EB372' extends [mscorlib]System.Object { // Methods .method private hidebysig specialname static void '<Extension>$' ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2085 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$F4B4FFE41AB49E80A4ECF390CF6EB372'::'<Extension>$' } // end of class <M>$F4B4FFE41AB49E80A4ECF390CF6EB372 // Methods .method private hidebysig instance void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::M .method private hidebysig specialname instance int32 get_P () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P .method private hidebysig specialname instance void set_P ( int32 'value' ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) // Method begins at RVA 0x207e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P // Properties .property instance int32 P() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) .get instance int32 E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P() .set instance void E/'<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_P(int32) } } // end of class <G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69 // Methods .method private hidebysig static void M ( int32 i ) cil managed internalcall { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) } // end of method E::M .method private hidebysig static int32 get_P ( int32 i ) cil managed internalcall { } // end of method E::get_P .method private hidebysig static void set_P ( int32 i, int32 'value' ) cil managed internalcall { } // end of method E::set_P } // end of class E """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); } [Fact] public void Extern_10() { var source = """ using System.Runtime.InteropServices; static class E { extension(int i) { [DllImport("something.dll")] void M() { } int P { [DllImport("something.dll")] get => 0; [DllImport("something.dll")] set { } } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,10): error CS0601: The DllImport attribute must be specified on a method marked 'extern' that is either 'static' or an extension member // [DllImport("something.dll")] Diagnostic(ErrorCode.ERR_DllImportOnInvalidMethod, "DllImport").WithLocation(6, 10), // (11,14): error CS0601: The DllImport attribute must be specified on a method marked 'extern' that is either 'static' or an extension member // [DllImport("something.dll")] Diagnostic(ErrorCode.ERR_DllImportOnInvalidMethod, "DllImport").WithLocation(11, 14), // (13,14): error CS0601: The DllImport attribute must be specified on a method marked 'extern' that is either 'static' or an extension member // [DllImport("something.dll")] Diagnostic(ErrorCode.ERR_DllImportOnInvalidMethod, "DllImport").WithLocation(13, 14)); } [Fact] public void Extern_11() { var source = """ using System.Runtime.InteropServices; static class E { extension(int i) { [DllImport("something.dll")] extern void M() { } extern int P { [DllImport("something.dll")] get => 0; [DllImport("something.dll")] set { } } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (7,21): error CS0179: 'E.extension(int).M()' cannot be extern and declare a body // extern void M() { } Diagnostic(ErrorCode.ERR_ExternHasBody, "M").WithArguments("E.extension(int).M()").WithLocation(7, 21), // (12,13): error CS0179: 'E.extension(int).P.get' cannot be extern and declare a body // get => 0; Diagnostic(ErrorCode.ERR_ExternHasBody, "get").WithArguments("E.extension(int).P.get").WithLocation(12, 13), // (14,13): error CS0179: 'E.extension(int).P.set' cannot be extern and declare a body // set { } Diagnostic(ErrorCode.ERR_ExternHasBody, "set").WithArguments("E.extension(int).P.set").WithLocation(14, 13)); } [Fact] public void Extern_12() { var source = """ using System.Runtime.InteropServices; static class E { extension(int) { int P { [DllImport("something.dll")] extern get; // 1 [DllImport("something.dll")] extern set; // 2 } } } static class C { static int P { [DllImport("something.dll")] extern get; // 3 [DllImport("something.dll")] extern set; // 4 } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,13): error CS9282: This member is not allowed in an extension block // int P Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "P").WithLocation(6, 13), // (6,13): error CS9303: 'P': cannot declare instance members in an extension block with an unnamed receiver parameter // int P Diagnostic(ErrorCode.ERR_InstanceMemberWithUnnamedExtensionsParameter, "P").WithArguments("P").WithLocation(6, 13), // (8,14): error CS0601: The DllImport attribute must be specified on a method marked 'extern' that is either 'static' or an extension member // [DllImport("something.dll")] Diagnostic(ErrorCode.ERR_DllImportOnInvalidMethod, "DllImport").WithLocation(8, 14), // (9,20): error CS0106: The modifier 'extern' is not valid for this item // extern get; // 1 Diagnostic(ErrorCode.ERR_BadMemberFlag, "get").WithArguments("extern").WithLocation(9, 20), // (10,14): error CS0601: The DllImport attribute must be specified on a method marked 'extern' that is either 'static' or an extension member // [DllImport("something.dll")] Diagnostic(ErrorCode.ERR_DllImportOnInvalidMethod, "DllImport").WithLocation(10, 14), // (11,20): error CS0106: The modifier 'extern' is not valid for this item // extern set; // 2 Diagnostic(ErrorCode.ERR_BadMemberFlag, "set").WithArguments("extern").WithLocation(11, 20), // (20,10): error CS0601: The DllImport attribute must be specified on a method marked 'extern' that is either 'static' or an extension member // [DllImport("something.dll")] Diagnostic(ErrorCode.ERR_DllImportOnInvalidMethod, "DllImport").WithLocation(20, 10), // (21,16): error CS0106: The modifier 'extern' is not valid for this item // extern get; // 3 Diagnostic(ErrorCode.ERR_BadMemberFlag, "get").WithArguments("extern").WithLocation(21, 16), // (22,10): error CS0601: The DllImport attribute must be specified on a method marked 'extern' that is either 'static' or an extension member // [DllImport("something.dll")] Diagnostic(ErrorCode.ERR_DllImportOnInvalidMethod, "DllImport").WithLocation(22, 10), // (23,16): error CS0106: The modifier 'extern' is not valid for this item // extern set; // 4 Diagnostic(ErrorCode.ERR_BadMemberFlag, "set").WithArguments("extern").WithLocation(23, 16)); } [Fact] public void Validation_Modifiers_Unsafe() { string source = """ static class E { extension(int i) { unsafe int* M() => throw null; unsafe int* P { get => throw null; set { } } unsafe int* this[int j] { get => throw null; } } } """; var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll); comp.VerifyEmitDiagnostics(); } [Fact] public void Validation_Modifiers_Protected() { string source = """ static class E { extension(int i) { protected void M() { } protected int P { get => 0; set { } } public int P2 { protected get => 0; set { } } public int P3 { get => 0; protected set { } } protected int this[int j] { get => throw null; } public int this[int j, int k] { protected get => throw null; set { } } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,24): error CS9302: 'E.extension(int).M()': new protected member declared in an extension block // protected void M() { } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "M").WithArguments("E.extension(int).M()").WithLocation(5, 24), // (6,23): error CS9302: 'E.extension(int).P': new protected member declared in an extension block // protected int P { get => 0; set { } } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "P").WithArguments("E.extension(int).P").WithLocation(6, 23), // (7,35): error CS9302: 'E.extension(int).P2.get': new protected member declared in an extension block // public int P2 { protected get => 0; set { } } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "get").WithArguments("E.extension(int).P2.get").WithLocation(7, 35), // (8,45): error CS9302: 'E.extension(int).P3.set': new protected member declared in an extension block // public int P3 { get => 0; protected set { } } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "set").WithArguments("E.extension(int).P3.set").WithLocation(8, 45), // (9,23): error CS9302: 'E.extension(int).this[int]': new protected member declared in an extension block // protected int this[int j] { get => throw null; } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "this").WithArguments("E.extension(int).this[int]").WithLocation(9, 23), // (10,51): error CS9302: 'E.extension(int).this[int, int].get': new protected member declared in an extension block // public int this[int j, int k] { protected get => throw null; set { } } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "get").WithArguments("E.extension(int).this[int, int].get").WithLocation(10, 51)); } [Fact] public void Validation_Modifiers_ProtectedInternal() { string source = """ static class E { extension(int i) { protected internal void M() { } protected internal int P { get => 0; set { } } public int P2 { protected internal get => 0; set { } } public int P3 { get => 0; protected internal set { } } protected internal int this[int j] { get => throw null; } public int this[int j, int k] { protected internal get => throw null; set { } } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,33): error CS9302: 'E.extension(int).M()': new protected member declared in an extension block // protected internal void M() { } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "M").WithArguments("E.extension(int).M()").WithLocation(5, 33), // (6,32): error CS9302: 'E.extension(int).P': new protected member declared in an extension block // protected internal int P { get => 0; set { } } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "P").WithArguments("E.extension(int).P").WithLocation(6, 32), // (7,44): error CS9302: 'E.extension(int).P2.get': new protected member declared in an extension block // public int P2 { protected internal get => 0; set { } } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "get").WithArguments("E.extension(int).P2.get").WithLocation(7, 44), // (8,54): error CS9302: 'E.extension(int).P3.set': new protected member declared in an extension block // public int P3 { get => 0; protected internal set { } } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "set").WithArguments("E.extension(int).P3.set").WithLocation(8, 54), // (9,32): error CS9302: 'E.extension(int).this[int]': new protected member declared in an extension block // protected internal int this[int j] { get => throw null; } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "this").WithArguments("E.extension(int).this[int]").WithLocation(9, 32), // (10,60): error CS9302: 'E.extension(int).this[int, int].get': new protected member declared in an extension block // public int this[int j, int k] { protected internal get => throw null; set { } } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "get").WithArguments("E.extension(int).this[int, int].get").WithLocation(10, 60)); } [Fact] public void Validation_Modifiers_PrivateProtected() { string source = """ static class E { extension(int i) { private protected void M() { } private protected int P { get => 0; set { } } public int P2 { private protected get => 0; set { } } public int P3 { get => 0; private protected set { } } private protected int this[int j] { get => throw null; } public int this[int j, int k] { private protected get => throw null; set { } } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,32): error CS9302: 'E.extension(int).M()': new protected member declared in an extension block // private protected void M() { } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "M").WithArguments("E.extension(int).M()").WithLocation(5, 32), // (6,31): error CS9302: 'E.extension(int).P': new protected member declared in an extension block // private protected int P { get => 0; set { } } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "P").WithArguments("E.extension(int).P").WithLocation(6, 31), // (7,43): error CS9302: 'E.extension(int).P2.get': new protected member declared in an extension block // public int P2 { private protected get => 0; set { } } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "get").WithArguments("E.extension(int).P2.get").WithLocation(7, 43), // (8,53): error CS9302: 'E.extension(int).P3.set': new protected member declared in an extension block // public int P3 { get => 0; private protected set { } } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "set").WithArguments("E.extension(int).P3.set").WithLocation(8, 53), // (9,31): error CS9302: 'E.extension(int).this[int]': new protected member declared in an extension block // private protected int this[int j] { get => throw null; } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "this").WithArguments("E.extension(int).this[int]").WithLocation(9, 31), // (10,59): error CS9302: 'E.extension(int).this[int, int].get': new protected member declared in an extension block // public int this[int j, int k] { private protected get => throw null; set { } } Diagnostic(ErrorCode.ERR_ProtectedInExtension, "get").WithArguments("E.extension(int).this[int, int].get").WithLocation(10, 59)); } [Fact] public void Validation_EntryPoint_01() { string source = """ static class E { extension(int i) { public static void Main() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(source, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithMainTypeName("E")); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void Validation_EntryPoint_02() { string source = """ static class E { extension(int) { public static System.Action Main => throw null; } } """; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // error CS5001: Program does not contain a static 'Main' method suitable for an entry point Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithMainTypeName("E")); comp.VerifyDiagnostics( // (1,14): error CS1558: 'E' does not have a suitable static 'Main' method // static class E Diagnostic(ErrorCode.ERR_NoMainInClass, "E").WithArguments("E").WithLocation(1, 14)); } [Fact] public void Validation_EntryPoint_03() { string source = """ static class E { extension(int i) { public static void Main() => throw null; } } """; var comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithMainTypeName("E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69")); comp.VerifyEmitDiagnostics( // error CS1555: Could not find 'E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' specified for Main method Diagnostic(ErrorCode.ERR_MainClassNotFound).WithArguments("E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69").WithLocation(1, 1)); AssertEx.Equal("<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69", comp.GetTypeByMetadataName("E").GetTypeMembers().Single().ExtensionGroupingName); } [Fact] public void Validation_EntryPoint_04() { string source = """ static class E { extension(int i) { public static void Main() { } } } """; var comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithMainTypeName("E.")); comp.VerifyEmitDiagnostics( // error CS7088: Invalid 'MainTypeName' value: 'E.'. Diagnostic(ErrorCode.ERR_BadCompilationOptionValue).WithArguments("MainTypeName", "E.").WithLocation(1, 1)); comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithMainTypeName("E. ")); comp.VerifyEmitDiagnostics( // error CS7088: Invalid 'MainTypeName' value: 'E. '. Diagnostic(ErrorCode.ERR_BadCompilationOptionValue).WithArguments("MainTypeName", "E. ").WithLocation(1, 1)); comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithMainTypeName("")); comp.VerifyEmitDiagnostics( Diagnostic(ErrorCode.ERR_BadCompilationOptionValue).WithArguments("MainTypeName", "").WithLocation(1, 1)); comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithMainTypeName(" ")); comp.VerifyEmitDiagnostics( // error CS7088: Invalid 'MainTypeName' value: ' '. Diagnostic(ErrorCode.ERR_BadCompilationOptionValue).WithArguments("MainTypeName", " ").WithLocation(1, 1)); comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithMainTypeName(".A")); comp.VerifyEmitDiagnostics( // error CS7088: Invalid 'MainTypeName' value: '.A'. Diagnostic(ErrorCode.ERR_BadCompilationOptionValue).WithArguments("MainTypeName", ".A").WithLocation(1, 1)); } [Fact] public void Validation_EntryPoint_05() { string source = """ static class E { extension(int i) { public static async System.Threading.Tasks.Task<int> Main() { System.Console.Write("ran"); await System.Threading.Tasks.Task.Yield(); return 0; } } } """; var comp = CreateCompilation(source, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithMainTypeName("E")); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void Validation_EntryPoint_06() { string source = """ static class E { extension(string[] args) { public void Main() { System.Console.Write("ran"); } } } """; var comp = CreateCompilation(source, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithMainTypeName("E")); CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); } [Fact] public void Validation_EntryPoint_07() { string source = """ static class E { extension(int i) { public void Main() => throw null; } } """; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // error CS5001: Program does not contain a static 'Main' method suitable for an entry point Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1), // (5,21): warning CS0028: 'E.Main(int)' has the wrong signature to be an entry point // public void Main() => throw null; Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("E.Main(int)").WithLocation(5, 21)); comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithMainTypeName("E")); comp.VerifyEmitDiagnostics( // (1,14): error CS1558: 'E' does not have a suitable static 'Main' method // static class E Diagnostic(ErrorCode.ERR_NoMainInClass, "E").WithArguments("E").WithLocation(1, 14), // (5,21): warning CS0028: 'E.Main(int)' has the wrong signature to be an entry point // public void Main() => throw null; Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("E.Main(int)").WithLocation(5, 21)); } [Fact] public void ReservedTypeName_01() { string source = """ using extension = int; class extension { } class C<extension> { } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics( // (1,1): hidden CS8019: Unnecessary using directive. // using extension = int; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using extension = int;").WithLocation(1, 1), // (1,7): warning CS8981: The type name 'extension' only contains lower-cased ascii characters. Such names may become reserved for the language. // using extension = int; Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "extension").WithArguments("extension").WithLocation(1, 7), // (2,7): warning CS8981: The type name 'extension' only contains lower-cased ascii characters. Such names may become reserved for the language. // class extension { } Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "extension").WithArguments("extension").WithLocation(2, 7), // (3,9): warning CS8981: The type name 'extension' only contains lower-cased ascii characters. Such names may become reserved for the language. // class C<extension> { } Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "extension").WithArguments("extension").WithLocation(3, 9)); comp = CreateCompilation(source, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics( // (1,7): error CS9306: Types and aliases cannot be named 'extension'. // using extension = int; Diagnostic(ErrorCode.ERR_ExtensionTypeNameDisallowed, "extension").WithLocation(1, 7), // (2,7): error CS9306: Types and aliases cannot be named 'extension'. // class extension { } Diagnostic(ErrorCode.ERR_ExtensionTypeNameDisallowed, "extension").WithLocation(2, 7), // (3,9): error CS9306: Types and aliases cannot be named 'extension'. // class C<extension> { } Diagnostic(ErrorCode.ERR_ExtensionTypeNameDisallowed, "extension").WithLocation(3, 9)); comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,7): error CS9306: Types and aliases cannot be named 'extension'. // using extension = int; Diagnostic(ErrorCode.ERR_ExtensionTypeNameDisallowed, "extension").WithLocation(1, 7), // (2,7): error CS9306: Types and aliases cannot be named 'extension'. // class extension { } Diagnostic(ErrorCode.ERR_ExtensionTypeNameDisallowed, "extension").WithLocation(2, 7), // (3,9): error CS9306: Types and aliases cannot be named 'extension'. // class C<extension> { } Diagnostic(ErrorCode.ERR_ExtensionTypeNameDisallowed, "extension").WithLocation(3, 9)); } [Fact] public void ReservedTypeName_02() { string source = """ using @extension = int; class @extension { } class C<@extension> { } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (1,1): hidden CS8019: Unnecessary using directive. // using @extension = int; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using @extension = int;").WithLocation(1, 1)); } [Fact] public void CallerAttribute_01() { var src = """ "".M(); static class E { extension([System.Runtime.CompilerServices.CallerMemberName] string name = "") { public void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,15): error CS9284: The receiver parameter of an extension cannot have a default value // extension([System.Runtime.CompilerServices.CallerMemberName] string name = "") Diagnostic(ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue, @"[System.Runtime.CompilerServices.CallerMemberName] string name = """"").WithLocation(5, 15)); } [Theory, CombinatorialData] public void ConditionalAttribute_01(bool withDebug) { var src = $$""" {{(withDebug ? "#define DEBUG" : "")}} 42.M(); 42.M2(); E.M(42); static class E { extension(int i) { [System.Diagnostics.Conditional("DEBUG")] public void M() { System.Console.Write("ran "); } } [System.Diagnostics.Conditional("DEBUG")] public static void M2(this int i) { System.Console.Write("ran "); } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: withDebug ? "ran ran ran" : ""); } [Fact] public void RefAnalysis_Invocation_01() { string source = """ class C { ref int M2() { int i = 0; return ref i.M(); } ref int M3() { int i = 0; return ref E.M(ref i); } } static class E { extension(ref int i) { public ref int M() => ref i; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,20): error CS8168: Cannot return local 'i' by reference because it is not a ref local // return ref i.M(); Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(6, 20), // (6,20): error CS8347: Cannot use a result of 'E.extension(ref int).M()' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope // return ref i.M(); Diagnostic(ErrorCode.ERR_EscapeCall, "i.M()").WithArguments("E.extension(ref int).M()", "i").WithLocation(6, 20), // (12,20): error CS8347: Cannot use a result of 'E.M(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope // return ref E.M(ref i); Diagnostic(ErrorCode.ERR_EscapeCall, "E.M(ref i)").WithArguments("E.M(ref int)", "i").WithLocation(12, 20), // (12,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local // return ref E.M(ref i); Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(12, 28)); } [Fact] public void RefAnalysis_Invocation_02() { string source = """ class C { ref int M2() { int i = 0; ref int ri = ref i; return ref ri.M(); } ref int M3() { int i = 0; ref int ri = ref i; return ref E.M(ref ri); } } static class E { extension(ref int i) { public ref int M() => ref i; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (7,20): error CS8157: Cannot return 'ri' by reference because it was initialized to a value that cannot be returned by reference // return ref ri.M(); Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "ri").WithArguments("ri").WithLocation(7, 20), // (7,20): error CS8347: Cannot use a result of 'E.extension(ref int).M()' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope // return ref ri.M(); Diagnostic(ErrorCode.ERR_EscapeCall, "ri.M()").WithArguments("E.extension(ref int).M()", "i").WithLocation(7, 20), // (14,20): error CS8347: Cannot use a result of 'E.M(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope // return ref E.M(ref ri); Diagnostic(ErrorCode.ERR_EscapeCall, "E.M(ref ri)").WithArguments("E.M(ref int)", "i").WithLocation(14, 20), // (14,28): error CS8157: Cannot return 'ri' by reference because it was initialized to a value that cannot be returned by reference // return ref E.M(ref ri); Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "ri").WithArguments("ri").WithLocation(14, 28)); } [Fact] public void RefAnalysis_Invocation_03() { string source = """ class C { RS MA(RS rs) => rs.M1(); RS MB(RS rs) => E.M1(rs); ref RS MC(ref RS rs) => ref rs.M2(); ref RS MD(ref RS rs) => ref E.M2(ref rs); } static class E { extension(RS rs) { public RS M1() => rs; } extension(ref RS rs) { public ref RS M2() => ref rs; } } ref struct RS { } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); } [Fact] public void RefAnalysis_Invocation_04() { string source = """ class C { ref int MA(ref int a) { int b = 42; return ref a.M(ref b); // 1 } ref int MB(ref int a) { int b = 42; return ref b.M(ref a); // 2 } ref int MC(ref int a) { int b = 42; return ref E.M(ref a, ref b); // 3 } } static class E { extension(ref int i) { public ref int M(ref int j) => throw null; } } ref struct RS { } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,20): error CS8347: Cannot use a result of 'E.extension(ref int).M(ref int)' in this context because it may expose variables referenced by parameter 'j' outside of their declaration scope // return ref a.M(ref b); // 1 Diagnostic(ErrorCode.ERR_EscapeCall, "a.M(ref b)").WithArguments("E.extension(ref int).M(ref int)", "j").WithLocation(6, 20), // (6,28): error CS8168: Cannot return local 'b' by reference because it is not a ref local // return ref a.M(ref b); // 1 Diagnostic(ErrorCode.ERR_RefReturnLocal, "b").WithArguments("b").WithLocation(6, 28), // (11,20): error CS8168: Cannot return local 'b' by reference because it is not a ref local // return ref b.M(ref a); // 2 Diagnostic(ErrorCode.ERR_RefReturnLocal, "b").WithArguments("b").WithLocation(11, 20), // (11,20): error CS8347: Cannot use a result of 'E.extension(ref int).M(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope // return ref b.M(ref a); // 2 Diagnostic(ErrorCode.ERR_EscapeCall, "b.M(ref a)").WithArguments("E.extension(ref int).M(ref int)", "i").WithLocation(11, 20), // (16,20): error CS8347: Cannot use a result of 'E.M(ref int, ref int)' in this context because it may expose variables referenced by parameter 'j' outside of their declaration scope // return ref E.M(ref a, ref b); // 3 Diagnostic(ErrorCode.ERR_EscapeCall, "E.M(ref a, ref b)").WithArguments("E.M(ref int, ref int)", "j").WithLocation(16, 20), // (16,35): error CS8168: Cannot return local 'b' by reference because it is not a ref local // return ref E.M(ref a, ref b); // 3 Diagnostic(ErrorCode.ERR_RefReturnLocal, "b").WithArguments("b").WithLocation(16, 35)); } [Fact] public void RefAnalysis_Invocation_05() { var text = """ class Program { void Test1() { S1 rOuter = default; System.Span<int> inner = stackalloc int[1]; S1 rInner = MayWrap(ref inner); rOuter.MayAssign(ref rOuter); rInner.MayAssign(ref rInner); rOuter.MayAssign(ref rInner); // 1 rInner.MayAssign(ref rOuter); // 2 rInner.MayAssign(arg2: ref rOuter); // 3 } static S1 MayWrap(ref System.Span<int> arg) => default; } ref struct S1 { } static class E { extension(ref S1 arg1) { public void MayAssign(ref S1 arg2) { arg1 = arg2; } } } """; var comp = CreateCompilation(text, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (13,30): error CS8352: Cannot use variable 'rInner' in this context because it may expose referenced variables outside of their declaration scope // rOuter.MayAssign(ref rInner); // 1 Diagnostic(ErrorCode.ERR_EscapeVariable, "rInner").WithArguments("rInner").WithLocation(13, 30), // (13,9): error CS8350: This combination of arguments to 'E.extension(ref S1).MayAssign(ref S1)' is disallowed because it may expose variables referenced by parameter 'arg2' outside of their declaration scope // rOuter.MayAssign(ref rInner); // 1 Diagnostic(ErrorCode.ERR_CallArgMixing, "rOuter.MayAssign(ref rInner)").WithArguments("E.extension(ref S1).MayAssign(ref S1)", "arg2").WithLocation(13, 9), // (14,9): error CS8352: Cannot use variable 'rInner' in this context because it may expose referenced variables outside of their declaration scope // rInner.MayAssign(ref rOuter); // 2 Diagnostic(ErrorCode.ERR_EscapeVariable, "rInner").WithArguments("rInner").WithLocation(14, 9), // (14,9): error CS8350: This combination of arguments to 'E.extension(ref S1).MayAssign(ref S1)' is disallowed because it may expose variables referenced by parameter 'arg1' outside of their declaration scope // rInner.MayAssign(ref rOuter); // 2 Diagnostic(ErrorCode.ERR_CallArgMixing, "rInner.MayAssign(ref rOuter)").WithArguments("E.extension(ref S1).MayAssign(ref S1)", "arg1").WithLocation(14, 9), // (15,9): error CS8352: Cannot use variable 'rInner' in this context because it may expose referenced variables outside of their declaration scope // rInner.MayAssign(arg2: ref rOuter); // 3 Diagnostic(ErrorCode.ERR_EscapeVariable, "rInner").WithArguments("rInner").WithLocation(15, 9), // (15,9): error CS8350: This combination of arguments to 'E.extension(ref S1).MayAssign(ref S1)' is disallowed because it may expose variables referenced by parameter 'arg1' outside of their declaration scope // rInner.MayAssign(arg2: ref rOuter); // 3 Diagnostic(ErrorCode.ERR_CallArgMixing, "rInner.MayAssign(arg2: ref rOuter)").WithArguments("E.extension(ref S1).MayAssign(ref S1)", "arg1").WithLocation(15, 9)); } [Fact] public void RefAnalysis_Invocation_05_Static() { var text = """ class Program { void Test1() { System.Span<int> inner = stackalloc int[1]; S1 rInner = MayWrap(ref inner); S1.MayAssign(ref rInner); } static S1 MayWrap(ref System.Span<int> arg) => default; } ref struct S1 { } static class E { extension(ref S1 arg1) { public static void MayAssign(ref S1 arg2) { } } } """; var comp = CreateCompilation(text, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); } [Fact] public void RefAnalysis_Invocation_06() { string source = """ class C { void M2(ref int j) { int i = 0; j = ref i.M(); } void M3(ref int j) { int i = 0; j = ref E.M(ref i); } } static class E { extension(ref int i) { public ref int M() => ref i; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,9): error CS8374: Cannot ref-assign 'i.M()' to 'j' because 'i.M()' has a narrower escape scope than 'j'. // j = ref i.M(); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "j = ref i.M()").WithArguments("j", "i.M()").WithLocation(6, 9), // (12,9): error CS8374: Cannot ref-assign 'E.M(ref i)' to 'j' because 'E.M(ref i)' has a narrower escape scope than 'j'. // j = ref E.M(ref i); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "j = ref E.M(ref i)").WithArguments("j", "E.M(ref i)").WithLocation(12, 9)); } [Fact] public void RefAnalysis_Invocation_07() { string source = """ class C { void MA(ref readonly int j) { int i = 0; j = ref i.M(); j = ref E.M(ref i); j = ref i.M2(); } } static class E { extension(ref readonly int i) { public ref readonly int M() => ref i; } public static ref readonly int M2(this ref readonly int i) => ref i; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,9): error CS8374: Cannot ref-assign 'i.M()' to 'j' because 'i.M()' has a narrower escape scope than 'j'. // j = ref i.M(); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "j = ref i.M()").WithArguments("j", "i.M()").WithLocation(6, 9), // (7,9): error CS8374: Cannot ref-assign 'E.M(ref i)' to 'j' because 'E.M(ref i)' has a narrower escape scope than 'j'. // j = ref E.M(ref i); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "j = ref E.M(ref i)").WithArguments("j", "E.M(ref i)").WithLocation(7, 9), // (8,9): error CS8374: Cannot ref-assign 'i.M2()' to 'j' because 'i.M2()' has a narrower escape scope than 'j'. // j = ref i.M2(); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "j = ref i.M2()").WithArguments("j", "i.M2()").WithLocation(8, 9)); } [Fact] public void RefAnalysis_Invocation_08() { string source = """ class C { void MA(ref readonly int j, ref int k) { int i = 0; j = ref i.M(ref k); j = ref E.M(ref i, ref k); j = ref i.M2(ref k); } } static class E { extension(ref readonly int i) { public ref readonly int M(ref int k) => ref i; } public static ref readonly int M2(this ref readonly int i, ref int k) => ref i; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,9): error CS8374: Cannot ref-assign 'i.M(ref k)' to 'j' because 'i.M(ref k)' has a narrower escape scope than 'j'. // j = ref i.M(ref k); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "j = ref i.M(ref k)").WithArguments("j", "i.M(ref k)").WithLocation(6, 9), // (7,9): error CS8374: Cannot ref-assign 'E.M(ref i, ref k)' to 'j' because 'E.M(ref i, ref k)' has a narrower escape scope than 'j'. // j = ref E.M(ref i, ref k); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "j = ref E.M(ref i, ref k)").WithArguments("j", "E.M(ref i, ref k)").WithLocation(7, 9), // (8,9): error CS8374: Cannot ref-assign 'i.M2(ref k)' to 'j' because 'i.M2(ref k)' has a narrower escape scope than 'j'. // j = ref i.M2(ref k); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "j = ref i.M2(ref k)").WithArguments("j", "i.M2(ref k)").WithLocation(8, 9)); } [Fact] public void RefAnalysis_Invocation_09() { string source = """ class C { void MA(ref int j, ref int k) { int i = 0; j = ref i.M(ref k); j = ref E.M(ref i, ref k); j = ref i.M2(ref k); } } static class E { extension(ref int i) { public ref int M(ref int k) => ref i; } public static ref int M2(this ref int i, ref int k) => ref i; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,9): error CS8374: Cannot ref-assign 'i.M(ref k)' to 'j' because 'i.M(ref k)' has a narrower escape scope than 'j'. // j = ref i.M(ref k); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "j = ref i.M(ref k)").WithArguments("j", "i.M(ref k)").WithLocation(6, 9), // (7,9): error CS8374: Cannot ref-assign 'E.M(ref i, ref k)' to 'j' because 'E.M(ref i, ref k)' has a narrower escape scope than 'j'. // j = ref E.M(ref i, ref k); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "j = ref E.M(ref i, ref k)").WithArguments("j", "E.M(ref i, ref k)").WithLocation(7, 9), // (8,9): error CS8374: Cannot ref-assign 'i.M2(ref k)' to 'j' because 'i.M2(ref k)' has a narrower escape scope than 'j'. // j = ref i.M2(ref k); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "j = ref i.M2(ref k)").WithArguments("j", "i.M2(ref k)").WithLocation(8, 9)); } [Fact] public void RefAnalysis_Invocation_10() { var source = """ class Program { static ref int G8A() { int t = default; int u = default; return ref t.F8(out u); // 1 } static ref int G8A_2() { int t = default; int u = default; return ref E.F8(t, out u); // 2 } static ref int G8A_3() { int t = default; int u = default; return ref E.F8(in t, out u); // 3 } } static class E { extension(in int t) { public ref int F8(out int u) => throw null; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (7,20): error CS8168: Cannot return local 't' by reference because it is not a ref local // return ref t.F8(out u); // 1 Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(7, 20), // (7,20): error CS8347: Cannot use a result of 'E.extension(in int).F8(out int)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope // return ref t.F8(out u); // 1 Diagnostic(ErrorCode.ERR_EscapeCall, "t.F8(out u)").WithArguments("E.extension(in int).F8(out int)", "t").WithLocation(7, 20), // (13,20): error CS8347: Cannot use a result of 'E.F8(in int, out int)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope // return ref E.F8(t, out u); // 2 Diagnostic(ErrorCode.ERR_EscapeCall, "E.F8(t, out u)").WithArguments("E.F8(in int, out int)", "t").WithLocation(13, 20), // (13,25): error CS8168: Cannot return local 't' by reference because it is not a ref local // return ref E.F8(t, out u); // 2 Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(13, 25), // (19,20): error CS8347: Cannot use a result of 'E.F8(in int, out int)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope // return ref E.F8(in t, out u); // 3 Diagnostic(ErrorCode.ERR_EscapeCall, "E.F8(in t, out u)").WithArguments("E.F8(in int, out int)", "t").WithLocation(19, 20), // (19,28): error CS8168: Cannot return local 't' by reference because it is not a ref local // return ref E.F8(in t, out u); // 3 Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(19, 28)); } [Fact] public void RefAnalysis_Invocation_11() { // Based on this extension, but missing the implementation method: // public static class E // { // extension(ref int i) // { // public ref int M() => ref i; // } // } string ilSrc = """ .class public auto ansi abstract sealed beforefieldinit E extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi sealed specialname '<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi abstract sealed specialname '<M>$56B5C634B2E52051C75D91F71BA8833A' extends System.Object { .method public hidebysig specialname static void '<Extension>$' ( int32& i ) cil managed { ret } } .method public hidebysig instance int32& M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 35 36 42 35 43 36 33 34 42 32 45 35 32 30 35 31 43 37 35 44 39 31 46 37 31 42 41 38 38 33 33 41 00 00 ) ldnull throw } } } """ + ExtensionMarkerAttributeIL; string source = """ class C { ref int M2() { int i = 0; return ref i.M(); } ref int M3() { int i = 0; return ref E.M(ref i); } } """; var comp = CreateCompilationWithIL(source, ilSrc); comp.VerifyEmitDiagnostics( // (6,22): error CS0570: 'E.extension(ref int).M()' is not supported by the language // return ref i.M(); Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension(ref int).M()").WithLocation(6, 22), // (12,22): error CS0570: 'E.extension(ref int).M()' is not supported by the language // return ref E.M(ref i); Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension(ref int).M()").WithLocation(12, 22)); } [Fact] public void RefAnalysis_Deconstruct_01() { var source = """ int i = 0; (int x1, int x2) = i; public static class E { extension(ref int i) { public void Deconstruct(out int x1, out int x2) => throw null!; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (2,1): error CS1510: A ref or out value must be an assignable variable // (int x1, int x2) = i; Diagnostic(ErrorCode.ERR_RefLvalueExpected, "(int x1, int x2) = i").WithLocation(2, 1)); source = """ int i = 0; (int x1, int x2) = i; public static class E { public static void Deconstruct(this ref int i, out int x1, out int x2) => throw null!; } """; comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (2,1): error CS1510: A ref or out value must be an assignable variable // (int x1, int x2) = i; Diagnostic(ErrorCode.ERR_RefLvalueExpected, "(int x1, int x2) = i").WithLocation(2, 1)); } [Fact] public void RefAnalysis_Deconstruct_02() { // Based on this extension, but missing the implementation method: // public static class E // { // extension(object o) // { // public void Deconstruct(out int x1, out int x2) => throw null!; // } // } string ilSrc = """ .class public auto ansi abstract sealed beforefieldinit E extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends System.Object { .method public hidebysig specialname static void '<Extension>$' ( object o ) cil managed { ret } } .method public hidebysig instance void Deconstruct ( [out] int32& x1, [out] int32& x2 ) cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) ldnull throw } } } """ + ExtensionMarkerAttributeIL; var source = """ object o = new object(); (int x1, int x2) = o; """; var comp = CreateCompilationWithIL(source, ilSrc); comp.VerifyEmitDiagnostics( // (2,20): error CS0570: 'E.extension(object).Deconstruct(out int, out int)' is not supported by the language // (int x1, int x2) = o; Diagnostic(ErrorCode.ERR_BindToBogus, "o").WithArguments("E.extension(object).Deconstruct(out int, out int)").WithLocation(2, 20), // (2,20): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'object', with 2 out parameters and a void return type. // (int x1, int x2) = o; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "o").WithArguments("object", "2").WithLocation(2, 20)); } [Fact] public void RefAnalysis_Deconstruct_03() { var source = """ int i = 0; (int x1, int x2) = ref i; public static class E { extension(ref int i) { public void Deconstruct(out int x1, out int x2) => throw null!; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (2,20): error CS1073: Unexpected token 'ref' // (int x1, int x2) = ref i; Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(2, 20)); } [Fact] public void RefAnalysis_Foreach_01() { // Based on this extension, but missing the implementation method: // public static class E // { // extension(object o) // { // public IEnumerator<int> GetEnumerator() => throw null!; // } // } string ilSrc = """ .class public auto ansi abstract sealed beforefieldinit E extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi abstract sealed specialname '<M>$119AA281C143547563250CAF89B48A76' extends System.Object { .method public hidebysig specialname static void '<Extension>$' ( object o ) cil managed { ret } } .method public hidebysig instance class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> GetEnumerator () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 31 31 39 41 41 32 38 31 43 31 34 33 35 34 37 35 36 33 32 35 30 43 41 46 38 39 42 34 38 41 37 36 00 00 ) ldnull throw } } } """ + ExtensionMarkerAttributeIL; var source = """ foreach (var x in new object()) { } """; var comp = CreateCompilationWithIL(source, ilSrc); comp.VerifyEmitDiagnostics( // (1,19): error CS0570: 'E.extension(object).GetEnumerator()' is not supported by the language // foreach (var x in new object()) { } Diagnostic(ErrorCode.ERR_BindToBogus, "new object()").WithArguments("E.extension(object).GetEnumerator()").WithLocation(1, 19), // (1,19): error CS1579: foreach statement cannot operate on variables of type 'object' because 'object' does not contain a public instance or extension definition for 'GetEnumerator' // foreach (var x in new object()) { } Diagnostic(ErrorCode.ERR_ForEachMissingMember, "new object()").WithArguments("object", "GetEnumerator").WithLocation(1, 19)); } [Fact] public void RefAnalysis_PropertyAccess_01() { string source = """ class C { ref int M2() { int i = 0; return ref i.P; } ref int M3() { int i = 0; return ref E.get_P(ref i); } } static class E { extension(ref int i) { public ref int P => ref i; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,20): error CS8168: Cannot return local 'i' by reference because it is not a ref local // return ref i.P; Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(6, 20), // (6,20): error CS8347: Cannot use a result of 'E.extension(ref int).P' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope // return ref i.P; Diagnostic(ErrorCode.ERR_EscapeCall, "i.P").WithArguments("E.extension(ref int).P", "i").WithLocation(6, 20), // (12,20): error CS8347: Cannot use a result of 'E.get_P(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope // return ref E.get_P(ref i); Diagnostic(ErrorCode.ERR_EscapeCall, "E.get_P(ref i)").WithArguments("E.get_P(ref int)", "i").WithLocation(12, 20), // (12,32): error CS8168: Cannot return local 'i' by reference because it is not a ref local // return ref E.get_P(ref i); Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(12, 32)); } [Fact] public void RefAnalysis_PropertyAccess_02() { string source = """ class C { ref int M2() { int i = 0; ref int ri = ref i; return ref ri.P; } ref int M3() { int i = 0; ref int ri = ref i; return ref E.get_P(ref ri); } } static class E { extension(ref int i) { public ref int P => ref i; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (7,20): error CS8157: Cannot return 'ri' by reference because it was initialized to a value that cannot be returned by reference // return ref ri.P; Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "ri").WithArguments("ri").WithLocation(7, 20), // (7,20): error CS8347: Cannot use a result of 'E.extension(ref int).P' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope // return ref ri.P; Diagnostic(ErrorCode.ERR_EscapeCall, "ri.P").WithArguments("E.extension(ref int).P", "i").WithLocation(7, 20), // (14,20): error CS8347: Cannot use a result of 'E.get_P(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope // return ref E.get_P(ref ri); Diagnostic(ErrorCode.ERR_EscapeCall, "E.get_P(ref ri)").WithArguments("E.get_P(ref int)", "i").WithLocation(14, 20), // (14,32): error CS8157: Cannot return 'ri' by reference because it was initialized to a value that cannot be returned by reference // return ref E.get_P(ref ri); Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "ri").WithArguments("ri").WithLocation(14, 32)); } [Fact] public void RefAnalysis_PropertyAccess_03() { string source = """ class C { void M() { int i = 0; i.P++; } } static class E { extension(ref int i) { public int P { get => i; set { i = value; } } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); } [Fact] public void RefAnalysis_PropertyAccess_04() { string source = """ class C { void M() { int i = 0; i.P++; } } static class E { extension(ref int i) { public ref int P => ref i; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); } [Fact] public void RefAnalysis_PropertyAccess_05() { string source = """ class C { void M() { int i = 0; i.P += 42; } } static class E { extension(ref int i) { public int P { get => i; set { i = value; } } } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79654")] public void RefAnalysis_PropertyAccess_06() { string source = """ using System; ref struct S { public Span<int> field; } static class E { extension(S s) { public S Property { get => throw null!; set => throw null!; } } extension(ref S s) { public S RefReceiverProperty { get => throw null!; set => throw null!; } } public static void Test1(S s) { var x = new S { field = stackalloc int[10] }; s.Property = x; s = x.Property; E.set_Property(s, x); s = E.get_Property(x); s.RefReceiverProperty = x; E.set_RefReceiverProperty(ref s, x); s = x.RefReceiverProperty; s = E.get_RefReceiverProperty(ref x); } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (24,13): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s = x.Property; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(24, 13), // (24,13): error CS8347: Cannot use a result of 'E.extension(S).Property' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // s = x.Property; Diagnostic(ErrorCode.ERR_EscapeCall, "x.Property").WithArguments("E.extension(S).Property", "s").WithLocation(24, 13), // (26,13): error CS8347: Cannot use a result of 'E.get_Property(S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // s = E.get_Property(x); Diagnostic(ErrorCode.ERR_EscapeCall, "E.get_Property(x)").WithArguments("E.get_Property(S)", "s").WithLocation(26, 13), // (26,28): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s = E.get_Property(x); Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(26, 28), // (28,9): error CS8350: This combination of arguments to 'E.extension(ref S).RefReceiverProperty' is disallowed because it may expose variables referenced by parameter 'value' outside of their declaration scope // s.RefReceiverProperty = x; Diagnostic(ErrorCode.ERR_CallArgMixing, "s.RefReceiverProperty").WithArguments("E.extension(ref S).RefReceiverProperty", "value").WithLocation(28, 9), // (28,33): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s.RefReceiverProperty = x; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(28, 33), // (29,9): error CS8350: This combination of arguments to 'E.set_RefReceiverProperty(ref S, S)' is disallowed because it may expose variables referenced by parameter 'value' outside of their declaration scope // E.set_RefReceiverProperty(ref s, x); Diagnostic(ErrorCode.ERR_CallArgMixing, "E.set_RefReceiverProperty(ref s, x)").WithArguments("E.set_RefReceiverProperty(ref S, S)", "value").WithLocation(29, 9), // (29,42): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // E.set_RefReceiverProperty(ref s, x); Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(29, 42), // (30,13): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s = x.RefReceiverProperty; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(30, 13), // (30,13): error CS8347: Cannot use a result of 'E.extension(ref S).RefReceiverProperty' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // s = x.RefReceiverProperty; Diagnostic(ErrorCode.ERR_EscapeCall, "x.RefReceiverProperty").WithArguments("E.extension(ref S).RefReceiverProperty", "s").WithLocation(30, 13), // (31,13): error CS8347: Cannot use a result of 'E.get_RefReceiverProperty(ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // s = E.get_RefReceiverProperty(ref x); Diagnostic(ErrorCode.ERR_EscapeCall, "E.get_RefReceiverProperty(ref x)").WithArguments("E.get_RefReceiverProperty(ref S)", "s").WithLocation(31, 13), // (31,43): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s = E.get_RefReceiverProperty(ref x); Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(31, 43) ); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79654")] public void RefAnalysis_PropertyAccess_07() { string source = """ using System; ref struct S { public Span<int> field; } static class E { extension(S s) { public ref S Property { get => throw null!; } } extension(ref S s) { public ref S RefReceiverProperty { get => throw null!; } } public static void Test1(S s) { var x = new S { field = stackalloc int[10] }; s.Property = x; x = s.Property; E.get_Property(s) = x; x = E.get_Property(s); s.RefReceiverProperty = x; s = x.RefReceiverProperty; E.get_RefReceiverProperty(ref s) = x; s = E.get_RefReceiverProperty(ref x); } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (23,22): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s.Property = x; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(23, 22), // (25,29): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // E.get_Property(s) = x; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(25, 29), // (28,33): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s.RefReceiverProperty = x; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(28, 33), // (29,13): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s = x.RefReceiverProperty; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(29, 13), // (29,13): error CS8347: Cannot use a result of 'E.extension(ref S).RefReceiverProperty' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // s = x.RefReceiverProperty; Diagnostic(ErrorCode.ERR_EscapeCall, "x.RefReceiverProperty").WithArguments("E.extension(ref S).RefReceiverProperty", "s").WithLocation(29, 13), // (30,44): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // E.get_RefReceiverProperty(ref s) = x; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(30, 44), // (31,13): error CS8347: Cannot use a result of 'E.get_RefReceiverProperty(ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // s = E.get_RefReceiverProperty(ref x); Diagnostic(ErrorCode.ERR_EscapeCall, "E.get_RefReceiverProperty(ref x)").WithArguments("E.get_RefReceiverProperty(ref S)", "s").WithLocation(31, 13), // (31,43): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s = E.get_RefReceiverProperty(ref x); Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(31, 43) ); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79654")] public void RefAnalysis_IndexerAccess_01() { string source = """ using System; ref struct S { public Span<int> field; } static class E { extension(S s) { public S this[int i] { get => throw null!; set => throw null!; } } extension(ref S s) { public S this[double d] { get => throw null!; set => throw null!; } } public static void Test1(S s) { var x = new S { field = stackalloc int[10] }; s[0] = x; E.set_Item(s, 0, x); s = x[0]; // 1, 2 s = E.get_Item(x, 0); // 3, 4 s[1.0] = x; // 5, 6 E.set_Item(ref s, 1.0, x); // 7, 8 s = x[1.0]; // 9, 10 s = E.get_Item(ref x, 1.0); // 11, 12 } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (25,13): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s = x[0]; // 1, 2 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(25, 13), // (25,13): error CS8347: Cannot use a result of 'E.extension(S).this[int]' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // s = x[0]; // 1, 2 Diagnostic(ErrorCode.ERR_EscapeCall, "x[0]").WithArguments("E.extension(S).this[int]", "s").WithLocation(25, 13), // (26,13): error CS8347: Cannot use a result of 'E.get_Item(S, int)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // s = E.get_Item(x, 0); // 3, 4 Diagnostic(ErrorCode.ERR_EscapeCall, "E.get_Item(x, 0)").WithArguments("E.get_Item(S, int)", "s").WithLocation(26, 13), // (26,24): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s = E.get_Item(x, 0); // 3, 4 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(26, 24), // (28,9): error CS8350: This combination of arguments to 'E.extension(ref S).this[double]' is disallowed because it may expose variables referenced by parameter 'value' outside of their declaration scope // s[1.0] = x; // 5, 6 Diagnostic(ErrorCode.ERR_CallArgMixing, "s[1.0]").WithArguments("E.extension(ref S).this[double]", "value").WithLocation(28, 9), // (28,18): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s[1.0] = x; // 5, 6 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(28, 18), // (29,9): error CS8350: This combination of arguments to 'E.set_Item(ref S, double, S)' is disallowed because it may expose variables referenced by parameter 'value' outside of their declaration scope // E.set_Item(ref s, 1.0, x); // 7, 8 Diagnostic(ErrorCode.ERR_CallArgMixing, "E.set_Item(ref s, 1.0, x)").WithArguments("E.set_Item(ref S, double, S)", "value").WithLocation(29, 9), // (29,32): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // E.set_Item(ref s, 1.0, x); // 7, 8 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(29, 32), // (30,13): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s = x[1.0]; // 9, 10 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(30, 13), // (30,13): error CS8347: Cannot use a result of 'E.extension(ref S).this[double]' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // s = x[1.0]; // 9, 10 Diagnostic(ErrorCode.ERR_EscapeCall, "x[1.0]").WithArguments("E.extension(ref S).this[double]", "s").WithLocation(30, 13), // (31,13): error CS8347: Cannot use a result of 'E.get_Item(ref S, double)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // s = E.get_Item(ref x, 1.0); // 11, 12 Diagnostic(ErrorCode.ERR_EscapeCall, "E.get_Item(ref x, 1.0)").WithArguments("E.get_Item(ref S, double)", "s").WithLocation(31, 13), // (31,28): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s = E.get_Item(ref x, 1.0); // 11, 12 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(31, 28)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79654")] public void RefAnalysis_IndexerAccess_02() { string source = """ using System; ref struct S { public Span<int> field; } static class E { extension(S s) { public ref S this[int i] { get => throw null!; } } extension(ref S s) { public ref S this[double d] { get => throw null!; } } public static void Test1(S s) { var x = new S { field = stackalloc int[10] }; s[0] = x; // 1 E.get_Item(s, 0) = x; // 2 s = x[0]; s = E.get_Item(x, 0); s[1.0] = x; // 3 E.get_Item(ref s, 1.0) = x; // 4 s = x[1.0]; // 5, 6 s = E.get_Item(ref x, 1.0); // 7, 8 } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (23,16): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s[0] = x; // 1 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(23, 16), // (24,28): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // E.get_Item(s, 0) = x; // 2 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(24, 28), // (28,18): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s[1.0] = x; // 3 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(28, 18), // (29,34): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // E.get_Item(ref s, 1.0) = x; // 4 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(29, 34), // (30,13): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s = x[1.0]; // 5, 6 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(30, 13), // (30,13): error CS8347: Cannot use a result of 'E.extension(ref S).this[double]' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // s = x[1.0]; // 5, 6 Diagnostic(ErrorCode.ERR_EscapeCall, "x[1.0]").WithArguments("E.extension(ref S).this[double]", "s").WithLocation(30, 13), // (31,13): error CS8347: Cannot use a result of 'E.get_Item(ref S, double)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // s = E.get_Item(ref x, 1.0); // 7, 8 Diagnostic(ErrorCode.ERR_EscapeCall, "E.get_Item(ref x, 1.0)").WithArguments("E.get_Item(ref S, double)", "s").WithLocation(31, 13), // (31,28): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // s = E.get_Item(ref x, 1.0); // 7, 8 Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(31, 28)); } [Fact] public void Nullability_Invocation_01() { var src = """ #nullable enable object? oNull = null; oNull.M(); object? oNotNull = new object(); oNotNull.M(); static class E { extension(object? o) { public void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void Nullability_Invocation_02() { var src = """ #nullable enable object? oNull = null; oNull.M(); // 1 object? oNotNull = new object(); oNotNull.M(); oNotNull?.M(); // 2 object? oNull2 = null; oNull2!.M(); static class E { extension(object o) { public void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,1): warning CS8604: Possible null reference argument for parameter 'o' in 'E.extension(object)'. // oNull.M(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceArgument, "oNull").WithArguments("o", "E.extension(object)").WithLocation(4, 1)); } [Fact] public void Nullability_Invocation_03() { var src = """ #nullable enable object? oNull = null; oNull.M().ToString(); object? oNotNull = new object(); oNotNull.M().ToString(); oNotNull?.M().ToString(); static class E { extension<T>(T t) { public T M() => t; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,1): warning CS8602: Dereference of a possibly null reference. // oNull.M().ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "oNull.M()").WithLocation(4, 1)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation1 = GetSyntax<InvocationExpressionSyntax>(tree, "oNull.M()"); AssertEx.Equal("System.Object? E.extension<System.Object?>(System.Object?).M()", model.GetSymbolInfo(invocation1).Symbol.ToTestDisplayString(includeNonNullable: true)); var invocation2 = GetSyntax<InvocationExpressionSyntax>(tree, "oNotNull.M()"); AssertEx.Equal("System.Object! E.extension<System.Object!>(System.Object!).M()", model.GetSymbolInfo(invocation2).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_Invocation_04() { var src = """ #nullable enable object? oNull = null; oNull.M().ToString(); object? oNotNull = new object(); oNotNull.M().ToString(); """; var libSrc = """ #nullable enable public static class E { extension<T>(T t) where T : notnull { public T M() => t; } } """; DiagnosticDescription[] expected = [ // (4,1): warning CS8714: The type 'object?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(T)'. Nullability of type argument 'object?' doesn't match 'notnull' constraint. // oNull.M().ToString(); Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "oNull.M").WithArguments("E.extension<T>(T)", "T", "object?").WithLocation(4, 1), // (4,1): warning CS8602: Dereference of a possibly null reference. // oNull.M().ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "oNull.M()").WithLocation(4, 1) ]; var comp = CreateCompilation([src, libSrc]); comp.VerifyEmitDiagnostics(expected); var libComp = CreateCompilation(libSrc); var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]); comp2.VerifyEmitDiagnostics(expected); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation1 = GetSyntax<InvocationExpressionSyntax>(tree, "oNull.M()"); AssertEx.Equal("System.Object? E.extension<System.Object?>(System.Object?).M()", model.GetSymbolInfo(invocation1).Symbol.ToTestDisplayString(includeNonNullable: true)); var invocation2 = GetSyntax<InvocationExpressionSyntax>(tree, "oNotNull.M()"); AssertEx.Equal("System.Object! E.extension<System.Object!>(System.Object!).M()", model.GetSymbolInfo(invocation2).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_Invocation_05() { var src = """ #nullable enable object? oNull = null; oNull.M(oNull).ToString(); object? oNotNull = new object(); oNotNull.M(oNotNull).ToString(); static class E { extension<T>(T t) where T : notnull { public U M<U>(U u) where U : notnull => u; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,1): warning CS8714: The type 'object?' cannot be used as type parameter 'U' in the generic type or method 'E.extension<object?>(object?).M<U>(U)'. Nullability of type argument 'object?' doesn't match 'notnull' constraint. // oNull.M(oNull).ToString(); Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "oNull.M").WithArguments("E.extension<object?>(object?).M<U>(U)", "U", "object?").WithLocation(4, 1), // (4,1): warning CS8714: The type 'object?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(T)'. Nullability of type argument 'object?' doesn't match 'notnull' constraint. // oNull.M(oNull).ToString(); Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "oNull.M").WithArguments("E.extension<T>(T)", "T", "object?").WithLocation(4, 1), // (4,1): warning CS8602: Dereference of a possibly null reference. // oNull.M(oNull).ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "oNull.M(oNull)").WithLocation(4, 1)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation1 = GetSyntax<InvocationExpressionSyntax>(tree, "oNull.M(oNull)"); AssertEx.Equal("System.Object? E.extension<System.Object?>(System.Object?).M<System.Object?>(System.Object? u)", model.GetSymbolInfo(invocation1).Symbol.ToTestDisplayString(includeNonNullable: true)); var invocation2 = GetSyntax<InvocationExpressionSyntax>(tree, "oNotNull.M(oNotNull)"); AssertEx.Equal("System.Object! E.extension<System.Object!>(System.Object!).M<System.Object!>(System.Object! u)", model.GetSymbolInfo(invocation2).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_Invocation_06() { var src = """ #nullable enable Derived1.M().ToString(); Derived2.M().ToString(); static class E { extension<T>(C<T> t) where T : notnull { public static T M() => throw null!; } } class Derived1 : C<object?> { } class Derived2 : C<object> { } class C<T> { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,1): warning CS8714: The type 'object?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(C<T>)'. Nullability of type argument 'object?' doesn't match 'notnull' constraint. // Derived1.M().ToString(); Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "Derived1.M").WithArguments("E.extension<T>(C<T>)", "T", "object?").WithLocation(3, 1), // (3,1): warning CS8602: Dereference of a possibly null reference. // Derived1.M().ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Derived1.M()").WithLocation(3, 1)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation1 = GetSyntax<InvocationExpressionSyntax>(tree, "Derived1.M()"); AssertEx.Equal("System.Object? E.extension<System.Object?>(C<System.Object?>!).M()", model.GetSymbolInfo(invocation1).Symbol.ToTestDisplayString(includeNonNullable: true)); var invocation2 = GetSyntax<InvocationExpressionSyntax>(tree, "Derived2.M()"); AssertEx.Equal("System.Object! E.extension<System.Object!>(C<System.Object!>!).M()", model.GetSymbolInfo(invocation2).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_Invocation_07() { var src = """ #nullable enable object.M<object>(42); static class E { extension<T>(T t) { public static void M() => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,8): error CS1501: No overload for method 'M' takes 1 arguments // object.M<object>(42); Diagnostic(ErrorCode.ERR_BadArgCount, "M<object>").WithArguments("M", "1").WithLocation(3, 8)); } [Fact] public void Nullability_Invocation_08() { var src = """ #nullable enable object? o = new object(); object? oNull1 = null; o.M(oNull1); object? oNotNull = new object(); o.M(oNotNull); object? oNull2 = null; o.M(oNull2!); object? oNull3 = null; object.M2(oNull3); object.M2(oNotNull); object? oNull4 = null; object.M2(oNull4!); static class E { extension(object o1) { public void M(object o2) { } public static void M2(object o2) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,5): warning CS8604: Possible null reference argument for parameter 'o2' in 'void E.extension(object).M(object o2)'. // o.M(oNull1); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "oNull1").WithArguments("o2", "void E.extension(object).M(object o2)").WithLocation(6, 5), // (15,11): warning CS8604: Possible null reference argument for parameter 'o2' in 'void E.extension(object).M2(object o2)'. // object.M2(oNull3); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "oNull3").WithArguments("o2", "void E.extension(object).M2(object o2)").WithLocation(15, 11)); } [Fact] public void Nullability_Invocation_09() { var src = """ #nullable enable object? oNull = null; object? oNotNull = new object(); oNull.M().M().ToString(); oNotNull.M().M().ToString(); object.M2().M().ToString(); static class E { extension<T>(T t) { public T M() => throw null!; public static T M2() => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,1): warning CS8602: Dereference of a possibly null reference. // oNull.M().M().ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "oNull.M().M()").WithLocation(6, 1)); } [Fact] public void Nullability_Invocation_10() { // nullability check on the return value var src = """ #nullable enable object.M().ToString(); // 1 E.M().ToString(); // 2 object.M2().ToString(); E.M2().ToString(); """; var libSrc = """ #nullable enable public static class E { extension(object) { public static object? M() => throw null!; public static object M2() => throw null!; } } """; DiagnosticDescription[] expected = [ // (3,1): warning CS8602: Dereference of a possibly null reference. // object.M().ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "object.M()").WithLocation(3, 1), // (4,1): warning CS8602: Dereference of a possibly null reference. // E.M().ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "E.M()").WithLocation(4, 1) ]; var comp = CreateCompilation([src, libSrc]); comp.VerifyEmitDiagnostics(expected); var libComp = CreateCompilation(libSrc); var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]); comp2.VerifyEmitDiagnostics(expected); } [Fact] public void Nullability_Invocation_11() { // nullability annotation in constraints var src = """ #nullable enable I? iNull = null; iNull.M(); // 1 I? iNull2 = null; iNull2.M2(); I iNotNull = getI(); iNotNull.M(); iNotNull.M2(); I getI() => throw null!; """; var libSrc = """ #nullable enable public interface I { } public static class E { extension<T>(T t) where T : I { public T M() => t; } extension<T>(T t) where T : I? { public T M2() => t; } } """; DiagnosticDescription[] expected = [ // (4,1): warning CS8631: The type 'I?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(T)'. Nullability of type argument 'I?' doesn't match constraint type 'I'. // iNull.M(); // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint, "iNull.M").WithArguments("E.extension<T>(T)", "I", "T", "I?").WithLocation(4, 1) ]; var comp = CreateCompilation([src, libSrc]); comp.VerifyEmitDiagnostics(expected); var libComp = CreateCompilation(libSrc); var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]); comp2.VerifyEmitDiagnostics(expected); } [Fact] public void Nullability_Invocation_12() { // optional parameter with nullability warning var src = """ #nullable enable object o = new object(); o.M(); static class E { extension(object o1) { public void M(object o2 = null) { } } } """; CreateCompilation(src).VerifyEmitDiagnostics( // (10,35): warning CS8625: Cannot convert null literal to non-nullable reference type. // public void M(object o2 = null) { } Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 35)); } [Fact] public void Nullability_MethodGroup_01() { var src = """ #nullable enable object? oNull = null; var x = oNull.M; object? oNotNull = new object(); var y = oNotNull.M; object? oNull2 = null; var z = oNull2!.M; static class E { extension(object? o) { public void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "oNull.M"); AssertEx.Equal("void E.extension(System.Object?).M()", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString(includeNonNullable: true)); var localDeclaration1 = GetSyntax<VariableDeclarationSyntax>(tree, "var x = oNull.M"); AssertEx.Equal("System.Action?", model.GetTypeInfo(localDeclaration1.Type).Type.ToTestDisplayString()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "oNotNull.M"); AssertEx.Equal("void E.extension(System.Object?).M()", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString(includeNonNullable: true)); var localDeclaration2 = GetSyntax<VariableDeclarationSyntax>(tree, "var y = oNotNull.M"); AssertEx.Equal("System.Action?", model.GetTypeInfo(localDeclaration2.Type).Type.ToTestDisplayString()); } [Fact] public void Nullability_MethodGroup_02() { var src = """ #nullable enable object? oNull = null; var x = oNull.M; object? oNotNull = new object(); var y = oNotNull.M; static class E { extension(object o) { public void M() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,9): warning CS8604: Possible null reference argument for parameter 'o' in 'E.extension(object)'. // var x = oNull.M; Diagnostic(ErrorCode.WRN_NullReferenceArgument, "oNull").WithArguments("o", "E.extension(object)").WithLocation(4, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "oNull.M"); AssertEx.Equal("void E.extension(System.Object!).M()", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString(includeNonNullable: true)); var localDeclaration1 = GetSyntax<VariableDeclarationSyntax>(tree, "var x = oNull.M"); AssertEx.Equal("System.Action?", model.GetTypeInfo(localDeclaration1.Type).Type.ToTestDisplayString()); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "oNotNull.M"); AssertEx.Equal("void E.extension(System.Object!).M()", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString(includeNonNullable: true)); var localDeclaration2 = GetSyntax<VariableDeclarationSyntax>(tree, "var y = oNotNull.M"); AssertEx.Equal("System.Action?", model.GetTypeInfo(localDeclaration2.Type).Type.ToTestDisplayString()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78022")] public void Nullability_MethodGroup_03() { var src = """ #nullable enable object? oNull = null; var x = oNull.M; var x2 = oNull.M2; object? oNull2 = null; System.Func<object> x3 = oNull2.M; // 1 System.Func<object> x4 = oNull2.M2; // 2 object? oNull3 = null; _ = new System.Func<object>(oNull3.M); // 3 _ = new System.Func<object>(oNull3.M2); // 4 object? oNotNull = new object(); var y = oNotNull.M; object? oNotNull2 = new object(); System.Func<object> y2 = oNotNull2.M; _ = new System.Func<object>(oNotNull2.M); static class E { extension<T>(T t) { public T M() { return t; } } public static T M2<T>(this T t) => t; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (8,26): warning CS8621: Nullability of reference types in return type of 'object? E.extension<object?>(object?).M()' doesn't match the target delegate 'Func<object>' (possibly because of nullability attributes). // System.Func<object> x3 = oNull2.M; // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOfTargetDelegate, "oNull2.M").WithArguments("object? E.extension<object?>(object?).M()", "System.Func<object>").WithLocation(8, 26), // (9,26): warning CS8621: Nullability of reference types in return type of 'object? E.M2<object?>(object? t)' doesn't match the target delegate 'Func<object>' (possibly because of nullability attributes). // System.Func<object> x4 = oNull2.M2; // 2 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOfTargetDelegate, "oNull2.M2").WithArguments("object? E.M2<object?>(object? t)", "System.Func<object>").WithLocation(9, 26), // (12,29): warning CS8621: Nullability of reference types in return type of 'object? E.extension<object?>(object?).M()' doesn't match the target delegate 'Func<object>' (possibly because of nullability attributes). // _ = new System.Func<object>(oNull3.M); // 3 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOfTargetDelegate, "oNull3.M").WithArguments("object? E.extension<object?>(object?).M()", "System.Func<object>").WithLocation(12, 29), // (13,29): warning CS8621: Nullability of reference types in return type of 'object? E.M2<object?>(object? t)' doesn't match the target delegate 'Func<object>' (possibly because of nullability attributes). // _ = new System.Func<object>(oNull3.M2); // 4 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOfTargetDelegate, "oNull3.M2").WithArguments("object? E.M2<object?>(object? t)", "System.Func<object>").WithLocation(13, 29)); // Tracked by https://github.com/dotnet/roslyn/issues/78022 : the semantic model is incorrect for re-inferred method group var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); // Should be "System.Object? E.extension<System.Object?>(System.Object?).M()" var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "oNull.M"); AssertEx.Equal("System.Object E.extension<System.Object>(System.Object).M()", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString(includeNonNullable: true)); // Should be "System.Func<System.Object?>?" var varDeclaration1 = GetSyntax<VariableDeclarationSyntax>(tree, "var x = oNull.M"); AssertEx.Equal("System.Func<System.Object>?", model.GetTypeInfo(varDeclaration1.Type).Type.ToTestDisplayString(includeNonNullable: true)); // Should be "System.Object? System.Object?.M2<System.Object?>()" var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "oNull.M2"); AssertEx.Equal("System.Object System.Object!.M2<System.Object>()", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString(includeNonNullable: true)); // Should be "System.Func<System.Object?>?" var varDeclaration2 = GetSyntax<VariableDeclarationSyntax>(tree, "var x2 = oNull.M2"); AssertEx.Equal("System.Func<System.Object>?", model.GetTypeInfo(varDeclaration2.Type).Type.ToTestDisplayString(includeNonNullable: true)); // Should be "System.Object? E.extension<System.Object?>(System.Object?).M()" var memberAccess3 = GetSyntax<MemberAccessExpressionSyntax>(tree, "oNull2.M"); AssertEx.Equal("System.Object E.extension<System.Object>(System.Object).M()", model.GetSymbolInfo(memberAccess3).Symbol.ToTestDisplayString(includeNonNullable: true)); // Should be "System.Object? System.Object?.M2<System.Object?>()" var memberAccess4 = GetSyntax<MemberAccessExpressionSyntax>(tree, "oNull2.M2"); AssertEx.Equal("System.Object System.Object!.M2<System.Object>()", model.GetSymbolInfo(memberAccess4).Symbol.ToTestDisplayString(includeNonNullable: true)); // Should be "System.Object! E.extension<System.Object!>(System.Object!).M()" var memberAccess5 = GetSyntax<MemberAccessExpressionSyntax>(tree, "oNotNull.M"); AssertEx.Equal("System.Object E.extension<System.Object>(System.Object).M()", model.GetSymbolInfo(memberAccess5).Symbol.ToTestDisplayString(includeNonNullable: true)); // Should be "System.Func<System.Object!>?" var varDeclaration3 = GetSyntax<VariableDeclarationSyntax>(tree, "var y = oNotNull.M"); AssertEx.Equal("System.Func<System.Object>?", model.GetTypeInfo(varDeclaration3.Type).Type.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_MethodGroup_04() { var src = """ #nullable enable object? oNull = null; System.Func<object, object> x = oNull.M; // 1 System.Func<object, object> x2 = oNull.M2; // 2 object? oNotNull = new object(); System.Func<object?, object?> y = oNotNull.M; System.Func<object?, object?> y2 = oNotNull.M2; static class E { extension<T>(T t) { public T M(T t2) { return t; } } public static T M2<T>(this T t, T t2) => t; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,33): warning CS8621: Nullability of reference types in return type of 'object? E.extension<object?>(object?).M(object? t2)' doesn't match the target delegate 'Func<object, object>' (possibly because of nullability attributes). // System.Func<object, object> x = oNull.M; // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOfTargetDelegate, "oNull.M").WithArguments("object? E.extension<object?>(object?).M(object? t2)", "System.Func<object, object>").WithLocation(4, 33), // (5,34): warning CS8621: Nullability of reference types in return type of 'object? E.M2<object?>(object? t, object? t2)' doesn't match the target delegate 'Func<object, object>' (possibly because of nullability attributes). // System.Func<object, object> x2 = oNull.M2; // 2 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOfTargetDelegate, "oNull.M2").WithArguments("object? E.M2<object?>(object? t, object? t2)", "System.Func<object, object>").WithLocation(5, 34)); } [Fact] public void Nullability_MethodGroup_05() { var src = """ #nullable enable System.Action<object?> x = Derived1.M; System.Action<object?> y = Derived2.M; System.Action<object?> z = Derived1.M2; System.Action<object?> t = Derived2.M2; _ = new System.Action<object?>(Derived2.M2); static class E { extension<T>(C<T> t) { public static void M(T t2) => throw null!; public static void M2(object t2) => throw null!; } } class Derived1 : C<object?> { } class Derived2 : C<object> { } class C<T> { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,28): warning CS8622: Nullability of reference types in type of parameter 't2' of 'void E.extension<object?>(C<object?>).M2(object t2)' doesn't match the target delegate 'Action<object?>' (possibly because of nullability attributes). // System.Action<object?> z = Derived1.M2; Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOfTargetDelegate, "Derived1.M2").WithArguments("t2", "void E.extension<object?>(C<object?>).M2(object t2)", "System.Action<object?>").WithLocation(6, 28), // (7,28): warning CS8622: Nullability of reference types in type of parameter 't2' of 'void E.extension<object>(C<object>).M2(object t2)' doesn't match the target delegate 'Action<object?>' (possibly because of nullability attributes). // System.Action<object?> t = Derived2.M2; Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOfTargetDelegate, "Derived2.M2").WithArguments("t2", "void E.extension<object>(C<object>).M2(object t2)", "System.Action<object?>").WithLocation(7, 28), // (8,32): warning CS8622: Nullability of reference types in type of parameter 't2' of 'void E.extension<object>(C<object>).M2(object t2)' doesn't match the target delegate 'Action<object?>' (possibly because of nullability attributes). // _ = new System.Action<object?>(Derived2.M2); Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOfTargetDelegate, "Derived2.M2").WithArguments("t2", "void E.extension<object>(C<object>).M2(object t2)", "System.Action<object?>").WithLocation(8, 32)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78022")] public void Nullability_MethodGroup_06() { var src = """ #nullable enable var x = Derived1.M; x().ToString(); var y = Derived2.M; y().ToString(); static class E { extension<T>(C<T> t) { public static T M() => throw null!; } } class Derived1 : C<object?> { } class Derived2 : C<object> { } class C<T> { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); // Tracked by https://github.com/dotnet/roslyn/issues/78022 : the semantic model is incorrect for re-inferred method group var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var invocation1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "Derived1.M"); // Should be "System.Object? E.extension<System.Object?>(C<System.Object?>!).M()" AssertEx.Equal("System.Object E.extension<System.Object>(C<System.Object>!).M()", model.GetSymbolInfo(invocation1).Symbol.ToTestDisplayString(includeNonNullable: true)); // Should be "System.Func<System.Object?>?" var localDeclaration1 = GetSyntax<VariableDeclarationSyntax>(tree, "var x = Derived1.M"); AssertEx.Equal("System.Func<System.Object>?", model.GetTypeInfo(localDeclaration1.Type).Type.ToTestDisplayString(includeNonNullable: true)); // Should be "System.Object! E.extension<System.Object!>(C<System.Object!>!).M()" var invocation2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "Derived2.M"); AssertEx.Equal("System.Object E.extension<System.Object>(C<System.Object>!).M()", model.GetSymbolInfo(invocation2).Symbol.ToTestDisplayString(includeNonNullable: true)); // Should be "System.Func<System.Object!>?" var localDeclaration2 = GetSyntax<VariableDeclarationSyntax>(tree, "var x = Derived1.M"); AssertEx.Equal("System.Func<System.Object>?", model.GetTypeInfo(localDeclaration2.Type).Type.ToTestDisplayString(includeNonNullable: true)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78022")] public void Nullability_MethodGroup_07() { var src = """ #nullable enable System.Func<object> x = Derived1.M; // 1 System.Func<object> y = Derived2.M; static class E { extension<T>(C<T> t) { public static T M() => throw null!; } } class Derived1 : C<object?> { } class Derived2 : C<object> { } class C<T> { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,25): warning CS8621: Nullability of reference types in return type of 'object? E.extension<object?>(C<object?>).M()' doesn't match the target delegate 'Func<object>' (possibly because of nullability attributes). // System.Func<object> x = Derived1.M; // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOfTargetDelegate, "Derived1.M").WithArguments("object? E.extension<object?>(C<object?>).M()", "System.Func<object>").WithLocation(3, 25)); // Tracked by https://github.com/dotnet/roslyn/issues/78022 : the semantic model is incorrect for re-inferred method group var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "Derived1.M"); // Should be "System.Object? E.extension<System.Object?>(C<System.Object?>!).M()" AssertEx.Equal("System.Object E.extension<System.Object>(C<System.Object>!).M()", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString(includeNonNullable: true)); var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "Derived2.M"); // Should be "System.Object! E.extension<System.Object!>(C<System.Object!>!).M()" AssertEx.Equal("System.Object E.extension<System.Object>(C<System.Object>!).M()", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_MethodGroup_08() { var src = """ #nullable enable var x = Derived1.M; var y = Derived2.M; var z = new Derived1().M2; static class E { extension<T>(C<T> t) where T : notnull { public static T M() => throw null!; } public static T M2<T>(this C<T> t) where T : notnull => throw null!; } class Derived1 : C<object?> { } class Derived2 : C<object> { } class C<T> { } """; // Tracked by https://github.com/dotnet/roslyn/issues/78022 : the analysis is incorrect for re-inferred method group // The warnings about return types are wrong var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,9): warning CS8714: The type 'object?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(C<T>)'. Nullability of type argument 'object?' doesn't match 'notnull' constraint. // var x = Derived1.M; Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "Derived1.M").WithArguments("E.extension<T>(C<T>)", "T", "object?").WithLocation(3, 9), // (3,9): warning CS8621: Nullability of reference types in return type of 'object? E.extension<object?>(C<object?>).M()' doesn't match the target delegate 'Func<object>' (possibly because of nullability attributes). // var x = Derived1.M; Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOfTargetDelegate, "Derived1.M").WithArguments("object? E.extension<object?>(C<object?>).M()", "System.Func<object>").WithLocation(3, 9), // (6,9): warning CS8714: The type 'object?' cannot be used as type parameter 'T' in the generic type or method 'E.M2<T>(C<T>)'. Nullability of type argument 'object?' doesn't match 'notnull' constraint. // var z = new Derived1().M2; Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "new Derived1().M2").WithArguments("E.M2<T>(C<T>)", "T", "object?").WithLocation(6, 9), // (6,9): warning CS8621: Nullability of reference types in return type of 'object? E.M2<object?>(C<object?> t)' doesn't match the target delegate 'Func<object>' (possibly because of nullability attributes). // var z = new Derived1().M2; Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOfTargetDelegate, "new Derived1().M2").WithArguments("object? E.M2<object?>(C<object?> t)", "System.Func<object>").WithLocation(6, 9)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); // Should be "System.Object? E.extension<System.Object?>(C<System.Object?>!).M()" var memberAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "Derived1.M"); AssertEx.Equal("System.Object! E.extension<System.Object>(C<System.Object!>!).M()", model.GetSymbolInfo(memberAccess1).Symbol.ToTestDisplayString(includeNonNullable: true)); // Should be "System.Func<System.Object?>?" var varDeclaration1 = GetSyntax<VariableDeclarationSyntax>(tree, "var x = Derived1.M"); AssertEx.Equal("System.Func<System.Object!>?", model.GetTypeInfo(varDeclaration1.Type).Type.ToTestDisplayString(includeNonNullable: true)); // Should be "System.Object! E.extension<System.Object!>(C<System.Object!>!).M()" var memberAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "Derived2.M"); AssertEx.Equal("System.Object! E.extension<System.Object>(C<System.Object!>!).M()", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString(includeNonNullable: true)); var varDeclaration2 = GetSyntax<VariableDeclarationSyntax>(tree, "var x = Derived1.M"); AssertEx.Equal("System.Func<System.Object!>?", model.GetTypeInfo(varDeclaration2.Type).Type.ToTestDisplayString(includeNonNullable: true)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78022")] public void Nullability_Deconstruct_01() { var src = """ #nullable enable object? oNull = null; var (x1, x2) = oNull; x1.ToString(); // 1 object oNotNull = new object(); var (y1, y2) = oNotNull; y1.ToString(); var (z1, z2, z3) = oNull; z1.ToString(); // 2 static class E { extension<T>(T t) { public void Deconstruct(out T t1, out T t2) => throw null!; } public static void Deconstruct<T>(this T t, out T t1, out T t2, out T t3) => throw null!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,1): warning CS8602: Dereference of a possibly null reference. // x1.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x1").WithLocation(5, 1), // (12,1): warning CS8602: Dereference of a possibly null reference. // z1.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "z1").WithLocation(12, 1)); // Tracked by https://github.com/dotnet/roslyn/issues/78022 : the semantic model is incorrect for re-inferred deconstruction var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignment1 = GetSyntax<AssignmentExpressionSyntax>(tree, "var (x1, x2) = oNull"); // Should be "void E.extension<System.Object?>(System.Object?).Deconstruct(out System.Object? t1, out System.Object? t2)" AssertEx.Equal("void E.extension<System.Object>(System.Object).Deconstruct(out System.Object t1, out System.Object t2)", model.GetDeconstructionInfo(assignment1).Method.ToTestDisplayString(includeNonNullable: true)); // Should be "void E.extension<System.Object!>(System.Object!).Deconstruct(out System.Object! t1, out System.Object! t2)" var assignment2 = GetSyntax<AssignmentExpressionSyntax>(tree, "var (y1, y2) = oNotNull"); AssertEx.Equal("void E.extension<System.Object>(System.Object).Deconstruct(out System.Object t1, out System.Object t2)", model.GetDeconstructionInfo(assignment2).Method.ToTestDisplayString(includeNonNullable: true)); // Should be "void E.Deconstruct<System.Object?>(this System.Object? t, out System.Object? t1, out System.Object? t2, out System.Object? t3)" var assignment3 = GetSyntax<AssignmentExpressionSyntax>(tree, "var (z1, z2, z3) = oNull"); AssertEx.Equal("void E.Deconstruct<System.Object>(this System.Object t, out System.Object t1, out System.Object t2, out System.Object t3)", model.GetDeconstructionInfo(assignment3).Method.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_Deconstruct_02() { var src = """ #nullable enable object? oNull = null; var (x1, x2) = oNull; // 1 object oNotNull = new object(); var (y1, y2) = oNotNull; static class E { extension(object o) { public void Deconstruct(out int i1, out int i2) => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,16): warning CS8604: Possible null reference argument for parameter 'o' in 'E.extension(object)'. // var (x1, x2) = oNull; // 1 Diagnostic(ErrorCode.WRN_NullReferenceArgument, "oNull").WithArguments("o", "E.extension(object)").WithLocation(4, 16)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignment1 = GetSyntax<AssignmentExpressionSyntax>(tree, "var (x1, x2) = oNull"); AssertEx.Equal("void E.extension(System.Object!).Deconstruct(out System.Int32 i1, out System.Int32 i2)", model.GetDeconstructionInfo(assignment1).Method.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_Deconstruct_03() { var src = """ #nullable enable (object?, object?) oNull = default; var ((x1, x2), _) = oNull; // 1 (object, object) oNotNull = (new object(), new object()); var ((y1, y2), _) = oNotNull; static class E { extension(object o) { public void Deconstruct(out int i1, out int i2) => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,21): warning CS8604: Possible null reference argument for parameter 'o' in 'E.extension(object)'. // var ((x1, x2), _) = oNull; // 1 Diagnostic(ErrorCode.WRN_NullReferenceArgument, "oNull").WithArguments("o", "E.extension(object)").WithLocation(4, 21)); } [Fact] public void Nullability_Deconstruct_04() { var src = """ #nullable enable object? oNull = default; var (x1, x2) = oNull; // 1 object oNotNull = new object(); var (y1, y2) = oNotNull; static class E { extension<T>(T t) where T : notnull { public void Deconstruct(out int i1, out int i2) => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,16): warning CS8714: The type 'object?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(T)'. Nullability of type argument 'object?' doesn't match 'notnull' constraint. // var (x1, x2) = oNull; // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "oNull").WithArguments("E.extension<T>(T)", "T", "object?").WithLocation(4, 16)); } [Fact] public void Nullability_Deconstruct_05() { var src = """ #nullable enable object o = new object(); var (x1, x2) = o; x1.ToString(); // 1 x2.ToString(); var (y1, y2, y3) = o; y1.ToString(); // 2 y2.ToString(); static class E { extension(object o) { public void Deconstruct(out object? o1, out object o2) => throw null!; } public static void Deconstruct(this object o, out object? o1, out object o2, out int i3) => throw null!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,1): warning CS8602: Dereference of a possibly null reference. // x1.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x1").WithLocation(5, 1), // (9,1): warning CS8602: Dereference of a possibly null reference. // y1.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y1").WithLocation(9, 1)); } [Fact] public void Nullability_Deconstruct_06() { // optional parameter with nullability warning var src = """ #nullable enable (int i1, int i2) = new object(); static class E { extension(object o1) { public void Deconstruct(out int i1, out int i2, object o2 = null) => throw null!; } } """; CreateCompilation(src).VerifyEmitDiagnostics( // (3,20): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'object', with 2 out parameters and a void return type. // (int i1, int i2) = new object(); Diagnostic(ErrorCode.ERR_MissingDeconstruct, "new object()").WithArguments("object", "2").WithLocation(3, 20), // (9,69): warning CS8625: Cannot convert null literal to non-nullable reference type. // public void Deconstruct(out int i1, out int i2, object o2 = null) => throw null!; Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(9, 69)); } [Fact] public void Nullability_Deconstruct_07() { // generic Deconstruct var src = """ #nullable enable object? o = null; var (o1, o2) = Infer(o); o1.ToString(); C<T> Infer<T>(T t) => throw null!; class C<T> { } static class E { extension<T>(C<T> c) { public void Deconstruct(out T t1, out T t2) => throw null!; } } """; CreateCompilation(src).VerifyEmitDiagnostics( // (5,1): warning CS8602: Dereference of a possibly null reference. // o1.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o1").WithLocation(5, 1)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78022")] public void Nullability_PositionalPattern_01() { var src = """ #nullable enable object? oNull = null; if (oNull is var (x1, x2)) { x1.ToString(); } object oNotNull = new object(); if (oNotNull is var (y1, y2)) { y1.ToString(); } if (oNull is var (z1, z2, z3)) { z1.ToString(); } static class E { extension<T>(T t) { public void Deconstruct(out T t1, out T t2) => throw null!; } public static void Deconstruct<T>(this T t, out T t1, out T t2, out T t3) => throw null!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); // Tracked by https://github.com/dotnet/roslyn/issues/78022 : verify nullability in the semantic model, possibly in IOperation } [Fact] public void Nullability_PositionalPattern_02() { var src = """ #nullable enable object? oNull = null; if (oNull is var (x1, x2)) { } object oNotNull = new object(); if (oNotNull is var (y1, y2)) { } object? oNull2 = null; if (oNull2 is var (z1, z2, z3)) { } if (oNotNull is var (t1, t2, t3)) { } static class E { extension(object o) { public void Deconstruct(out int i1, out int i2) => throw null!; } public static void Deconstruct(this object o, out int i1, out int i2, out int i3) => throw null!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); // Tracked by https://github.com/dotnet/roslyn/issues/78022 : verify nullability in the semantic model, possibly in IOperation } [Fact] public void Nullability_PositionalPattern_03() { var src = """ #nullable enable (object?, object?) oNull = default; if (oNull is var ((x1, x2), _)) { } (object, object) oNotNull = (new object(), new object()); if (oNotNull is var ((y1, y2), _)) { } (object?, object?) oNull2 = default; if (oNull2 is var ((z1, z2, z3), _)) { } if (oNotNull is var ((t1, t2, t3), _)) { } static class E { extension(object o) { public void Deconstruct(out int i1, out int i2) => throw null!; } public static void Deconstruct(this object o, out int i1, out int i2, out int i3) => throw null!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void Nullability_PositionalPattern_04() { var src = """ #nullable enable object? oNull = default; if (oNull is var (x1, x2)) { } else { System.Console.Write("skipped "); } object oNotNull = new object(); if (oNotNull is var (y1, y2)) { } object? oNull2 = default; if (oNull2 is var (z1, z2, z3)) { } else { System.Console.Write(" skipped "); } if (oNotNull is var (t1, t2, t3)) { } static class E { extension<T>(T t) where T : notnull { public void Deconstruct(out int i1, out int i2) { System.Console.Write(t is not null); i1 = i2 = 0; } } public static void Deconstruct<T>(this T t, out int i1, out int i2, out int i3) where T : notnull { System.Console.Write(t is not null); i1 = i2 = i3 = 0; } } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "skipped True skipped True").VerifyDiagnostics(); } [Fact] public void Nullability_PositionalPattern_05() { var src = """ #nullable enable object o = new object(); if (o is var (x1, x2)) { x1.ToString(); // 1 x2.ToString(); } if (o is var (y1, y2, y3)) { y1.ToString(); // 2 y2.ToString(); } static class E { extension(object o) { public void Deconstruct(out object? o1, out object o2) => throw null!; } public static void Deconstruct(this object o, out object? o1, out object o2, out int i3) => throw null!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,5): warning CS8602: Dereference of a possibly null reference. // x1.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x1").WithLocation(6, 5), // (12,5): warning CS8602: Dereference of a possibly null reference. // y1.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y1").WithLocation(12, 5)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78022")] public void Nullability_ForeachDeconstruct_01() { var src = """ #nullable enable object?[] oNull = new object?[] { }; foreach (var (x1, x2) in oNull) { x1.ToString(); // 1 } static class E { extension<T>(T t) { public void Deconstruct(out T t1, out T t2) => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,5): warning CS8602: Dereference of a possibly null reference. // x1.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x1").WithLocation(6, 5)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); // Tracked by https://github.com/dotnet/roslyn/issues/78022 : the semantic model is incorrect for re-inferred deconstruction var assignment = tree.GetRoot().DescendantNodes().OfType<ForEachVariableStatementSyntax>().Single(); // Should be "void E.extension<System.Object?>(System.Object).Deconstruct(out System.Object? t1, out System.Object? t2)" AssertEx.Equal("void E.extension<System.Object>(System.Object).Deconstruct(out System.Object t1, out System.Object t2)", model.GetDeconstructionInfo(assignment).Method.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_ForeachDeconstruct_02() { var src = """ #nullable enable object?[] oNull = new object?[] { }; foreach (var (x1, x2) in oNull) { x1.ToString(); // 1 } object[] oNotNull = new object[] { }; foreach (var (y1, y2) in oNotNull) { y1.ToString(); // 1 } static class E { extension<T>(T t) { public void Deconstruct(out T t1, out T t2) => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,5): warning CS8602: Dereference of a possibly null reference. // x1.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x1").WithLocation(6, 5)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignments = tree.GetRoot().DescendantNodes().OfType<ForEachVariableStatementSyntax>().ToArray(); AssertEx.Equal("void E.extension<System.Object>(System.Object).Deconstruct(out System.Object t1, out System.Object t2)", model.GetDeconstructionInfo(assignments[0]).Method.ToTestDisplayString(includeNonNullable: true)); AssertEx.Equal("void E.extension<System.Object>(System.Object).Deconstruct(out System.Object t1, out System.Object t2)", model.GetDeconstructionInfo(assignments[1]).Method.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_ForeachDeconstruct_03() { var src = """ #nullable enable object?[] oNull = new object?[] { }; foreach (var (x1, x2) in oNull) { x1.ToString(); } static class E { extension<T>(T t) where T : notnull { public void Deconstruct(out T t1, out T t2) => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,26): warning CS8714: The type 'object?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(T)'. Nullability of type argument 'object?' doesn't match 'notnull' constraint. // foreach (var (x1, x2) in oNull) Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "oNull").WithArguments("E.extension<T>(T)", "T", "object?").WithLocation(4, 26), // (6,5): warning CS8602: Dereference of a possibly null reference. // x1.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x1").WithLocation(6, 5)); } [Fact] public void Nullability_ForeachDeconstruct_04() { var src = """ #nullable enable object?[] oNull = new object?[] { }; foreach ((_, _) in oNull) { } foreach ((_, _, _) in oNull) { } // 1 object[] oNotNull = new object[] { }; foreach ((_, _) in oNotNull) { } foreach ((_, _, _) in oNotNull) { } static class E { extension(object? o) { public void Deconstruct(out int i1, out int i2) => throw null!; } extension(object o) { public void Deconstruct(out int i1, out int i2, out int i3) => throw null!; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,23): warning CS8604: Possible null reference argument for parameter 'o' in 'E.extension(object)'. // foreach ((_, _, _) in oNull) { } // 1 Diagnostic(ErrorCode.WRN_NullReferenceArgument, "oNull").WithArguments("o", "E.extension(object)").WithLocation(5, 23)); } [Fact] public void Nullability_ForeachDeconstruct_05() { var src = """ #nullable enable object[] o = new object[] { }; foreach (var (x1, x2) in o) { x1.ToString(); // 1 x2.ToString(); } foreach (var (y1, y2, y3) in o) { y1.ToString(); // 2 y2.ToString(); } static class E { extension(object o) { public void Deconstruct(out object? o1, out object o2) => throw null!; } public static void Deconstruct(this object o, out object? o1, out object o2, out int i3) => throw null!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,5): warning CS8602: Dereference of a possibly null reference. // x1.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x1").WithLocation(6, 5), // (12,5): warning CS8602: Dereference of a possibly null reference. // y1.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y1").WithLocation(12, 5)); } [Fact] public void Nullability_Parameter_01() { var src = """ #nullable enable object? o = null; o.M(); object? o2 = null; E.M(o2); object o3 = new object(); o3.M2(); // 1 object o4 = new object(); E.M2(o4); // 2 object o5 = new object(); o5.M(); E.M(o5); o5.M2(); E.M(o5); """; var libSrc = """ #nullable enable public static class E { extension(object? o) { public void M() { o.ToString(); } // 3 } extension(object o) { public void M2() { o.ToString(); } } } """; var comp = CreateCompilation([src, libSrc]); comp.VerifyEmitDiagnostics( // (7,27): warning CS8602: Dereference of a possibly null reference. // public void M() { o.ToString(); } Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(7, 27)); var libComp = CreateCompilation(libSrc); CompileAndVerify(libComp).VerifyTypeIL("E", """ .class public auto ansi abstract sealed beforefieldinit E extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$C43E2675C7BBF9284AF22FB8A9BF0280' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$FCD10F86264A5A381A31E52427E53CAB' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20c4 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$FCD10F86264A5A381A31E52427E53CAB'::'<Extension>$' } // end of class <M>$FCD10F86264A5A381A31E52427E53CAB .class nested public auto ansi abstract sealed specialname '<M>$FB03ECDF5D1B3883A99E213C2D618E82' extends [mscorlib]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( object o ) cil managed { .custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 01 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20c4 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$FB03ECDF5D1B3883A99E213C2D618E82'::'<Extension>$' } // end of class <M>$FB03ECDF5D1B3883A99E213C2D618E82 // Methods .method public hidebysig instance void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 43 44 31 30 46 38 36 32 36 34 41 35 41 33 38 31 41 33 31 45 35 32 34 32 37 45 35 33 43 41 42 00 00 ) // Method begins at RVA 0x20bd // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M .method public hidebysig instance void M2 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 46 42 30 33 45 43 44 46 35 44 31 42 33 38 38 33 41 39 39 45 32 31 33 43 32 44 36 31 38 45 38 32 00 00 ) // Method begins at RVA 0x20bd // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$C43E2675C7BBF9284AF22FB8A9BF0280'::M2 } // end of class <G>$C43E2675C7BBF9284AF22FB8A9BF0280 // Methods .method public hidebysig static void M ( object o ) cil managed { .custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20b4 // Code size 8 (0x8) .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance string [mscorlib]System.Object::ToString() IL_0006: pop IL_0007: ret } // end of method E::M .method public hidebysig static void M2 ( object o ) cil managed { .custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 01 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20b4 // Code size 8 (0x8) .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance string [mscorlib]System.Object::ToString() IL_0006: pop IL_0007: ret } // end of method E::M2 } // end of class E """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]); comp2.VerifyEmitDiagnostics(); } [Fact] public void Nullability_Parameter_02() { var src = """ #nullable enable static class E { extension((object?, object?) o) { public void M() { (object, object) o2 = o; o2.Item1.ToString(); } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (9,35): warning CS8619: Nullability of reference types in value of type '(object?, object?)' doesn't match target type '(object, object)'. // (object, object) o2 = o; Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "o").WithArguments("(object?, object?)", "(object, object)").WithLocation(9, 35), // (10,13): warning CS8602: Dereference of a possibly null reference. // o2.Item1.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o2.Item1").WithLocation(10, 13)); } [Fact] public void Nullability_Attribute_01() { var src = """ #nullable enable object? o = null; if (o.Try()) { o.ToString(); } object? o2 = null; if (o2.Try2()) { o2.ToString(); } object? o3 = null; if (E.Try(o3)) { o3.ToString(); } """; var libSrc = """ #nullable enable public static class E { extension([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] object? o) { public bool Try(bool b = false) { if (b) { return true; } if (o is null) { return false; } return true; } public static bool M() => throw null!; // no warning } public static bool Try2([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] this object? o) => throw null!; public static void M2([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] object? o) { } // no warning } """; // Note: the enforcement within body only kicks in for ref/out parameters var comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net90); var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()], targetFramework: TargetFramework.Net90); comp2.VerifyEmitDiagnostics(); } [Fact] public void Nullability_Attribute_02() { var src = """ #nullable enable int? i = null; if (i.Try()) { i.Value.ToString(); } int? o2 = null; if (o2.Try2()) { o2.Value.ToString(); } static class E { extension([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] ref int? o) { public bool Try(bool b = false) { if (b) { return true; // 1 } if (b) { o = 42; return true; } if (b) { return false; } return true; // 2 } } public static bool Try2([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] this ref int? o) => throw null!; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (23,17): warning CS8762: Parameter 'o' must have a non-null value when exiting with 'true'. // return true; // 1 Diagnostic(ErrorCode.WRN_ParameterConditionallyDisallowsNull, "return true;").WithArguments("o", "true").WithLocation(23, 17), // (37,13): warning CS8762: Parameter 'o' must have a non-null value when exiting with 'true'. // return true; // 2 Diagnostic(ErrorCode.WRN_ParameterConditionallyDisallowsNull, "return true;").WithArguments("o", "true").WithLocation(37, 13)); } [Fact] public void Nullability_Attribute_03() { var src = """ #nullable enable object? oNull = null; oNull.M(); static class E { extension([System.Diagnostics.CodeAnalysis.DisallowNull] object? o) { public void M() { o.ToString(); } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (4,1): warning CS8604: Possible null reference argument for parameter 'o' in 'extension(object?)'. // oNull.M(); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "oNull").WithArguments("o", "E.extension(object?)").WithLocation(4, 1)); } [Fact] public void Nullability_Attribute_04() { var src = """ #nullable enable int? iNull = null; iNull.M(); int? iNotNull = 42; iNotNull.M(); static class E { extension([System.Diagnostics.CodeAnalysis.DisallowNull] int? i) { public void M() { i.Value.ToString(); } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (4,1): warning CS8607: A possible null value may not be used for a type marked with [NotNull] or [DisallowNull] // iNull.M(); Diagnostic(ErrorCode.WRN_DisallowNullAttributeForbidsMaybeNullAssignment, "iNull").WithLocation(4, 1)); } [Fact] public void Nullability_Attribute_05() { var src = """ #nullable enable object? oNull = null; oNull.M(); object? oNotNull = new object(); oNotNull.M(); static class E { extension([System.Diagnostics.CodeAnalysis.AllowNull] object o) { public void M() { o.ToString(); } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (15,13): warning CS8602: Dereference of a possibly null reference. // o.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(15, 13)); } [Fact] public void Nullability_Attribute_06() { var src = """ #nullable enable object? oNull = null; oNull.M(); oNull.ToString(); object? oNull2 = null; oNull2.M2(); oNull2.ToString(); static class E { extension([System.Diagnostics.CodeAnalysis.NotNull] object? o) { public void M() { } // 1 } public static void M2([System.Diagnostics.CodeAnalysis.NotNull] this object? o) { } // 2 } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (17,9): warning CS8777: Parameter 'o' must have a non-null value when exiting. // } // 1 Diagnostic(ErrorCode.WRN_ParameterDisallowsNull, "}").WithArguments("o").WithLocation(17, 9), // (22,5): warning CS8777: Parameter 'o' must have a non-null value when exiting. // } // 2 Diagnostic(ErrorCode.WRN_ParameterDisallowsNull, "}").WithArguments("o").WithLocation(22, 5)); } [Fact] public void Nullability_Attribute_07() { var src = """ #nullable enable int? iNull = null; iNull.M(); iNull.Value.ToString(); int? iNull2 = null; iNull2.M2(); iNull2.Value.ToString(); static class E { extension([System.Diagnostics.CodeAnalysis.NotNull] ref int? o) { public void M() { } // 1 public void M3() { o = 42; } } public static void M2([System.Diagnostics.CodeAnalysis.NotNull] this ref int? o) { } // 2 } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (17,9): warning CS8777: Parameter 'o' must have a non-null value when exiting. // } // 1 Diagnostic(ErrorCode.WRN_ParameterDisallowsNull, "}").WithArguments("o").WithLocation(17, 9), // (27,5): warning CS8777: Parameter 'o' must have a non-null value when exiting. // } // 2 Diagnostic(ErrorCode.WRN_ParameterDisallowsNull, "}").WithArguments("o").WithLocation(27, 5)); } [Fact] public void Nullability_Attribute_08() { var src = """ #nullable enable int? iNull = null; iNull.M(); iNull.Value.ToString(); int? iNull2 = null; iNull2.M2(); iNull2.Value.ToString(); static class E { extension([System.Diagnostics.CodeAnalysis.NotNull] ref int? o) { public void M(bool b = false) { if (b) return; // 1 o = 42; return; } } public static void M2([System.Diagnostics.CodeAnalysis.NotNull] this ref int? o) { return; // 2 } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (18,17): warning CS8777: Parameter 'o' must have a non-null value when exiting. // return; // 1 Diagnostic(ErrorCode.WRN_ParameterDisallowsNull, "return;").WithArguments("o").WithLocation(18, 17), // (27,9): warning CS8777: Parameter 'o' must have a non-null value when exiting. // return; // 2 Diagnostic(ErrorCode.WRN_ParameterDisallowsNull, "return;").WithArguments("o").WithLocation(27, 9)); } [Fact] public void Nullability_Attribute_09() { var src = """ #nullable enable object? oNotNull = new object(); oNotNull.M(out var x); x.ToString(); object? oNull = null; oNull.M(out var y); y.ToString(); // 1 oNotNull.M2(out var x2); x2.ToString(); object? oNull2 = null; oNull2.M2(out var y2); y2.ToString(); // 2 static class E { extension(object? o) { public void M([System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o))] out object? o2, bool b = false) { if (o is null) { o2 = null; return; } if (b) { o2 = null; return; // 3 } if (b) { o2 = 42; return; } o2 = null; } // 4 } public static void M2(this object? o, [System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o))] out object? o2, bool b = false) => throw null!; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (9,1): warning CS8602: Dereference of a possibly null reference. // y.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y").WithLocation(9, 1), // (16,1): warning CS8602: Dereference of a possibly null reference. // y2.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y2").WithLocation(16, 1), // (33,17): warning CS8824: Parameter 'o2' must have a non-null value when exiting because parameter 'o' is non-null. // return; // 3 Diagnostic(ErrorCode.WRN_ParameterNotNullIfNotNull, "return;").WithArguments("o2", "o").WithLocation(33, 17), // (43,9): warning CS8824: Parameter 'o2' must have a non-null value when exiting because parameter 'o' is non-null. // } // 4 Diagnostic(ErrorCode.WRN_ParameterNotNullIfNotNull, "}").WithArguments("o2", "o").WithLocation(43, 9)); } [Fact] public void Nullability_Attribute_10() { var src = """ #nullable enable object.M(out var x); x.ToString(); // 1 object.M2(out var x2); x2.ToString(); // 2 static class E { extension(object? o) { public static void M([System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o))] out object? o2, bool b = false) { if (b) { o2 = null; return; } if (b) { o2 = 42; return; } o2 = null; } } extension(object o) { public static void M2([System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o))] out object? o2, bool b = false) { if (b) { o2 = null; return; } if (b) { o2 = 42; return; } o2 = null; } } public static void M3([System.Diagnostics.CodeAnalysis.NotNullIfNotNull("missing")] out object? o) => throw null!; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (4,1): warning CS8602: Dereference of a possibly null reference. // x.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(4, 1), // (7,1): warning CS8602: Dereference of a possibly null reference. // x2.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x2").WithLocation(7, 1)); } [Fact] public void Nullability_Attribute_11() { var src = """ #nullable enable int? iNotNull = 42; iNotNull.M(new object()); iNotNull.ToString(); int? iNull = null; iNull.M(new object()); iNull.ToString(); static class E { extension([ /*<bind>*/ System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o)) /*</bind>*/ ] [System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(i))] ref int? i) { public void M(object? o) => throw null!; } } """; var expectedDiagnostics = new[] { // (13,84): error CS0103: The name 'o' does not exist in the current context // extension([ /*<bind>*/ System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o)) /*</bind>*/ ] ref int? i) Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(13, 84) }; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(expectedDiagnostics); string expectedOperationTree = """ IAttributeOperation (OperationKind.Attribute, Type: null, IsInvalid) (Syntax: 'System.Diag ... (nameof(o))') IObjectCreationOperation (Constructor: System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute..ctor(System.String parameterName)) (OperationKind.ObjectCreation, Type: System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute, IsInvalid, IsImplicit) (Syntax: 'System.Diag ... (nameof(o))') Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: parameterName) (OperationKind.Argument, Type: null, IsInvalid) (Syntax: 'nameof(o)') INameOfOperation (OperationKind.NameOf, Type: System.String, Constant: "o", IsInvalid) (Syntax: 'nameof(o)') IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'o') Children(0) InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Initializer: null """; VerifyOperationTreeAndDiagnosticsForTest<AttributeSyntax>(src, expectedOperationTree, expectedDiagnostics, targetFramework: TargetFramework.Net90); src = """ #nullable enable int? iNotNull = 42; iNotNull.M(new object()); iNotNull.ToString(); int? iNull = null; iNull.M(new object()); iNull.ToString(); static class E { extension([System.Diagnostics.CodeAnalysis.NotNullIfNotNull("o")] ref int? i) { public void M(object? o) => throw null!; } } """; comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); src = """ #nullable enable int? iNull = null; iNull.M2(new object()); iNull.Value.ToString(); static class E { public static void M2([System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o))] this ref int? i, object? o) => throw null!; } """; comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); } [Fact] public void Nullability_Attribute_12() { var src = """ #nullable enable object? oNull = null; oNull.M().ToString(); object? oNotNull = new object(); oNotNull.M().ToString(); static class E { extension(object? o) { [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o))] public object? M() => o; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (4,1): warning CS8602: Dereference of a possibly null reference. // oNull.M().ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "oNull.M()").WithLocation(4, 1)); } [Fact] public void Nullability_Attribute_13() { var src = """ #nullable enable static class E { static void Method(object? oNull, object oNotNull) { oNull.M(oNotNull); oNull.ToString(); // 1 } static void Method2(object? oNull, object oNotNull) { oNull.M2(oNotNull); oNull.ToString(); // 2 } extension([System.Diagnostics.CodeAnalysis.NotNullIfNotNull("o2")] object? o) { public void M(object? o2) => throw null!; } public static void M2([System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o2))] this object? o, object? o2) => throw null!; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (8,9): warning CS8602: Dereference of a possibly null reference. // oNull.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "oNull").WithLocation(8, 9), // (14,9): warning CS8602: Dereference of a possibly null reference. // oNull.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "oNull").WithLocation(14, 9)); } [Fact] public void Nullability_Attribute_14() { var src = """ #nullable enable object o = new object(); if (o.M()) o.P.ToString(); // 1 else o.P.ToString(); // 2 static class E { extension(object o) { [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, "P")] public bool M() => throw null!; public object? P => null; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (5,5): warning CS8602: Dereference of a possibly null reference. // o.P.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o.P").WithLocation(5, 5), // (7,5): warning CS8602: Dereference of a possibly null reference. // o.P.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o.P").WithLocation(7, 5)); } [Fact] public void Nullability_Attribute_15() { var src = """ #nullable enable object o = new object(); if (o.M()) o.P.ToString(); // 1 else o.P.ToString(); // 2 static class E { extension(object o) { [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(P))] public bool M() => throw null!; public object? P => null; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (5,5): warning CS8602: Dereference of a possibly null reference. // o.P.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o.P").WithLocation(5, 5), // (7,5): warning CS8602: Dereference of a possibly null reference. // o.P.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o.P").WithLocation(7, 5), // (13,73): error CS0103: The name 'P' does not exist in the current context // [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(P))] Diagnostic(ErrorCode.ERR_NameNotInContext, "P").WithArguments("P").WithLocation(13, 73)); src = """ #nullable enable object o = new object(); if (o.M()) o.P.ToString(); // 1 else o.P.ToString(); // 2 static class E { extension(object o) { [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(object.P))] public bool M() => throw null!; public object? P => null; } } class C { [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(C.P))] public bool M() => throw null!; public object? P => null; } """; comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (5,5): warning CS8602: Dereference of a possibly null reference. // o.P.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o.P").WithLocation(5, 5), // (7,5): warning CS8602: Dereference of a possibly null reference. // o.P.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o.P").WithLocation(7, 5), // (13,73): error CS0120: An object reference is required for the non-static field, method, or property 'E.extension(object).P' // [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(object.P))] Diagnostic(ErrorCode.ERR_ObjectRequired, "object").WithArguments("E.extension(object).P").WithLocation(13, 73)); src = """ #nullable enable object o = new object(); if (o.M()) o.P.ToString(); // 1 else o.P.ToString(); // 2 static class E { extension(object o) { [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(new object().P))] public bool M() => throw null!; public object? P => null; } } """; comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (5,5): warning CS8602: Dereference of a possibly null reference. // o.P.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o.P").WithLocation(5, 5), // (7,5): warning CS8602: Dereference of a possibly null reference. // o.P.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o.P").WithLocation(7, 5), // (13,73): error CS8082: Sub-expression cannot be used in an argument to nameof. // [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(new object().P))] Diagnostic(ErrorCode.ERR_SubexpressionNotInNameof, "new object()").WithLocation(13, 73), // (13,73): error CS9316: Extension members are not allowed as an argument to 'nameof'. // [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(new object().P))] Diagnostic(ErrorCode.ERR_NameofExtensionMember, "new object().P").WithLocation(13, 73)); src = """ class E { [My(nameof(E.P))] public bool M() => throw null!; public object P => null; } class MyAttribute : System.Attribute { public MyAttribute(string s) { } } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void Nullability_Attribute_15_Static() { var src = """ #nullable enable static class E { extension(object o) { [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(P))] public static bool M() => throw null!; public static object? P => null; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (7,73): error CS0103: The name 'P' does not exist in the current context // [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(P))] Diagnostic(ErrorCode.ERR_NameNotInContext, "P").WithArguments("P").WithLocation(7, 73)); src = """ #nullable enable static class E { extension(object o) { [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(object.P))] public static bool M() => throw null!; public static object? P => null; } } """; comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (7,73): error CS9316: Extension members are not allowed as an argument to 'nameof'. // [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(object.P))] Diagnostic(ErrorCode.ERR_NameofExtensionMember, "object.P").WithLocation(7, 73)); } [Fact] public void Nullability_Attribute_16() { var src = """ #nullable enable object o = new object(); o.M(); o.P.ToString(); // 1 static class E { extension(object o) { [System.Diagnostics.CodeAnalysis.MemberNotNull("P")] public void M() => throw null!; public object? P => null; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (5,1): warning CS8602: Dereference of a possibly null reference. // o.P.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o.P").WithLocation(5, 1)); } [Fact] public void Nullability_Attribute_17() { var src = """ #nullable enable object? o = null; (o is not null).AssertTrue(); o.ToString(); object? o2 = null; E.AssertTrue(o2 is not null); o2.ToString(); object? o3 = null; object.AssertTrue2(o3 is not null); o3.ToString(); object? o4 = null; E.AssertTrue2(o4 is not null); o4.ToString(); object? o5 = null; (o5 is not null).AssertTrue3(); o5.ToString(); object? o6 = null; E.AssertTrue3(o6 is not null); o6.ToString(); static class E { extension([System.Diagnostics.CodeAnalysis.DoesNotReturnIf(false)] bool b) { public void AssertTrue() => throw null!; } extension(object) { public static void AssertTrue2([System.Diagnostics.CodeAnalysis.DoesNotReturnIf(false)] bool b) => throw null!; } public static void AssertTrue3([System.Diagnostics.CodeAnalysis.DoesNotReturnIf(false)] this bool b) => throw null!; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); } [Fact] public void Nullability_Attribute_18() { var src = """ #nullable enable object? o = null; (o is not null).AssertTrue().M(o); object? o2 = null; (o2 is null).AssertTrue().M(o2); class C { public void M(object o) { } } static class E { extension([System.Diagnostics.CodeAnalysis.DoesNotReturnIf(false)] bool b) { public C AssertTrue() => throw null!; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (7,29): warning CS8604: Possible null reference argument for parameter 'o' in 'void C.M(object o)'. // (o2 is null).AssertTrue().M(o2); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "o2").WithArguments("o", "void C.M(object o)").WithLocation(7, 29)); } [Fact] public void Nullability_Attribute_19() { var src = """ #nullable enable object o = new object(); C.M(o = null).M2(); class C { public static object M(object o) => throw null!; } static class E { extension(object o) { public void M2() => throw null!; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (4,5): warning CS8604: Possible null reference argument for parameter 'o' in 'object C.M(object o)'. // C.M(o = null).M2(); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "o = null").WithArguments("o", "object C.M(object o)").WithLocation(4, 5), // (4,9): warning CS8600: Converting null literal or possible null value to non-nullable type. // C.M(o = null).M2(); Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(4, 9)); } [Fact] public void Nullability_Attribute_20() { var src = """ #nullable enable object o = new object(); (o = null).M().M(); static class E { extension(object? o) { public object M() => throw null!; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (4,6): warning CS8600: Converting null literal or possible null value to non-nullable type. // (o = null).M().M(); Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(4, 6)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78182")] public void Nullability_Attribute_21() { var source = @" #nullable enable static class Strings { extension([System.Diagnostics.CodeAnalysis.MaybeNullWhen(true), System.Diagnostics.CodeAnalysis.NotNullWhen(false)] string? s) { public bool IsEmpty() => string.IsNullOrEmpty(s); } public static bool IsEmpty2([System.Diagnostics.CodeAnalysis.MaybeNullWhen(true), System.Diagnostics.CodeAnalysis.NotNullWhen(false)] this string? s) => string.IsNullOrEmpty(s); } class C { public string? TextKey { get; set; } bool IsValid => !TextKey.IsEmpty(); bool IsValid2 => !TextKey.IsEmpty2(); } "; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); } [Fact] public void Nullability_Attribute_22() { var src = """ #nullable enable C.Try(out var x).AssertTrue().M(x); C.Try(out var y).AssertFalse().M(y); public class C { public static bool Try([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out object? o) => throw null!; public void M(object o) { } } public static class E { extension([System.Diagnostics.CodeAnalysis.DoesNotReturnIf(false)] bool b) { public C AssertTrue() => throw null!; } extension([System.Diagnostics.CodeAnalysis.DoesNotReturnIf(true)] bool b) { public C AssertFalse() => throw null!; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); CompileAndVerify(comp, symbolValidator: (m) => { var container = m.GlobalNamespace.GetTypeMember("E"); var extensions = container.GetTypeMembers(); AssertEx.Equal("System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute(false)", extensions[0].ExtensionParameter.GetAttributes().Single().ToString()); AssertEx.Equal("<M>$7073A58FCA9AF178F78C9DFB2EC1CFCB", extensions[0].MetadataName); Symbol m1 = extensions[0].GetMembers().Single(); AssertEx.Equal("E.extension(bool).AssertTrue()", m1.ToDisplayString()); AssertEx.Equal([], m1.GetAttributes()); AssertEx.Equal("System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute(true)", extensions[1].ExtensionParameter.GetAttributes().Single().ToString()); AssertEx.Equal("<M>$B2C5862F475D26FF0E9CB6F2B30AA3F7", extensions[1].MetadataName); Symbol m2 = extensions[1].GetMembers().Single(); AssertEx.Equal("E.extension(bool).AssertFalse()", m2.ToDisplayString()); AssertEx.Equal([], m2.GetAttributes()); }, verify: Verification.FailsPEVerify). VerifyDiagnostics( // (4,34): warning CS8604: Possible null reference argument for parameter 'o' in 'void C.M(object o)'. // C.Try(out var y).AssertFalse().M(y); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "y").WithArguments("o", "void C.M(object o)").WithLocation(4, 34)). VerifyTypeIL("E", """ .class public auto ansi abstract sealed beforefieldinit E extends [System.Runtime]System.Object { .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 01 00 00 ) .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 00 00 00 ) .custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi sealed specialname '<G>$A73C5770D9DE823384DE9FB3AFAAD000' extends [System.Runtime]System.Object { .custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Nested Types .class nested public auto ansi abstract sealed specialname '<M>$7073A58FCA9AF178F78C9DFB2EC1CFCB' extends [System.Runtime]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( bool b ) cil managed { .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .param [1] .custom instance void [System.Runtime]System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute::.ctor(bool) = ( 01 00 00 00 00 ) // Method begins at RVA 0x20ac // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$7073A58FCA9AF178F78C9DFB2EC1CFCB'::'<Extension>$' } // end of class <M>$7073A58FCA9AF178F78C9DFB2EC1CFCB .class nested public auto ansi abstract sealed specialname '<M>$B2C5862F475D26FF0E9CB6F2B30AA3F7' extends [System.Runtime]System.Object { // Methods .method public hidebysig specialname static void '<Extension>$' ( bool b ) cil managed { .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .param [1] .custom instance void [System.Runtime]System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute::.ctor(bool) = ( 01 00 01 00 00 ) // Method begins at RVA 0x20ac // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<M>$B2C5862F475D26FF0E9CB6F2B30AA3F7'::'<Extension>$' } // end of class <M>$B2C5862F475D26FF0E9CB6F2B30AA3F7 // Methods .method public hidebysig instance class C AssertTrue () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 37 30 37 33 41 35 38 46 43 41 39 41 46 31 37 38 46 37 38 43 39 44 46 42 32 45 43 31 43 46 43 42 00 00 ) // Method begins at RVA 0x20ae // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [System.Runtime]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$A73C5770D9DE823384DE9FB3AFAAD000'::AssertTrue .method public hidebysig instance class C AssertFalse () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 24 3c 4d 3e 24 42 32 43 35 38 36 32 46 34 37 35 44 32 36 46 46 30 45 39 43 42 36 46 32 42 33 30 41 41 33 46 37 00 00 ) // Method begins at RVA 0x20ae // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [System.Runtime]System.NotSupportedException::.ctor() IL_0005: throw } // end of method '<G>$A73C5770D9DE823384DE9FB3AFAAD000'::AssertFalse } // end of class <G>$A73C5770D9DE823384DE9FB3AFAAD000 // Methods .method public hidebysig static class C AssertTrue ( bool b ) cil managed { .custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .param [1] .custom instance void [System.Runtime]System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute::.ctor(bool) = ( 01 00 00 00 00 ) // Method begins at RVA 0x20a9 // Code size 2 (0x2) .maxstack 8 IL_0000: ldnull IL_0001: throw } // end of method E::AssertTrue .method public hidebysig static class C AssertFalse ( bool b ) cil managed { .custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .param [1] .custom instance void [System.Runtime]System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute::.ctor(bool) = ( 01 00 01 00 00 ) // Method begins at RVA 0x20a9 // Code size 2 (0x2) .maxstack 8 IL_0000: ldnull IL_0001: throw } // end of method E::AssertFalse } // end of class E """.Replace("[mscorlib]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var src2 = """ #nullable enable C.Try(out var x).AssertTrue().M(x); C.Try(out var y).AssertFalse().M(y); """; var comp2 = CreateCompilation(src2, references: [comp.EmitToImageReference()], targetFramework: TargetFramework.Net90); CompileAndVerify(comp2, verify: Verification.FailsPEVerify).VerifyDiagnostics( // (4,34): warning CS8604: Possible null reference argument for parameter 'o' in 'void C.M(object o)'. // C.Try(out var y).AssertFalse().M(y); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "y").WithArguments("o", "void C.M(object o)").WithLocation(4, 34)); } [Fact] public void Nullability_Attribute_23() { var src = """ #nullable enable bool b = true; if (b) { object? o = null; int.Throws(); o.ToString(); } else { object? o2 = null; E.Throws(); o2.ToString(); } """; var libSrc = """ #nullable enable public static class E { extension(int) { [System.Diagnostics.CodeAnalysis.DoesNotReturn] public static void Throws() => throw null!; } } """; var comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net90); var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()], targetFramework: TargetFramework.Net90); comp2.VerifyEmitDiagnostics(); } [Fact] public void Nullability_Attributes_24() { // NotNullIfNotNull should be enforced in getter body var src = """ #nullable enable public static class E { extension(object? o) { [property: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o))] public object? P { get { if (o is null) return null; else return null; // 1 } set { } } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o))] public object? M() { if (o is null) return null; else return null; // 2 } } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o))] public static object? M2(object? o) { if (o is null) return null; else return null; // 3 } } """; // Tracked by https://github.com/dotnet/roslyn/issues/37238 : need to track and enforce NotNullIfNotNull on properties/indexers var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics( // (26,17): warning CS8825: Return value must be non-null because parameter 'o' is non-null. // return null; // 2 Diagnostic(ErrorCode.WRN_ReturnNotNullIfNotNull, "return null;").WithArguments("o").WithLocation(26, 17), // (36,13): warning CS8825: Return value must be non-null because parameter 'o' is non-null. // return null; // 3 Diagnostic(ErrorCode.WRN_ReturnNotNullIfNotNull, "return null;").WithArguments("o").WithLocation(36, 13)); src = """ #nullable enable class C { [property: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o))] public object? this[object? o] { get { if (o is null) return null; else return null; // 1 } set { } } } """; comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); // Tracked by https://github.com/dotnet/roslyn/issues/37238 : indexers lack support for NotNullIfNotNull comp.VerifyEmitDiagnostics(); } [Fact] public void Nullability_ForEach_01() { var src = """ #nullable enable using System.Collections.Generic; object? oNull = null; foreach (var x in oNull) x.ToString(); // 1 object? oNotNull = new object(); foreach (var y in oNotNull) y.ToString(); static class E { extension<T>(T t) { public IEnumerator<T> GetEnumerator() { yield return t; } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (6,5): warning CS8602: Dereference of a possibly null reference. // x.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(6, 5)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var loop = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().First(); // Tracked by https://github.com/dotnet/roslyn/issues/78022 : incorrect nullability AssertEx.Equal("System.Collections.Generic.IEnumerator<System.Object>! E.extension<System.Object>(System.Object).GetEnumerator()", model.GetForEachStatementInfo(loop).GetEnumeratorMethod.ToTestDisplayString(includeNonNullable: true)); src = """ #nullable enable using System.Collections.Generic; object? oNull = null; foreach (var x in oNull) { x.ToString(); } object? oNotNull = new object(); foreach (var y in oNotNull) { y.ToString(); } static class E { public static IEnumerator<T> GetEnumerator<T>(this T t) { yield return t; } } """; comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,28): warning CS8602: Dereference of a possibly null reference. // foreach (var x in oNull) { x.ToString(); } Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(5, 28)); // Tracked by https://github.com/dotnet/roslyn/issues/78022 : incorrect nullability tree = comp.SyntaxTrees.Single(); model = comp.GetSemanticModel(tree); loop = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().First(); AssertEx.Equal("System.Collections.Generic.IEnumerator<System.Object>! E.GetEnumerator<System.Object>(this System.Object t)", model.GetForEachStatementInfo(loop).GetEnumeratorMethod.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_CollectionInitializer_01() { var src = """ #nullable enable using System.Collections; using System.Collections.Generic; object? oNull = null; object oNotNull = new object(); MyCollection c = new MyCollection() { oNull, oNotNull }; static class E { extension(MyCollection c) { public void Add(object o) { } } } public class MyCollection : IEnumerable<object> { IEnumerator<object> IEnumerable<object>.GetEnumerator() => throw null!; IEnumerator IEnumerable.GetEnumerator() => throw null!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,39): warning CS8604: Possible null reference argument for parameter 'o' in 'void E.extension(MyCollection).Add(object o)'. // MyCollection c = new MyCollection() { oNull, oNotNull }; Diagnostic(ErrorCode.WRN_NullReferenceArgument, "oNull").WithArguments("o", "void E.extension(MyCollection).Add(object o)").WithLocation(7, 39)); } [Fact] public void Nullability_CollectionExpression_Add_01() { var src = """ #nullable enable using System.Collections; using System.Collections.Generic; object? oNull = null; object oNotNull = new object(); MyCollection c = [oNull, oNotNull]; static class E { extension(MyCollection c) { public void Add(object o) { } } } public class MyCollection : IEnumerable<object> { IEnumerator<object> IEnumerable<object>.GetEnumerator() => throw null!; IEnumerator IEnumerable.GetEnumerator() => throw null!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,19): warning CS8604: Possible null reference argument for parameter 'o' in 'void E.extension(MyCollection).Add(object o)'. // MyCollection c = [oNull, oNotNull]; Diagnostic(ErrorCode.WRN_NullReferenceArgument, "oNull").WithArguments("o", "void E.extension(MyCollection).Add(object o)").WithLocation(7, 19)); } [Fact] public void Nullability_CollectionExpression_Add_01_Classic() { var src = """ #nullable enable using System.Collections; using System.Collections.Generic; object? oNull = null; object oNotNull = new object(); MyCollection c = [oNull, oNotNull]; static class E { public static void Add(this MyCollection c, object o) { } } public class MyCollection : IEnumerable<object> { IEnumerator<object> IEnumerable<object>.GetEnumerator() => throw null!; IEnumerator IEnumerable.GetEnumerator() => throw null!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,19): warning CS8604: Possible null reference argument for parameter 'o' in 'void E.Add(MyCollection c, object o)'. // MyCollection c = [oNull, oNotNull]; Diagnostic(ErrorCode.WRN_NullReferenceArgument, "oNull").WithArguments("o", "void E.Add(MyCollection c, object o)").WithLocation(7, 19)); } [Fact] public void Nullability_CollectionExpression_Add_02() { var src = """ #nullable enable using System.Collections; using System.Collections.Generic; object? oNull = null; object oNotNull = new object(); MyCollection<object> c = [oNull, oNotNull]; static class E { extension<T>(MyCollection<T> c) { public void Add(T o) { System.Console.Write(o is null ? "True " : "False "); } } } public class MyCollection<T> : IEnumerable<T> { IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null!; IEnumerator IEnumerable.GetEnumerator() => throw null!; } """; var comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "True False").VerifyDiagnostics(); src = """ #nullable enable using System.Collections; using System.Collections.Generic; object? oNull = null; object oNotNull = new object(); MyCollection<object> c = [oNull, oNotNull]; static class E { public static void Add<T>(this MyCollection<T> c, T o) { System.Console.Write(o is null ? "True " : "False "); } } public class MyCollection<T> : IEnumerable<T> { IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null!; IEnumerator IEnumerable.GetEnumerator() => throw null!; } """; comp = CreateCompilation(src); CompileAndVerify(comp, expectedOutput: "True False").VerifyDiagnostics(); } [Fact] public void Nullability_CollectionExpression_Add_02_Classic() { var src = """ #nullable enable using System.Collections; using System.Collections.Generic; object? oNull = null; object oNotNull = new object(); MyCollection<object> c = [oNull, oNotNull]; static class E { public static void Add<T>(this MyCollection<T> c, T o) { } } public class MyCollection<T> : IEnumerable<T> { IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null!; IEnumerator IEnumerable.GetEnumerator() => throw null!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); } [Fact] public void Nullability_ObjectInitializer_01() { var src = """ #nullable enable object? oNull = null; _ = new object() { Property = oNull }; object oNotNull = new object(); _ = new object() { Property = oNotNull }; static class E { extension(object o) { public object Property { set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,31): warning CS8601: Possible null reference assignment. // _ = new object() { Property = oNull }; Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "oNull").WithLocation(4, 31)); } [Fact] public void Nullability_ObjectInitializer_02() { var src = """ #nullable enable _ = new object() { Property = 42 }; static class E { extension<T>(T t) { public int Property { set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntax<AssignmentExpressionSyntax>(tree, "Property = 42"); AssertEx.Equal("System.Int32 E.extension<System.Object!>(System.Object!).Property { set; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_ObjectInitializer_03() { var src = """ #nullable enable object? oNull = null; _ = new object() { Property = oNull }; object oNotNull = new object(); _ = new object() { Property = oNotNull }; static class E { extension<T>(T t) { public T Property { set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,31): warning CS8601: Possible null reference assignment. // _ = new object() { Property = oNull }; Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "oNull").WithLocation(4, 31)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntax<AssignmentExpressionSyntax>(tree, "Property = oNull"); AssertEx.Equal("System.Object! E.extension<System.Object!>(System.Object!).Property { set; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString(includeNonNullable: true)); assignment = GetSyntax<AssignmentExpressionSyntax>(tree, "Property = oNotNull"); AssertEx.Equal("System.Object! E.extension<System.Object!>(System.Object!).Property { set; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_ObjectInitializer_04() { var src = """ #nullable enable _ = new C<string>() { Property = null }; _ = new C<string>() { Property = "a" }; _ = new C<string?>() { Property = null }; _ = new C<string?>() { Property = "a" }; class C<T> { } static class E { extension<T>(C<T> c) { public T Property { set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,34): warning CS8625: Cannot convert null literal to non-nullable reference type. // _ = new C<string>() { Property = null }; Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(3, 34)); } [Fact] public void Nullability_ObjectInitializer_05() { var src = """ #nullable enable var s = "a"; Use(s, (new(s) { Property = null })/*T:C<string!>!*/); // 1 Use(s, (new(s) { Property = "a" })/*T:C<string!>!*/); Use("a", (new(s) { Property = null })/*T:C<string!>!*/); // 2 Use("a", (new(s) { Property = "a" })/*T:C<string!>!*/); Use(s, (new("a") { Property = null })/*T:C<string!>!*/); // 3 Use(s, (new("a") { Property = "a" })/*T:C<string!>!*/); Use("a", (new("a") { Property = null })/*T:C<string!>!*/); // 4 Use("a", (new("a") { Property = "a" })/*T:C<string!>!*/); if (s != null) return; Use(s, (new(s) { Property = null })/*T:C<string?>!*/); if (s != null) return; Use(s, (new(s) { Property = "a" })/*T:C<string?>!*/); if (s != null) return; Use("a", (new(s) { Property = null })/*T:C<string!>!*/); // 5, 6 if (s != null) return; Use("a", (new(s) { Property = "a" })/*T:C<string!>!*/); // 7 if (s != null) return; Use(s, (new("a") { Property = null })/*T:C<string?>!*/); if (s != null) return; Use(s, (new("a") { Property = "a" })/*T:C<string?>!*/); if (s != null) return; Use("a", (new("a") { Property = null })/*T:C<string!>!*/); // 8 if (s != null) return; Use("a", (new("a") { Property = "a" })/*T:C<string!>!*/); void Use<T>(T value, C<T> c) => throw null!; record C<T>(T Value) { } static class E { extension<T>(C<T> c) { public T Property { set { } } } } """; var comp = CreateCompilation([src, IsExternalInitTypeDefinition]); comp.VerifyTypes(comp.SyntaxTrees[0]); comp.VerifyEmitDiagnostics( // (4,29): warning CS8625: Cannot convert null literal to non-nullable reference type. // Use(s, (new(s) { Property = null })/*T:C<string!>!*/); // 1 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(4, 29), // (7,31): warning CS8625: Cannot convert null literal to non-nullable reference type. // Use("a", (new(s) { Property = null })/*T:C<string!>!*/); // 2 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 31), // (10,31): warning CS8625: Cannot convert null literal to non-nullable reference type. // Use(s, (new("a") { Property = null })/*T:C<string!>!*/); // 3 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 31), // (13,33): warning CS8625: Cannot convert null literal to non-nullable reference type. // Use("a", (new("a") { Property = null })/*T:C<string!>!*/); // 4 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(13, 33), // (23,15): warning CS8604: Possible null reference argument for parameter 'Value' in 'C<string>.C(string Value)'. // Use("a", (new(s) { Property = null })/*T:C<string!>!*/); // 5, 6 Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("Value", "C<string>.C(string Value)").WithLocation(23, 15), // (23,31): warning CS8625: Cannot convert null literal to non-nullable reference type. // Use("a", (new(s) { Property = null })/*T:C<string!>!*/); // 5, 6 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(23, 31), // (26,15): warning CS8604: Possible null reference argument for parameter 'Value' in 'C<string>.C(string Value)'. // Use("a", (new(s) { Property = "a" })/*T:C<string!>!*/); // 7 Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("Value", "C<string>.C(string Value)").WithLocation(26, 15), // (35,33): warning CS8625: Cannot convert null literal to non-nullable reference type. // Use("a", (new("a") { Property = null })/*T:C<string!>!*/); // 8 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(35, 33)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntaxes<AssignmentExpressionSyntax>(tree, "Property = null").First(); AssertEx.Equal("System.String! E.extension<System.String!>(C<System.String!>!).Property { set; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_ObjectInitializer_06() { // notnull constraint var src = """ #nullable enable var s = "a"; Use(s, (new(s) { Property = null })/*T:C<string!>!*/); // 1 Use(s, (new(s) { Property = "a" })/*T:C<string!>!*/); Use("a", (new(s) { Property = null })/*T:C<string!>!*/); // 2 Use("a", (new(s) { Property = "a" })/*T:C<string!>!*/); Use(s, (new("a") { Property = null })/*T:C<string!>!*/); // 3 Use(s, (new("a") { Property = "a" })/*T:C<string!>!*/); Use("a", (new("a") { Property = null })/*T:C<string!>!*/); // 4 Use("a", (new("a") { Property = "a" })/*T:C<string!>!*/); if (s != null) return; Use(s, (new(s) { Property = null })/*T:C<string?>!*/); // 5 if (s != null) return; Use(s, (new(s) { Property = "a" })/*T:C<string?>!*/); // 6 if (s != null) return; Use("a", (new(s) { Property = null })/*T:C<string!>!*/); // 7, 8 if (s != null) return; Use("a", (new(s) { Property = "a" })/*T:C<string!>!*/); // 9 if (s != null) return; Use(s, (new("a") { Property = null })/*T:C<string?>!*/); // 10 if (s != null) return; Use(s, (new("a") { Property = "a" })/*T:C<string?>!*/); // 11 if (s != null) return; Use("a", (new("a") { Property = null })/*T:C<string!>!*/); // 12 if (s != null) return; Use("a", (new("a") { Property = "a" })/*T:C<string!>!*/); // 13 void Use<T>(T value, C<T> c) => throw null!; record C<T>(T Value) { } static class E { extension<T>(C<T> c) where T : notnull { public T Property { set { } } } } """; var comp = CreateCompilation([src, IsExternalInitTypeDefinition]); comp.VerifyTypes(comp.SyntaxTrees[0]); comp.VerifyEmitDiagnostics( // (4,29): warning CS8625: Cannot convert null literal to non-nullable reference type. // Use(s, (new(s) { Property = null })/*T:C<string!>!*/); // 1 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(4, 29), // (7,31): warning CS8625: Cannot convert null literal to non-nullable reference type. // Use("a", (new(s) { Property = null })/*T:C<string!>!*/); // 2 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 31), // (10,31): warning CS8625: Cannot convert null literal to non-nullable reference type. // Use(s, (new("a") { Property = null })/*T:C<string!>!*/); // 3 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 31), // (13,33): warning CS8625: Cannot convert null literal to non-nullable reference type. // Use("a", (new("a") { Property = null })/*T:C<string!>!*/); // 4 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(13, 33), // (17,18): warning CS8714: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(C<T>)'. Nullability of type argument 'string?' doesn't match 'notnull' constraint. // Use(s, (new(s) { Property = null })/*T:C<string?>!*/); // 5 Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "Property").WithArguments("E.extension<T>(C<T>)", "T", "string?").WithLocation(17, 18), // (20,18): warning CS8714: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(C<T>)'. Nullability of type argument 'string?' doesn't match 'notnull' constraint. // Use(s, (new(s) { Property = "a" })/*T:C<string?>!*/); // 6 Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "Property").WithArguments("E.extension<T>(C<T>)", "T", "string?").WithLocation(20, 18), // (23,15): warning CS8604: Possible null reference argument for parameter 'Value' in 'C<string>.C(string Value)'. // Use("a", (new(s) { Property = null })/*T:C<string!>!*/); // 7, 8 Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("Value", "C<string>.C(string Value)").WithLocation(23, 15), // (23,31): warning CS8625: Cannot convert null literal to non-nullable reference type. // Use("a", (new(s) { Property = null })/*T:C<string!>!*/); // 7, 8 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(23, 31), // (26,15): warning CS8604: Possible null reference argument for parameter 'Value' in 'C<string>.C(string Value)'. // Use("a", (new(s) { Property = "a" })/*T:C<string!>!*/); // 9 Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("Value", "C<string>.C(string Value)").WithLocation(26, 15), // (29,20): warning CS8714: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(C<T>)'. Nullability of type argument 'string?' doesn't match 'notnull' constraint. // Use(s, (new("a") { Property = null })/*T:C<string?>!*/); // 10 Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "Property").WithArguments("E.extension<T>(C<T>)", "T", "string?").WithLocation(29, 20), // (32,20): warning CS8714: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(C<T>)'. Nullability of type argument 'string?' doesn't match 'notnull' constraint. // Use(s, (new("a") { Property = "a" })/*T:C<string?>!*/); // 11 Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "Property").WithArguments("E.extension<T>(C<T>)", "T", "string?").WithLocation(32, 20), // (35,33): warning CS8625: Cannot convert null literal to non-nullable reference type. // Use("a", (new("a") { Property = null })/*T:C<string!>!*/); // 12 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(35, 33)); } [Fact] public void Nullability_ObjectInitializer_07() { var src = """ #nullable enable var s = "a"; Create(s).Use(new() { Property = null }); // 1 Create(s).Use(new() { Property = "a" }); if (s != null) return; Create(s).Use(new() { Property = null }); if (s != null) return; Create(s).Use(new() { Property = "a" }); Consumer<T> Create<T>(T value) => throw null!; class Consumer<T> { public void Use(C<T> c) => throw null!; } record C<T> { } static class E { extension<T>(C<T> c) { public T Property { set { } } } } """; var comp = CreateCompilation([src, IsExternalInitTypeDefinition]); comp.VerifyEmitDiagnostics( // (5,34): warning CS8625: Cannot convert null literal to non-nullable reference type. // Create(s).Use(new() { Property = null }); // 1 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(5, 34)); } [Fact] public void Nullability_ObjectInitializer_08() { // nested var src = """ #nullable enable _ = new object() { P = { F = "" } }; public static class E { extension<T>(T t) { public C P { get => new C(); } } } public class C { public string? F; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntax<AssignmentExpressionSyntax>(tree, """P = { F = "" }"""); AssertEx.Equal("C! E.extension<System.Object!>(System.Object!).P { get; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_ObjectInitializer_09() { // nested var src = """ #nullable enable object o = new() { P = { F = "" } }; public static class E { extension<T>(T t) { public C P { get => new C(); } } } public class C { public string? F; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntax<AssignmentExpressionSyntax>(tree, """P = { F = "" }"""); AssertEx.Equal("C! E.extension<System.Object!>(System.Object!).P { get; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_ObjectInitializer_10() { // nested var src = """ #nullable enable _ = new C<string>() { P = { F = null } }; public static class E { extension<T>(C<T> c) { public C<T> P { get => c; } } } public class C<T> { public T F = default!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,33): warning CS8625: Cannot convert null literal to non-nullable reference type. // _ = new C<string>() { P = { F = null } }; Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(3, 33)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntax<AssignmentExpressionSyntax>(tree, "P = { F = null }"); AssertEx.Equal("C<System.String!>! E.extension<System.String!>(C<System.String!>!).P { get; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_ObjectInitializer_11() { // nested var src = """ #nullable enable C<string> c = new() { P = { F = null } }; public static class E { extension<T>(C<T> c) { public C<T> P { get => c; } } } public class C<T> { public T F = default!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,33): warning CS8625: Cannot convert null literal to non-nullable reference type. // C<string> c = new() { P = { F = null } }; Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(3, 33)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntax<AssignmentExpressionSyntax>(tree, "P = { F = null }"); AssertEx.Equal("C<System.String!>! E.extension<System.String!>(C<System.String!>!).P { get; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_ObjectInitializer_12() { // nested var src = """ #nullable enable C<string> c = new() { P = { F = null } }; public static class E { extension<T>(C<T> c) { public C<T> P { set { } } // no getter } } public class C<T> { public T F = default!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,23): error CS0154: The property or indexer 'E.extension<string>(C<string>).P' cannot be used in this context because it lacks the get accessor // C<string> c = new() { P = { F = null } }; Diagnostic(ErrorCode.ERR_PropertyLacksGet, "P").WithArguments("E.extension<string>(C<string>).P").WithLocation(3, 23), // (3,33): warning CS8625: Cannot convert null literal to non-nullable reference type. // C<string> c = new() { P = { F = null } }; Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(3, 33)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntax<AssignmentExpressionSyntax>(tree, "P = { F = null }"); Assert.Null(model.GetSymbolInfo(assignment.Left).Symbol); } [Fact] public void Nullability_ObjectInitializer_13() { // nested var src = """ #nullable enable _ = new C<string>() { P = { F = null } }; public static class E { extension<T>(C<T> c) { public T F => default!; // no setter } } public class C<T> { public C<T> P { get => this; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,29): error CS0200: Property or indexer 'E.extension<string>(C<string>).F' cannot be assigned to -- it is read only // _ = new C<string>() { P = { F = null } }; Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "F").WithArguments("E.extension<string>(C<string>).F").WithLocation(3, 29), // (3,33): warning CS8625: Cannot convert null literal to non-nullable reference type. // _ = new C<string>() { P = { F = null } }; Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(3, 33)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntax<AssignmentExpressionSyntax>(tree, "F = null"); Assert.Null(model.GetSymbolInfo(assignment.Left).Symbol); } [Fact] public void Nullability_ObjectInitializer_14() { // nested var src = """ #nullable enable _ = new C<string>() { P = { F = null } }; public static class E { extension<T>(C<T> c) { public T F { set { } } } } public class C<T> { public C<T> P { get => this; } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (3,33): warning CS8625: Cannot convert null literal to non-nullable reference type. // _ = new C<string>() { P = { F = null } }; Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(3, 33)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntax<AssignmentExpressionSyntax>(tree, "F = null"); AssertEx.Equal("System.String! E.extension<System.String!>(C<System.String!>!).F { set; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_With_01() { var src = """ #nullable enable object? oNull = null; _ = new S() with { Property = oNull }; // 1 object oNotNull = new object(); _ = new S() with { Property = oNotNull }; struct S { } static class E { extension(object o) { public object Property { set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,31): warning CS8601: Possible null reference assignment. // _ = new S() with { Property = oNull }; // 1 Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "oNull").WithLocation(4, 31)); } [Fact] public void Nullability_With_02() { var src = """ #nullable enable C? cNull = null; _ = cNull with { Property = 42 }; C cNotNull = new C(); _ = cNotNull with { Property = 42 }; record C { } static class E { extension(object o) { public int Property { set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,5): warning CS8602: Dereference of a possibly null reference. // _ = cNull with { Property = 42 }; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "cNull").WithLocation(4, 5)); } [Fact] public void Nullability_With_03() { var src = """ #nullable enable C? cNull = null; _ = cNull with { Property = 42 }; C cNotNull = new C(); _ = cNotNull with { Property = 42 }; record C { } static class E { extension(object? o) { public int Property { set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,5): warning CS8602: Dereference of a possibly null reference. // _ = cNull with { Property = 42 }; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "cNull").WithLocation(4, 5)); } [Fact] public void Nullability_With_04() { var src = """ #nullable enable C? cNull = null; _ = cNull with { Property = 42 }; C cNotNull = new C(); _ = cNotNull with { Property = 42 }; record C { } static class E { extension<T>(T t) { public int Property { set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,5): warning CS8602: Dereference of a possibly null reference. // _ = cNull with { Property = 42 }; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "cNull").WithLocation(4, 5)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntaxes<AssignmentExpressionSyntax>(tree, "Property = 42").First(); AssertEx.Equal("System.Int32 E.extension<C!>(C!).Property { set; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_With_05() { var src = """ #nullable enable C? cNull = null; _ = cNull with { Property = 42 }; C cNotNull = new C(); _ = cNotNull with { Property = 42 }; record C { } static class E { extension<T>(T t) where T : notnull { public int Property { set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,5): warning CS8602: Dereference of a possibly null reference. // _ = cNull with { Property = 42 }; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "cNull").WithLocation(4, 5)); } [Fact] public void Nullability_With_06() { var src = """ #nullable enable C? cNull = null; _ = cNull with { Property = null }; C cNotNull = new C(); _ = cNotNull with { Property = null }; record C { } static class E { extension(object? o) { public string Property { set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (4,5): warning CS8602: Dereference of a possibly null reference. // _ = cNull with { Property = null }; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "cNull").WithLocation(4, 5), // (4,29): warning CS8625: Cannot convert null literal to non-nullable reference type. // _ = cNull with { Property = null }; Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(4, 29), // (7,32): warning CS8625: Cannot convert null literal to non-nullable reference type. // _ = cNotNull with { Property = null }; Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 32)); } [Fact] public void Nullability_With_07() { var src = """ #nullable enable var s = "a"; var c1 = Create(s); c1 = c1 with { Property = null }; // 1 c1 = c1 with { Property = "a" }; if (s != null) return; var c2 = Create(s); c2 = c2 with { Property = null }; c2 = c2 with { Property = "a" }; C<T> Create<T>(T value) => throw null!; record C<T> { } static class E { extension<T>(C<T> c) { public T Property { set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (5,27): warning CS8625: Cannot convert null literal to non-nullable reference type. // c1 = c1 with { Property = null }; // 1 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(5, 27)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var assignment = GetSyntaxes<AssignmentExpressionSyntax>(tree, "Property = null").Last(); AssertEx.Equal("System.String? E.extension<System.String?>(C<System.String?>!).Property { set; }", model.GetSymbolInfo(assignment.Left).Symbol.ToTestDisplayString(includeNonNullable: true)); } [Fact] public void Nullability_Fixed_01() { var src = """ #nullable enable unsafe class C { public static void M() { fixed (S<object>* p = new Fixable()) { } // 1 fixed (S<object?>* p = new Fixable()) { } } } class Fixable { } struct S<T> { } static class E { extension(Fixable f) { public ref S<object?> GetPinnableReference() => throw null!; } } """; // We don't yet analyze the nullability of `fixed` statements for extension methods var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugDll); comp.VerifyEmitDiagnostics(); src = """ #nullable enable unsafe class C { public static void M() { fixed (S<object>* p = new Fixable()) { } // 1 fixed (S<object?>* p = new Fixable()) { } } } class Fixable { } struct S<T> { } static class E { public static ref S<object?> GetPinnableReference(this Fixable f) => throw null!; } """; comp = CreateCompilation(src, options: TestOptions.UnsafeDebugDll); comp.VerifyEmitDiagnostics(); } [Fact] public void Nullability_Await_GetAwaiter_01() { var src = """ #nullable enable using System; using System.Runtime.CompilerServices; C? cNull = null; _ = await cNull; C cNotNull = new C(); _ = await cNotNull; class C { } class D : INotifyCompletion { public int GetResult() => 42; public void OnCompleted(Action continuation) => throw null!; public bool IsCompleted => true; } static class E { extension(C c) { public D GetAwaiter() => new D(); } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (7,11): warning CS8604: Possible null reference argument for parameter 'c' in 'E.extension(C)'. // _ = await cNull; Diagnostic(ErrorCode.WRN_NullReferenceArgument, "cNull").WithArguments("c", "E.extension(C)").WithLocation(7, 11)); } [Fact] public void BuildArgumentsForErrorRecovery_01() { var src = """ /*<bind>*/ "".M(""); /*</bind>*/ static class E { extension(object o) { public void M(string s) => throw null!; } extension(string s) { public void M(object o) => throw null!; } } """; var comp = CreateCompilation(src); var expectedDiagnostics = new[] { // (2,4): error CS0121: The call is ambiguous between the following methods or properties: 'E.extension(object).M(string)' and 'E.extension(string).M(object)' // "".M(""); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E.extension(object).M(string)", "E.extension(string).M(object)").WithLocation(2, 4) }; comp.VerifyEmitDiagnostics(expectedDiagnostics); string expectedOperationTree = """ IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: '"".M("");') Expression: IInvalidOperation (OperationKind.Invalid, Type: System.Void, IsInvalid) (Syntax: '"".M("")') Children(2): ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "") (Syntax: '""') ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "") (Syntax: '""') """; VerifyOperationTreeAndDiagnosticsForTest<ExpressionStatementSyntax>(src, expectedOperationTree, expectedDiagnostics); } [Fact] public void BuildArgumentsForErrorRecovery_02() { var src = """ string s = ""; /*<bind>*/ s.M(s); /*</bind>*/ static class E { extension(object o) { public void M(string s) => throw null!; } extension(string s) { public void M(object o) => throw null!; } } """; var comp = CreateCompilation(src); var expectedDiagnostics = new[] { // (3,3): error CS0121: The call is ambiguous between the following methods or properties: 'E.extension(object).M(string)' and 'E.extension(string).M(object)' // s.M(s); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("E.extension(object).M(string)", "E.extension(string).M(object)").WithLocation(3, 3) }; comp.VerifyEmitDiagnostics(expectedDiagnostics); string expectedOperationTree = """ IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 's.M(s);') Expression: IInvalidOperation (OperationKind.Invalid, Type: System.Void, IsInvalid) (Syntax: 's.M(s)') Children(2): ILocalReferenceOperation: s (OperationKind.LocalReference, Type: System.String) (Syntax: 's') ILocalReferenceOperation: s (OperationKind.LocalReference, Type: System.String) (Syntax: 's') """; VerifyOperationTreeAndDiagnosticsForTest<ExpressionStatementSyntax>(src, expectedOperationTree, expectedDiagnostics); } [Fact] public void BuildArgumentsForErrorRecovery_03() { var source = @" #nullable enable bool b = true; (b switch { true => 1, false => null}).M(ERROR); static class E { extension(int? i) { public void M(object o) => throw null!; } } "; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,4): error CS8506: No best type was found for the switch expression. // (b switch { true => 1, false => null}).M(ERROR); Diagnostic(ErrorCode.ERR_SwitchExpressionNoBestType, "switch").WithLocation(5, 4), // (5,33): warning CS8619: Nullability of reference types in value of type '<null>' doesn't match target type 'int'. // (b switch { true => 1, false => null}).M(ERROR); Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "null").WithArguments("<null>", "int").WithLocation(5, 33), // (5,42): error CS0103: The name 'ERROR' does not exist in the current context // (b switch { true => 1, false => null}).M(ERROR); Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(5, 42)); } [Fact] public void BuildArgumentsForErrorRecovery_04() { var source = @" object.M(ERROR); static class E { extension(object) { public static void M(object o) => throw null!; } } "; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (2,10): error CS0103: The name 'ERROR' does not exist in the current context // object.M(ERROR); Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(2, 10)); } [Fact] public void SpecialName_01() { // extension(int i) // { // public void M() { } // public int P { get; } // } // but with specialname missing from marker method // Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading) var ilSrc = """ .class public auto ansi abstract sealed beforefieldinit E extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi abstract sealed specialname '<Marker>$F4B4FFE41AB49E80A4ECF390CF6EB372' extends System.Object { .method public hidebysig static void '<Extension>$' ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) IL_0000: ret } } .method public hidebysig instance void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) IL_0000: ldnull IL_0001: throw } .method public hidebysig specialname instance int32 get_P () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) IL_0000: ldnull IL_0001: throw } .property instance int32 P() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) .get instance int32 E/'<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P() } } .method public hidebysig static void M ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) IL_0000: ret } .method public hidebysig static int32 get_P ( int32 i ) cil managed { IL_0000: ldc.i4.0 IL_0001: ret } } """ + ExtensionMarkerAttributeIL; string source = """ 42.M(); _ = 42.P; """; var comp = CreateCompilationWithIL(source, ilSrc); comp.VerifyEmitDiagnostics( // (2,8): error CS1061: 'int' does not contain a definition for 'P' and no accessible extension method 'P' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) // _ = 42.P; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "P").WithArguments("int", "P").WithLocation(2, 8)); } [Fact] public void SpecialName_02() { // extension(int i) // { // public void M() { } // public void M2() { } // public int P { get; } // public int P2 { get; } // } // but with specialname mismatch between skeleton and implementation methods // Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading) var ilSrc = """ .class public auto ansi abstract sealed beforefieldinit E extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi abstract sealed specialname '<Marker>$F4B4FFE41AB49E80A4ECF390CF6EB372' extends [mscorlib]System.Object { .method public hidebysig specialname static void '<Extension>$' ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) IL_0000: ret } } .method public hidebysig instance void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) IL_0000: ldnull IL_0001: throw } .method public hidebysig specialname instance void M2 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) IL_0000: ldnull IL_0001: throw } .method public hidebysig specialname instance int32 get_P () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) IL_0000: ldnull IL_0001: throw } .method public hidebysig instance int32 get_P2 () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) IL_0000: ldnull IL_0001: throw } .property instance int32 P() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) .get instance int32 E/'<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P() } .property instance int32 P2() { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) .get instance int32 E/'<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P2() } } .method public hidebysig specialname static void M ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) IL_0000: ret } .method public hidebysig static void M2 ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) IL_0000: ret } .method public hidebysig static int32 get_P ( int32 i ) cil managed { IL_0000: ldc.i4.0 IL_0001: ret } .method public hidebysig specialname static int32 get_P2 ( int32 i ) cil managed { IL_0000: ldc.i4.0 IL_0001: ret } } """ + ExtensionMarkerAttributeIL; string source = """ 42.M(); 42.M2(); _ = 42.P; _ = 42.P2; """; var comp = CreateCompilationWithIL(source, ilSrc); comp.VerifyEmitDiagnostics(); } [Fact] public void SpecialName_03() { // extension(int) // { // public static void M() { } // } // but no specialname on marker type // Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading) var ilSrc = """ .class public auto ansi abstract sealed beforefieldinit E extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi abstract sealed '<Marker>$F4B4FFE41AB49E80A4ECF390CF6EB372' extends System.Object { .method public hidebysig specialname static void '<Extension>$' ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) IL_0000: ret } } .method public hidebysig static void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) IL_0000: ldnull IL_0001: throw } } .method public hidebysig static void M () cil managed { IL_0000: ret } } """ + ExtensionMarkerAttributeIL; string source = """ int.M(); """; var comp = CreateCompilationWithIL(source, ilSrc); comp.VerifyEmitDiagnostics( // (1,5): error CS0117: 'int' does not contain a definition for 'M' // int.M(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5)); Assert.Empty(comp.GlobalNamespace.GetTypeMember("E").GetTypeMembers()); } [Fact] public void SpecialName_04() { var src = """ static class E { extension(int i) { [System.Runtime.CompilerServices.SpecialName] public void M() => throw null!; public void M2() => throw null!; [System.Runtime.CompilerServices.SpecialName] public int P => throw null!; public int P2 => throw null!; } [System.Runtime.CompilerServices.SpecialName] public static void M3() => throw null!; } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var extension = comp.GlobalNamespace.GetTypeMember("E").GetTypeMembers().Single(); Assert.True(extension.GetMember<MethodSymbol>("M").HasSpecialName); Assert.False(extension.GetMember<MethodSymbol>("M2").HasSpecialName); Assert.True(extension.GetMember<PropertySymbol>("P").HasSpecialName); Assert.True(extension.GetMember<MethodSymbol>("get_P").HasSpecialName); Assert.False(extension.GetMember<PropertySymbol>("P2").HasSpecialName); Assert.True(extension.GetMember<MethodSymbol>("get_P2").HasSpecialName); Assert.True(comp.GetMember<MethodSymbol>("E.M").HasSpecialName); Assert.False(comp.GetMember<MethodSymbol>("E.M2").HasSpecialName); Assert.True(comp.GetMember<MethodSymbol>("E.M3").HasSpecialName); Assert.False(comp.GetMember<MethodSymbol>("E.get_P").HasSpecialName); Assert.False(comp.GetMember<MethodSymbol>("E.get_P2").HasSpecialName); } [Fact] public void SpecialName_05() { var src = """ static class E { extension(int i) { public int P { [System.Runtime.CompilerServices.SpecialName] get => 0; [System.Runtime.CompilerServices.SpecialName] set { } } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); var extension = comp.GlobalNamespace.GetTypeMember("E").GetTypeMembers().Single(); Assert.False(extension.GetMember<PropertySymbol>("P").HasSpecialName); Assert.True(extension.GetMember<MethodSymbol>("get_P").HasSpecialName); Assert.True(extension.GetMember<MethodSymbol>("set_P").HasSpecialName); Assert.True(comp.GetMember<MethodSymbol>("E.get_P").HasSpecialName); Assert.True(comp.GetMember<MethodSymbol>("E.set_P").HasSpecialName); } [Fact] public void SpecialName_06() { // extension(int) // { // public static void M() { } // } // but no specialname on grouping type // Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading) var ilSrc = """ .class public auto ansi abstract sealed beforefieldinit E extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi sealed '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69' extends System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) .class nested public auto ansi abstract sealed specialname '<Marker>$F4B4FFE41AB49E80A4ECF390CF6EB372' extends System.Object { .method public hidebysig specialname static void '<Extension>$' ( int32 i ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) IL_0000: ret } } .method public hidebysig static void M () cil managed { .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( 01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34 46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 46 36 45 42 33 37 32 00 00 ) IL_0000: ldnull IL_0001: throw } } .method public hidebysig static void M () cil managed { IL_0000: ret } } """ + ExtensionMarkerAttributeIL; string source = """ int.M(); """; var comp = CreateCompilationWithIL(source, ilSrc); comp.VerifyEmitDiagnostics( // (1,5): error CS0117: 'int' does not contain a definition for 'M' // int.M(); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5)); Assert.False(comp.GlobalNamespace.GetTypeMember("E").GetTypeMembers().Single().IsExtension); } [Fact] public void WellKnownAttribute_SkipLocalsInit_01() { string source = """ static unsafe class E { extension(int i) { [System.Runtime.CompilerServices.SkipLocalsInitAttribute] public int P { get { int j = 0; return j; } } public int P2 { get { int j = 0; return j; } } } } """; var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp, verify: Verification.Skipped); Assert.False(verifier.HasLocalsInit("E.get_P")); Assert.True(verifier.HasLocalsInit("E.get_P2")); } [Fact] public void WellKnownAttribute_SkipLocalsInit_02() { string source = """ static unsafe class E { extension(int i) { [System.Runtime.CompilerServices.SkipLocalsInitAttribute] public int M() { int j = 0; return j; } public int M2() { int j = 0; return j; } } } """; var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll, targetFramework: TargetFramework.Net90); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp, verify: Verification.Skipped); Assert.False(verifier.HasLocalsInit("E.M")); Assert.True(verifier.HasLocalsInit("E.M2")); } [Fact] public void XmlDoc_01() { // Instance members var src = """ /// <summary>Summary for E</summary> static class E { /// <summary>Summary for extension block</summary> /// <typeparam name="T">Description for T</typeparam> /// <param name="t">Description for t</param> extension<T>(T t) { /// <summary>Summary for M</summary> /// <typeparam name="U">Description for U</typeparam> /// <param name="u">Description for u</param> public void M<U>(U u) => throw null!; /// <summary>Summary for P</summary> public int P => 0; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "Test"); comp.VerifyEmitDiagnostics(); var e = comp.GetMember<NamedTypeSymbol>("E"); AssertEx.Equal(""" <member name="T:E"> <summary>Summary for E</summary> </member> """, e.GetDocumentationCommentXml()); var extension = e.GetTypeMembers().Single(); AssertEx.Equal("T:E.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F", extension.GetDocumentationCommentId()); AssertEx.Equal(""" <member name="T:E.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>Summary for extension block</summary> <typeparam name="T">Description for T</typeparam> <param name="t">Description for t</param> </member> """, extension.GetDocumentationCommentXml()); var mSkeleton = extension.GetMember<MethodSymbol>("M"); AssertEx.Equal(""" <member name="M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M``1(``0)"> <summary>Summary for M</summary> <typeparam name="U">Description for U</typeparam> <param name="u">Description for u</param> </member> """, mSkeleton.GetDocumentationCommentXml()); var mImplementation = e.GetMember<MethodSymbol>("M"); AssertEx.Equal(""" <member name="M:E.M``2(``0,``1)"> <inheritdoc cref="M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M``1(``0)"/> </member> """, mImplementation.GetDocumentationCommentXml()); var p = extension.GetMember<PropertySymbol>("P"); AssertEx.Equal(""" <member name="P:E.<G>$8048A6C8BE30A622530249B904B537EB`1.P"> <summary>Summary for P</summary> </member> """, p.GetDocumentationCommentXml()); var pGetImplementation = e.GetMember<MethodSymbol>("get_P"); AssertEx.Equal(""" <member name="M:E.get_P``1(``0)"> <inheritdoc cref="P:E.<G>$8048A6C8BE30A622530249B904B537EB`1.P"/> </member> """, pGetImplementation.GetDocumentationCommentXml()); var expected = """ <?xml version="1.0"?> <doc> <assembly> <name>Test</name> </assembly> <members> <member name="T:E"> <summary>Summary for E</summary> </member> <member name="M:E.M``2(``0,``1)"> <inheritdoc cref="M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M``1(``0)"/> </member> <member name="M:E.get_P``1(``0)"> <inheritdoc cref="P:E.<G>$8048A6C8BE30A622530249B904B537EB`1.P"/> </member> <member name="T:E.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>Summary for extension block</summary> <typeparam name="T">Description for T</typeparam> <param name="t">Description for t</param> </member> <member name="M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M``1(``0)"> <summary>Summary for M</summary> <typeparam name="U">Description for U</typeparam> <param name="u">Description for u</param> </member> <member name="P:E.<G>$8048A6C8BE30A622530249B904B537EB`1.P"> <summary>Summary for P</summary> </member> </members> </doc> """; AssertEx.Equal(expected, GetDocumentationCommentText(comp)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); AssertEx.SequenceEqual(["(T, T)", "(t, T t)", "(U, U)", "(u, U u)"], PrintXmlNameSymbols(tree, model)); } [Fact] public void XmlDoc_02() { // Static members var src = """ /// <summary>Summary for E</summary> static class E { /// <summary>Summary for extension block</summary> /// <typeparam name="T">Description for T</typeparam> /// <param name="t">Description for t</param> extension<T>(T t) { /// <summary>Summary for M</summary> /// <typeparam name="U">Description for U</typeparam> /// <param name="u">Description for u</param> public static void M<U>(U u) => throw null!; /// <summary>Summary for P</summary> public static int P => 0; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics(); var e = comp.GetMember<NamedTypeSymbol>("E"); AssertEx.Equal(""" <member name="T:E"> <summary>Summary for E</summary> </member> """, e.GetDocumentationCommentXml()); var extension = e.GetTypeMembers().Single(); AssertEx.Equal(""" <member name="T:E.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>Summary for extension block</summary> <typeparam name="T">Description for T</typeparam> <param name="t">Description for t</param> </member> """, extension.GetDocumentationCommentXml()); var mSkeleton = extension.GetMember<MethodSymbol>("M"); AssertEx.Equal(""" <member name="M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M``1(``0)"> <summary>Summary for M</summary> <typeparam name="U">Description for U</typeparam> <param name="u">Description for u</param> </member> """, mSkeleton.GetDocumentationCommentXml()); var mImplementation = e.GetMember<MethodSymbol>("M"); AssertEx.Equal(""" <member name="M:E.M``2(``1)"> <inheritdoc cref="M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M``1(``0)"/> </member> """, mImplementation.GetDocumentationCommentXml()); var p = extension.GetMember<PropertySymbol>("P"); AssertEx.Equal(""" <member name="P:E.<G>$8048A6C8BE30A622530249B904B537EB`1.P"> <summary>Summary for P</summary> </member> """, p.GetDocumentationCommentXml()); var pGetImplementation = e.GetMember<MethodSymbol>("get_P"); AssertEx.Equal(""" <member name="M:E.get_P``1"> <inheritdoc cref="P:E.<G>$8048A6C8BE30A622530249B904B537EB`1.P"/> </member> """, pGetImplementation.GetDocumentationCommentXml()); } [Fact] public void XmlDoc_03() { // No docs var src = """ static class E { extension<T>(T t) { // comment public static void M<U>(U u) => throw null!; // comment public static int P => 0; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics(); var e = comp.GetMember<NamedTypeSymbol>("E"); Assert.Empty(e.GetDocumentationCommentXml()); var extension = e.GetTypeMembers().Single(); Assert.Empty(extension.GetDocumentationCommentXml()); var mSkeleton = extension.GetMember<MethodSymbol>("M"); Assert.Empty(mSkeleton.GetDocumentationCommentXml()); var mImplementation = e.GetMember<MethodSymbol>("M"); Assert.Empty(mImplementation.GetDocumentationCommentXml()); var p = extension.GetMember<PropertySymbol>("P"); Assert.Empty(p.GetDocumentationCommentXml()); var pGetImplementation = e.GetMember<MethodSymbol>("get_P"); Assert.Empty(pGetImplementation.GetDocumentationCommentXml()); } [Fact] public void XmlDoc_04() { // Error docs var src = """ static class E { extension<T>(T t) { /// <summary></error> public static void M<U>(U u) => throw null!; /// <summary></error> public static int P => 0; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (5,24): warning CS1570: XML comment has badly formed XML -- 'End tag 'error' does not match the start tag 'summary'.' // /// <summary></error> Diagnostic(ErrorCode.WRN_XMLParseError, "error").WithArguments("error", "summary").WithLocation(5, 24), // (8,24): warning CS1570: XML comment has badly formed XML -- 'End tag 'error' does not match the start tag 'summary'.' // /// <summary></error> Diagnostic(ErrorCode.WRN_XMLParseError, "error").WithArguments("error", "summary").WithLocation(8, 24)); var e = comp.GetMember<NamedTypeSymbol>("E"); var extension = e.GetTypeMembers().Single(); var mSkeleton = extension.GetMember<MethodSymbol>("M"); AssertEx.Equal(""" <!-- Badly formed XML comment ignored for member "M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M``1(``0)" --> """, mSkeleton.GetDocumentationCommentXml()); var mImplementation = e.GetMember<MethodSymbol>("M"); AssertEx.Equal(""" <member name="M:E.M``2(``1)"> <inheritdoc cref="M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M``1(``0)"/> </member> """, mImplementation.GetDocumentationCommentXml()); var p = extension.GetMember<PropertySymbol>("P"); AssertEx.Equal(""" <!-- Badly formed XML comment ignored for member "P:E.<G>$8048A6C8BE30A622530249B904B537EB`1.P" --> """, p.GetDocumentationCommentXml()); var pGetImplementation = e.GetMember<MethodSymbol>("get_P"); AssertEx.Equal(""" <member name="M:E.get_P``1"> <inheritdoc cref="P:E.<G>$8048A6C8BE30A622530249B904B537EB`1.P"/> </member> """, pGetImplementation.GetDocumentationCommentXml()); } [Fact] public void XmlDoc_05() { // Merging docs on extension blocks var src = """ static class E { /// <summary>First summary for extension block</summary> /// <typeparam name="T">First description for T</typeparam> /// <param name="t">First description for t</param> extension<T>(T t) { /// <summary>First method</summary> public static void M(int i) => throw null!; } /// <summary>Second summary for extension block</summary> /// <typeparam name="T">Second description for T</typeparam> /// <param name="t">Second description for t</param> extension<T>(T t) { /// <summary>Second method</summary> public static void M(string s) => throw null!; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "test"); // Tracked by https://github.com/dotnet/roslyn/issues/78967 : missing WRN_DuplicateTypeParamTag and WRN_DuplicateParamTag warnings DiagnosticDescription[] expectedDiagnostics = []; comp.VerifyEmitDiagnostics(expectedDiagnostics); var e = comp.GetMember<NamedTypeSymbol>("E"); var extensions = e.GetTypeMembers(); AssertEx.Equal(""" <member name="T:E.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>First summary for extension block</summary> <typeparam name="T">First description for T</typeparam> <param name="t">First description for t</param> <summary>Second summary for extension block</summary> <typeparam name="T">Second description for T</typeparam> <param name="t">Second description for t</param> </member> """, extensions[0].GetDocumentationCommentXml()); AssertEx.Equal(""" <member name="T:E.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>First summary for extension block</summary> <typeparam name="T">First description for T</typeparam> <param name="t">First description for t</param> <summary>Second summary for extension block</summary> <typeparam name="T">Second description for T</typeparam> <param name="t">Second description for t</param> </member> """, extensions[1].GetDocumentationCommentXml()); var expected = """ <?xml version="1.0"?> <doc> <assembly> <name>test</name> </assembly> <members> <member name="M:E.M``1(System.Int32)"> <inheritdoc cref="M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M(System.Int32)"/> </member> <member name="M:E.M``1(System.String)"> <inheritdoc cref="M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M(System.String)"/> </member> <member name="T:E.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>First summary for extension block</summary> <typeparam name="T">First description for T</typeparam> <param name="t">First description for t</param> <summary>Second summary for extension block</summary> <typeparam name="T">Second description for T</typeparam> <param name="t">Second description for t</param> </member> <member name="M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M(System.Int32)"> <summary>First method</summary> </member> <member name="M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M(System.String)"> <summary>Second method</summary> </member> </members> </doc> """; AssertEx.Equal(expected, GetDocumentationCommentText(comp, expectedDiagnostics)); } [Fact] public void XmlDoc_06() { // Merging docs on extension blocks var src = """ static class E { /// <summary>First summary for extension block</summary> extension<T>(T t) { public static void M(int i) => throw null!; } /// <summary>Second summary for extension block</summary> extension<T>(T t) { public static void M(string s) => throw null!; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "test"); comp.VerifyEmitDiagnostics(); var e = comp.GetMember<NamedTypeSymbol>("E"); var extensions = e.GetTypeMembers().ToArray(); foreach (var extension in extensions) { AssertEx.Equal(""" <member name="T:E.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>First summary for extension block</summary> <summary>Second summary for extension block</summary> </member> """, extension.GetDocumentationCommentXml()); } var expected = """ <?xml version="1.0"?> <doc> <assembly> <name>test</name> </assembly> <members> <member name="T:E.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>First summary for extension block</summary> <summary>Second summary for extension block</summary> </member> </members> </doc> """; AssertEx.Equal(expected, GetDocumentationCommentText(comp)); } [Fact] public void XmlDoc_07() { // nested extension var src = """ static class E { extension(object) { /// <summary>First summary for extension block</summary> extension<T>(T t) { /// <summary>method</summary> public static void M(int i) => throw null!; } /// <summary>Second summary for extension block</summary> extension<T>(T t) { } } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "test"); comp.VerifyEmitDiagnostics( // (6,9): error CS9282: This member is not allowed in an extension block // extension<T>(T t) Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "extension").WithLocation(6, 9), // (13,9): error CS9282: This member is not allowed in an extension block // extension<T>(T t) Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "extension").WithLocation(13, 9)); var e = comp.GetMember<NamedTypeSymbol>("E"); var nestedExtension = e.GetTypeMembers().Single().GetTypeMembers().First(); AssertEx.Equal("T:E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F", nestedExtension.GetDocumentationCommentId()); var expected = """ <?xml version="1.0"?> <doc> <assembly> <name>test</name> </assembly> <members> <member name="T:E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>First summary for extension block</summary> <summary>Second summary for extension block</summary> </member> <member name="M:E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<G>$8048A6C8BE30A622530249B904B537EB`1.M(System.Int32)"> <summary>method</summary> </member> <member name="T:E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>First summary for extension block</summary> <summary>Second summary for extension block</summary> </member> </members> </doc> """; AssertEx.Equal(expected, GetDocumentationCommentText(comp)); } [Fact] public void XmlDoc_08() { // nested extension var src = """ static class E1 { static class E2 { /// <summary>First summary for extension block</summary> extension<T>(T t) { /// <summary>method</summary> public static void M(int i) => throw null!; } /// <summary>Second summary for extension block</summary> extension<T>(T t) { } } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "test"); comp.VerifyEmitDiagnostics( // (6,9): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension<T>(T t) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(6, 9), // (13,9): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension<T>(T t) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(13, 9)); var expected = """ <?xml version="1.0"?> <doc> <assembly> <name>test</name> </assembly> <members> <member name="M:E1.E2.M``1(System.Int32)"> <inheritdoc cref="M:E1.E2.<G>$8048A6C8BE30A622530249B904B537EB`1.M(System.Int32)"/> </member> <member name="T:E1.E2.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>First summary for extension block</summary> <summary>Second summary for extension block</summary> </member> <member name="M:E1.E2.<G>$8048A6C8BE30A622530249B904B537EB`1.M(System.Int32)"> <summary>method</summary> </member> </members> </doc> """; AssertEx.Equal(expected, GetDocumentationCommentText(comp)); } [Fact] public void XmlDoc_09() { // top-level extension var src = """ /// <summary>First summary for extension block</summary> extension<T>(T t) { /// <summary>method</summary> public static void M(int i) => throw null!; } /// <summary>Second summary for extension block</summary> extension<T>(T t) { } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "test"); comp.VerifyEmitDiagnostics( // (2,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension<T>(T t) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(2, 1), // (9,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension<T>(T t) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(9, 1)); var expected = """ <?xml version="1.0"?> <doc> <assembly> <name>test</name> </assembly> <members> <member name="T:<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>First summary for extension block</summary> </member> <member name="M:<G>$8048A6C8BE30A622530249B904B537EB`1.M(System.Int32)"> <summary>method</summary> </member> <member name="T:<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>Second summary for extension block</summary> </member> </members> </doc> """; AssertEx.Equal(expected, GetDocumentationCommentText(comp)); } [Fact] public void XmlDoc_10() { // xml error in a merged extension block var src = """ static class E { /// <summary>First summary for extension block</summary> extension(int) { /// <summary>Summary for M</summary> public static void M() { } } /// <summary>ERROR extension(int) { } /// <summary>Other summary for extension block</summary> extension(int) { } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "test"); comp.VerifyEmitDiagnostics( // (11,1): warning CS1570: XML comment has badly formed XML -- 'Expected an end tag for element 'summary'.' // extension(int) Diagnostic(ErrorCode.WRN_XMLParseError, "").WithArguments("summary").WithLocation(11, 1)); var e = comp.GetMember<NamedTypeSymbol>("E"); var extension1 = e.GetTypeMembers().First(); AssertEx.Equal(""" <!-- Badly formed XML comment ignored for member "T:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69" --> """, extension1.GetDocumentationCommentXml()); var expected = """ <?xml version="1.0"?> <doc> <assembly> <name>test</name> </assembly> <members> <member name="M:E.M"> <inheritdoc cref="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M"/> </member> <!-- Badly formed XML comment ignored for member "T:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69" --> <member name="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M"> <summary>Summary for M</summary> </member> </members> </doc> """; AssertEx.Equal(expected, GetDocumentationCommentText(comp)); } [Fact] public void XmlDoc_11() { // merged extension blocks without comments var src = """ static class E { extension(int) { public static void M() { } } extension(int) { } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "test"); comp.VerifyEmitDiagnostics(); var e = comp.GetMember<NamedTypeSymbol>("E"); var extension1 = e.GetTypeMembers().First(); AssertEx.Equal(""" """, extension1.GetDocumentationCommentXml()); var expected = """ <?xml version="1.0"?> <doc> <assembly> <name>test</name> </assembly> <members> </members> </doc> """; AssertEx.Equal(expected, GetDocumentationCommentText(comp)); } [Fact] public void XmlDoc_12() { // include var xml = """ <root> <target stuff="things" /> </root> """; var xmlFile = Temp.CreateFile(extension: ".xml").WriteAllText(xml); string xmlFilePath = xmlFile.Path; var source = $$""" static class E { /// <include file='{{xmlFilePath}}' path='//target'/> extension(int) { public static void M() { } } } """; var comp = CreateCompilation( source, options: TestOptions.ReleaseDll.WithXmlReferenceResolver(XmlFileResolver.Default), parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "test"); var e = comp.GetMember<NamedTypeSymbol>("E"); var extension = e.GetTypeMembers().Single(); AssertEx.Equal($$""" <member name="T:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69"> <include file='{{xmlFilePath}}' path='//target'/> </member> """, extension.GetDocumentationCommentXml()); AssertEx.Equal(""" <?xml version="1.0"?> <doc> <assembly> <name>test</name> </assembly> <members> <member name="T:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69"> <target stuff="things" /> </member> </members> </doc> """, GetDocumentationCommentText(comp)); } [Fact] public void XmlDoc_13() { // include on merged extension block var xml = """ <root> <target1 stuff="things1" /> <target2 stuff="things2" /> </root> """; var xmlFile = Temp.CreateFile(extension: ".xml").WriteAllText(xml); string xmlFilePath = xmlFile.Path; var source = $$""" static class E { /// <include file='{{xmlFilePath}}' path='//target1'/> extension(int) { public static void M() { } } /// <include file='{{xmlFilePath}}' path='//target2'/> extension(int) { } } """; var comp = CreateCompilation( source, options: TestOptions.ReleaseDll.WithXmlReferenceResolver(XmlFileResolver.Default), parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "test"); var e = comp.GetMember<NamedTypeSymbol>("E"); var extension = e.GetTypeMembers().First(); AssertEx.Equal($$""" <member name="T:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69"> <include file='{{xmlFilePath}}' path='//target1'/> <include file='{{xmlFilePath}}' path='//target2'/> </member> """, extension.GetDocumentationCommentXml()); AssertEx.Equal(""" <?xml version="1.0"?> <doc> <assembly> <name>test</name> </assembly> <members> <member name="T:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.<M>$BA41CFE2B5EDAEB8C1B9062F59ED4D69"> <target1 stuff="things1" /> <target2 stuff="things2" /> </member> </members> </doc> """, GetDocumentationCommentText(comp)); } [Fact] public void XmlDoc_14() { // DocID for PE symbol var src = """ public static class E { extension<T>(T t) { public int P => 0; } } """; var libComp = CreateCompilation(src); libComp.VerifyEmitDiagnostics(); var extension = libComp.GetMember<NamedTypeSymbol>("E").GetTypeMembers().Single(); Debug.Assert(extension.IsExtension); AssertEx.Equal("T:E.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F", extension.GetDocumentationCommentId()); var p = extension.GetMember<PropertySymbol>("P"); AssertEx.Equal("P:E.<G>$8048A6C8BE30A622530249B904B537EB`1.P", p.GetDocumentationCommentId()); var comp = CreateCompilation("", references: [libComp.EmitToImageReference()]); extension = comp.GetMember<NamedTypeSymbol>("E").GetTypeMembers().Single(); Debug.Assert(extension.IsExtension); AssertEx.Equal("T:E.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F", extension.GetDocumentationCommentId()); p = extension.GetMember<PropertySymbol>("P"); AssertEx.Equal("P:E.<G>$8048A6C8BE30A622530249B904B537EB`1.P", p.GetDocumentationCommentId()); } [Fact] public void XmlDoc_16() { var src = """ static class E { /// <typeparam name="T">description for T</typeparam> extension<T, T>(int) { } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (4,18): error CS0692: Duplicate type parameter 'T' // extension<T, T>(int) Diagnostic(ErrorCode.ERR_DuplicateTypeParameter, "T").WithArguments("T").WithLocation(4, 18)); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/80294")] public void XmlDoc_17(bool withDocumentationProvider) { string source = """ public static class E { extension(int i) { public void M() { } } } """ + ExtensionMarkerAttributeDefinition; var moduleComp = CreateCompilation(source, options: TestOptions.ReleaseModule, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); var moduleRef = moduleComp.EmitToImageReference(documentation: withDocumentationProvider ? new TestDocumentationProvider() : null); var comp = CreateCompilation("", references: [moduleRef], parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics(); var e = comp.GlobalNamespace.GetTypeMember("E"); Assert.Equal("", e.GetDocumentationCommentXml()); var extension = e.GetTypeMembers().Single(); Assert.True(extension.IsExtension); Assert.Equal("", extension.GetDocumentationCommentXml()); Assert.Equal("", extension.ContainingSymbol.GetDocumentationCommentXml()); Assert.Equal("", comp.GlobalNamespace.GetDocumentationCommentXml()); // Baseline without extensions source = """ /// <summary>Summary</summary> public class C { } """; moduleComp = CreateCompilation(source, options: TestOptions.ReleaseModule, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); moduleRef = moduleComp.EmitToImageReference(documentation: withDocumentationProvider ? new TestDocumentationProvider() : null); string source2 = """ /// <summary>Summary for D</summary> public class D { } """; comp = CreateCompilation(source2, assemblyName: "name", references: [moduleRef], parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics(); AssertEx.Equal(""" <?xml version="1.0"?> <doc> <assembly> <name>name</name> </assembly> <members> <member name="T:D"> <summary>Summary for D</summary> </member> </members> </doc> """, GetDocumentationCommentText(comp)); } [Fact] public void XmlDoc_18() { // Extension without containing type var src = """ /// <summary>Summary for extension block</summary> extension<T>(T t) { } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "Test"); comp.VerifyEmitDiagnostics( // (2,1): error CS9283: Extensions must be declared in a top-level, non-generic, static class // extension<T>(T t) Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(2, 1)); var extension = comp.GlobalNamespace.GetTypeMember(""); AssertEx.Equal("T:<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F", extension.GetDocumentationCommentId()); AssertEx.Equal(""" <member name="T:<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>Summary for extension block</summary> </member> """, extension.GetDocumentationCommentXml()); var expected = """ <?xml version="1.0"?> <doc> <assembly> <name>Test</name> </assembly> <members> <member name="T:<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F"> <summary>Summary for extension block</summary> </member> </members> </doc> """; AssertEx.Equal(expected, GetDocumentationCommentText(comp)); } [Fact] public void XmlDoc_Param_01() { // Unnamed extension parameter, with an attempted corresponding param var src = """ /// <summary>Summary for E</summary> static class E { /// <summary>Summary for extension block</summary> /// <param name="">Description for extension parameter</param> extension(object) { } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (5,22): warning CS1572: XML comment has a param tag for '', but there is no parameter by that name // /// <param name="">Description for extension parameter</param> Diagnostic(ErrorCode.WRN_UnmatchedParamTag, "").WithArguments("").WithLocation(5, 22)); } [Fact] public void XmlDoc_Param_02() { // Unnamed and undocumented extension parameter var src = """ static class E { /// <summary>Summary for extension block</summary> extension(object) { } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics(); } [Fact] public void XmlDoc_Param_03() { // param on member instead of extension block var src = """ /// <summary>Summary for E</summary> static class E { /// <summary>Summary for extension block</summary> extension(object o) { /// <summary>Summary for M</summary> /// <param name="o">Description for o</param> public void M(object o2) => throw null!; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (8,26): warning CS1572: XML comment has a param tag for 'o', but there is no parameter by that name // /// <param name="o">Description for o</param> Diagnostic(ErrorCode.WRN_UnmatchedParamTag, "o").WithArguments("o").WithLocation(8, 26), // (9,30): warning CS1573: Parameter 'o2' has no matching param tag in the XML comment for 'E.extension(object).M(object)' (but other parameters do) // public void M(object o2) => throw null!; Diagnostic(ErrorCode.WRN_MissingParamTag, "o2").WithArguments("o2", "E.extension(object).M(object)").WithLocation(9, 30)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); AssertEx.SequenceEqual(["(o, null)"], PrintXmlNameSymbols(tree, model)); } [Fact] public void XmlDoc_Param_04() { var src = """ /// <summary>Summary for E</summary> static class E { /// <summary>Summary for extension block</summary> /// <param name="o">Description for o</param> extension(object o) { /// <summary>Summary for M</summary> public void M(object o2) => throw null!; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); AssertEx.SequenceEqual(["(o, System.Object o)"], PrintXmlNameSymbols(tree, model)); } [Fact] public void XmlDoc_Param_05() { // multiple parameters in extension block, one is covered by param var src = """ static class E { /// <summary>Summary for extension block</summary> /// <param name="o">Description for o</param> extension(object o, object o2) { } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (5,25): error CS9285: An extension container can have only one receiver parameter // extension(object o, object o2) Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "object o2").WithLocation(5, 25)); } [Fact] public void XmlDoc_Param_06() { var src = """ static class E { /// <summary>Summary for extension block</summary> /// <param name="o">First description for o</param> /// <param name="o">Second description for o</param> extension(object o) { } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (5,16): warning CS1571: XML comment has a duplicate param tag for 'o' // /// <param name="o">Second description for o</param> Diagnostic(ErrorCode.WRN_DuplicateParamTag, @"name=""o""").WithArguments("o").WithLocation(5, 16)); } [Fact] public void XmlDoc_Param_07() { var src = """ static class E { /// <summary>Summary for extension block</summary> /// <param name="other">Description for other</param> extension(object o) { } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (4,22): warning CS1572: XML comment has a param tag for 'other', but there is no parameter by that name // /// <param name="other">Description for other</param> Diagnostic(ErrorCode.WRN_UnmatchedParamTag, "other").WithArguments("other").WithLocation(4, 22)); } [Fact] public void XmlDoc_TypeParam_01() { var src = """ static class E { /// <summary>Summary for extension block</summary> /// <typeparam name="T">First description for T</typeparam> /// <typeparam name="T">Second description for T</typeparam> extension<T>(T t) { } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (5,20): warning CS1710: XML comment has a duplicate typeparam tag for 'T' // /// <typeparam name="T">Second description for T</typeparam> Diagnostic(ErrorCode.WRN_DuplicateTypeParamTag, @"name=""T""").WithArguments("T").WithLocation(5, 20)); } [Fact] public void XmlDoc_TypeParam_02() { // only one type parameter documented var src = """ static class E { /// <summary>Summary for extension block</summary> /// <typeparam name="T">Description for T</typeparam> extension<T, U>(C<T, U> c) { } } class C<T, U> { } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (5,18): warning CS1712: Type parameter 'U' has no matching typeparam tag in the XML comment on 'E.extension<T, U>(C<T, U>)' (but other type parameters do) // extension<T, U>(C<T, U> c) Diagnostic(ErrorCode.WRN_MissingTypeParamTag, "U").WithArguments("U", "E.extension<T, U>(C<T, U>)").WithLocation(5, 18)); } [Fact] public void XmlDoc_TypeParam_03() { // typeparam on member instead of extension block var src = """ /// <summary>Summary for E</summary> static class E { /// <summary>Summary for extension block</summary> extension<T>(T t) { /// <summary>Summary for M <typeparamref name="T"/> </summary> /// <typeparam name="T">Description for T</typeparam> public static void M<U>(U u) => throw null!; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (8,30): warning CS1711: XML comment has a typeparam tag for 'T', but there is no type parameter by that name // /// <typeparam name="T">Description for T</typeparam> Diagnostic(ErrorCode.WRN_UnmatchedTypeParamTag, "T").WithArguments("T").WithLocation(8, 30), // (9,30): warning CS1712: Type parameter 'U' has no matching typeparam tag in the XML comment on 'E.extension<T>(T).M<U>(U)' (but other type parameters do) // public static void M<U>(U u) => throw null!; Diagnostic(ErrorCode.WRN_MissingTypeParamTag, "U").WithArguments("U", "E.extension<T>(T).M<U>(U)").WithLocation(9, 30)); } [Fact] public void XmlDoc_TypeParam_04() { var src = """ /// <summary>Summary for E</summary> static class E { /// <summary>Summary for extension block</summary> /// <typeparam name="T">Description for T</typeparam> extension<T>(T t) { /// <summary>Summary for M</summary> public static void M<U>(U u) => throw null!; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics(); } [Fact] public void XmlDoc_TypeParam_05() { var src = """ static class E { /// <summary>Summary for extension block</summary> /// <typeparam name="TOther">Description for TOther</typeparam> extension<T>(T t) { } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (4,26): warning CS1711: XML comment has a typeparam tag for 'TOther', but there is no type parameter by that name // /// <typeparam name="TOther">Description for TOther</typeparam> Diagnostic(ErrorCode.WRN_UnmatchedTypeParamTag, "TOther").WithArguments("TOther").WithLocation(4, 26), // (5,15): warning CS1712: Type parameter 'T' has no matching typeparam tag in the XML comment on 'E.extension<T>(T)' (but other type parameters do) // extension<T>(T t) Diagnostic(ErrorCode.WRN_MissingTypeParamTag, "T").WithArguments("T", "E.extension<T>(T)").WithLocation(5, 15)); } [Fact] public void XmlDoc_TypeParam_06() { // type parameter documented in different parts var src = """ static class E { /// <summary>Summary for extension block</summary> /// <typeparam name="T">Description for T</typeparam> extension<T, U>(C<T, U> c) { } /// <typeparam name="U">Description for U</typeparam> extension<T, U>(C<T, U> c) { } } class C<T, U> { } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics(); } [Fact] public void XmlDoc_TypeParam_07() { var src = """ static class E { /// <summary>Summary for extension block</summary> /// <typeparam name="T1">Description for T1</typeparam> extension<T1, U>(C<T1, U> c) { } /// <typeparam name="T2">Description for T2</typeparam> extension<T2, U>(C<T2, U> c) { } } class C<T, U> { } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (5,19): warning CS1712: Type parameter 'U' has no matching typeparam tag in the XML comment on 'E.extension<T1, U>(C<T1, U>)' (but other type parameters do) // extension<T1, U>(C<T1, U> c) Diagnostic(ErrorCode.WRN_MissingTypeParamTag, "U").WithArguments("U", "E.extension<T1, U>(C<T1, U>)").WithLocation(5, 19), // (10,19): warning CS1712: Type parameter 'U' has no matching typeparam tag in the XML comment on 'E.extension<T2, U>(C<T2, U>)' (but other type parameters do) // extension<T2, U>(C<T2, U> c) Diagnostic(ErrorCode.WRN_MissingTypeParamTag, "U").WithArguments("U", "E.extension<T2, U>(C<T2, U>)").WithLocation(10, 19)); } [Fact] public void XmlDoc_TypeParam_08() { var src = """ static class E { /// <summary>Summary for extension block</summary> /// <typeparam name="T1">Description for T1</typeparam> extension<T1, U>(C<T1, U> c) { } extension<T1, U>(C<T1, U> c) { } } class C<T, U> { } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (5,19): warning CS1712: Type parameter 'U' has no matching typeparam tag in the XML comment on 'E.extension<T1, U>(C<T1, U>)' (but other type parameters do) // extension<T1, U>(C<T1, U> c) Diagnostic(ErrorCode.WRN_MissingTypeParamTag, "U").WithArguments("U", "E.extension<T1, U>(C<T1, U>)").WithLocation(5, 19)); } [Fact] public void XmlDoc_ParamRef_01() { // paramref to extension parameter var src = """ /// <summary>Summary for E</summary> static class E { /// <summary>Good paramref <paramref name="o"/></summary> extension(object o) { /// <summary>Good paramref <paramref name="o"/></summary> public void M(object o2) => throw null!; /// <summary>Error paramref <paramref name="o"/></summary> public static void M2(object o2) => throw null!; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (10,53): warning CS1734: XML comment on 'E.extension(object).M2(object)' has a paramref tag for 'o', but there is no parameter by that name // /// <summary>Error paramref <paramref name="o"/></summary> Diagnostic(ErrorCode.WRN_UnmatchedParamRefTag, "o").WithArguments("o", "E.extension(object).M2(object)").WithLocation(10, 53)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); AssertEx.SequenceEqual(["(o, System.Object o)", "(o, System.Object o)", "(o, null)"], PrintXmlNameSymbols(tree, model)); } [Fact] public void XmlDoc_ParamRef_02() { // paramref to extension parameter on properties var src = """ static class E { extension(object o) { /// <summary>Good paramref <paramref name="o"/></summary> public int P => 42; /// <summary>Error paramref <paramref name="o"/></summary> public static int P2 => 42; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (8,53): warning CS1734: XML comment on 'E.extension(object).P2' has a paramref tag for 'o', but there is no parameter by that name // /// <summary>Error paramref <paramref name="o"/></summary> Diagnostic(ErrorCode.WRN_UnmatchedParamRefTag, "o").WithArguments("o", "E.extension(object).P2").WithLocation(8, 53)); } [Fact] public void XmlDoc_ParamRef_03() { var src = """ static class E { extension(object o) { /// <summary>Error paramref <paramref name="value"/></summary> public int P => 42; /// <summary>Error paramref <paramref name="value"/></summary> public static int P2 => 42; /// <summary>Good paramref <paramref name="value"/></summary> public int P3 { set { } } /// <summary>Good paramref <paramref name="value"/></summary> public static int P4 { set { } } } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (5,53): warning CS1734: XML comment on 'E.extension(object).P' has a paramref tag for 'value', but there is no parameter by that name // /// <summary>Error paramref <paramref name="value"/></summary> Diagnostic(ErrorCode.WRN_UnmatchedParamRefTag, "value").WithArguments("value", "E.extension(object).P").WithLocation(5, 53), // (8,53): warning CS1734: XML comment on 'E.extension(object).P2' has a paramref tag for 'value', but there is no parameter by that name // /// <summary>Error paramref <paramref name="value"/></summary> Diagnostic(ErrorCode.WRN_UnmatchedParamRefTag, "value").WithArguments("value", "E.extension(object).P2").WithLocation(8, 53)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/81217")] public void XmlDoc_ParamRef_04() { // No parameter on method var src = """ static class E { extension(object o) { /// <returns><paramref name="o"/></returns> public object M() => o; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "paramref_04"); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); AssertEx.SequenceEqual(["(o, System.Object o)"], PrintXmlNameSymbols(tree, model)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/81217")] public void XmlDoc_ParamRef_05() { // One parameter on method var src = """ static class E { extension(object o) { /// <summary><paramref name="o"/></summary> public object M(int i) => o; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "paramref_05"); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); AssertEx.SequenceEqual(["(o, System.Object o)"], PrintXmlNameSymbols(tree, model)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/81217")] public void XmlDoc_ParamRef_06() { // <params> preceeds <paramref> var src = """ using System; static class E { /// <param name="value">Param value</param> extension(ReadOnlySpan<char> value) { /// <param name="n">Param n</param> /// <param name="delimiter">Param delimiter</param> /// <returns><paramref name="value"/></returns> public ReadOnlySpan<char> GetNthDelimitedItem(int n, ReadOnlySpan<char> delimiter) => throw null !; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments, assemblyName: "paramref_06", targetFramework: TargetFramework.Net100); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); AssertEx.SequenceEqual([ "(value, System.ReadOnlySpan<System.Char> value)", "(n, System.Int32 n)", "(delimiter, System.ReadOnlySpan<System.Char> delimiter)", "(value, System.ReadOnlySpan<System.Char> value)"], PrintXmlNameSymbols(tree, model)); } [Fact] public void XmlDoc_TypeParamRef_01() { var src = """ static class E { /// <summary>Summary for extension block with typeparamref <typeparamref name="T"/></summary> extension<T>(T t) { /// <summary>Summary for M with typeparamref <typeparamref name="T"/></summary> public void M() => throw null!; /// <summary>Summary for M with typeparamref <typeparamref name="T"/></summary> public static void M2() => throw null!; /// <summary>Summary for M with typeparamref <typeparamref name="T"/></summary> public int P => 42; /// <summary>Summary for M with typeparamref <typeparamref name="T"/></summary> public static int P2 => 42; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); AssertEx.SequenceEqual(["(T, T)", "(T, T)", "(T, T)", "(T, T)", "(T, T)"], PrintXmlNameSymbols(tree, model)); } [Fact] public void XmlDoc_TypeParamRef_02() { var src = """ static class E { /// <summary>Error typeparamref <typeparamref name="T"/></summary> extension(int) { /// <summary>Good typeparamref <typeparamref name="T"/></summary> public static void M<T>(T t) => throw null!; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics( // (3,57): warning CS1735: XML comment on 'E.extension(int)' has a typeparamref tag for 'T', but there is no type parameter by that name // /// <summary>Error typeparamref <typeparamref name="T"/></summary> Diagnostic(ErrorCode.WRN_UnmatchedTypeParamRefTag, "T").WithArguments("T", "E.extension(int)").WithLocation(3, 57)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); AssertEx.SequenceEqual(["(T, null)", "(T, T)"], PrintXmlNameSymbols(tree, model)); } [Fact] public void XmlDoc_TypeParamRef_03() { var src = """ static class E { /// <typeparam name="T1"/> extension<T1>(int) { /// <summary><typeparamref name="T1"/></summary> /// <typeparam name="T2"/> public static void M<T2>() => throw null!; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); AssertEx.SequenceEqual(["(T1, T1)", "(T1, T1)", "(T2, T2)"], PrintXmlNameSymbols(tree, model)); } [Fact] public void XmlDoc_TypeParamRef_04() { var src = """ static class E { /// <typeparam name="T1"/> extension<T1>(int) { /// <summary><typeparamref name="T1"/></summary> public static void M() => throw null!; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); AssertEx.SequenceEqual(["(T1, T1)", "(T1, T1)"], PrintXmlNameSymbols(tree, model)); } [Fact] public void XmlDoc_TypeParamRef_05() { var src = """ static class E { /// <typeparam name="T1"/> extension<T1>(T1) { /// <summary><typeparamref name="T1"/></summary> public static int Property => throw null!; } } """; var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); AssertEx.SequenceEqual(["(T1, T1)", "(T1, T1)"], PrintXmlNameSymbols(tree, model)); } [Fact] public void AnalyzerActions_01() { var src = """ static class E { extension<T>([Attr] T t) { [Attr2] public void M() { } [Attr3] public int P => 0; [Attr4] public int this[int j] { [Attr5] get => 0; [Attr6] set { } } } } """; var analyzer = new AnalyzerActions_01_Analyzer(); var comp = CreateCompilation(src); comp.GetAnalyzerDiagnostics([analyzer], null).Verify(); AssertEx.SetEqual([ "Attr2 -> void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M()", "M -> void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M()", "Attr3 -> System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<T>.P { get; }", "P -> System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<T>.P { get; }", "T -> E.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$4294E9E080371DCE7DAC7C951C4773A1", "Attr -> E.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$4294E9E080371DCE7DAC7C951C4773A1", "extension -> E.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$4294E9E080371DCE7DAC7C951C4773A1", "Attr4 -> System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<T>.this[System.Int32 j] { get; set; }", "Attr5 -> System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<T>.this[System.Int32 j].get", "Attr6 -> void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.this[System.Int32 j].set", "this -> System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<T>.this[System.Int32 j] { get; set; }", "get -> System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<T>.this[System.Int32 j].get", "set -> void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.this[System.Int32 j].set"], analyzer._results.ToArray()); } private class AnalyzerActions_01_Analyzer : DiagnosticAnalyzer { public ConcurrentQueue<string> _results = new ConcurrentQueue<string>(); private static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test"); public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Descriptor]; public override void Initialize(AnalysisContext context) { context.RegisterSyntaxNodeAction(handle, SyntaxKind.ExtensionBlockDeclaration); context.RegisterSyntaxNodeAction(handle, SyntaxKind.IdentifierName); context.RegisterSyntaxNodeAction(handle, SyntaxKind.MethodDeclaration); context.RegisterSyntaxNodeAction(handle, SyntaxKind.PropertyDeclaration); context.RegisterSyntaxNodeAction(handle, SyntaxKind.IndexerDeclaration); context.RegisterSyntaxNodeAction(handle, SyntaxKind.GetAccessorDeclaration); context.RegisterSyntaxNodeAction(handle, SyntaxKind.SetAccessorDeclaration); void handle(SyntaxNodeAnalysisContext context) { _results.Enqueue(print(context)); Assert.Same(context.Node.SyntaxTree, context.ContainingSymbol.DeclaringSyntaxReferences.Single().SyntaxTree); } static string print(SyntaxNodeAnalysisContext context) { var syntaxString = context.Node switch { ExtensionBlockDeclarationSyntax => "extension", MethodDeclarationSyntax method => method.Identifier.ValueText, PropertyDeclarationSyntax property => property.Identifier.ValueText, IndexerDeclarationSyntax indexer => indexer.ThisKeyword.ValueText, AccessorDeclarationSyntax accessor => accessor.Keyword.ValueText, _ => context.Node.ToString() }; return $"{syntaxString} -> {context.ContainingSymbol.ToTestDisplayString()}"; } } } [Fact] public void AnalyzerActions_02() { var src = """ static class E { extension<T>(T t) { public void M(int i) { } public int P => 0; } extension(__arglist) { } extension(object o1, object o2) { } } """; var analyzer = new AnalyzerActions_02_Analyzer(); var comp = CreateCompilation(src); comp.GetAnalyzerDiagnostics([analyzer], null).Verify(); AssertEx.SetEqual([ "E", "E.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$D1693D81A12E8DED4ED68FE22D9E856F", "System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<T>.P { get; }", "T t", "E.<G>$865F3E9780C1FF12019ECA0B40816384.<M>$865F3E9780C1FF12019ECA0B40816384", "E.<G>$C43E2675C7BBF9284AF22FB8A9BF0280.<M>$64C7DA4F599E1426EA88DEA0AE9DC8CD", "System.Object o1", "void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M(System.Int32 i)", "System.Int32 i", "System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<T>.P.get"], analyzer._results.ToArray()); } private class AnalyzerActions_02_Analyzer : DiagnosticAnalyzer { public ConcurrentQueue<string> _results = new ConcurrentQueue<string>(); private static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test"); public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Descriptor]; public override void Initialize(AnalysisContext context) { context.RegisterSymbolAction(handle, SymbolKind.NamedType); context.RegisterSymbolAction(handle, SymbolKind.Parameter); context.RegisterSymbolAction(handle, SymbolKind.TypeParameter); context.RegisterSymbolAction(handle, SymbolKind.Method); context.RegisterSymbolAction(handle, SymbolKind.Property); void handle(SymbolAnalysisContext context) { _results.Enqueue(context.Symbol.ToTestDisplayString()); } } } [Fact] public void AnalyzerActions_03() { var src = """ static class E { extension<T>(T t) { public void M() { } public int P { get { return 0; } } } } """; var analyzer = new AnalyzerActions_03_Analyzer(); var comp = CreateCompilation(src); comp.GetAnalyzerDiagnostics([analyzer], null).Verify(); AssertEx.SetEqual([ "public void M() { } -> void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M()", "get { return 0; } -> System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<T>.P.get"], analyzer._results.ToArray()); } private class AnalyzerActions_03_Analyzer : DiagnosticAnalyzer { public ConcurrentQueue<string> _results = new ConcurrentQueue<string>(); private static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test"); public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Descriptor]; public override void Initialize(AnalysisContext context) { context.RegisterOperationAction(handle, OperationKind.MethodBody); void handle(OperationAnalysisContext context) { _results.Enqueue($"{context.Operation.Syntax.ToString()} -> {context.ContainingSymbol.ToTestDisplayString()}"); } } } [Fact] public void AnalyzerActions_04() { var src = """ static class E { extension<T>(T t) { public void M(int i) { } public int P { get { return 0; } } } } """; var analyzer = new AnalyzerActions_04_Analyzer(); var comp = CreateCompilation(src); comp.GetAnalyzerDiagnostics([analyzer], null).Verify(); AssertEx.SetEqual([ "Start: E", "Start: E.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$D1693D81A12E8DED4ED68FE22D9E856F", "Start: void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M(System.Int32 i)", "Start: System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<T>.P { get; }", "Start: System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<T>.P.get", "End: System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<T>.P { get; }", "End: System.Int32 E.<G>$8048A6C8BE30A622530249B904B537EB<T>.P.get", "End: void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M(System.Int32 i)", "End: E.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$D1693D81A12E8DED4ED68FE22D9E856F", "End: E"], analyzer._results.ToArray()); } private class AnalyzerActions_04_Analyzer : DiagnosticAnalyzer { public ConcurrentQueue<string> _results = new ConcurrentQueue<string>(); private static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test"); public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Descriptor]; public override void Initialize(AnalysisContext context) { context.RegisterSymbolStartAction(handleStart, SymbolKind.NamedType); context.RegisterSymbolStartAction(handleStart, SymbolKind.Method); context.RegisterSymbolStartAction(handleStart, SymbolKind.Property); context.RegisterSymbolStartAction(handleStart, SymbolKind.Parameter); context.RegisterSymbolStartAction(handleStart, SymbolKind.TypeParameter); void handleStart(SymbolStartAnalysisContext context) { _results.Enqueue($"Start: {context.Symbol.ToTestDisplayString()}"); context.RegisterSymbolEndAction(handleEnd); } void handleEnd(SymbolAnalysisContext context) { _results.Enqueue($"End: {context.Symbol.ToTestDisplayString()}"); } } } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78487")] public void Async_01() { string source = """ await System.Threading.Tasks.Task.FromResult(true).M(); await System.Threading.Tasks.Task<bool>.M2(); static class E { extension<T>(System.Threading.Tasks.Task<T> source) { public async System.Threading.Tasks.Task M() { System.Console.Write(await source); System.Console.Write(" ran "); } public static async System.Threading.Tasks.Task M2() { await System.Threading.Tasks.Task.FromResult(default(T)); System.Console.Write("ran2"); } } } """; var comp = CreateCompilation(source); CompileAndVerify(comp, expectedOutput: "True ran ran2").VerifyDiagnostics(); } }