@@ -1149,22 +1149,25 @@ static void checkValidMethodOverride(
11491149 MethodSymbol overridingMethod ,
11501150 BindingDiagnosticBag diagnostics )
11511151 {
1152- CheckValidScopedOverride (
1153- overriddenMethod ,
1154- overridingMethod ,
1155- diagnostics ,
1156- static ( diagnostics , overriddenMethod , overridingMethod , overridingParameter , _ , location ) =>
1157- {
1158- diagnostics . Add (
1159- ReportInvalidScopedOverrideAsError ( overriddenMethod , overridingMethod ) ?
1160- ErrorCode . ERR_ScopedMismatchInParameterOfOverrideOrImplementation :
1161- ErrorCode . WRN_ScopedMismatchInParameterOfOverrideOrImplementation ,
1162- location ,
1163- new FormattedSymbol ( overridingParameter , SymbolDisplayFormat . ShortFormat ) ) ;
1164- } ,
1165- overridingMemberLocation ,
1166- allowVariance : true ,
1167- invokedAsExtensionMethod : false ) ;
1152+ if ( RequiresValidScopedOverrideForRefSafety ( overriddenMethod ) )
1153+ {
1154+ CheckValidScopedOverride (
1155+ overriddenMethod ,
1156+ overridingMethod ,
1157+ diagnostics ,
1158+ static ( diagnostics , overriddenMethod , overridingMethod , overridingParameter , _ , location ) =>
1159+ {
1160+ diagnostics . Add (
1161+ ReportInvalidScopedOverrideAsError ( overriddenMethod , overridingMethod ) ?
1162+ ErrorCode . ERR_ScopedMismatchInParameterOfOverrideOrImplementation :
1163+ ErrorCode . WRN_ScopedMismatchInParameterOfOverrideOrImplementation ,
1164+ location ,
1165+ new FormattedSymbol ( overridingParameter , SymbolDisplayFormat . ShortFormat ) ) ;
1166+ } ,
1167+ overridingMemberLocation ,
1168+ allowVariance : true ,
1169+ invokedAsExtensionMethod : false ) ;
1170+ }
11681171
11691172 CheckValidNullableMethodOverride ( overridingMethod . DeclaringCompilation , overriddenMethod , overridingMethod , diagnostics ,
11701173 ReportBadReturn ,
@@ -1367,55 +1370,60 @@ static bool isValidNullableConversion(
13671370
13681371#nullable enable
13691372 /// <summary>
1370- /// Returns true if a scoped mismatch should be reported as an error rather than a warning.
1373+ /// Returns true if the method signature must match, with respect to scoped for ref safety,
1374+ /// in overrides, interface implementations, or delegate conversions.
13711375 /// </summary>
1372- internal static bool ReportInvalidScopedOverrideAsError ( MethodSymbol baseMethod , MethodSymbol overrideMethod )
1376+ internal static bool RequiresValidScopedOverrideForRefSafety ( MethodSymbol ? method )
13731377 {
1374- // https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#scoped-mismatch
1375- // 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.
1376- return baseMethod . UseUpdatedEscapeRules && overrideMethod . UseUpdatedEscapeRules &&
1377- // We have removed exceptions to the scoped mismatch error reporting, but to avoid breaks
1378- // we report the new scenarios (previously exempted) as warnings in C# 12 and earlier.
1379- // https://github.com/dotnet/roslyn/issues/76100
1380- ( overrideMethod . DeclaringCompilation . LanguageVersion > LanguageVersion . CSharp12 || usedToBeReported ( baseMethod ) ) ;
1381-
1382- static bool usedToBeReported ( MethodSymbol method )
1383- {
1384- var parameters = method . Parameters ;
1385-
1386- // https://github.com/dotnet/csharplang/blob/1f7f23f/proposals/csharp-11.0/low-level-struct-improvements.md#scoped-mismatch
1387- // The compiler will report a diagnostic for _unsafe scoped mismatches_ across overrides, interface implementations, and delegate conversions when:
1388- // - 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
1389- // ...
1390- int nRefParametersRequired ;
1391- if ( method . ReturnType . IsRefLikeOrAllowsRefLikeType ( ) ||
1392- ( method . RefKind is RefKind . Ref or RefKind . RefReadOnly ) )
1393- {
1394- nRefParametersRequired = 1 ;
1395- }
1396- else if ( parameters . Any ( p => ( p . RefKind is RefKind . Ref or RefKind . Out ) && p . Type . IsRefLikeOrAllowsRefLikeType ( ) ) )
1397- {
1398- nRefParametersRequired = 2 ; // including the parameter found above
1399- }
1400- else
1401- {
1402- return false ;
1403- }
1378+ if ( method is null )
1379+ {
1380+ return false ;
1381+ }
14041382
1405- // ...
1406- // - The method has at least one additional `ref`, `in`, `ref readonly`, or `out` parameter, or a parameter of `ref struct` type.
1407- int nRefParameters = parameters . Count ( p => p . RefKind is RefKind . Ref or RefKind . In or RefKind . RefReadOnlyParameter or RefKind . Out ) ;
1408- if ( nRefParameters >= nRefParametersRequired )
1409- {
1410- return true ;
1411- }
1412- else if ( parameters . Any ( p => p . RefKind == RefKind . None && p . Type . IsRefLikeOrAllowsRefLikeType ( ) ) )
1413- {
1414- return true ;
1415- }
1383+ var parameters = method . Parameters ;
14161384
1385+ // https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#scoped-mismatch
1386+ // The compiler will report a diagnostic for _unsafe scoped mismatches_ across overrides, interface implementations, and delegate conversions when:
1387+ // - 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
1388+ // ...
1389+ int nRefParametersRequired ;
1390+ if ( method . ReturnType . IsRefLikeOrAllowsRefLikeType ( ) ||
1391+ ( method . RefKind is RefKind . Ref or RefKind . RefReadOnly ) )
1392+ {
1393+ nRefParametersRequired = 1 ;
1394+ }
1395+ else if ( parameters . Any ( p => ( p . RefKind is RefKind . Ref or RefKind . Out ) && p . Type . IsRefLikeOrAllowsRefLikeType ( ) ) )
1396+ {
1397+ nRefParametersRequired = 2 ; // including the parameter found above
1398+ }
1399+ else
1400+ {
14171401 return false ;
14181402 }
1403+
1404+ // ...
1405+ // - The method has at least one additional `ref`, `in`, `ref readonly`, or `out` parameter, or a parameter of `ref struct` type.
1406+ int nRefParameters = parameters . Count ( p => p . RefKind is RefKind . Ref or RefKind . In or RefKind . RefReadOnlyParameter or RefKind . Out ) ;
1407+ if ( nRefParameters >= nRefParametersRequired )
1408+ {
1409+ return true ;
1410+ }
1411+ else if ( parameters . Any ( p => p . RefKind == RefKind . None && p . Type . IsRefLikeOrAllowsRefLikeType ( ) ) )
1412+ {
1413+ return true ;
1414+ }
1415+
1416+ return false ;
1417+ }
1418+
1419+ /// <summary>
1420+ /// Returns true if a scoped mismatch should be reported as an error rather than a warning.
1421+ /// </summary>
1422+ internal static bool ReportInvalidScopedOverrideAsError ( MethodSymbol baseMethod , MethodSymbol overrideMethod )
1423+ {
1424+ // https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#scoped-mismatch
1425+ // 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.
1426+ return baseMethod . UseUpdatedEscapeRules && overrideMethod . UseUpdatedEscapeRules ;
14191427 }
14201428
14211429 /// <summary>
0 commit comments