Skip to content

Commit 7720689

Browse files
danrubelcommit-bot@chromium.org
danrubel
authored andcommitted
Add support for prefixed nullable type
This adds support for nullable types of the form <identifier> '.' <identifier> '?' and <identifier> '.' <identifier> '?' 'Function' '(' ... This is an increment CL in the ongoing effort to add nullable type support as outlined in dart-lang/language#110 Change-Id: I526aecbe64bacbd442cea0b4c52d36ff23b0443b Reviewed-on: https://dart-review.googlesource.com/c/87083 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Dan Rubel <[email protected]>
1 parent b9463d0 commit 7720689

File tree

4 files changed

+92
-13
lines changed

4 files changed

+92
-13
lines changed

pkg/analyzer/test/generated/parser_test.dart

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1987,6 +1987,35 @@ mixin ComplexParserTestMixin implements AbstractParserTestCase {
19871987
BinaryExpression, expression.condition);
19881988
}
19891989

1990+
void test_conditionalExpression_prefixedValue() {
1991+
ExpressionStatement statement = parseStatement('a.b ? y : z;');
1992+
ConditionalExpression expression = statement.expression;
1993+
EngineTestCase.assertInstanceOf((obj) => obj is PrefixedIdentifier,
1994+
PrefixedIdentifier, expression.condition);
1995+
}
1996+
1997+
void test_conditionalExpression_prefixedValue2() {
1998+
ExpressionStatement statement = parseStatement('a.b ? x.y : z;');
1999+
ConditionalExpression expression = statement.expression;
2000+
EngineTestCase.assertInstanceOf((obj) => obj is PrefixedIdentifier,
2001+
PrefixedIdentifier, expression.condition);
2002+
EngineTestCase.assertInstanceOf((obj) => obj is PrefixedIdentifier,
2003+
PrefixedIdentifier, expression.thenExpression);
2004+
}
2005+
2006+
void test_conditionalExpression_precedence_prefixedNullableType_as() {
2007+
Expression expression = parseExpression('x as p.A ? (x + y) : z');
2008+
expect(expression, isNotNull);
2009+
expect(expression, new TypeMatcher<ConditionalExpression>());
2010+
ConditionalExpression conditional = expression;
2011+
Expression condition = conditional.condition;
2012+
expect(condition, new TypeMatcher<AsExpression>());
2013+
Expression thenExpression = conditional.thenExpression;
2014+
expect(thenExpression, new TypeMatcher<ParenthesizedExpression>());
2015+
Expression elseExpression = conditional.elseExpression;
2016+
expect(elseExpression, new TypeMatcher<SimpleIdentifier>());
2017+
}
2018+
19902019
void test_conditionalExpression_precedence_nullableType_as() {
19912020
Expression expression = parseExpression('x as String ? (x + y) : z');
19922021
expect(expression, isNotNull);

pkg/front_end/lib/src/fasta/parser/type_info.dart

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import 'parser.dart' show Parser;
1212

1313
import 'type_info_impl.dart';
1414

15-
import 'util.dart' show isOneOf, isOneOfOrEof, optional;
15+
import 'util.dart' show isOneOf, optional;
1616

1717
/// [TypeInfo] provides information collected by [computeType]
1818
/// about a particular type reference.
@@ -231,14 +231,23 @@ TypeInfo computeType(final Token token, bool required,
231231
// We've seen identifier `.` identifier
232232
typeParamOrArg = computeTypeParamOrArg(next, inDeclaration);
233233
next = next.next;
234-
if (typeParamOrArg == noTypeParamOrArg &&
235-
!isGeneralizedFunctionType(next)) {
236-
if (required || looksLikeName(next)) {
237-
// identifier `.` identifier identifier
238-
return prefixedType;
239-
} else {
240-
// identifier `.` identifier non-identifier
241-
return noType;
234+
if (typeParamOrArg == noTypeParamOrArg) {
235+
if (optional('?', next)) {
236+
next = next.next;
237+
// identifier `.` identifier `?`
238+
if (!required &&
239+
!looksLikeVarName(next) &&
240+
!isGeneralizedFunctionType(next)) {
241+
return noType;
242+
}
243+
} else if (!isGeneralizedFunctionType(next)) {
244+
if (required || looksLikeName(next)) {
245+
// identifier `.` identifier identifier
246+
return prefixedType;
247+
} else {
248+
// identifier `.` identifier non-identifier
249+
return noType;
250+
}
242251
}
243252
}
244253
// identifier `.` identifier
@@ -267,10 +276,7 @@ TypeInfo computeType(final Token token, bool required,
267276
// identifier `?` Function `(`
268277
return new ComplexTypeInfo(token, noTypeParamOrArg)
269278
.computeIdentifierQuestionGFT(required);
270-
} else if (required ||
271-
(looksLikeName(next) &&
272-
isOneOfOrEof(
273-
next.next, const [';', ',', '=', '>', '>=', '>>', '>>>']))) {
279+
} else if (required || looksLikeVarName(next)) {
274280
// identifier `?`
275281
return simpleNullableType;
276282
}

pkg/front_end/lib/src/fasta/parser/type_info_impl.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import 'type_info.dart';
2626

2727
import 'util.dart'
2828
show
29+
isOneOfOrEof,
2930
optional,
3031
skipMetadata,
3132
splitGtEq,
@@ -367,6 +368,16 @@ bool looksLikeTypeParamOrArg(bool inDeclaration, Token token) {
367368
return false;
368369
}
369370

371+
bool looksLikeVarName(Token token) {
372+
return (looksLikeName(token) &&
373+
isOneOfOrEof(token.next, const [
374+
';', ',',
375+
// TODO(danrubel): Consider refactoring this into TokenType.isAssignment
376+
'=', '&&=', '&=', '||=', '|=', '^=', '>>=', '<<=', '-=', '%=', '+=',
377+
'??=', '/=', '*=', '~/=',
378+
]));
379+
}
380+
370381
/// Instances of [ComplexTypeInfo] are returned by [computeType] to represent
371382
/// type references that cannot be represented by the constants above.
372383
class ComplexTypeInfo implements TypeInfo {

pkg/front_end/test/fasta/parser/type_info_test.dart

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,39 @@ class TypeInfoTest {
10131013
required: true);
10141014
}
10151015

1016+
void test_computeType_prefixedGFT_questionMark() {
1017+
expectComplexInfo('C.a? Function(', // Scanner inserts synthetic ')'.
1018+
required: true,
1019+
expectedCalls: [
1020+
'handleNoTypeVariables (',
1021+
'beginFunctionType C',
1022+
'handleIdentifier C prefixedTypeReference',
1023+
'handleIdentifier a typeReferenceContinuation',
1024+
'handleQualified .',
1025+
'handleNoTypeArguments ?',
1026+
'handleType C ?',
1027+
'beginFormalParameters ( MemberKind.GeneralizedFunctionType',
1028+
'endFormalParameters 0 ( ) MemberKind.GeneralizedFunctionType',
1029+
'endFunctionType Function null',
1030+
]);
1031+
expectComplexInfo('C.a? Function<T>(int x) Function<T>(int x)',
1032+
required: false, expectedAfter: 'Function');
1033+
expectComplexInfo('C.a? Function<T>(int x) Function<T>(int x)',
1034+
required: true);
1035+
}
1036+
1037+
void test_computeType_prefixedQuestionMark() {
1038+
expectComplexInfo('C.a? Function',
1039+
expectedAfter: 'Function',
1040+
expectedCalls: [
1041+
'handleIdentifier C prefixedTypeReference',
1042+
'handleIdentifier a typeReferenceContinuation',
1043+
'handleQualified .',
1044+
'handleNoTypeArguments ?',
1045+
'handleType C ?',
1046+
]);
1047+
}
1048+
10161049
void test_computeType_prefixedTypeArg() {
10171050
expectComplexInfo('C.a<T>', required: true, expectedCalls: [
10181051
'handleIdentifier C prefixedTypeReference',

0 commit comments

Comments
 (0)