Skip to content

Commit bc8c7cf

Browse files
Dan Rubelcommit-bot@chromium.org
Dan Rubel
authored andcommitted
Add support for parsing simple nullable types
... as part of adding NNBD as outlined in dart-lang/language#110 This only supports parsing simple nullable types such as int? and List<int>? while subsequent CLs will add support for parsing more complex types. Change-Id: I3cc5c65d20bf3732a39cab0e823b2f7332342866 Reviewed-on: https://dart-review.googlesource.com/c/86961 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Dan Rubel <[email protected]>
1 parent e2db967 commit bc8c7cf

File tree

3 files changed

+210
-10
lines changed

3 files changed

+210
-10
lines changed

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

Lines changed: 29 additions & 7 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, optional;
15+
import 'util.dart' show isOneOf, isOneOfOrEof, optional;
1616

1717
/// [TypeInfo] provides information collected by [computeType]
1818
/// about a particular type reference.
@@ -199,13 +199,19 @@ TypeInfo computeType(final Token token, bool required,
199199
// We've seen identifier `<` identifier `>`
200200
next = typeParamOrArg.skip(next).next;
201201
if (!isGeneralizedFunctionType(next)) {
202-
if (required || looksLikeName(next)) {
203-
// identifier `<` identifier `>` identifier
204-
return typeParamOrArg.typeInfo;
202+
if (optional('?', next) && typeParamOrArg == simpleTypeArgument1) {
203+
if (required || looksLikeName(next.next)) {
204+
// identifier `<` identifier `>` `?` identifier
205+
return simpleNullableTypeWith1Argument;
206+
}
205207
} else {
206-
// identifier `<` identifier `>` non-identifier
207-
return noType;
208+
if (required || looksLikeName(next)) {
209+
// identifier `<` identifier `>` identifier
210+
return typeParamOrArg.typeInfo;
211+
}
208212
}
213+
// identifier `<` identifier `>` non-identifier
214+
return noType;
209215
}
210216
}
211217
// TODO(danrubel): Consider adding a const for
@@ -255,7 +261,23 @@ TypeInfo computeType(final Token token, bool required,
255261
.computeIdentifierGFT(required);
256262
}
257263

258-
if (required || looksLikeName(next)) {
264+
if (optional('?', next)) {
265+
if (required) {
266+
// identifier `?`
267+
return simpleNullableType;
268+
} else {
269+
next = next.next;
270+
if (isGeneralizedFunctionType(next)) {
271+
// identifier `?` Function `(`
272+
return simpleNullableType;
273+
} else if (looksLikeName(next) &&
274+
isOneOfOrEof(
275+
next.next, const [';', ',', '=', '>', '>=', '>>', '>>>'])) {
276+
// identifier `?` identifier `=`
277+
return simpleNullableType;
278+
}
279+
}
280+
} else if (required || looksLikeName(next)) {
259281
// identifier identifier
260282
return simpleType;
261283
}

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ import 'util.dart'
3838
/// when there is a single identifier as the type reference.
3939
const TypeInfo simpleType = const SimpleType();
4040

41+
/// [SimpleNullableType] is a specialized [TypeInfo] returned by [computeType]
42+
/// when there is a single identifier followed by `?` as the type reference.
43+
const TypeInfo simpleNullableType = const SimpleNullableType();
44+
4145
/// [PrefixedType] is a specialized [TypeInfo] returned by [computeType]
4246
/// when the type reference is of the form: identifier `.` identifier.
4347
const TypeInfo prefixedType = const PrefixedType();
@@ -60,6 +64,12 @@ const TypeInfo simpleTypeWith1ArgumentGtEq =
6064
const TypeInfo simpleTypeWith1ArgumentGtGt =
6165
const SimpleTypeWith1Argument(simpleTypeArgument1GtGt);
6266

67+
/// [SimpleNullableTypeWith1Argument] is a specialized [TypeInfo] returned by
68+
/// [computeType] when the type reference is of the form:
69+
/// identifier `<` identifier `>` `?`.
70+
const TypeInfo simpleNullableTypeWith1Argument =
71+
const SimpleNullableTypeWith1Argument();
72+
6373
/// [SimpleTypeArgument1] is a specialized [TypeParamOrArgInfo] returned by
6474
/// [computeTypeParamOrArg] when the type reference is of the form:
6575
/// `<` identifier `>`.
@@ -164,6 +174,29 @@ class PrefixedType implements TypeInfo {
164174
}
165175
}
166176

177+
/// See documentation on the [simpleNullableTypeWith1Argument] const.
178+
class SimpleNullableTypeWith1Argument extends SimpleTypeWith1Argument {
179+
const SimpleNullableTypeWith1Argument() : super(simpleTypeArgument1);
180+
181+
@override
182+
TypeInfo asNonNullableType() => simpleTypeWith1Argument;
183+
184+
@override
185+
Token parseTypeRest(Token start, Token token, Parser parser) {
186+
token = token.next;
187+
assert(optional('?', token));
188+
parser.listener.handleType(start, token);
189+
return token;
190+
}
191+
192+
@override
193+
Token skipType(Token token) {
194+
token = super.skipType(token).next;
195+
assert(optional('?', token));
196+
return token;
197+
}
198+
}
199+
167200
/// See documentation on the [simpleTypeWith1Argument] const.
168201
class SimpleTypeWith1Argument implements TypeInfo {
169202
final TypeParamOrArgInfo typeArg;
@@ -210,6 +243,27 @@ class SimpleTypeWith1Argument implements TypeInfo {
210243
}
211244
}
212245

246+
/// See documentation on the [simpleNullableType] const.
247+
class SimpleNullableType extends SimpleType {
248+
const SimpleNullableType();
249+
250+
@override
251+
TypeInfo asNonNullableType() => simpleType;
252+
253+
@override
254+
Token parseTypeRest(Token start, Parser parser) {
255+
Token token = start.next;
256+
assert(optional('?', token));
257+
parser.listener.handleType(start, token);
258+
return token;
259+
}
260+
261+
@override
262+
Token skipType(Token token) {
263+
return token.next.next;
264+
}
265+
}
266+
213267
/// See documentation on the [simpleType] const.
214268
class SimpleType implements TypeInfo {
215269
const SimpleType();

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

Lines changed: 127 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ main() {
1919
defineReflectiveSuite(() {
2020
defineReflectiveTests(NoTypeInfoTest);
2121
defineReflectiveTests(PrefixedTypeInfoTest);
22-
defineReflectiveTests(SimpleTypeInfoTest);
22+
defineReflectiveTests(SimpleNullableTypeTest);
23+
defineReflectiveTests(SimpleNullableTypeWith1ArgumentTest);
24+
defineReflectiveTests(SimpleTypeTest);
2325
defineReflectiveTests(SimpleTypeWith1ArgumentTest);
2426
defineReflectiveTests(TypeInfoTest);
2527
defineReflectiveTests(VoidTypeInfoTest);
@@ -309,7 +311,124 @@ class PrefixedTypeInfoTest {
309311
}
310312

311313
@reflectiveTest
312-
class SimpleTypeInfoTest {
314+
class SimpleNullableTypeTest {
315+
void test_compute() {
316+
expectInfo(simpleNullableType, 'C?', required: true);
317+
expectInfo(simpleNullableType, 'C?;', required: true);
318+
expectInfo(simpleNullableType, 'C?(', required: true);
319+
expectInfo(simpleNullableType, 'C?<', required: true);
320+
expectInfo(simpleNullableType, 'C?=', required: true);
321+
expectInfo(simpleNullableType, 'C?*', required: true);
322+
expectInfo(simpleNullableType, 'C? do', required: true);
323+
324+
expectInfo(simpleNullableType, 'C? foo');
325+
expectInfo(simpleNullableType, 'C? get');
326+
expectInfo(simpleNullableType, 'C? set');
327+
expectInfo(simpleNullableType, 'C? operator');
328+
expectInfo(simpleNullableType, 'C? this');
329+
expectInfo(simpleNullableType, 'C? Function');
330+
331+
expectInfo(simpleNullableType, 'C? Function()', required: false);
332+
expectInfo(simpleNullableType, 'C? Function<T>()', required: false);
333+
expectInfo(simpleNullableType, 'C? Function(int)', required: false);
334+
expectInfo(simpleNullableType, 'C? Function<T>(int)', required: false);
335+
expectInfo(simpleNullableType, 'C? Function(int x)', required: false);
336+
expectInfo(simpleNullableType, 'C? Function<T>(int x)', required: false);
337+
}
338+
339+
void test_simpleNullableType() {
340+
final Token start = scanString('before C? ;').tokens;
341+
final Token expectedEnd = start.next.next;
342+
343+
expect(simpleNullableType.skipType(start), expectedEnd);
344+
expect(simpleNullableType.couldBeExpression, isTrue);
345+
346+
TypeInfoListener listener;
347+
assertResult(Token actualEnd) {
348+
expect(actualEnd, expectedEnd);
349+
expect(listener.calls, [
350+
'handleIdentifier C typeReference',
351+
'handleNoTypeArguments ?',
352+
'handleType C ?',
353+
]);
354+
expect(listener.errors, isNull);
355+
}
356+
357+
listener = new TypeInfoListener();
358+
assertResult(
359+
simpleNullableType.ensureTypeNotVoid(start, new Parser(listener)));
360+
361+
listener = new TypeInfoListener();
362+
assertResult(
363+
simpleNullableType.ensureTypeOrVoid(start, new Parser(listener)));
364+
365+
listener = new TypeInfoListener();
366+
assertResult(
367+
simpleNullableType.parseTypeNotVoid(start, new Parser(listener)));
368+
369+
listener = new TypeInfoListener();
370+
assertResult(simpleNullableType.parseType(start, new Parser(listener)));
371+
}
372+
}
373+
374+
@reflectiveTest
375+
class SimpleNullableTypeWith1ArgumentTest {
376+
void test_compute() {
377+
expectInfo(simpleNullableTypeWith1Argument, 'C<T>?', required: true);
378+
expectInfo(simpleNullableTypeWith1Argument, 'C<T>?;', required: true);
379+
expectInfo(simpleNullableTypeWith1Argument, 'C<T>?(', required: true);
380+
expectInfo(simpleNullableTypeWith1Argument, 'C<T>? do', required: true);
381+
382+
expectInfo(simpleNullableTypeWith1Argument, 'C<T>? foo');
383+
expectInfo(simpleNullableTypeWith1Argument, 'C<T>? get');
384+
expectInfo(simpleNullableTypeWith1Argument, 'C<T>? set');
385+
expectInfo(simpleNullableTypeWith1Argument, 'C<T>? operator');
386+
expectInfo(simpleNullableTypeWith1Argument, 'C<T>? Function');
387+
}
388+
389+
void test_gt_questionMark() {
390+
final Token start = scanString('before C<T>? ;').tokens;
391+
final Token expectedEnd = start.next.next.next.next.next;
392+
expect(expectedEnd.lexeme, '?');
393+
394+
expect(simpleNullableTypeWith1Argument.skipType(start), expectedEnd);
395+
expect(simpleNullableTypeWith1Argument.couldBeExpression, isFalse);
396+
397+
TypeInfoListener listener;
398+
assertResult(Token actualEnd) {
399+
expect(actualEnd, expectedEnd);
400+
expect(listener.calls, [
401+
'handleIdentifier C typeReference',
402+
'beginTypeArguments <',
403+
'handleIdentifier T typeReference',
404+
'handleNoTypeArguments >',
405+
'handleType T null',
406+
'endTypeArguments 1 < >',
407+
'handleType C ?',
408+
]);
409+
expect(listener.errors, isNull);
410+
}
411+
412+
listener = new TypeInfoListener();
413+
assertResult(simpleNullableTypeWith1Argument.ensureTypeNotVoid(
414+
start, new Parser(listener)));
415+
416+
listener = new TypeInfoListener();
417+
assertResult(simpleNullableTypeWith1Argument.ensureTypeOrVoid(
418+
start, new Parser(listener)));
419+
420+
listener = new TypeInfoListener();
421+
assertResult(simpleNullableTypeWith1Argument.parseTypeNotVoid(
422+
start, new Parser(listener)));
423+
424+
listener = new TypeInfoListener();
425+
assertResult(
426+
simpleNullableTypeWith1Argument.parseType(start, new Parser(listener)));
427+
}
428+
}
429+
430+
@reflectiveTest
431+
class SimpleTypeTest {
313432
void test_compute() {
314433
expectInfo(simpleType, 'C', required: true);
315434
expectInfo(simpleType, 'C;', required: true);
@@ -336,7 +455,7 @@ class SimpleTypeInfoTest {
336455
expectInfo(simpleType, 'C Function<T>(int x)', required: false);
337456
}
338457

339-
void test_simpleTypeInfo() {
458+
void test_simpleType() {
340459
final Token start = scanString('before C ;').tokens;
341460
final Token expectedEnd = start.next;
342461

@@ -818,10 +937,15 @@ class TypeInfoTest {
818937
expectedErrors: [
819938
error(codeExpectedType, 2, 1)
820939
]);
940+
}
821941

942+
void test_computeType_statements() {
822943
// Statements that should not have a type
823944
expectInfo(noType, 'C<T ; T>U;', required: false);
824945
expectInfo(noType, 'C<T && T>U;', required: false);
946+
947+
expectInfo(noType, 'C? D : E;', required: false);
948+
expectInfo(noType, 'C? D.foo : E;', required: false);
825949
}
826950

827951
void test_computeType_nested() {

0 commit comments

Comments
 (0)