diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index ac21571f750df..31f88b937ad7e 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -3851,6 +3851,9 @@ You should consider suppressing the warning only if you're sure that you don't w Invalid variance: The type parameter '{1}' must be {3} valid on '{0}'. '{1}' is {2}. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + '{0}': cannot derive from the dynamic type @@ -6348,4 +6351,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ A module initializer must be an ordinary member method + + variance safety for static interface members + diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 7ddf7a993bd77..4d3516595b7a4 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1868,6 +1868,9 @@ internal enum ErrorCode ERR_NonPrivateAPIInRecord = 8879, #endregion diagnostics introduced for C# 9.0 + + ERR_UnexpectedVarianceStaticMember = 9100, + // Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd) } } diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index cfb7b66dba2f5..262809a089c5c 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -209,6 +209,7 @@ internal enum MessageID IDS_FeatureNullPointerConstantPattern = MessageBase + 12783, IDS_FeatureModuleInitializers = MessageBase + 12784, IDS_FeatureTargetTypedConditional = MessageBase + 12785, + IDS_FeatureVarianceSafetyForStaticInterfaceMembers = MessageBase + 12786, } // Message IDs may refer to strings that need to be localized. @@ -336,6 +337,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureTargetTypedConditional: // semantic check case MessageID.IDS_FeatureStaticAnonymousFunction: // syntax check case MessageID.IDS_FeatureModuleInitializers: // semantic check on method attribute + case MessageID.IDS_FeatureVarianceSafetyForStaticInterfaceMembers: //semantic check return LanguageVersion.Preview; // C# 8.0 features. diff --git a/src/Compilers/CSharp/Portable/Symbols/VarianceSafety.cs b/src/Compilers/CSharp/Portable/Symbols/VarianceSafety.cs index d867858b582b7..dabb102cd2093 100644 --- a/src/Compilers/CSharp/Portable/Symbols/VarianceSafety.cs +++ b/src/Compilers/CSharp/Portable/Symbols/VarianceSafety.cs @@ -145,6 +145,11 @@ private static void CheckMethodVarianceSafety(this MethodSymbol method, Diagnost private static void CheckMethodVarianceSafety(this MethodSymbol method, LocationProvider returnTypeLocationProvider, DiagnosticBag diagnostics) { + if (SkipVarianceSafetyChecks(method)) + { + return; + } + // Spec 13.2.1: "Furthermore, each class type constraint, interface type constraint and // type parameter constraint on any type parameter of the method must be input-safe." CheckTypeParametersVarianceSafety(method.TypeParameters, method, diagnostics); @@ -162,11 +167,26 @@ private static void CheckMethodVarianceSafety(this MethodSymbol method, Location CheckParametersVarianceSafety(method.Parameters, method, diagnostics); } + private static bool SkipVarianceSafetyChecks(Symbol member) + { + if (member.IsStatic) + { + return MessageID.IDS_FeatureVarianceSafetyForStaticInterfaceMembers.RequiredVersion() <= member.DeclaringCompilation.LanguageVersion; + } + + return false; + } + /// /// Accumulate diagnostics related to the variance safety of an interface property. /// private static void CheckPropertyVarianceSafety(PropertySymbol property, DiagnosticBag diagnostics) { + if (SkipVarianceSafetyChecks(property)) + { + return; + } + bool hasGetter = (object)property.GetMethod != null; bool hasSetter = (object)property.SetMethod != null; if (hasGetter || hasSetter) @@ -193,6 +213,11 @@ private static void CheckPropertyVarianceSafety(PropertySymbol property, Diagnos /// private static void CheckEventVarianceSafety(EventSymbol @event, DiagnosticBag diagnostics) { + if (SkipVarianceSafetyChecks(@event)) + { + return; + } + IsVarianceUnsafe( @event.Type, requireOutputSafety: false, @@ -442,7 +467,15 @@ private static void AddVarianceError( // "requires output-safe", and "requires input-safe and output-safe". This would make the error codes much easier to document and // much more actionable. // UNDONE: related location for use is much more useful - diagnostics.Add(ErrorCode.ERR_UnexpectedVariance, location, context, unsafeTypeParameter, actualVariance.Localize(), expectedVariance.Localize()); + if (!(context is TypeSymbol) && context.IsStatic) + { + diagnostics.Add(ErrorCode.ERR_UnexpectedVarianceStaticMember, location, context, unsafeTypeParameter, actualVariance.Localize(), expectedVariance.Localize(), + new CSharpRequiredLanguageVersion(MessageID.IDS_FeatureVarianceSafetyForStaticInterfaceMembers.RequiredVersion())); + } + else + { + diagnostics.Add(ErrorCode.ERR_UnexpectedVariance, location, context, unsafeTypeParameter, actualVariance.Localize(), expectedVariance.Localize()); + } } private static T GetDeclaringSyntax(this Symbol symbol) where T : SyntaxNode diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 67706e1184e5e..83c3a365c671c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -862,6 +862,11 @@ A constructor declared in a record with parameters must have 'this' constructor initializer. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + + '{0}': cannot specify both a constraint class and the 'unmanaged' constraint {0}: Nejde zadat třídu omezení a zároveň omezení unmanaged. @@ -1486,6 +1491,11 @@ deklarace using + + variance safety for static interface members + variance safety for static interface members + + <null> <null> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 647e546a29c0b..78edc4f3aec81 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -862,6 +862,11 @@ A constructor declared in a record with parameters must have 'this' constructor initializer. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + + '{0}': cannot specify both a constraint class and the 'unmanaged' constraint "{0}": Eine Einschränkungsklasse kann nicht gleichzeitig mit einer unmanaged-Einschränkung angegeben werden. @@ -1486,6 +1491,11 @@ Using-Deklarationen + + variance safety for static interface members + variance safety for static interface members + + <null> <NULL> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 7408480b97336..828e53e3adbd5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -862,6 +862,11 @@ A constructor declared in a record with parameters must have 'this' constructor initializer. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + + '{0}': cannot specify both a constraint class and the 'unmanaged' constraint "{0}": no se puede especificar a la vez una clase de restricción y la restricción "unmanaged" @@ -1486,6 +1491,11 @@ declaraciones using + + variance safety for static interface members + variance safety for static interface members + + <null> <NULL> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 5ed60113522ae..fd50759b51000 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -862,6 +862,11 @@ A constructor declared in a record with parameters must have 'this' constructor initializer. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + + '{0}': cannot specify both a constraint class and the 'unmanaged' constraint '{0}' : impossible de spécifier à la fois une classe de contrainte et la contrainte 'unmanaged' @@ -1486,6 +1491,11 @@ Déclarations using + + variance safety for static interface members + variance safety for static interface members + + <null> <Null> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index d047313f33244..7c37069b61a7f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -862,6 +862,11 @@ A constructor declared in a record with parameters must have 'this' constructor initializer. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + + '{0}': cannot specify both a constraint class and the 'unmanaged' constraint '{0}': non è possibile specificare sia una classe constraint che il vincolo 'unmanaged' @@ -1486,6 +1491,11 @@ dichiarazioni using + + variance safety for static interface members + variance safety for static interface members + + <null> <Null> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index fcb3f384ed1b2..d61d620e8e519 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -862,6 +862,11 @@ A constructor declared in a record with parameters must have 'this' constructor initializer. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + + '{0}': cannot specify both a constraint class and the 'unmanaged' constraint '{0}': 制約クラスと 'unmanaged' 制約の両方を指定することはできません @@ -1486,6 +1491,11 @@ using 宣言 + + variance safety for static interface members + variance safety for static interface members + + <null> <null> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 3f38b24ab4b1b..e708e2d63f58d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -862,6 +862,11 @@ A constructor declared in a record with parameters must have 'this' constructor initializer. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + + '{0}': cannot specify both a constraint class and the 'unmanaged' constraint '{0}': constraint 클래스와 'unmanaged' 제약 조건을 둘 다 지정할 수는 없습니다. @@ -1486,6 +1491,11 @@ using 선언 + + variance safety for static interface members + variance safety for static interface members + + <null> <null> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index da8b9557460ba..23064b9436870 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -862,6 +862,11 @@ A constructor declared in a record with parameters must have 'this' constructor initializer. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + + '{0}': cannot specify both a constraint class and the 'unmanaged' constraint „{0}”: nie można jednocześnie określić klasy ograniczenia i ograniczenia „unmanaged” @@ -1486,6 +1491,11 @@ deklaracje using + + variance safety for static interface members + variance safety for static interface members + + <null> <null> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 7dd2f85929a88..ba0235152bce7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -862,6 +862,11 @@ A constructor declared in a record with parameters must have 'this' constructor initializer. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + + '{0}': cannot specify both a constraint class and the 'unmanaged' constraint '{0}': não é possível especificar uma classe de restrição e a restrição 'unmanaged' @@ -1484,6 +1489,11 @@ declarações using + + variance safety for static interface members + variance safety for static interface members + + <null> <nulo> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 589e2349f6ee6..4d84bcc89ab0f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -862,6 +862,11 @@ A constructor declared in a record with parameters must have 'this' constructor initializer. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + + '{0}': cannot specify both a constraint class and the 'unmanaged' constraint "{0}": невозможно одновременно задать класс ограничения и ограничение "unmanaged" @@ -1486,6 +1491,11 @@ объявления using + + variance safety for static interface members + variance safety for static interface members + + <null> <NULL> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 2d769a5a0b11a..341f92044c214 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -862,6 +862,11 @@ A constructor declared in a record with parameters must have 'this' constructor initializer. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + + '{0}': cannot specify both a constraint class and the 'unmanaged' constraint '{0}': hem bir kısıtlama sınıfı hem de 'unmanaged' kısıtlaması belirtilemez @@ -1486,6 +1491,11 @@ using bildirimleri + + variance safety for static interface members + variance safety for static interface members + + <null> <null> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index b969ffe8a241e..786004ec1fe85 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -862,6 +862,11 @@ A constructor declared in a record with parameters must have 'this' constructor initializer. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + + '{0}': cannot specify both a constraint class and the 'unmanaged' constraint “{0}”: 不能既指定约束类又指定 “unmanaged” 约束 @@ -1486,6 +1491,11 @@ Using 声明 + + variance safety for static interface members + variance safety for static interface members + + <null> <null> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 41d869502e6fa..df095239c7fcb 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -862,6 +862,11 @@ A constructor declared in a record with parameters must have 'this' constructor initializer. + + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}. + + '{0}': cannot specify both a constraint class and the 'unmanaged' constraint '{0}': 不可在指定條件約束類型的同時,又指定 'unmanaged' 條件約束 @@ -1486,6 +1491,11 @@ using 宣告 + + variance safety for static interface members + variance safety for static interface members + + <null> <null> diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs index 73f7476e891ba..3d419b8d63617 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs @@ -59246,6 +59246,168 @@ private void M1(T1 x) {} ); } + [Fact] + public void VarianceSafety_13() + { + var source1 = +@" +class Program +{ + static void Main() + { + I2.P1 = ""a""; + I2.P2 = ""b""; + System.Console.WriteLine(I2.P1); + System.Console.WriteLine(I2.P2); + } +} + +interface I2 +{ + static T1 P1 { get; set; } + static T2 P2 { get; set; } +} +"; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.Regular8, + targetFramework: TargetFramework.NetStandardLatest); + compilation1.VerifyDiagnostics( + // (15,12): error CS9100: Invalid variance: The type parameter 'T1' must be invariantly valid on 'I2.P1' unless language version 'preview' or greater is used. 'T1' is covariant. + // static T1 P1 { get; set; } + Diagnostic(ErrorCode.ERR_UnexpectedVarianceStaticMember, "T1").WithArguments("I2.P1", "T1", "covariant", "invariantly", "preview").WithLocation(15, 12), + // (16,12): error CS9100: Invalid variance: The type parameter 'T2' must be invariantly valid on 'I2.P2' unless language version 'preview' or greater is used. 'T2' is contravariant. + // static T2 P2 { get; set; } + Diagnostic(ErrorCode.ERR_UnexpectedVarianceStaticMember, "T2").WithArguments("I2.P2", "T2", "contravariant", "invariantly", "preview").WithLocation(16, 12) + ); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularPreview, + targetFramework: TargetFramework.NetStandardLatest); + +#if false // PROTOTYPE: enable this branch once https://github.com/dotnet/runtime/issues/39612 is fixed + CompileAndVerify(compilation1, verify: VerifyOnMonoOrCoreClr, expectedOutput: !ExecutionConditionUtil.IsMonoOrCoreClr ? null : +@"a +b").VerifyDiagnostics(); +#else + compilation1.VerifyEmitDiagnostics(); +#endif + } + + [Fact] + public void VarianceSafety_14() + { + var source1 = +@" +class Program +{ + static void Main() + { + System.Console.WriteLine(I2.M1(""a"")); + System.Console.WriteLine(I2.M2(""b"")); + } +} + +interface I2 +{ + static T1 M1(T1 x) => x; + static T2 M2(T2 x) => x; +} +"; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.Regular8, + targetFramework: TargetFramework.NetStandardLatest); + compilation1.VerifyDiagnostics( + // (13,18): error CS9100: Invalid variance: The type parameter 'T1' must be contravariantly valid on 'I2.M1(T1)' unless language version 'preview' or greater is used. 'T1' is covariant. + // static T1 M1(T1 x) => x; + Diagnostic(ErrorCode.ERR_UnexpectedVarianceStaticMember, "T1").WithArguments("I2.M1(T1)", "T1", "covariant", "contravariantly", "preview").WithLocation(13, 18), + // (14,12): error CS9100: Invalid variance: The type parameter 'T2' must be covariantly valid on 'I2.M2(T2)' unless language version 'preview' or greater is used. 'T2' is contravariant. + // static T2 M2(T2 x) => x; + Diagnostic(ErrorCode.ERR_UnexpectedVarianceStaticMember, "T2").WithArguments("I2.M2(T2)", "T2", "contravariant", "covariantly", "preview").WithLocation(14, 12) + ); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularPreview, + targetFramework: TargetFramework.NetStandardLatest); + +#if false // PROTOTYPE: enable this branch once https://github.com/dotnet/runtime/issues/39612 is fixed + CompileAndVerify(compilation1, verify: VerifyOnMonoOrCoreClr, expectedOutput: !ExecutionConditionUtil.IsMonoOrCoreClr ? null : +@"a +b").VerifyDiagnostics(); +#else + compilation1.VerifyEmitDiagnostics(); +#endif + } + + [Fact] + public void VarianceSafety_15() + { + var source1 = +@" +class Program +{ + static void Main() + { + I2.E1 += Print1; + I2.E2 += Print2; + I2.Raise(); + } + + static void Print1(System.Func x) + { + System.Console.WriteLine(x(""a"")); + } + + static void Print2(System.Func x) + { + System.Console.WriteLine(x(""b"")); + } +} + +interface I2 +{ + static event System.Action> E1; + static event System.Action> E2; + + static void Raise() + { + E1(Print); + E2(Print); + } + + static T3 Print(T3 x) + { + return x; + } +} +"; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.Regular8, + targetFramework: TargetFramework.NetStandardLatest); + compilation1.VerifyDiagnostics( + // (24,53): error CS9100: Invalid variance: The type parameter 'T1' must be contravariantly valid on 'I2.E1' unless language version 'preview' or greater is used. 'T1' is covariant. + // static event System.Action> E1; + Diagnostic(ErrorCode.ERR_UnexpectedVarianceStaticMember, "E1").WithArguments("I2.E1", "T1", "covariant", "contravariantly", "preview").WithLocation(24, 53), + // (25,53): error CS9100: Invalid variance: The type parameter 'T2' must be covariantly valid on 'I2.E2' unless language version 'preview' or greater is used. 'T2' is contravariant. + // static event System.Action> E2; + Diagnostic(ErrorCode.ERR_UnexpectedVarianceStaticMember, "E2").WithArguments("I2.E2", "T2", "contravariant", "covariantly", "preview").WithLocation(25, 53) + ); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularPreview, + targetFramework: TargetFramework.NetStandardLatest); + +#if false // PROTOTYPE: enable this branch once https://github.com/dotnet/runtime/issues/39612 is fixed + CompileAndVerify(compilation1, verify: VerifyOnMonoOrCoreClr, expectedOutput: !ExecutionConditionUtil.IsMonoOrCoreClr ? null : +@"a +b").VerifyDiagnostics(); +#else + compilation1.VerifyEmitDiagnostics(); +#endif + } + [Fact] [WorkItem(1029574, "https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1029574")] public void Errors_01() diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs index dc843c5c1a770..53d59fa955c88 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs @@ -946,5 +946,19 @@ public void N() ", expectedActionSet: Enumerable.Empty()); } + + [Fact] + public async Task UpgradeProjectForVarianceSafetyForStaticInterfaceMembers_CS9100() + { + await TestLanguageVersionUpgradedAsync( +@" +interface I2 +{ + static T1 M1([|T1|] x) => x; +} +", + expected: LanguageVersion.Preview, + new CSharpParseOptions(LanguageVersion.CSharp8)); + } } } diff --git a/src/Features/CSharp/Portable/UpgradeProject/CSharpUpgradeProjectCodeFixProvider.cs b/src/Features/CSharp/Portable/UpgradeProject/CSharpUpgradeProjectCodeFixProvider.cs index f6d4610797baf..9b3f46ef7705c 100644 --- a/src/Features/CSharp/Portable/UpgradeProject/CSharpUpgradeProjectCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/UpgradeProject/CSharpUpgradeProjectCodeFixProvider.cs @@ -46,6 +46,7 @@ public CSharpUpgradeProjectCodeFixProvider() "CS8652", // error CS8652: The feature '' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. "CS8703", // error CS8703: The modifier '{0}' is not valid for this item in C# {1}. Please use language version '{2}' or greater. "CS8706", // error CS8706: '{0}' cannot implement interface member '{1}' in type '{2}' because feature '{3}' is not available in C# {4}. Please use language version '{5}' or greater. + "CS9100", // error CS9100: Invalid variance: The type parameter 'T1' must be contravariantly valid on 'I2.M1(T1)' unless language version 'preview' or greater is used. 'T1' is covariant. }); public override string UpgradeThisProjectResource => CSharpFeaturesResources.Upgrade_this_project_to_csharp_language_version_0;