From 7388c945474cfd58ed38fb79354d8a3483a9df6d Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Tue, 2 Apr 2019 15:41:20 -0700 Subject: [PATCH] `t is null` with LangVersion 7 should produce a diagnostic Fixes #34678 --- .../CSharp/Portable/Binder/Binder_Patterns.cs | 19 +++++++-- .../CSharp/Portable/Binder/Binder_Symbols.cs | 2 +- .../Portable/CSharpResources.Designer.cs | 9 +++++ .../CSharp/Portable/CSharpResources.resx | 3 ++ .../CSharp/Portable/Errors/ErrorCode.cs | 2 +- .../FlowAnalysis/AbstractFlowPass_Switch.cs | 2 +- .../Portable/xlf/CSharpResources.cs.xlf | 5 +++ .../Portable/xlf/CSharpResources.de.xlf | 5 +++ .../Portable/xlf/CSharpResources.es.xlf | 5 +++ .../Portable/xlf/CSharpResources.fr.xlf | 5 +++ .../Portable/xlf/CSharpResources.it.xlf | 5 +++ .../Portable/xlf/CSharpResources.ja.xlf | 5 +++ .../Portable/xlf/CSharpResources.ko.xlf | 5 +++ .../Portable/xlf/CSharpResources.pl.xlf | 5 +++ .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 +++ .../Portable/xlf/CSharpResources.ru.xlf | 5 +++ .../Portable/xlf/CSharpResources.tr.xlf | 5 +++ .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 +++ .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 +++ .../Semantics/PatternMatchingTests2.cs | 37 ++++++++++++++++++ .../UpgradeProject/UpgradeProjectTests.cs | 39 +++++++++++++++++++ .../CSharpUpgradeProjectCodeFixProvider.cs | 1 + 22 files changed, 173 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs index 1e9d910526104..d4c57bfbcce6e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs @@ -185,8 +185,7 @@ internal BoundExpression ConvertPatternExpression( // If we are pattern-matching against an open type, we do not convert the constant to the type of the input. // This permits us to match a value of type `IComparable` with a pattern of type `int`. - bool inputContainsTypeParameter = inputType.ContainsTypeParameter(); - if (inputContainsTypeParameter) + if (inputType.ContainsTypeParameter()) { convertedExpression = expression; if (!hasErrors) @@ -198,11 +197,25 @@ internal BoundExpression ConvertPatternExpression( { // We do not permit matching null against a struct type. diagnostics.Add(ErrorCode.ERR_ValueCantBeNull, expression.Syntax.Location, inputType); + hasErrors = true; } } else if (ExpressionOfTypeMatchesPatternType(Conversions, inputType, expression.Type, ref useSiteDiagnostics, out _, operandConstantValue: null) == false) { diagnostics.Add(ErrorCode.ERR_PatternWrongType, expression.Syntax.Location, inputType, expression.Display); + hasErrors = true; + } + + if (!hasErrors) + { + var requiredVersion = MessageID.IDS_FeatureRecursivePatterns.RequiredVersion(); + if (Compilation.LanguageVersion < requiredVersion && + // A null pattern can be tested against a type that can be assigned null, even in C# 7.3 + !(expression.ConstantValue == ConstantValue.Null && inputType.CanBeAssignedNull())) + { + diagnostics.Add(ErrorCode.ERR_ConstantPatternVsOpenType, + expression.Syntax.Location, inputType, expression.Display, new CSharpRequiredLanguageVersion(requiredVersion)); + } } diagnostics.Add(node, useSiteDiagnostics); @@ -222,7 +235,7 @@ internal BoundExpression ConvertPatternExpression( if (inputType.IsNullableType() && (convertedExpression.ConstantValue == null || !convertedExpression.ConstantValue.IsNull)) { // Null is a special case here because we want to compare null to the Nullable itself, not to the underlying type. - var discardedDiagnostics = DiagnosticBag.GetInstance(); // We are not intested in the diagnostic that get created here + var discardedDiagnostics = DiagnosticBag.GetInstance(); // We are not interested in the diagnostic that get created here convertedExpression = CreateConversion(operand, inputType.GetNullableUnderlyingType(), discardedDiagnostics); discardedDiagnostics.Free(); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index eb4269b1b1ab2..f5ef09a33bcbe 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -786,7 +786,7 @@ protected NamespaceOrTypeOrAliasSymbolWithAnnotations BindNonGenericSimpleNamesp SyntaxFacts.IsInTypeOnlyContext(node)) && node.Identifier.ValueText == "dynamic" && !IsViableType(result) && - ((CSharpParseOptions)node.SyntaxTree.Options).LanguageVersion >= MessageID.IDS_FeatureDynamic.RequiredVersion()) + Compilation.LanguageVersion >= MessageID.IDS_FeatureDynamic.RequiredVersion()) { bindingResult = Compilation.DynamicType; ReportUseSiteDiagnosticForDynamic(diagnostics, node); diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index bf04ada563931..6a6a73ce98dfc 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -3156,6 +3156,15 @@ internal static string ERR_ConstantExpected { } } + /// + /// Looks up a localized string similar to An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern.. + /// + internal static string ERR_ConstantPatternVsOpenType { + get { + return ResourceManager.GetString("ERR_ConstantPatternVsOpenType", resourceCulture); + } + } + /// /// Looks up a localized string similar to Length of String constant exceeds current memory limit. Try splitting the string into multiple constants.. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 580bc1a872df1..6d0e0f9fa9b68 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5076,6 +5076,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ An expression of type '{0}' cannot be handled by a pattern of type '{1}'. + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + Attribute '{0}' is ignored when public signing is specified. diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 4d6432b45a6e5..4cbf046640268 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1610,7 +1610,7 @@ internal enum ErrorCode ERR_VarMayNotBindToType = 8508, WRN_SwitchExpressionNotExhaustive = 8509, ERR_SwitchArmSubsumed = 8510, - // 8511, // available + ERR_ConstantPatternVsOpenType = 8511, WRN_CaseConstantNamedUnderscore = 8512, WRN_IsTypeNamedUnderscore = 8513, ERR_ExpressionTreeContainsSwitchExpression = 8514, diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_Switch.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_Switch.cs index 33490ac1274cd..7bc36f470e175 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_Switch.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_Switch.cs @@ -88,7 +88,7 @@ private bool IsTraditionalSwitch(BoundSwitchStatement node) // If we are in a recent enough language version, we treat the switch as a fully pattern-based switch // for the purposes of flow analysis. - if (((CSharpParseOptions)node.Syntax.SyntaxTree.Options).LanguageVersion >= MessageID.IDS_FeatureRecursivePatterns.RequiredVersion()) + if (compilation.LanguageVersion >= MessageID.IDS_FeatureRecursivePatterns.RequiredVersion()) { return false; } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 59399e45e0f50..f908b8866cdfc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -67,6 +67,11 @@ Parametr typu {1} má omezení unmanaged, takže není možné používat {1} jako omezení pro {0}. + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. Název {0} neodpovídá příslušnému parametru Deconstruct {1}. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index e9923fef4563f..6b2cbce23fa2c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -67,6 +67,11 @@ Der {1}-Typparameter enthält die Einschränkung "unmanaged". "{1}" kann daher nicht als Einschränkung für "{0}" verwendet werden. + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. Der Name "{0}" stimmt nicht mit dem entsprechenden Deconstruct-Parameter "{1}" überein. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 719b47e8e812d..dc1ba9c048d53 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -67,6 +67,11 @@ El parámetro de tipo "{1}" tiene la restricción "unmanaged"; por tanto, "{1}" no se puede usar como restricción para "{0}" + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. El nombre "{0}" no coincide con el parámetro de "Deconstruct" correspondiente, "{1}". diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index a59a429763819..ae2912d6ef03d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -67,6 +67,11 @@ Le paramètre de type '{1}' a la contrainte 'unmanaged'. '{1}' ne peut donc pas être utilisé comme contrainte pour '{0}' + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. Le nom '{0}' ne correspond pas au paramètre 'Deconstruct' correspondant '{1}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 38f7e570dd832..8889d115914ab 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -67,6 +67,11 @@ Il parametro di tipo '{1}' ha il vincolo 'managed'. Non è quindi possibile usare '{1}' come vincolo per '{0}' + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. Il nome '{0}' non corrisponde al parametro '{1}' di 'Deconstruct' corrispondente. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 10970e8496c91..e26f5b1dbee79 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -67,6 +67,11 @@ 型パラメーター '{1}' は 'unmanaged' 制約を含むので、'{0}' の制約として '{1}' を使用することはできません + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. 名前 '{0}' は対応する 'Deconstruct' パラメーター '{1}' と一致しません。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 0c62b51a4d316..8e89bd2ebebd9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -67,6 +67,11 @@ 형식 매개 변수 '{1}'에 'unmanaged' 제약 조건이 있으므로 '{1}'은(는) '{0}'에 대한 제약 조건으로 사용할 수 없습니다. + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. '{0}' 이름이 해당 'Deconstruct' 매개 변수 '{1}'과(와) 일치하지 않습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 1a3723a177ec5..1a2c4d6a457ea 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -67,6 +67,11 @@ Parametr typu „{1}” ma ograniczenie „unmanaged”, dlatego elementu „{1}” nie można użyć jako ograniczenia dla elementu „{0}” + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. Nazwa „{0}” nie jest zgodna z odpowiednim parametrem „Deconstruct” „{1}”. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index badcf494e3423..df83a73caa980 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -67,6 +67,11 @@ O parâmetro de tipo '{1}' tem a restrição 'unmanaged' e, por isso, '{1}' não pode ser usado como uma restrição de '{0}' + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. O nome '{0}' não corresponde ao parâmetro 'Deconstruct' '{1}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index d4d31024571b1..bc566a2805e9b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -67,6 +67,11 @@ Параметр типа "{1}" имеет ограничение "unmanaged", поэтому "{1}" не может использоваться в качестве ограничения для "{0}". + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. Имя "{0}" не соответствует указанному параметру "Deconstruct" "{1}". diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index bd1f3442b862e..b25ff43c95dd6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -67,6 +67,11 @@ '{1}' tür parametresinde 'unmanaged' kısıtlaması olduğundan '{1}', '{0}' için kısıtlama olarak kullanılamaz + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. '{0}' adı ilgili '{1}' 'Deconstruct' parametresiyle eşleşmiyor. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index ab24e5403f177..5706342f1a2f9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -67,6 +67,11 @@ 类型参数“{1}”具有 "unmanaged" 约束,因此“{1}”不能用作“{0}”的约束 + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. 名称“{0}”与相应 "Deconstruct" 参数“{1}”不匹配。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 87365bfbf484e..c95ca142bdb9a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -67,6 +67,11 @@ 類型參數 '{1}' 有 'unmanaged' 條件約束,因此 '{1}' 不可作為 '{0}' 的條件約束 + + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + An expression of type '{0}' cannot be handled by a pattern of type '{1}'. Please use language version '{2}' or greater to match an open type with a constant pattern. + + The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'. 名稱 '{0}' 與對應的 'Deconstruct' 參數 '{1}' 不相符。 diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests2.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests2.cs index 40ebaebb6a32c..03e748290934f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests2.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests2.cs @@ -2280,5 +2280,42 @@ void M(object o) Assert.Equal("Q7", ti.ConvertedType.ToTestDisplayString()); Assert.Equal(TypeKind.Error, ti.ConvertedType.TypeKind); } + + [Fact] + [WorkItem(34678, "https://github.com/dotnet/roslyn/issues/34678")] + public void ConstantPatternVsUnconstrainedTypeParameter05() + { + var source = +@"class C +{ + static bool Test1(T t) + { + return t is null; // 1 + } + static bool Test2(C t) + { + return t is null; // ok + } + static bool Test3(T t) + { + return t is 1; // 2 + } + static bool Test4(T t) + { + return t is ""frog""; // 3 + } +}"; + CreateCompilation(source, options: TestOptions.ReleaseDll).VerifyDiagnostics(); + CreateCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.Regular7_3).VerifyDiagnostics( + // (5,21): error CS8511: An expression of type 'T' cannot be handled by a pattern of type ''. Please use language version 'preview' or greater to match an open type with a constant pattern. + // return t is null; // 1 + Diagnostic(ErrorCode.ERR_ConstantPatternVsOpenType, "null").WithArguments("T", "", "preview").WithLocation(5, 21), + // (13,21): error CS8511: An expression of type 'T' cannot be handled by a pattern of type 'int'. Please use language version 'preview' or greater to match an open type with a constant pattern. + // return t is 1; // 2 + Diagnostic(ErrorCode.ERR_ConstantPatternVsOpenType, "1").WithArguments("T", "int", "preview").WithLocation(13, 21), + // (17,21): error CS8511: An expression of type 'T' cannot be handled by a pattern of type 'string'. Please use language version 'preview' or greater to match an open type with a constant pattern. + // return t is "frog"; // 3 + Diagnostic(ErrorCode.ERR_ConstantPatternVsOpenType, @"""frog""").WithArguments("T", "string", "preview").WithLocation(17, 21)); + } } } diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs index 72dd7c54f65fc..a906a387de378 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs @@ -776,5 +776,44 @@ void M1() expected: LanguageVersion.Preview, new CSharpParseOptions(LanguageVersion.CSharp7_3)); } + + [Fact] + public async Task UpgradeProjectWithOpenTypeMatchingConstantPattern_01() + { + await TestLanguageVersionUpgradedAsync( +@" +class Test +{ + bool M(T t) => t is [|null|]; +}", + LanguageVersion.Preview, + new CSharpParseOptions(LanguageVersion.CSharp7_3)); + } + + [Fact] + public async Task UpgradeProjectWithOpenTypeMatchingConstantPattern_02() + { + await TestLanguageVersionUpgradedAsync( +@" +class Test +{ + bool M(T t) => t is [|100|]; +}", + LanguageVersion.Preview, + new CSharpParseOptions(LanguageVersion.CSharp7_3)); + } + + [Fact] + public async Task UpgradeProjectWithOpenTypeMatchingConstantPattern_03() + { + await TestLanguageVersionUpgradedAsync( +@" +class Test +{ + bool M(T t) => t is [|""frog""|]; +}", + LanguageVersion.Preview, + new CSharpParseOptions(LanguageVersion.CSharp7_3)); + } } } diff --git a/src/Features/CSharp/Portable/UpgradeProject/CSharpUpgradeProjectCodeFixProvider.cs b/src/Features/CSharp/Portable/UpgradeProject/CSharpUpgradeProjectCodeFixProvider.cs index 3d6852b19f07f..b33f3669fd084 100644 --- a/src/Features/CSharp/Portable/UpgradeProject/CSharpUpgradeProjectCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/UpgradeProject/CSharpUpgradeProjectCodeFixProvider.cs @@ -31,6 +31,7 @@ internal class CSharpUpgradeProjectCodeFixProvider : AbstractUpgradeProjectCodeF "CS8371", // warning CS8371: Field-targeted attributes on auto-properties are not supported in language version 7.2. Please use language version 7.3 or greater. "CS8400", // error CS8400: Feature is not available in C# 8.0. Please use language version X or greater. "CS8401", // error CS8401: To use '@$' instead of '$@" for a verbatim interpolated string, please use language version 8.0 or greater. + "CS8511", // error CS8511: An expression of type 'T' cannot be handled by a pattern of type ''. Please use language version 'preview' or greater to match an open type with a constant pattern. "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.