diff --git a/src/Compilers/CSharp/Portable/CSharpExtensions.cs b/src/Compilers/CSharp/Portable/CSharpExtensions.cs index 039b46209c35a..dbebfad0ff99e 100644 --- a/src/Compilers/CSharp/Portable/CSharpExtensions.cs +++ b/src/Compilers/CSharp/Portable/CSharpExtensions.cs @@ -317,6 +317,22 @@ internal static SeparatedSyntaxList AsSeparatedList(this SyntaxN return builder.ToList(); } + #region ITypeSymbol + + /// + /// Returns true iff the supplied type is sbyte, byte, short, ushort, int, uint, + /// long, ulong, bool, char, string, or an enum-type, or if it is the nullable type + /// corresponding to one of those types. These types were permitted as the governing + /// type of a switch statement in C# 6. + /// + public static bool IsValidV6SwitchGoverningType(this ITypeSymbol type) + { + var typeSymbol = type as TypeSymbol; + return (typeSymbol == null) ? false : + TypeSymbolExtensions.IsValidV6SwitchGoverningType(typeSymbol); + } + #endregion ITypeSymbol + #region SyntaxNode internal static IList GetDirectives(this SyntaxNode node, Func filter = null) { diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 948e83df54b94..f8ad6ed7b4d4a 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -268,6 +268,7 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax.Accept(M static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(this Microsoft.CodeAnalysis.SemanticModel semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax declarationSyntax, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.ILocalSymbol static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(this Microsoft.CodeAnalysis.SemanticModel semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax designationSyntax, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.ISymbol static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetForEachStatementInfo(this Microsoft.CodeAnalysis.SemanticModel semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.CommonForEachStatementSyntax forEachStatement) -> Microsoft.CodeAnalysis.CSharp.ForEachStatementInfo +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.IsValidV6SwitchGoverningType(this Microsoft.CodeAnalysis.ITypeSymbol type) -> bool static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.CasePatternSwitchLabel(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax pattern, Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax whenClause, Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.CasePatternSwitchLabelSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.CasePatternSwitchLabel(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax pattern, Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.CasePatternSwitchLabelSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.CasePatternSwitchLabel(Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax pattern, Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax whenClause, Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.CasePatternSwitchLabelSyntax diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs index 419ed2de01fa6..d86aab33a9a31 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs @@ -5,6 +5,7 @@ using Roslyn.Test.Utilities; using Xunit; using System.Collections.Generic; +using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -1304,7 +1305,13 @@ public static int Main() "; CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6).VerifyDiagnostics(); CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6WithV7SwitchBinder).VerifyDiagnostics(); - CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var tree = compilation.SyntaxTrees[0]; + var model = compilation.GetSemanticModel(tree); + var switchExpression = tree.GetRoot().DescendantNodes().OfType().Where(s => s.ToString() == "t").Single(); + var typeInfo = model.GetTypeInfo(switchExpression); + Assert.False(typeInfo.Type.IsValidV6SwitchGoverningType()); + Assert.True(typeInfo.ConvertedType.IsValidV6SwitchGoverningType()); } [Fact] @@ -1346,7 +1353,13 @@ public static int Main() "; CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6).VerifyDiagnostics(); CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6WithV7SwitchBinder).VerifyDiagnostics(); - CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var tree = compilation.SyntaxTrees[0]; + var model = compilation.GetSemanticModel(tree); + var switchExpression = tree.GetRoot().DescendantNodes().OfType().Where(s => s.ToString() == "C").Single(); + var typeInfo = model.GetTypeInfo(switchExpression); + Assert.False(typeInfo.Type.IsValidV6SwitchGoverningType()); + Assert.True(typeInfo.ConvertedType.IsValidV6SwitchGoverningType()); } [Fact] @@ -1397,7 +1410,13 @@ public static int Main() "; CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6).VerifyDiagnostics(); CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6WithV7SwitchBinder).VerifyDiagnostics(); - CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var tree = compilation.SyntaxTrees[0]; + var model = compilation.GetSemanticModel(tree); + var switchExpression = tree.GetRoot().DescendantNodes().OfType().Where(s => s.ToString() == "C").Single(); + var typeInfo = model.GetTypeInfo(switchExpression); + Assert.False(typeInfo.Type.IsValidV6SwitchGoverningType()); + Assert.True(typeInfo.ConvertedType.IsValidV6SwitchGoverningType()); } [Fact] @@ -1441,7 +1460,13 @@ public static int Main() "; CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6).VerifyDiagnostics(); CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6WithV7SwitchBinder).VerifyDiagnostics(); - CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var tree = compilation.SyntaxTrees[0]; + var model = compilation.GetSemanticModel(tree); + var switchExpression = tree.GetRoot().DescendantNodes().OfType().Where(s => s.ToString() == "D").Single(); + var typeInfo = model.GetTypeInfo(switchExpression); + Assert.False(typeInfo.Type.IsValidV6SwitchGoverningType()); + Assert.True(typeInfo.ConvertedType.IsValidV6SwitchGoverningType()); } [Fact] @@ -1480,7 +1505,13 @@ public static int Main() "; CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6).VerifyDiagnostics(); CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6WithV7SwitchBinder).VerifyDiagnostics(); - CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var tree = compilation.SyntaxTrees[0]; + var model = compilation.GetSemanticModel(tree); + var switchExpression = tree.GetRoot().DescendantNodes().OfType().Where(s => s.ToString() == "C").Single(); + var typeInfo = model.GetTypeInfo(switchExpression); + Assert.False(typeInfo.Type.IsValidV6SwitchGoverningType()); + Assert.True(typeInfo.ConvertedType.IsValidV6SwitchGoverningType()); } [Fact] @@ -1524,7 +1555,13 @@ public static int Main() "; CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6).VerifyDiagnostics(); CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6WithV7SwitchBinder).VerifyDiagnostics(); - CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var tree = compilation.SyntaxTrees[0]; + var model = compilation.GetSemanticModel(tree); + var switchExpression = tree.GetRoot().DescendantNodes().OfType().Where(s => s.ToString() == "C").Single(); + var typeInfo = model.GetTypeInfo(switchExpression); + Assert.False(typeInfo.Type.IsValidV6SwitchGoverningType()); + Assert.True(typeInfo.ConvertedType.IsValidV6SwitchGoverningType()); } [Fact] @@ -1575,8 +1612,13 @@ static void M(B2 b2) where T : A2 // (20,17): error CS0151: A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type Diagnostic(ErrorCode.ERR_V6SwitchGoverningTypeValueExpected, "b1.F()").WithLocation(20, 17) ); - CreateCompilationWithMscorlib(text).VerifyDiagnostics( - ); + var compilation = CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var tree = compilation.SyntaxTrees[0]; + var model = compilation.GetSemanticModel(tree); + var switchExpression = tree.GetRoot().DescendantNodes().OfType().Where(s => s.ToString() == "b1.F()").Single(); + var typeInfo = model.GetTypeInfo(switchExpression); + Assert.False(typeInfo.Type.IsValidV6SwitchGoverningType()); + Assert.False(typeInfo.ConvertedType.IsValidV6SwitchGoverningType()); } [WorkItem(543673, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543673")] @@ -1631,8 +1673,13 @@ static void Main() // switch(a) Diagnostic(ErrorCode.ERR_V6SwitchGoverningTypeValueExpected, "a").WithLocation(28, 20) ); - CreateCompilationWithMscorlib(text).VerifyDiagnostics( - ); + var compilation = CreateCompilationWithMscorlib(text).VerifyDiagnostics(); + var tree = compilation.SyntaxTrees[0]; + var model = compilation.GetSemanticModel(tree); + var switchExpression = tree.GetRoot().DescendantNodes().OfType().Where(s => s.ToString() == "a").Single(); + var typeInfo = model.GetTypeInfo(switchExpression); + Assert.False(typeInfo.Type.IsValidV6SwitchGoverningType()); + Assert.False(typeInfo.ConvertedType.IsValidV6SwitchGoverningType()); } [WorkItem(543673, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543673")]