diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs index 6ce272ab77f62..5a070ce61a793 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs @@ -9012,6 +9012,59 @@ struct B : I1 expectedOutput: "FalseFalseTrueTrue"); } + [Fact, WorkItem(16195, "https://github.com/dotnet/roslyn/issues/16195")] + public void TestMatchWithTypeParameter_07() + { + var source = +@"using System; +class Program +{ + public static void Main(string[] args) + { + Console.Write(M1(new A())); + Console.Write(M2(new A())); + Console.Write(M1(new A())); + Console.Write(M2(new A())); + } + public static bool M1(A o) where T : new() + { + return o is T t; + } + public static bool M2(A o) where T : new() + { + switch (o) + { + case T t: + return true; + default: + return false; + } + } +} +struct A +{ +} +struct B +{ +} +"; + CreateStandardCompilation(source, parseOptions: TestOptions.Regular7).VerifyDiagnostics( + // (13,21): error CS9003: An expression of type 'A' cannot be handled by a pattern of type 'T' in C# 7. Please use language version 7.1 or greater. + // return o is T t; + Diagnostic(ErrorCode.ERR_PatternWrongGenericTypeInVersion, "T").WithArguments("A", "T", "7", "7.1").WithLocation(13, 21), + // (19,18): error CS9003: An expression of type 'A' cannot be handled by a pattern of type 'T' in C# 7. Please use language version 7.1 or greater. + // case T t: + Diagnostic(ErrorCode.ERR_PatternWrongGenericTypeInVersion, "T").WithArguments("A", "T", "7", "7.1").WithLocation(19, 18) + ); + var compilation = CreateStandardCompilation(source, + options: TestOptions.DebugDll.WithOutputKind(OutputKind.ConsoleApplication), + parseOptions: TestOptions.Regular7_1) + .VerifyDiagnostics(); + var compVerifier = CompileAndVerify(compilation, + expectedOutput: "FalseFalseTrueTrue"); + compVerifier.VerifyDiagnostics(); + } + [Fact, WorkItem(16195, "https://github.com/dotnet/roslyn/issues/16195")] public void TestIgnoreDynamicVsObjectAndTupleElementNames_01() { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs index 6dff2d693bb76..2418905478958 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs @@ -5162,6 +5162,45 @@ public static void Main(string[] args) 3"); } + [Fact, WorkItem(16195, "https://github.com/dotnet/roslyn/issues/16195")] + public void TypeParameterSubsumption05() + { + var program = @" +public class Program +{ + static void M(T t, U u) where T : U + { + switch(""test"") + { + case U uu: + break; + case T tt: // Produces a diagnostic about subsumption/unreachability + break; + } + } +} +"; + CreateStandardCompilation(program, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular7).VerifyDiagnostics( + // (8,18): error CS8314: An expression of type 'string' cannot be handled by a pattern of type 'U' in C# 7. Please use language version 7.1 or greater. + // case U uu: + Diagnostic(ErrorCode.ERR_PatternWrongGenericTypeInVersion, "U").WithArguments("string", "U", "7", "7.1").WithLocation(8, 18), + // (10,18): error CS8314: An expression of type 'string' cannot be handled by a pattern of type 'T' in C# 7. Please use language version 7.1 or greater. + // case T tt: // Produces a diagnostic about subsumption/unreachability + Diagnostic(ErrorCode.ERR_PatternWrongGenericTypeInVersion, "T").WithArguments("string", "T", "7", "7.1").WithLocation(10, 18), + // (11,17): warning CS0162: Unreachable code detected + // break; + Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(11, 17) + ); + CreateStandardCompilation(program, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular7_1).VerifyDiagnostics( + // (10,18): error CS8120: The switch case has already been handled by a previous case. + // case T tt: // Produces a diagnostic about subsumption/unreachability + Diagnostic(ErrorCode.ERR_PatternIsSubsumed, "T tt").WithLocation(10, 18), + // (11,17): warning CS0162: Unreachable code detected + // break; + Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(11, 17) + ); + } + [Fact, WorkItem(17103, "https://github.com/dotnet/roslyn/issues/17103")] public void IsConstantPatternConversion_Positive() { @@ -5926,5 +5965,184 @@ void M1(int? i) Diagnostic(ErrorCode.ERR_NameNotInContext, "b").WithArguments("b").WithLocation(14, 17) ); } + + [Fact, WorkItem(19038, "https://github.com/dotnet/roslyn/issues/19038")] + public void GenericDynamicIsObject() + { + var program = @" +using System; +public class Program +{ + static void Main(string[] args) + { + M(new object()); + M(null); + M(""xyzzy""); + } + static void M(object x) + { + switch (x) + { + case T t: + Console.Write(""T""); + break; + case null: + Console.Write(""n""); + break; + } + } +} +"; + var compilation = CreateStandardCompilation(program, options: TestOptions.DebugExe); + compilation.VerifyDiagnostics( + ); + var comp = CompileAndVerify(compilation, expectedOutput: @"TnT"); + } + + [Fact, WorkItem(19038, "https://github.com/dotnet/roslyn/issues/19038")] + public void MatchNullableTypeParameter() + { + var program = @" +using System; +public class Program +{ + static void Main(string[] args) + { + M(1); + M(null); + M(3.14F); + } + static void M(T? x) where T : struct + { + switch (x) + { + case T t: + Console.Write(""T""); + break; + case null: + Console.Write(""n""); + break; + } + } +} +"; + var compilation = CreateStandardCompilation(program, options: TestOptions.DebugExe); + compilation.VerifyDiagnostics( + ); + var comp = CompileAndVerify(compilation, expectedOutput: @"TnT"); + } + + [Fact, WorkItem(16195, "https://github.com/dotnet/roslyn/issues/16195")] + public void MatchRecursiveGenerics() + { + var program = +@"using System; +class Packet { } +class Packet : Packet { } +public class C { + static void Main() + { + Console.Write(M(null)); + Console.Write(M(new Packet())); + Console.Write(M(new Packet())); + Console.Write(M>(new Packet())); + } + static bool M(T p) where T : Packet => p is Packet p1; +}"; + CreateStandardCompilation(program, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7).VerifyDiagnostics( + // (12,52): error CS8314: An expression of type 'T' cannot be handled by a pattern of type 'Packet' in C# 7. Please use language version 7.1 or greater. + // static bool M(T p) where T : Packet => p is Packet p1; + Diagnostic(ErrorCode.ERR_PatternWrongGenericTypeInVersion, "Packet").WithArguments("T", "Packet", "7", "7.1").WithLocation(12, 52) + ); + var compilation = CreateStandardCompilation(program, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_1); + compilation.VerifyDiagnostics( + ); + var comp = CompileAndVerify(compilation, expectedOutput: @"FalseTrueFalseFalse"); + } + + [Fact, WorkItem(19038, "https://github.com/dotnet/roslyn/issues/19038")] + public void MatchRestrictedTypes_Fail() + { + + var program = +@"using System; +unsafe public class C { + static bool M(TypedReference x, int* p, ref int z) + { + var n1 = x is TypedReference x0; // ok + var p1 = p is int* p0; // syntax error 1 + var r1 = z is ref int z0; // syntax error 2 + + var b1 = x is object o1; // not allowed 1 + var b2 = p is object o2; // not allowed 2 + var b3 = z is object o3; // ok + + return b1 && b2 && b3; + } +}"; + var compilation = CreateStandardCompilation(program, options: TestOptions.DebugDll.WithAllowUnsafe(true)); + compilation.VerifyDiagnostics( + // (6,23): error CS1525: Invalid expression term 'int' + // var p1 = p is int* p0; // syntax error 1 + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(6, 23), + // (7,23): error CS1525: Invalid expression term 'ref' + // var r1 = z is ref int z0; // syntax error 2 + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref").WithArguments("ref").WithLocation(7, 23), + // (7,23): error CS1002: ; expected + // var r1 = z is ref int z0; // syntax error 2 + Diagnostic(ErrorCode.ERR_SemicolonExpected, "ref").WithLocation(7, 23), + // (6,28): error CS0103: The name 'p0' does not exist in the current context + // var p1 = p is int* p0; // syntax error 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "p0").WithArguments("p0").WithLocation(6, 28), + // (7,31): error CS8174: A declaration of a by-reference variable must have an initializer + // var r1 = z is ref int z0; // syntax error 2 + Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "z0").WithLocation(7, 31), + // (9,23): error CS8121: An expression of type 'TypedReference' cannot be handled by a pattern of type 'object'. + // var b1 = x is object o1; // not allowed 1 + Diagnostic(ErrorCode.ERR_PatternWrongType, "object").WithArguments("System.TypedReference", "object").WithLocation(9, 23), + // (10,23): error CS0244: Neither 'is' nor 'as' is valid on pointer types + // var b2 = p is object o2; // not allowed 2 + Diagnostic(ErrorCode.ERR_PointerInAsOrIs, "object o2").WithLocation(10, 23), + // (7,31): warning CS0168: The variable 'z0' is declared but never used + // var r1 = z is ref int z0; // syntax error 2 + Diagnostic(ErrorCode.WRN_UnreferencedVar, "z0").WithArguments("z0").WithLocation(7, 31) + ); + } + + [Fact, WorkItem(19038, "https://github.com/dotnet/roslyn/issues/19038")] + public void MatchRestrictedTypes_Success() + { + var program = +@"using System; +using System.Reflection; +unsafe public class C { + public int Value; + + static void Main() + { + C a = new C { Value = 12 }; + FieldInfo info = typeof(C).GetField(""Value""); + TypedReference reference = __makeref(a); + if (!(reference is TypedReference reference0)) throw new Exception(""TypedReference""); + info.SetValueDirect(reference0, 34); + if (a.Value != 34) throw new Exception(""SetValueDirect""); + + int z = 56; + if (CopyRefInt(ref z) != 56) throw new Exception(""ref z""); + + Console.WriteLine(""ok""); + } + + static int CopyRefInt(ref int z) + { + if (!(z is int z0)) throw new Exception(""CopyRefInt""); + return z0; + } +}"; + var compilation = CreateStandardCompilation(program, options: TestOptions.DebugExe.WithAllowUnsafe(true)); + compilation.VerifyDiagnostics( + ); + var comp = CompileAndVerify(compilation, expectedOutput: "ok"); + } } }