未验证 提交 c4598d72 编写于 作者: C Charles Stoner 提交者: GitHub

Parse array type in conditional operator (#31050)

上级 d1e0dd9f
......@@ -4524,7 +4524,7 @@ private static bool CanReuseVariableDeclarator(CSharp.Syntax.VariableDeclaratorS
case SyntaxKind.OpenBracketToken:
bool sawNonOmittedSize;
_termState |= TerminatorState.IsPossibleEndOfVariableDeclaration;
var specifier = this.ParseArrayRankSpecifier(isArrayCreation: false, expectSizes: flags == VariableFlags.Fixed, allowQuestionToken: false, sawNonOmittedSize: out sawNonOmittedSize);
var specifier = this.ParseArrayRankSpecifier(isArrayCreation: false, expectSizes: flags == VariableFlags.Fixed, questionTokenModeOpt: null, sawNonOmittedSize: out sawNonOmittedSize);
_termState = saveTerm;
var open = specifier.OpenBracketToken;
var sizes = specifier.Sizes;
......@@ -6214,7 +6214,6 @@ private enum ParseTypeMode
ParseTypeMode mode,
bool expectSizes)
{
var isOrAs = mode == ParseTypeMode.AsExpression || mode == ParseTypeMode.AfterIs;
NameOptions nameOptions;
switch (mode)
{
......@@ -6244,31 +6243,15 @@ private enum ParseTypeMode
}
var type = this.ParseUnderlyingType(parentIsParameter: mode == ParseTypeMode.Parameter, options: nameOptions);
Debug.Assert(type != null);
if (this.CurrentToken.Kind == SyntaxKind.QuestionToken &&
// we do not permit nullable types in a declaration pattern
(mode != ParseTypeMode.AfterIs && mode != ParseTypeMode.AfterCase || !IsTrueIdentifier(this.PeekToken(1))))
if (this.CurrentToken.Kind == SyntaxKind.QuestionToken)
{
var resetPoint = this.GetResetPoint();
try
var question = EatNullableQualifierIfApplicable(mode);
if (question != null)
{
var question = this.EatToken();
if (isOrAs && (IsTerm() || IsPredefinedType(this.CurrentToken.Kind) || SyntaxFacts.IsAnyUnaryExpression(this.CurrentToken.Kind)))
{
this.Reset(ref resetPoint);
Debug.Assert(type != null);
return type;
}
question = CheckFeatureAvailability(question, MessageID.IDS_FeatureNullable);
type = _syntaxFactory.NullableType(type, question);
}
finally
{
this.Release(ref resetPoint);
}
}
switch (mode)
......@@ -6301,7 +6284,7 @@ private enum ParseTypeMode
while (this.IsPossibleRankAndDimensionSpecifier())
{
bool unused;
var rank = this.ParseArrayRankSpecifier(mode == ParseTypeMode.ArrayCreation, expectSizes, allowQuestionToken: true, out unused);
var rank = this.ParseArrayRankSpecifier(mode == ParseTypeMode.ArrayCreation, expectSizes, questionTokenModeOpt: mode, out unused);
ranks.Add(rank);
expectSizes = false;
}
......@@ -6318,6 +6301,36 @@ private enum ParseTypeMode
return type;
}
private SyntaxToken EatNullableQualifierIfApplicable(ParseTypeMode mode)
{
Debug.Assert(this.CurrentToken.Kind == SyntaxKind.QuestionToken);
// we do not permit nullable types in a declaration pattern
if (mode != ParseTypeMode.AfterIs && mode != ParseTypeMode.AfterCase || !IsTrueIdentifier(this.PeekToken(1)))
{
var resetPoint = this.GetResetPoint();
try
{
var question = this.EatToken();
var isOrAs = mode == ParseTypeMode.AsExpression || mode == ParseTypeMode.AfterIs;
if (isOrAs && (IsTerm() || IsPredefinedType(this.CurrentToken.Kind) || SyntaxFacts.IsAnyUnaryExpression(this.CurrentToken.Kind)))
{
this.Reset(ref resetPoint);
return null;
}
return CheckFeatureAvailability(question, MessageID.IDS_FeatureNullable);
}
finally
{
this.Release(ref resetPoint);
}
}
return null;
}
private bool PointerTypeModsFollowedByRankAndDimensionSpecifier()
{
// Are pointer specifiers (if any) followed by an array specifier?
......@@ -6340,7 +6353,7 @@ private bool IsPossibleRankAndDimensionSpecifier()
return this.CurrentToken.Kind == SyntaxKind.OpenBracketToken;
}
private ArrayRankSpecifierSyntax ParseArrayRankSpecifier(bool isArrayCreation, bool expectSizes, bool allowQuestionToken, out bool sawNonOmittedSize)
private ArrayRankSpecifierSyntax ParseArrayRankSpecifier(bool isArrayCreation, bool expectSizes, ParseTypeMode? questionTokenModeOpt, out bool sawNonOmittedSize)
{
sawNonOmittedSize = false;
bool sawOmittedSize = false;
......@@ -6407,9 +6420,9 @@ private ArrayRankSpecifierSyntax ParseArrayRankSpecifier(bool isArrayCreation, b
var close = this.EatToken(SyntaxKind.CloseBracketToken);
SyntaxToken questionToken = null;
if (allowQuestionToken && this.CurrentToken.Kind == SyntaxKind.QuestionToken)
if (questionTokenModeOpt != null && this.CurrentToken.Kind == SyntaxKind.QuestionToken)
{
questionToken = this.EatToken();
questionToken = EatNullableQualifierIfApplicable(questionTokenModeOpt.GetValueOrDefault());
}
return _syntaxFactory.ArrayRankSpecifier(open, list, close, questionToken);
......
......@@ -456,6 +456,72 @@ static void F2(object? w)
Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(14, 26));
}
[Fact]
public void NullableAndConditionalOperators()
{
var source =
@"class Program
{
static void F1(object x)
{
_ = x is string? 1 : 2;
_ = x is string? ? 1 : 2;
_ = x is string ? ? 1 : 2;
_ = x as string?? x;
_ = x as string ? ?? x;
}
static void F2(object y)
{
_ = y is object[]? 1 : 2;
_ = y is object[]? ? 1 : 2;
_ = y is object[] ? ? 1 : 2;
_ = y as object[]?? y;
_ = y as object[] ? ?? y;
}
static void F3<T>(object z)
{
_ = z is T[][]? 1 : 2;
_ = z is T[]?[] ? 1 : 2;
_ = z is T[] ? [] ? 1 : 2;
_ = z as T[][]?? z;
_ = z as T[] ? [] ?? z;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7);
comp.VerifyDiagnostics(
// (6,24): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater.
// _ = x is string? ? 1 : 2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(6, 24),
// (7,25): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater.
// _ = x is string ? ? 1 : 2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(7, 25),
// (9,25): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater.
// _ = x as string ? ?? x;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(9, 25),
// (14,26): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater.
// _ = y is object[]? ? 1 : 2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(14, 26),
// (15,27): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater.
// _ = y is object[] ? ? 1 : 2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(15, 27),
// (17,27): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater.
// _ = y as object[] ? ?? y;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(17, 27),
// (22,21): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater.
// _ = z is T[]?[] ? 1 : 2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(22, 21),
// (23,22): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater.
// _ = z is T[] ? [] ? 1 : 2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(23, 22),
// (25,22): error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater.
// _ = z as T[] ? [] ?? z;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "?").WithArguments("nullable reference types", "8.0").WithLocation(25, 22));
comp = CreateCompilation(source, options: WithNonNullTypesTrue());
comp.VerifyDiagnostics();
}
[Fact, WorkItem(29318, "https://github.com/dotnet/roslyn/issues/29318")]
public void IsOperatorOnNonNullExpression()
{
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册