diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md index 1d315df482f1a..f9f737e36085d 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md @@ -172,40 +172,6 @@ struct S } ``` -## Variance of `scoped` and `[UnscopedRef]` is more strict - -***Introduced in Visual Studio 2022 version 17.13*** - -Scope can be changed when overriding a method, implementing an interface, or converting a lambda/method to a delegate under -[some conditions](https://github.com/dotnet/csharplang/blob/05064c2a9567b7a58a07e526dff403ece1866541/proposals/csharp-11.0/low-level-struct-improvements.md#scoped-mismatch) -(roughly, `scoped` can be added and `[UnscopedRef]` can be removed). -Previously, the compiler did not report an error/warning for such mismatch under some circumstances, but it is now always reported. -Note that the error is downgraded to a warning in `unsafe` contexts and also (in scenarios where it would be a breaking change) with LangVersion 12 or lower. - -```cs -D1 d1 = (ref int i) => { }; // previously no mismatch error reported, now: - // error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D1'. - -D2 d2 = (ref int i) => ref i; // an error was and continues to be reported: - // error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D2'. - -delegate void D1(scoped ref int x); -delegate ref int D2(scoped ref int x); -``` - -```cs -using System.Diagnostics.CodeAnalysis; - -D1 d1 = ([UnscopedRef] ref int i) => { }; // previously no mismatch error reported, now: - // error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D1'. - -D2 d2 = ([UnscopedRef] ref int i) => ref i; // an error was and continues to be reported: - // error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D2'. - -delegate void D1(ref int x); -delegate ref int D2(ref int x); -``` - ## `Microsoft.CodeAnalysis.EmbeddedAttribute` is validated on declaration ***Introduced in Visual Studio 2022 version 17.13*** diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index fae2378ed5b04..7df03440b692e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -2274,23 +2274,26 @@ private static void CheckParameterModifierMismatchMethodConversion(SyntaxNode sy return; } - SourceMemberContainerTypeSymbol.CheckValidScopedOverride( - delegateMethod, - lambdaOrMethod, - diagnostics, - static (diagnostics, delegateMethod, lambdaOrMethod, parameter, _, typeAndSyntax) => - { - diagnostics.Add( - SourceMemberContainerTypeSymbol.ReportInvalidScopedOverrideAsError(delegateMethod, lambdaOrMethod) ? - ErrorCode.ERR_ScopedMismatchInParameterOfTarget : - ErrorCode.WRN_ScopedMismatchInParameterOfTarget, - typeAndSyntax.Syntax.Location, - new FormattedSymbol(parameter, SymbolDisplayFormat.ShortFormat), - typeAndSyntax.Type); - }, - (Type: targetType, Syntax: syntax), - allowVariance: true, - invokedAsExtensionMethod: invokedAsExtensionMethod); + if (SourceMemberContainerTypeSymbol.RequiresValidScopedOverrideForRefSafety(delegateMethod)) + { + SourceMemberContainerTypeSymbol.CheckValidScopedOverride( + delegateMethod, + lambdaOrMethod, + diagnostics, + static (diagnostics, delegateMethod, lambdaOrMethod, parameter, _, typeAndSyntax) => + { + diagnostics.Add( + SourceMemberContainerTypeSymbol.ReportInvalidScopedOverrideAsError(delegateMethod, lambdaOrMethod) ? + ErrorCode.ERR_ScopedMismatchInParameterOfTarget : + ErrorCode.WRN_ScopedMismatchInParameterOfTarget, + typeAndSyntax.Syntax.Location, + new FormattedSymbol(parameter, SymbolDisplayFormat.ShortFormat), + typeAndSyntax.Type); + }, + (Type: targetType, Syntax: syntax), + allowVariance: true, + invokedAsExtensionMethod: invokedAsExtensionMethod); + } SourceMemberContainerTypeSymbol.CheckRefReadonlyInMismatch( delegateMethod, lambdaOrMethod, diagnostics, diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs index f767fe8561191..0f2216f4fef46 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs @@ -1149,22 +1149,25 @@ static void checkValidMethodOverride( MethodSymbol overridingMethod, BindingDiagnosticBag diagnostics) { - CheckValidScopedOverride( - overriddenMethod, - overridingMethod, - diagnostics, - static (diagnostics, overriddenMethod, overridingMethod, overridingParameter, _, location) => - { - diagnostics.Add( - ReportInvalidScopedOverrideAsError(overriddenMethod, overridingMethod) ? - ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation : - ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, - location, - new FormattedSymbol(overridingParameter, SymbolDisplayFormat.ShortFormat)); - }, - overridingMemberLocation, - allowVariance: true, - invokedAsExtensionMethod: false); + if (RequiresValidScopedOverrideForRefSafety(overriddenMethod)) + { + CheckValidScopedOverride( + overriddenMethod, + overridingMethod, + diagnostics, + static (diagnostics, overriddenMethod, overridingMethod, overridingParameter, _, location) => + { + diagnostics.Add( + ReportInvalidScopedOverrideAsError(overriddenMethod, overridingMethod) ? + ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation : + ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, + location, + new FormattedSymbol(overridingParameter, SymbolDisplayFormat.ShortFormat)); + }, + overridingMemberLocation, + allowVariance: true, + invokedAsExtensionMethod: false); + } CheckValidNullableMethodOverride(overridingMethod.DeclaringCompilation, overriddenMethod, overridingMethod, diagnostics, ReportBadReturn, @@ -1367,55 +1370,60 @@ static bool isValidNullableConversion( #nullable enable /// - /// Returns true if a scoped mismatch should be reported as an error rather than a warning. + /// Returns true if the method signature must match, with respect to scoped for ref safety, + /// in overrides, interface implementations, or delegate conversions. /// - internal static bool ReportInvalidScopedOverrideAsError(MethodSymbol baseMethod, MethodSymbol overrideMethod) + internal static bool RequiresValidScopedOverrideForRefSafety(MethodSymbol? method) { - // https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#scoped-mismatch - // The diagnostic is reported as an error if the mismatched signatures are both using C#11 ref safety rules; otherwise, the diagnostic is a warning. - return baseMethod.UseUpdatedEscapeRules && overrideMethod.UseUpdatedEscapeRules && - // We have removed exceptions to the scoped mismatch error reporting, but to avoid breaks - // we report the new scenarios (previously exempted) as warnings in C# 12 and earlier. - // https://github.com/dotnet/roslyn/issues/76100 - (overrideMethod.DeclaringCompilation.LanguageVersion > LanguageVersion.CSharp12 || usedToBeReported(baseMethod)); - - static bool usedToBeReported(MethodSymbol method) - { - var parameters = method.Parameters; - - // https://github.com/dotnet/csharplang/blob/1f7f23f/proposals/csharp-11.0/low-level-struct-improvements.md#scoped-mismatch - // The compiler will report a diagnostic for _unsafe scoped mismatches_ across overrides, interface implementations, and delegate conversions when: - // - The method returns a `ref struct` or returns a `ref` or `ref readonly`, or the method has a `ref` or `out` parameter of `ref struct` type, and - // ... - int nRefParametersRequired; - if (method.ReturnType.IsRefLikeOrAllowsRefLikeType() || - (method.RefKind is RefKind.Ref or RefKind.RefReadOnly)) - { - nRefParametersRequired = 1; - } - else if (parameters.Any(p => (p.RefKind is RefKind.Ref or RefKind.Out) && p.Type.IsRefLikeOrAllowsRefLikeType())) - { - nRefParametersRequired = 2; // including the parameter found above - } - else - { - return false; - } + if (method is null) + { + return false; + } - // ... - // - The method has at least one additional `ref`, `in`, `ref readonly`, or `out` parameter, or a parameter of `ref struct` type. - int nRefParameters = parameters.Count(p => p.RefKind is RefKind.Ref or RefKind.In or RefKind.RefReadOnlyParameter or RefKind.Out); - if (nRefParameters >= nRefParametersRequired) - { - return true; - } - else if (parameters.Any(p => p.RefKind == RefKind.None && p.Type.IsRefLikeOrAllowsRefLikeType())) - { - return true; - } + var parameters = method.Parameters; + // https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#scoped-mismatch + // The compiler will report a diagnostic for _unsafe scoped mismatches_ across overrides, interface implementations, and delegate conversions when: + // - The method returns a `ref struct` or returns a `ref` or `ref readonly`, or the method has a `ref` or `out` parameter of `ref struct` type, and + // ... + int nRefParametersRequired; + if (method.ReturnType.IsRefLikeOrAllowsRefLikeType() || + (method.RefKind is RefKind.Ref or RefKind.RefReadOnly)) + { + nRefParametersRequired = 1; + } + else if (parameters.Any(p => (p.RefKind is RefKind.Ref or RefKind.Out) && p.Type.IsRefLikeOrAllowsRefLikeType())) + { + nRefParametersRequired = 2; // including the parameter found above + } + else + { return false; } + + // ... + // - The method has at least one additional `ref`, `in`, `ref readonly`, or `out` parameter, or a parameter of `ref struct` type. + int nRefParameters = parameters.Count(p => p.RefKind is RefKind.Ref or RefKind.In or RefKind.RefReadOnlyParameter or RefKind.Out); + if (nRefParameters >= nRefParametersRequired) + { + return true; + } + else if (parameters.Any(p => p.RefKind == RefKind.None && p.Type.IsRefLikeOrAllowsRefLikeType())) + { + return true; + } + + return false; + } + + /// + /// Returns true if a scoped mismatch should be reported as an error rather than a warning. + /// + internal static bool ReportInvalidScopedOverrideAsError(MethodSymbol baseMethod, MethodSymbol overrideMethod) + { + // https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#scoped-mismatch + // The diagnostic is reported as an error if the mismatched signatures are both using C#11 ref safety rules; otherwise, the diagnostic is a warning. + return baseMethod.UseUpdatedEscapeRules && overrideMethod.UseUpdatedEscapeRules; } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs index 4763f5d7fa071..61fd5fa1bc95e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs @@ -1855,23 +1855,25 @@ static void checkMethodOverride( reportMismatchInParameterType, (implementingType, isExplicit)); - SourceMemberContainerTypeSymbol.CheckValidScopedOverride( - implementedMethod, - implementingMethod, - diagnostics, - static (diagnostics, implementedMethod, implementingMethod, implementingParameter, _, arg) => - { - diagnostics.Add( - SourceMemberContainerTypeSymbol.ReportInvalidScopedOverrideAsError(implementedMethod, implementingMethod) ? - ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation : - ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, - GetImplicitImplementationDiagnosticLocation(implementedMethod, arg.implementingType, implementingMethod), - new FormattedSymbol(implementingParameter, SymbolDisplayFormat.ShortFormat)); - }, - (implementingType, isExplicit), - allowVariance: true, - invokedAsExtensionMethod: false); - + if (SourceMemberContainerTypeSymbol.RequiresValidScopedOverrideForRefSafety(implementedMethod)) + { + SourceMemberContainerTypeSymbol.CheckValidScopedOverride( + implementedMethod, + implementingMethod, + diagnostics, + static (diagnostics, implementedMethod, implementingMethod, implementingParameter, _, arg) => + { + diagnostics.Add( + SourceMemberContainerTypeSymbol.ReportInvalidScopedOverrideAsError(implementedMethod, implementingMethod) ? + ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation : + ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, + GetImplicitImplementationDiagnosticLocation(implementedMethod, arg.implementingType, implementingMethod), + new FormattedSymbol(implementingParameter, SymbolDisplayFormat.ShortFormat)); + }, + (implementingType, isExplicit), + allowVariance: true, + invokedAsExtensionMethod: false); + } SourceMemberContainerTypeSymbol.CheckRefReadonlyInMismatch( implementedMethod, implementingMethod, diagnostics, static (diagnostics, implementedMethod, implementingMethod, implementingParameter, _, arg) => diff --git a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs index 0c86323939911..dfd89fae251fe 100644 --- a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs @@ -21358,7 +21358,7 @@ class Helper delegate void D2(T x); static D1 d11 = M1; - static D1 d12 = M2; // 1 + static D1 d12 = M2; static D2 d21 = M1; static D2 d22 = M2; @@ -21372,7 +21372,7 @@ class Helper delegate void D2(Span x); static D1 d11 = M1; - static D1 d12 = M2; // 2 + static D1 d12 = M2; static D2 d21 = M1; static D2 d22 = M2; @@ -21381,13 +21381,7 @@ static void M2(Span x) {} } "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); - comp.VerifyEmitDiagnostics( - // (11,21): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'Helper.D1'. - // static D1 d12 = M2; // 1 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M2").WithArguments("x", "Helper.D1").WithLocation(11, 21), - // (25,21): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'Helper.D1'. - // static D1 d12 = M2; // 2 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M2").WithArguments("x", "Helper.D1").WithLocation(25, 21)); + comp.VerifyEmitDiagnostics(); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs index 79326aa71c089..b5b93d987d5e0 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs @@ -10878,341 +10878,5 @@ public static void M([UnscopedRef] ref S s) """; CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); } - - [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] - public void SelfAssignment_ScopeVariance_UnscopedRef_Disallowed_ImplicitInterface( - [CombinatorialValues("ref", "out")] string modifier) - { - var source = $$""" - using System.Diagnostics.CodeAnalysis; - - interface I - { - void M({{modifier}} R r); - } - - class C : I - { - public void M([UnscopedRef] {{modifier}} R r) { } - } - - ref struct R; - """; - - var expectedDiagnostics = new[] - { - // (10,17): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public void M([UnscopedRef] ref R r) { } - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(10, 17) - }; - - CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular13).VerifyDiagnostics(expectedDiagnostics); - - CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular12).VerifyDiagnostics( - // (10,17): warning CS9074: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public void M([UnscopedRef] ref R r) { } - Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(10, 17)); - } - - [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] - public void SelfAssignment_ScopeVariance_UnscopedRef_Disallowed_ExplicitInterface( - [CombinatorialValues("ref", "out")] string modifier) - { - var source = $$""" - using System.Diagnostics.CodeAnalysis; - - interface I - { - void M({{modifier}} R r); - } - - class C : I - { - void I.M([UnscopedRef] {{modifier}} R r) { } - } - - ref struct R; - """; - CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( - // (10,12): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // void I.M([UnscopedRef] ref R r) { } - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(10, 12)); - } - - [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] - public void SelfAssignment_ScopeVariance_UnscopedRef_Disallowed_Override( - [CombinatorialValues("ref", "out")] string modifier) - { - var source = $$""" - using System.Diagnostics.CodeAnalysis; - - abstract class B - { - public abstract void M({{modifier}} R r); - } - - class C : B - { - public override void M([UnscopedRef] {{modifier}} R r) { } - } - - ref struct R; - """; - CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( - // (10,26): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public override void M([UnscopedRef] ref R r) { } - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(10, 26)); - } - - [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] - public void SelfAssignment_ScopeVariance_UnscopedRef_Disallowed_DelegateConversion( - [CombinatorialValues("ref", "out")] string modifier) - { - var source = $$""" - using System.Diagnostics.CodeAnalysis; - - D d = C.M; - - delegate void D({{modifier}} R r); - - static class C - { - public static void M([UnscopedRef] {{modifier}} R r) { } - } - - ref struct R; - """; - CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( - // (3,7): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D'. - // D d = C.M; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "C.M").WithArguments("r", "D").WithLocation(3, 7)); - } - - [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] - [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "")] - [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "[System.Diagnostics.CodeAnalysis.UnscopedRef]")] - [InlineData("", "")] - public void SelfAssignment_ScopeVariance_UnscopedRef_Allowed_ImplicitInterface(string attr1, string attr2) - { - var source = $$""" - interface I - { - void M({{attr1}} ref R r); - } - - class C : I - { - public void M({{attr2}} ref R r) { } - } - - ref struct R; - """; - CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); - } - - [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] - public void SelfAssignment_ScopeVariance_ScopedRef_ImplicitInterface( - [CombinatorialValues("scoped", "")] string scoped1, - [CombinatorialValues("scoped", "")] string scoped2, - [CombinatorialValues("ref", "out")] string modifier) - { - var source = $$""" - interface I - { - void M({{scoped1}} {{modifier}} R r); - } - - class C : I - { - public void M({{scoped2}} {{modifier}} R r) { } - } - - ref struct R; - """; - - var comp = CreateCompilation(source); - - if (scoped1 == "scoped" && scoped2 == "" && modifier == "ref") - { - comp.VerifyDiagnostics( - // (8,17): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public void M( ref R r) { } - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(8, 17)); - } - else - { - comp.VerifyDiagnostics(); - } - } - - [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] - [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "")] - [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "[System.Diagnostics.CodeAnalysis.UnscopedRef]")] - [InlineData("", "")] - public void SelfAssignment_ScopeVariance_UnscopedRef_Allowed_ExplicitInterface(string attr1, string attr2) - { - var source = $$""" - interface I - { - void M({{attr1}} ref R r); - } - - class C : I - { - void I.M({{attr2}} ref R r) { } - } - - ref struct R; - """; - CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); - } - - [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] - public void SelfAssignment_ScopeVariance_ScopedRef_ExplicitInterface( - [CombinatorialValues("scoped", "")] string scoped1, - [CombinatorialValues("scoped", "")] string scoped2, - [CombinatorialValues("ref", "out")] string modifier) - { - var source = $$""" - interface I - { - void M({{scoped1}} {{modifier}} R r); - } - - class C : I - { - void I.M({{scoped2}} {{modifier}} R r) { } - } - - ref struct R; - """; - - var comp = CreateCompilation(source); - - if (scoped1 == "scoped" && scoped2 == "" && modifier == "ref") - { - comp.VerifyDiagnostics( - // (8,12): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // void I.M( ref R r) { } - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(8, 12)); - } - else - { - comp.VerifyDiagnostics(); - } - } - - [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] - [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "")] - [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "[System.Diagnostics.CodeAnalysis.UnscopedRef]")] - [InlineData("", "")] - public void SelfAssignment_ScopeVariance_UnscopedRef_Allowed_Override(string attr1, string attr2) - { - var source = $$""" - abstract class B - { - public abstract void M({{attr1}} ref R r); - } - - class C : B - { - public override void M({{attr2}} ref R r) { } - } - - ref struct R; - """; - CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); - } - - [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] - public void SelfAssignment_ScopeVariance_ScopedRef_Override( - [CombinatorialValues("scoped", "")] string scoped1, - [CombinatorialValues("scoped", "")] string scoped2, - [CombinatorialValues("ref", "out")] string modifier) - { - var source = $$""" - abstract class B - { - public abstract void M({{scoped1}} {{modifier}} R r); - } - - class C : B - { - public override void M({{scoped2}} {{modifier}} R r) { } - } - - ref struct R; - """; - - var comp = CreateCompilation(source); - - if (scoped1 == "scoped" && scoped2 == "" && modifier == "ref") - { - comp.VerifyDiagnostics( - // (8,26): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public override void M( ref R r) { } - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(8, 26)); - } - else - { - comp.VerifyDiagnostics(); - } - } - - [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] - [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "")] - [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "[System.Diagnostics.CodeAnalysis.UnscopedRef]")] - [InlineData("", "")] - public void SelfAssignment_ScopeVariance_UnscopedRef_Allowed_DelegateConversion(string attr1, string attr2) - { - var source = $$""" - D d = C.M; - - delegate void D({{attr1}} ref R r); - - static class C - { - public static void M({{attr2}} ref R r) { } - } - - ref struct R; - """; - CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); - } - - [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] - public void SelfAssignment_ScopeVariance_ScopedRef_DelegateConversion( - [CombinatorialValues("scoped", "")] string scoped1, - [CombinatorialValues("scoped", "")] string scoped2, - [CombinatorialValues("ref", "out")] string modifier) - { - var source = $$""" - D d = C.M; - - delegate void D({{scoped1}} {{modifier}} R r); - - static class C - { - public static void M({{scoped2}} {{modifier}} R r) { } - } - - ref struct R; - """; - - var comp = CreateCompilation(source); - - if (scoped1 == "scoped" && scoped2 == "" && modifier == "ref") - { - comp.VerifyDiagnostics( - // (1,7): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D'. - // D d = C.M; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "C.M").WithArguments("r", "D").WithLocation(1, 7)); - } - else - { - comp.VerifyDiagnostics(); - } - } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index 8c8f24c91e07e..5b9edc3c4fc13 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -11071,9 +11071,6 @@ static void Main() // (8,30): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // var f3 = (in int x3, scoped in int y3) => { }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 30), - // (9,18): warning CS9073: The 'scoped' modifier of parameter 'z4' doesn't match target ''. - // var f4 = (out int x4, scoped out int y4, [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] out int z4) => { x4 = 0; y4 = 0; z4 = 0; }; - Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfTarget, "(out int x4, scoped out int y4, [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] out int z4) => { x4 = 0; y4 = 0; z4 = 0; }").WithArguments("z4", "").WithLocation(9, 18), // (9,31): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // var f4 = (out int x4, scoped out int y4, [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] out int z4) => { x4 = 0; y4 = 0; z4 = 0; }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 31), @@ -16252,27 +16249,21 @@ static void Main() {{ D0 d0 = ({refModifier} int i) => {{ }}; D1 d1 = ({refModifier} int i) => F(); - D2 d2 = ({refModifier} int i) => ref F(); - D3 d3 = ({refModifier} int i) => ref F(); - D4 d4 = ({refModifier} int i) => new R(); + D2 d2 = ({refModifier} int i) => ref F(); // 1 + D3 d3 = ({refModifier} int i) => ref F(); // 2 + D4 d4 = ({refModifier} int i) => new R(); // 3 }} }}"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (12,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D0'. - // D0 d0 = (ref int i) => { }; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i) => {{ }}").WithArguments("i", "D0").WithLocation(12, 22), - // (13,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D1'. - // D1 d1 = (ref int i) => F(); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i) => F()").WithArguments("i", "D1").WithLocation(13, 22), // (14,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D2'. - // D2 d2 = (ref int i) => ref F(); + // D2 d2 = (ref int i) => ref F(); // 1 Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i) => ref F()").WithArguments("i", "D2").WithLocation(14, 22), // (15,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D3'. - // D3 d3 = (ref int i) => ref F(); + // D3 d3 = (ref int i) => ref F(); // 2 Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i) => ref F()").WithArguments("i", "D3").WithLocation(15, 22), // (16,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D4'. - // D4 d4 = (ref int i) => new R(); + // D4 d4 = (ref int i) => new R(); // 3 Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i) => new R()").WithArguments("i", "D4").WithLocation(16, 22)); } @@ -16293,24 +16284,18 @@ class Program static void Main() {{ D0 d0 = ({refModifier} int i, R r) => {{ }}; - D1 d1 = ({refModifier} int i, ref R r) => {{ }}; + D1 d1 = ({refModifier} int i, ref R r) => {{ }}; // 1 D2 d2 = ({refModifier} int i, in R r) => {{ }}; - D3 d3 = ({refModifier} int i, out R r) => {{ r = default; }}; + D3 d3 = ({refModifier} int i, out R r) => {{ r = default; }}; // 2 }} }}"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (11,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D0'. - // D0 d0 = (ref int i, R r) => { }; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i, R r) => {{ }}").WithArguments("i", "D0").WithLocation(11, 22), // (12,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D1'. - // D1 d1 = (ref int i, ref R r) => { }; + // D1 d1 = (ref int i, ref R r) => { }; // 1 Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i, ref R r) => {{ }}").WithArguments("i", "D1").WithLocation(12, 22), - // (13,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D2'. - // D2 d2 = (ref int i, in R r) => { }; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i, in R r) => {{ }}").WithArguments("i", "D2").WithLocation(13, 22), // (14,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D3'. - // D3 d3 = (ref int i, out R r) => { r = default; }; + // D3 d3 = (ref int i, out R r) => { r = default; }; // 2 Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i, out R r) => {{ r = default; }}").WithArguments("i", "D3").WithLocation(14, 22)); } @@ -16780,10 +16765,7 @@ public static void M(object? o) comp.VerifyDiagnostics( // (3,17): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. // delegate R D(scoped T t); - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(3, 17), - // (14,27): error CS8986: The 'scoped' modifier of parameter 'o2' doesn't match target 'D'. - // D d = o2 => throw null!; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "o2 => throw null!").WithArguments("o2", "D").WithLocation(14, 27) + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(3, 17) ); var syntaxTree = comp.SyntaxTrees[0]; @@ -17406,10 +17388,7 @@ public class C : Base Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(11, 38), // (12,45): error CS8987: The 'scoped' modifier of parameter 'rs' doesn't match overridden or implemented member. // public override RS this[RS rs, int _] { get => default; set { } } // 2 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(12, 45), - // (12,61): error CS8987: The 'scoped' modifier of parameter 'rs' doesn't match overridden or implemented member. - // public override RS this[RS rs, int _] { get => default; set { } } // 2 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "set").WithArguments("rs").WithLocation(12, 61)); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(12, 45)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73384")] @@ -17438,10 +17417,7 @@ public class C : I Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(11, 29), // (12,36): error CS8987: The 'scoped' modifier of parameter 'rs' doesn't match overridden or implemented member. // public RS this[RS rs, int _] { get => default; set { } } // 2 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(12, 36), - // (12,52): error CS8987: The 'scoped' modifier of parameter 'rs' doesn't match overridden or implemented member. - // public RS this[RS rs, int _] { get => default; set { } } // 2 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "set").WithArguments("rs").WithLocation(12, 52)); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(12, 36)); } [CombinatorialData] @@ -22691,21 +22667,14 @@ public static void M([UnscopedRef] ref int x) { } var expectedOutput = "<>A{00000001}`1[System.Int32]"; - var expectedDiagnostics = new[] - { - // (3,14): warning CS9073: The 'scoped' modifier of parameter 'x' doesn't match target ''. - // Delegate d = C.M; - Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfTarget, "C.M").WithArguments("x", "").WithLocation(3, 14) - }; - CompileAndVerify(source2, [ref1], parseOptions: TestOptions.Regular10, symbolValidator: validate, - expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics); + expectedOutput: expectedOutput).VerifyDiagnostics(); CompileAndVerify(source2, [ref1], symbolValidator: validate, - expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics); + expectedOutput: expectedOutput).VerifyDiagnostics(); static void validate(ModuleSymbol module) { @@ -26202,12 +26171,9 @@ [UnscopedRef] void I.F2() { } comp.VerifyEmitDiagnostics(); } - [Theory] - [InlineData(LanguageVersion.Preview)] - [InlineData(LanguageVersion.CSharp13)] - [InlineData(LanguageVersion.CSharp12)] + [Fact] [WorkItem(64508, "https://github.com/dotnet/roslyn/issues/64508")] - public void UnscopedRefAttribute_InterfaceImplementation_03(LanguageVersion langVersion) + public void UnscopedRefAttribute_InterfaceImplementation_03() { string source = """ using System.Diagnostics.CodeAnalysis; @@ -26239,7 +26205,7 @@ struct S3 : I2, I3 public int P3 { [UnscopedRef] set { } } // 7 } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion), targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (16,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I1.P1.get' doesn't have this attribute. // [UnscopedRef] public ref int P1 => throw null; // 1