提交 e459e69d 编写于 作者: N Neal Gafter 提交者: GitHub

Make ScanType() and ParseType() agree not to accept pointer types in deconstruction (#15975)

Fixes #15934
上级 c7bcaed1
......@@ -6179,7 +6179,12 @@ private ScanTypeFlags ScanType()
private ScanTypeFlags ScanType(out SyntaxToken lastTokenOfType)
{
ScanTypeFlags result = this.ScanNonArrayType(out lastTokenOfType);
return ScanType(ParseTypeMode.Normal, out lastTokenOfType);
}
private ScanTypeFlags ScanType(ParseTypeMode mode, out SyntaxToken lastTokenOfType)
{
ScanTypeFlags result = this.ScanNonArrayType(mode, out lastTokenOfType);
if (result == ScanTypeFlags.NotType)
{
......@@ -6236,10 +6241,10 @@ private ScanTypeFlags ScanNamedTypePart(out SyntaxToken lastTokenOfType)
private ScanTypeFlags ScanNonArrayType()
{
SyntaxToken lastTokenOfType;
return ScanNonArrayType(out lastTokenOfType);
return ScanNonArrayType(ParseTypeMode.Normal, out lastTokenOfType);
}
private ScanTypeFlags ScanNonArrayType(out SyntaxToken lastTokenOfType)
private ScanTypeFlags ScanNonArrayType(ParseTypeMode mode, out SyntaxToken lastTokenOfType)
{
ScanTypeFlags result;
......@@ -6311,17 +6316,27 @@ private ScanTypeFlags ScanNonArrayType(out SyntaxToken lastTokenOfType)
}
// Now check for pointer type(s)
while (this.CurrentToken.Kind == SyntaxKind.AsteriskToken)
switch (mode)
{
lastTokenOfType = this.EatToken();
if (result == ScanTypeFlags.GenericTypeOrExpression || result == ScanTypeFlags.NonGenericTypeOrExpression)
{
result = ScanTypeFlags.PointerOrMultiplication;
}
else if (result == ScanTypeFlags.GenericTypeOrMethod)
{
result = ScanTypeFlags.MustBeType;
}
case ParseTypeMode.FirstElementOfPossibleTupleLiteral:
case ParseTypeMode.AfterTupleComma:
// We are parsing the type for a declaration expression in a tuple, which does
// not permit pointer types. In that context a `*` is parsed as a multiplication.
break;
default:
while (this.CurrentToken.Kind == SyntaxKind.AsteriskToken)
{
lastTokenOfType = this.EatToken();
if (result == ScanTypeFlags.GenericTypeOrExpression || result == ScanTypeFlags.NonGenericTypeOrExpression)
{
result = ScanTypeFlags.PointerOrMultiplication;
}
else if (result == ScanTypeFlags.GenericTypeOrMethod)
{
result = ScanTypeFlags.MustBeType;
}
}
break;
}
return result;
......
......@@ -152,18 +152,9 @@ private bool IsPossibleDeclarationExpression(ParseTypeMode mode, bool permitTupl
{
bool typeIsVar = IsVarType();
SyntaxToken lastTokenOfType;
switch (ScanType(out lastTokenOfType))
if (ScanType(mode, out lastTokenOfType) == ScanTypeFlags.NotType)
{
case ScanTypeFlags.PointerOrMultiplication:
if (mode == ParseTypeMode.FirstElementOfPossibleTupleLiteral || mode == ParseTypeMode.AfterTupleComma)
{
// Tuples cannot contain pointer types because pointers may not be generic type arguments.
return false;
}
break;
case ScanTypeFlags.NotType:
return false;
return false;
}
// check for a designation
......
......@@ -2601,5 +2601,125 @@ static void Main()
Diagnostic(ErrorCode.ERR_TypeVarNotFound, "var").WithLocation(6, 15)
);
}
[Fact, WorkItem(15934, "https://github.com/dotnet/roslyn/issues/15934")]
public void PointerTypeInDeconstruction()
{
string source = @"
unsafe class C
{
static void Main(C c)
{
(int* x1, int y1) = c;
(var* x2, int y2) = c;
(int*[] x3, int y3) = c;
(var*[] x4, int y4) = c;
}
public void Deconstruct(out dynamic x, out dynamic y)
{
x = y = null;
}
}
";
var comp = CreateCompilationWithMscorlibAndSystemCore(source,
references: new[] { ValueTupleRef, SystemRuntimeFacadeRef },
options: TestOptions.UnsafeDebugDll);
// The precise diagnostics here are not important, and may be sensitive to parser
// adjustments. This is a test that we don't crash. The errors here are likely to
// change as we adjust the parser and semantic analysis of error cases.
comp.VerifyDiagnostics(
// (6,10): error CS1525: Invalid expression term 'int'
// (int* x1, int y1) = c;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(6, 10),
// (8,10): error CS1525: Invalid expression term 'int'
// (int*[] x3, int y3) = c;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(8, 10),
// (8,14): error CS1525: Invalid expression term '['
// (int*[] x3, int y3) = c;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "[").WithArguments("[").WithLocation(8, 14),
// (8,15): error CS0443: Syntax error; value expected
// (int*[] x3, int y3) = c;
Diagnostic(ErrorCode.ERR_ValueExpected, "]").WithLocation(8, 15),
// (8,17): error CS1026: ) expected
// (int*[] x3, int y3) = c;
Diagnostic(ErrorCode.ERR_CloseParenExpected, "x3").WithLocation(8, 17),
// (8,17): error CS1002: ; expected
// (int*[] x3, int y3) = c;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "x3").WithLocation(8, 17),
// (8,19): error CS1002: ; expected
// (int*[] x3, int y3) = c;
Diagnostic(ErrorCode.ERR_SemicolonExpected, ",").WithLocation(8, 19),
// (8,19): error CS1513: } expected
// (int*[] x3, int y3) = c;
Diagnostic(ErrorCode.ERR_RbraceExpected, ",").WithLocation(8, 19),
// (8,27): error CS1002: ; expected
// (int*[] x3, int y3) = c;
Diagnostic(ErrorCode.ERR_SemicolonExpected, ")").WithLocation(8, 27),
// (8,27): error CS1513: } expected
// (int*[] x3, int y3) = c;
Diagnostic(ErrorCode.ERR_RbraceExpected, ")").WithLocation(8, 27),
// (8,29): error CS1525: Invalid expression term '='
// (int*[] x3, int y3) = c;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(8, 29),
// (9,14): error CS1525: Invalid expression term '['
// (var*[] x4, int y4) = c;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "[").WithArguments("[").WithLocation(9, 14),
// (9,15): error CS0443: Syntax error; value expected
// (var*[] x4, int y4) = c;
Diagnostic(ErrorCode.ERR_ValueExpected, "]").WithLocation(9, 15),
// (9,17): error CS1026: ) expected
// (var*[] x4, int y4) = c;
Diagnostic(ErrorCode.ERR_CloseParenExpected, "x4").WithLocation(9, 17),
// (9,17): error CS1002: ; expected
// (var*[] x4, int y4) = c;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "x4").WithLocation(9, 17),
// (9,19): error CS1002: ; expected
// (var*[] x4, int y4) = c;
Diagnostic(ErrorCode.ERR_SemicolonExpected, ",").WithLocation(9, 19),
// (9,19): error CS1513: } expected
// (var*[] x4, int y4) = c;
Diagnostic(ErrorCode.ERR_RbraceExpected, ",").WithLocation(9, 19),
// (9,27): error CS1002: ; expected
// (var*[] x4, int y4) = c;
Diagnostic(ErrorCode.ERR_SemicolonExpected, ")").WithLocation(9, 27),
// (9,27): error CS1513: } expected
// (var*[] x4, int y4) = c;
Diagnostic(ErrorCode.ERR_RbraceExpected, ")").WithLocation(9, 27),
// (9,29): error CS1525: Invalid expression term '='
// (var*[] x4, int y4) = c;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(9, 29),
// (6,15): error CS0103: The name 'x1' does not exist in the current context
// (int* x1, int y1) = c;
Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(6, 15),
// (6,9): error CS8184: A deconstruction cannot mix declarations and expressions on the left-hand-side.
// (int* x1, int y1) = c;
Diagnostic(ErrorCode.ERR_MixedDeconstructionUnsupported, "(int* x1, int y1)").WithLocation(6, 9),
// (7,10): error CS0103: The name 'var' does not exist in the current context
// (var* x2, int y2) = c;
Diagnostic(ErrorCode.ERR_NameNotInContext, "var").WithArguments("var").WithLocation(7, 10),
// (7,15): error CS0103: The name 'x2' does not exist in the current context
// (var* x2, int y2) = c;
Diagnostic(ErrorCode.ERR_NameNotInContext, "x2").WithArguments("x2").WithLocation(7, 15),
// (7,9): error CS8184: A deconstruction cannot mix declarations and expressions on the left-hand-side.
// (var* x2, int y2) = c;
Diagnostic(ErrorCode.ERR_MixedDeconstructionUnsupported, "(var* x2, int y2)").WithLocation(7, 9),
// (8,17): error CS0103: The name 'x3' does not exist in the current context
// (int*[] x3, int y3) = c;
Diagnostic(ErrorCode.ERR_NameNotInContext, "x3").WithArguments("x3").WithLocation(8, 17),
// (9,10): error CS0103: The name 'var' does not exist in the current context
// (var*[] x4, int y4) = c;
Diagnostic(ErrorCode.ERR_NameNotInContext, "var").WithArguments("var").WithLocation(9, 10),
// (9,17): error CS0103: The name 'x4' does not exist in the current context
// (var*[] x4, int y4) = c;
Diagnostic(ErrorCode.ERR_NameNotInContext, "x4").WithArguments("x4").WithLocation(9, 17),
// (8,25): warning CS0168: The variable 'y3' is declared but never used
// (int*[] x3, int y3) = c;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "y3").WithArguments("y3").WithLocation(8, 25),
// (9,25): warning CS0168: The variable 'y4' is declared but never used
// (var*[] x4, int y4) = c;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "y4").WithArguments("y4").WithLocation(9, 25)
);
}
}
}
......@@ -4057,5 +4057,103 @@ public static void Main()
Diagnostic(ErrorCode.ERR_NameNotInContext, "_").WithArguments("_").WithLocation(19, 23)
);
}
[Fact]
public void PointerTypeInPattern()
{
// pointer types are not supported in patterns. Therefore an attempt to use
// a pointer type will be interpreted by the parser as a multiplication
// (i.e. an expression that is a constant pattern rather than a declaration
// pattern)
var source =
@"
public class var {}
unsafe public class Typ
{
public static void Main(int* a, var* c, Typ* e)
{
{
if (a is int* b) {}
if (c is var* d) {}
if (e is Typ* f) {}
}
{
switch (a) { case int* b: break; }
switch (c) { case var* d: break; }
switch (e) { case Typ* f: break; }
}
}
}
";
var compilation = CreateCompilationWithMscorlibAndSystemCore(source, options: TestOptions.UnsafeDebugDll);
compilation.VerifyDiagnostics(
// if (a is int* b) {}
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(8, 22),
// (13,31): error CS1525: Invalid expression term 'int'
// switch (a) { case int* b: break; }
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(13, 31),
// (5,37): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('var')
// public static void Main(int* a, var* c, Typ* e)
Diagnostic(ErrorCode.ERR_ManagedAddr, "var*").WithArguments("var").WithLocation(5, 37),
// (5,45): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('Typ')
// public static void Main(int* a, var* c, Typ* e)
Diagnostic(ErrorCode.ERR_ManagedAddr, "Typ*").WithArguments("Typ").WithLocation(5, 45),
// (8,27): error CS0103: The name 'b' does not exist in the current context
// if (a is int* b) {}
Diagnostic(ErrorCode.ERR_NameNotInContext, "b").WithArguments("b").WithLocation(8, 27),
// (9,22): error CS0119: 'var' is a type, which is not valid in the given context
// if (c is var* d) {}
Diagnostic(ErrorCode.ERR_BadSKunknown, "var").WithArguments("var", "type").WithLocation(9, 22),
// (9,27): error CS0103: The name 'd' does not exist in the current context
// if (c is var* d) {}
Diagnostic(ErrorCode.ERR_NameNotInContext, "d").WithArguments("d").WithLocation(9, 27),
// (10,22): error CS0119: 'Typ' is a type, which is not valid in the given context
// if (e is Typ* f) {}
Diagnostic(ErrorCode.ERR_BadSKunknown, "Typ").WithArguments("Typ", "type").WithLocation(10, 22),
// (10,27): error CS0103: The name 'f' does not exist in the current context
// if (e is Typ* f) {}
Diagnostic(ErrorCode.ERR_NameNotInContext, "f").WithArguments("f").WithLocation(10, 27),
// (13,36): error CS0103: The name 'b' does not exist in the current context
// switch (a) { case int* b: break; }
Diagnostic(ErrorCode.ERR_NameNotInContext, "b").WithArguments("b").WithLocation(13, 36),
// (14,31): error CS0119: 'var' is a type, which is not valid in the given context
// switch (c) { case var* d: break; }
Diagnostic(ErrorCode.ERR_BadSKunknown, "var").WithArguments("var", "type").WithLocation(14, 31),
// (14,36): error CS0103: The name 'd' does not exist in the current context
// switch (c) { case var* d: break; }
Diagnostic(ErrorCode.ERR_NameNotInContext, "d").WithArguments("d").WithLocation(14, 36),
// (15,31): error CS0119: 'Typ' is a type, which is not valid in the given context
// switch (e) { case Typ* f: break; }
Diagnostic(ErrorCode.ERR_BadSKunknown, "Typ").WithArguments("Typ", "type").WithLocation(15, 31),
// (15,36): error CS0103: The name 'f' does not exist in the current context
// switch (e) { case Typ* f: break; }
Diagnostic(ErrorCode.ERR_NameNotInContext, "f").WithArguments("f").WithLocation(15, 36)
);
}
[Fact]
public void MultiplyInPattern()
{
// pointer types are not supported in patterns. Therefore an attempt to use
// a pointer type will be interpreted by the parser as a multiplication
// (i.e. an expression that is a constant pattern rather than a declaration
// pattern)
var source =
@"
public class Program
{
public static void Main()
{
const int two = 2;
const int three = 3;
int six = two * three;
System.Console.WriteLine(six is two * three);
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics();
var comp = CompileAndVerify(compilation, expectedOutput: "True");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册