Skip to content

Commit

Permalink
Allow static members in interfaces to treat type parameters as invari…
Browse files Browse the repository at this point in the history
  • Loading branch information
AlekseyTs authored Jul 22, 2020
1 parent 1e511fa commit 6a5ba0a
Show file tree
Hide file tree
Showing 20 changed files with 352 additions and 1 deletion.
6 changes: 6 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -3851,6 +3851,9 @@ You should consider suppressing the warning only if you're sure that you don't w
<data name="ERR_UnexpectedVariance" xml:space="preserve">
<value>Invalid variance: The type parameter '{1}' must be {3} valid on '{0}'. '{1}' is {2}.</value>
</data>
<data name="ERR_UnexpectedVarianceStaticMember" xml:space="preserve">
<value>Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</value>
</data>
<data name="ERR_DeriveFromDynamic" xml:space="preserve">
<value>'{0}': cannot derive from the dynamic type</value>
</data>
Expand Down Expand Up @@ -6348,4 +6351,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_ModuleInitializerMethodMustBeOrdinary" xml:space="preserve">
<value>A module initializer must be an ordinary member method</value>
</data>
<data name="IDS_FeatureVarianceSafetyForStaticInterfaceMembers" xml:space="preserve">
<value>variance safety for static interface members</value>
</data>
</root>
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/MessageID.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
35 changes: 34 additions & 1 deletion src/Compilers/CSharp/Portable/Symbols/VarianceSafety.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@ private static void CheckMethodVarianceSafety(this MethodSymbol method, Diagnost

private static void CheckMethodVarianceSafety(this MethodSymbol method, LocationProvider<MethodSymbol> 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);
Expand All @@ -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;
}

/// <summary>
/// Accumulate diagnostics related to the variance safety of an interface property.
/// </summary>
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)
Expand All @@ -193,6 +213,11 @@ private static void CheckPropertyVarianceSafety(PropertySymbol property, Diagnos
/// </summary>
private static void CheckEventVarianceSafety(EventSymbol @event, DiagnosticBag diagnostics)
{
if (SkipVarianceSafetyChecks(@event))
{
return;
}

IsVarianceUnsafe(
@event.Type,
requireOutputSafety: false,
Expand Down Expand Up @@ -442,7 +467,15 @@ private static void AddVarianceError<T>(
// "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<T>(this Symbol symbol) where T : SyntaxNode
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,11 @@
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedVarianceStaticMember">
<source>Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</source>
<target state="new">Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">{0}: Nejde zadat třídu omezení a zároveň omezení unmanaged.</target>
Expand Down Expand Up @@ -1486,6 +1491,11 @@
<target state="translated">deklarace using</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureVarianceSafetyForStaticInterfaceMembers">
<source>variance safety for static interface members</source>
<target state="new">variance safety for static interface members</target>
<note />
</trans-unit>
<trans-unit id="IDS_NULL">
<source>&lt;null&gt;</source>
<target state="translated">&lt;null&gt;</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,11 @@
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedVarianceStaticMember">
<source>Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</source>
<target state="new">Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">"{0}": Eine Einschränkungsklasse kann nicht gleichzeitig mit einer unmanaged-Einschränkung angegeben werden.</target>
Expand Down Expand Up @@ -1486,6 +1491,11 @@
<target state="translated">Using-Deklarationen</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureVarianceSafetyForStaticInterfaceMembers">
<source>variance safety for static interface members</source>
<target state="new">variance safety for static interface members</target>
<note />
</trans-unit>
<trans-unit id="IDS_NULL">
<source>&lt;null&gt;</source>
<target state="translated">&lt;NULL&gt;</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,11 @@
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedVarianceStaticMember">
<source>Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</source>
<target state="new">Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">"{0}": no se puede especificar a la vez una clase de restricción y la restricción "unmanaged"</target>
Expand Down Expand Up @@ -1486,6 +1491,11 @@
<target state="translated">declaraciones using</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureVarianceSafetyForStaticInterfaceMembers">
<source>variance safety for static interface members</source>
<target state="new">variance safety for static interface members</target>
<note />
</trans-unit>
<trans-unit id="IDS_NULL">
<source>&lt;null&gt;</source>
<target state="translated">&lt;NULL&gt;</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,11 @@
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedVarianceStaticMember">
<source>Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</source>
<target state="new">Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">'{0}' : impossible de spécifier à la fois une classe de contrainte et la contrainte 'unmanaged'</target>
Expand Down Expand Up @@ -1486,6 +1491,11 @@
<target state="translated">Déclarations using</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureVarianceSafetyForStaticInterfaceMembers">
<source>variance safety for static interface members</source>
<target state="new">variance safety for static interface members</target>
<note />
</trans-unit>
<trans-unit id="IDS_NULL">
<source>&lt;null&gt;</source>
<target state="translated">&lt;Null&gt;</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,11 @@
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedVarianceStaticMember">
<source>Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</source>
<target state="new">Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">'{0}': non è possibile specificare sia una classe constraint che il vincolo 'unmanaged'</target>
Expand Down Expand Up @@ -1486,6 +1491,11 @@
<target state="translated">dichiarazioni using</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureVarianceSafetyForStaticInterfaceMembers">
<source>variance safety for static interface members</source>
<target state="new">variance safety for static interface members</target>
<note />
</trans-unit>
<trans-unit id="IDS_NULL">
<source>&lt;null&gt;</source>
<target state="translated">&lt;Null&gt;</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,11 @@
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedVarianceStaticMember">
<source>Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</source>
<target state="new">Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">'{0}': 制約クラスと 'unmanaged' 制約の両方を指定することはできません</target>
Expand Down Expand Up @@ -1486,6 +1491,11 @@
<target state="translated">using 宣言</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureVarianceSafetyForStaticInterfaceMembers">
<source>variance safety for static interface members</source>
<target state="new">variance safety for static interface members</target>
<note />
</trans-unit>
<trans-unit id="IDS_NULL">
<source>&lt;null&gt;</source>
<target state="translated">&lt;null&gt;</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,11 @@
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedVarianceStaticMember">
<source>Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</source>
<target state="new">Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">'{0}': constraint 클래스와 'unmanaged' 제약 조건을 둘 다 지정할 수는 없습니다.</target>
Expand Down Expand Up @@ -1486,6 +1491,11 @@
<target state="translated">using 선언</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureVarianceSafetyForStaticInterfaceMembers">
<source>variance safety for static interface members</source>
<target state="new">variance safety for static interface members</target>
<note />
</trans-unit>
<trans-unit id="IDS_NULL">
<source>&lt;null&gt;</source>
<target state="translated">&lt;null&gt;</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,11 @@
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedVarianceStaticMember">
<source>Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</source>
<target state="new">Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">„{0}”: nie można jednocześnie określić klasy ograniczenia i ograniczenia „unmanaged”</target>
Expand Down Expand Up @@ -1486,6 +1491,11 @@
<target state="translated">deklaracje using</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureVarianceSafetyForStaticInterfaceMembers">
<source>variance safety for static interface members</source>
<target state="new">variance safety for static interface members</target>
<note />
</trans-unit>
<trans-unit id="IDS_NULL">
<source>&lt;null&gt;</source>
<target state="translated">&lt;null&gt;</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,11 @@
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedVarianceStaticMember">
<source>Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</source>
<target state="new">Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">'{0}': não é possível especificar uma classe de restrição e a restrição 'unmanaged'</target>
Expand Down Expand Up @@ -1484,6 +1489,11 @@
<target state="translated">declarações using</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureVarianceSafetyForStaticInterfaceMembers">
<source>variance safety for static interface members</source>
<target state="new">variance safety for static interface members</target>
<note />
</trans-unit>
<trans-unit id="IDS_NULL">
<source>&lt;null&gt;</source>
<target state="translated">&lt;nulo&gt;</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,11 @@
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedVarianceStaticMember">
<source>Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</source>
<target state="new">Invalid variance: The type parameter '{1}' must be {3} valid on '{0}' unless language version '{4}' or greater is used. '{1}' is {2}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">"{0}": невозможно одновременно задать класс ограничения и ограничение "unmanaged"</target>
Expand Down Expand Up @@ -1486,6 +1491,11 @@
<target state="translated">объявления using</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureVarianceSafetyForStaticInterfaceMembers">
<source>variance safety for static interface members</source>
<target state="new">variance safety for static interface members</target>
<note />
</trans-unit>
<trans-unit id="IDS_NULL">
<source>&lt;null&gt;</source>
<target state="translated">&lt;NULL&gt;</target>
Expand Down
Loading

0 comments on commit 6a5ba0a

Please sign in to comment.