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