Revert "Add support for parsing simple nullable types"

This reverts commit c5fd11b5d67b0014581e8688f86e046494114d41.

Reason for revert: Conditional expression lookahead may modify the token stream

Original change's description:
> Add support for parsing simple nullable types
> 
> ... as part of adding NNBD as outlined in
> https://github.com/dart-lang/language/issues/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: I144858946cb115755af437299899c2631105bf8c
> Reviewed-on: https://dart-review.googlesource.com/c/87501
> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
> Commit-Queue: Dan Rubel <danrubel@google.com>

TBR=brianwilkerson@google.com,danrubel@google.com

Change-Id: Ie1f47e7384ff51159aa2ebeb21561455b8e6287f
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/87620
Reviewed-by: Dan Rubel <danrubel@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index 92ef4bb..8b0ff26 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -4489,7 +4489,11 @@
     Token name = beforeName.next;
     if (name.isIdentifier) {
       TypeParamOrArgInfo typeParam = computeTypeParamOrArg(name);
-      Token next = typeParam.skip(name).next;
+      Token next = name;
+      if (typeParam != noTypeParamOrArg) {
+        next = typeParam.skip(next);
+      }
+      next = next.next;
       if (optional('(', next)) {
         if (looksLikeFunctionBody(next.endGroup.next)) {
           return parseFunctionLiteral(
@@ -4869,10 +4873,8 @@
     if (optional('!', token.next)) {
       not = token = token.next;
     }
-    TypeInfo typeInfo = computeType(token, true);
-    if (typeInfo.isConditionalExpressionStart(token, this)) {
-      typeInfo = typeInfo.asNonNullable;
-    }
+    // Ignore trailing `?` if there is one as it may be part of an expression
+    TypeInfo typeInfo = computeType(token, true).asNonNullableType();
     token = typeInfo.ensureTypeNotVoid(token, this);
     listener.handleIsOperator(operator, not);
     return skipChainedAsIsOperators(token);
@@ -4886,10 +4888,8 @@
   Token parseAsOperatorRest(Token token) {
     Token operator = token = token.next;
     assert(optional('as', operator));
-    TypeInfo typeInfo = computeType(token, true);
-    if (typeInfo.isConditionalExpressionStart(token, this)) {
-      typeInfo = typeInfo.asNonNullable;
-    }
+    // Ignore trailing `?` if there is one as it may be part of an expression
+    TypeInfo typeInfo = computeType(token, true).asNonNullableType();
     token = typeInfo.ensureTypeNotVoid(token, this);
     listener.handleAsOperator(operator);
     return skipChainedAsIsOperators(token);
@@ -4908,11 +4908,7 @@
       if (optional('!', next.next)) {
         next = next.next;
       }
-      TypeInfo typeInfo = computeType(next, true);
-      if (typeInfo.isConditionalExpressionStart(next, this)) {
-        typeInfo = typeInfo.asNonNullable;
-      }
-      token = typeInfo.skipType(next);
+      token = computeType(next, true).skipType(next);
       next = token.next;
       value = next.stringValue;
     }
@@ -5033,10 +5029,6 @@
       TypeInfo typeInfo,
       bool onlyParseVariableDeclarationStart = false]) {
     typeInfo ??= computeType(beforeType, false);
-    if (typeInfo.isConditionalExpressionStart(beforeType, this)) {
-      typeInfo = noType;
-    }
-
     Token token = typeInfo.skipType(beforeType);
     Token next = token.next;
 
diff --git a/pkg/front_end/lib/src/fasta/parser/type_info.dart b/pkg/front_end/lib/src/fasta/parser/type_info.dart
index c42442a..5e9f636 100644
--- a/pkg/front_end/lib/src/fasta/parser/type_info.dart
+++ b/pkg/front_end/lib/src/fasta/parser/type_info.dart
@@ -19,12 +19,12 @@
 abstract class TypeInfo {
   /// Return type info representing the receiver without the trailing `?`
   /// or the receiver if the receiver does not represent a nullable type.
-  TypeInfo get asNonNullable;
+  TypeInfo asNonNullableType();
 
   /// Return `true` if the tokens comprising the type represented by the
   /// receiver could be interpreted as a valid standalone expression.
-  /// For example, `A` or `A.b` could be interpreted as type references
-  /// or expressions, while `A<T>` only looks like a type reference.
+  /// For example, `A` or `A.b` could be interpreted as a type references
+  /// or as expressions, while `A<T>` only looks like a type reference.
   bool get couldBeExpression;
 
   /// Call this function when the token after [token] must be a type (not void).
@@ -41,13 +41,6 @@
   /// in valid code or during recovery.
   Token ensureTypeOrVoid(Token token, Parser parser);
 
-  /// Return `true` if the tokens comprising the type represented by the
-  /// receiver are the start of a conditional expression.
-  /// For example, `A?` or `A.b?` could be the start of a conditional expression
-  /// and require arbitrary look ahead to determine if it is,
-  /// while `A<T>?` cannot be the start of a conditional expression.
-  bool isConditionalExpressionStart(Token token, Parser parser);
-
   /// Call this function to parse an optional type (not void) after [token].
   /// This function will call the appropriate event methods on the [Parser]'s
   /// listener to handle the type. This may modify the token stream
@@ -206,19 +199,13 @@
       // We've seen identifier `<` identifier `>`
       next = typeParamOrArg.skip(next).next;
       if (!isGeneralizedFunctionType(next)) {
-        if (optional('?', next) && typeParamOrArg == simpleTypeArgument1) {
-          if (required || looksLikeName(next.next)) {
-            // identifier `<` identifier `>` `?` identifier
-            return simpleNullableTypeWith1Argument;
-          }
+        if (required || looksLikeName(next)) {
+          // identifier `<` identifier `>` identifier
+          return typeParamOrArg.typeInfo;
         } else {
-          if (required || looksLikeName(next)) {
-            // identifier `<` identifier `>` identifier
-            return typeParamOrArg.typeInfo;
-          }
+          // identifier `<` identifier `>` non-identifier
+          return noType;
         }
-        // identifier `<` identifier `>` non-identifier
-        return noType;
       }
     }
     // TODO(danrubel): Consider adding a const for
@@ -268,21 +255,7 @@
         .computeIdentifierGFT(required);
   }
 
-  if (optional('?', next)) {
-    if (required) {
-      // identifier `?`
-      return simpleNullableType;
-    } else {
-      next = next.next;
-      if (isGeneralizedFunctionType(next)) {
-        // identifier `?` Function `(`
-        return simpleNullableType;
-      } else if (looksLikeName(next)) {
-        // identifier `?` identifier `=`
-        return simpleNullableType;
-      }
-    }
-  } else if (required || looksLikeName(next)) {
+  if (required || looksLikeName(next)) {
     // identifier identifier
     return simpleType;
   }
diff --git a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
index 7cb7f45..2a2b6ab 100644
--- a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
@@ -38,10 +38,6 @@
 /// when there is a single identifier as the type reference.
 const TypeInfo simpleType = const SimpleType();
 
-/// [SimpleNullableType] is a specialized [TypeInfo] returned by [computeType]
-/// when there is a single identifier followed by `?` as the type reference.
-const TypeInfo simpleNullableType = const SimpleNullableType();
-
 /// [PrefixedType] is a specialized [TypeInfo] returned by [computeType]
 /// when the type reference is of the form: identifier `.` identifier.
 const TypeInfo prefixedType = const PrefixedType();
@@ -64,12 +60,6 @@
 const TypeInfo simpleTypeWith1ArgumentGtGt =
     const SimpleTypeWith1Argument(simpleTypeArgument1GtGt);
 
-/// [SimpleNullableTypeWith1Argument] is a specialized [TypeInfo] returned by
-/// [computeType] when the type reference is of the form:
-/// identifier `<` identifier `>` `?`.
-const TypeInfo simpleNullableTypeWith1Argument =
-    const SimpleNullableTypeWith1Argument();
-
 /// [SimpleTypeArgument1] is a specialized [TypeParamOrArgInfo] returned by
 /// [computeTypeParamOrArg] when the type reference is of the form:
 /// `<` identifier `>`.
@@ -92,10 +82,10 @@
   const NoType();
 
   @override
-  TypeInfo get asNonNullable => this;
+  bool get couldBeExpression => false;
 
   @override
-  bool get couldBeExpression => false;
+  TypeInfo asNonNullableType() => this;
 
   @override
   Token ensureTypeNotVoid(Token token, Parser parser) {
@@ -110,9 +100,6 @@
       ensureTypeNotVoid(token, parser);
 
   @override
-  bool isConditionalExpressionStart(Token token, Parser parser) => false;
-
-  @override
   Token parseTypeNotVoid(Token token, Parser parser) =>
       parseType(token, parser);
 
@@ -133,10 +120,10 @@
   const PrefixedType();
 
   @override
-  TypeInfo get asNonNullable => this;
+  bool get couldBeExpression => true;
 
   @override
-  bool get couldBeExpression => true;
+  TypeInfo asNonNullableType() => this;
 
   @override
   Token ensureTypeNotVoid(Token token, Parser parser) =>
@@ -147,9 +134,6 @@
       parseType(token, parser);
 
   @override
-  bool isConditionalExpressionStart(Token token, Parser parser) => false;
-
-  @override
   Token parseTypeNotVoid(Token token, Parser parser) =>
       parseType(token, parser);
 
@@ -180,33 +164,6 @@
   }
 }
 
-/// See documentation on the [simpleNullableTypeWith1Argument] const.
-class SimpleNullableTypeWith1Argument extends SimpleTypeWith1Argument {
-  const SimpleNullableTypeWith1Argument() : super(simpleTypeArgument1);
-
-  @override
-  TypeInfo get asNonNullable => simpleTypeWith1Argument;
-
-  @override
-  bool isConditionalExpressionStart(Token token, Parser parser) =>
-      isConditionalThenExpression(skipType(token), parser);
-
-  @override
-  Token parseTypeRest(Token start, Token token, Parser parser) {
-    token = token.next;
-    assert(optional('?', token));
-    parser.listener.handleType(start, token);
-    return token;
-  }
-
-  @override
-  Token skipType(Token token) {
-    token = super.skipType(token).next;
-    assert(optional('?', token));
-    return token;
-  }
-}
-
 /// See documentation on the [simpleTypeWith1Argument] const.
 class SimpleTypeWith1Argument implements TypeInfo {
   final TypeParamOrArgInfo typeArg;
@@ -214,10 +171,10 @@
   const SimpleTypeWith1Argument(this.typeArg);
 
   @override
-  TypeInfo get asNonNullable => this;
+  bool get couldBeExpression => false;
 
   @override
-  bool get couldBeExpression => false;
+  TypeInfo asNonNullableType() => this;
 
   @override
   Token ensureTypeNotVoid(Token token, Parser parser) =>
@@ -228,9 +185,6 @@
       parseType(token, parser);
 
   @override
-  bool isConditionalExpressionStart(Token token, Parser parser) => false;
-
-  @override
   Token parseTypeNotVoid(Token token, Parser parser) =>
       parseType(token, parser);
 
@@ -256,40 +210,15 @@
   }
 }
 
-/// See documentation on the [simpleNullableType] const.
-class SimpleNullableType extends SimpleType {
-  const SimpleNullableType();
-
-  @override
-  TypeInfo get asNonNullable => simpleType;
-
-  @override
-  bool isConditionalExpressionStart(Token token, Parser parser) =>
-      isConditionalThenExpression(skipType(token), parser);
-
-  @override
-  Token parseTypeRest(Token start, Parser parser) {
-    Token token = start.next;
-    assert(optional('?', token));
-    parser.listener.handleType(start, token);
-    return token;
-  }
-
-  @override
-  Token skipType(Token token) {
-    return token.next.next;
-  }
-}
-
 /// See documentation on the [simpleType] const.
 class SimpleType implements TypeInfo {
   const SimpleType();
 
   @override
-  TypeInfo get asNonNullable => this;
+  bool get couldBeExpression => true;
 
   @override
-  bool get couldBeExpression => true;
+  TypeInfo asNonNullableType() => this;
 
   @override
   Token ensureTypeNotVoid(Token token, Parser parser) =>
@@ -300,9 +229,6 @@
       parseType(token, parser);
 
   @override
-  bool isConditionalExpressionStart(Token token, Parser parser) => false;
-
-  @override
   Token parseTypeNotVoid(Token token, Parser parser) =>
       parseType(token, parser);
 
@@ -331,10 +257,10 @@
   const VoidType();
 
   @override
-  TypeInfo get asNonNullable => this;
+  bool get couldBeExpression => false;
 
   @override
-  bool get couldBeExpression => false;
+  TypeInfo asNonNullableType() => this;
 
   @override
   Token ensureTypeNotVoid(Token token, Parser parser) {
@@ -348,9 +274,6 @@
       parseType(token, parser);
 
   @override
-  bool isConditionalExpressionStart(Token token, Parser parser) => false;
-
-  @override
   Token parseTypeNotVoid(Token token, Parser parser) =>
       ensureTypeNotVoid(token, parser);
 
@@ -414,12 +337,12 @@
       : this.start = beforeStart.next;
 
   @override
-  TypeInfo get asNonNullable {
-    return this;
-  }
+  bool get couldBeExpression => false;
 
   @override
-  bool get couldBeExpression => false;
+  TypeInfo asNonNullableType() {
+    return this;
+  }
 
   @override
   Token ensureTypeNotVoid(Token token, Parser parser) =>
@@ -430,12 +353,6 @@
       parseType(token, parser);
 
   @override
-  bool isConditionalExpressionStart(Token token, Parser parser) {
-    //return isConditionalThenExpression(token.next.next, parser);
-    return false;
-  }
-
-  @override
   Token parseTypeNotVoid(Token token, Parser parser) =>
       parseType(token, parser);
 
@@ -1144,16 +1061,3 @@
   }
   return null;
 }
-
-/// Return `true` if the tokens after [token]
-/// represent a valid expression followed by a `:`.
-bool isConditionalThenExpression(Token token, Parser parser) {
-  // TODO(danrubel): Consider adding checks for simple situations
-  // before resorting to heavy weight lookahead.
-
-  final originalListener = parser.listener;
-  parser.listener = new ForwardingListener();
-  token = parser.parseExpression(token);
-  parser.listener = originalListener;
-  return optional(':', token.next);
-}
diff --git a/pkg/front_end/test/fasta/parser/type_info_test.dart b/pkg/front_end/test/fasta/parser/type_info_test.dart
index 0febbe0..9a0400d 100644
--- a/pkg/front_end/test/fasta/parser/type_info_test.dart
+++ b/pkg/front_end/test/fasta/parser/type_info_test.dart
@@ -19,9 +19,7 @@
   defineReflectiveSuite(() {
     defineReflectiveTests(NoTypeInfoTest);
     defineReflectiveTests(PrefixedTypeInfoTest);
-    defineReflectiveTests(SimpleNullableTypeTest);
-    defineReflectiveTests(SimpleNullableTypeWith1ArgumentTest);
-    defineReflectiveTests(SimpleTypeTest);
+    defineReflectiveTests(SimpleTypeInfoTest);
     defineReflectiveTests(SimpleTypeWith1ArgumentTest);
     defineReflectiveTests(TypeInfoTest);
     defineReflectiveTests(VoidTypeInfoTest);
@@ -311,124 +309,7 @@
 }
 
 @reflectiveTest
-class SimpleNullableTypeTest {
-  void test_compute() {
-    expectInfo(simpleNullableType, 'C?', required: true);
-    expectInfo(simpleNullableType, 'C?;', required: true);
-    expectInfo(simpleNullableType, 'C?(', required: true);
-    expectInfo(simpleNullableType, 'C?<', required: true);
-    expectInfo(simpleNullableType, 'C?=', required: true);
-    expectInfo(simpleNullableType, 'C?*', required: true);
-    expectInfo(simpleNullableType, 'C? do', required: true);
-
-    expectInfo(simpleNullableType, 'C? foo');
-    expectInfo(simpleNullableType, 'C? get');
-    expectInfo(simpleNullableType, 'C? set');
-    expectInfo(simpleNullableType, 'C? operator');
-    expectInfo(simpleNullableType, 'C? this');
-    expectInfo(simpleNullableType, 'C? Function');
-
-    expectInfo(simpleNullableType, 'C? Function()', required: false);
-    expectInfo(simpleNullableType, 'C? Function<T>()', required: false);
-    expectInfo(simpleNullableType, 'C? Function(int)', required: false);
-    expectInfo(simpleNullableType, 'C? Function<T>(int)', required: false);
-    expectInfo(simpleNullableType, 'C? Function(int x)', required: false);
-    expectInfo(simpleNullableType, 'C? Function<T>(int x)', required: false);
-  }
-
-  void test_simpleNullableType() {
-    final Token start = scanString('before C? ;').tokens;
-    final Token expectedEnd = start.next.next;
-
-    expect(simpleNullableType.skipType(start), expectedEnd);
-    expect(simpleNullableType.couldBeExpression, isTrue);
-
-    TypeInfoListener listener;
-    assertResult(Token actualEnd) {
-      expect(actualEnd, expectedEnd);
-      expect(listener.calls, [
-        'handleIdentifier C typeReference',
-        'handleNoTypeArguments ?',
-        'handleType C ?',
-      ]);
-      expect(listener.errors, isNull);
-    }
-
-    listener = new TypeInfoListener();
-    assertResult(
-        simpleNullableType.ensureTypeNotVoid(start, new Parser(listener)));
-
-    listener = new TypeInfoListener();
-    assertResult(
-        simpleNullableType.ensureTypeOrVoid(start, new Parser(listener)));
-
-    listener = new TypeInfoListener();
-    assertResult(
-        simpleNullableType.parseTypeNotVoid(start, new Parser(listener)));
-
-    listener = new TypeInfoListener();
-    assertResult(simpleNullableType.parseType(start, new Parser(listener)));
-  }
-}
-
-@reflectiveTest
-class SimpleNullableTypeWith1ArgumentTest {
-  void test_compute() {
-    expectInfo(simpleNullableTypeWith1Argument, 'C<T>?', required: true);
-    expectInfo(simpleNullableTypeWith1Argument, 'C<T>?;', required: true);
-    expectInfo(simpleNullableTypeWith1Argument, 'C<T>?(', required: true);
-    expectInfo(simpleNullableTypeWith1Argument, 'C<T>? do', required: true);
-
-    expectInfo(simpleNullableTypeWith1Argument, 'C<T>? foo');
-    expectInfo(simpleNullableTypeWith1Argument, 'C<T>? get');
-    expectInfo(simpleNullableTypeWith1Argument, 'C<T>? set');
-    expectInfo(simpleNullableTypeWith1Argument, 'C<T>? operator');
-    expectInfo(simpleNullableTypeWith1Argument, 'C<T>? Function');
-  }
-
-  void test_gt_questionMark() {
-    final Token start = scanString('before C<T>? ;').tokens;
-    final Token expectedEnd = start.next.next.next.next.next;
-    expect(expectedEnd.lexeme, '?');
-
-    expect(simpleNullableTypeWith1Argument.skipType(start), expectedEnd);
-    expect(simpleNullableTypeWith1Argument.couldBeExpression, isFalse);
-
-    TypeInfoListener listener;
-    assertResult(Token actualEnd) {
-      expect(actualEnd, expectedEnd);
-      expect(listener.calls, [
-        'handleIdentifier C typeReference',
-        'beginTypeArguments <',
-        'handleIdentifier T typeReference',
-        'handleNoTypeArguments >',
-        'handleType T null',
-        'endTypeArguments 1 < >',
-        'handleType C ?',
-      ]);
-      expect(listener.errors, isNull);
-    }
-
-    listener = new TypeInfoListener();
-    assertResult(simpleNullableTypeWith1Argument.ensureTypeNotVoid(
-        start, new Parser(listener)));
-
-    listener = new TypeInfoListener();
-    assertResult(simpleNullableTypeWith1Argument.ensureTypeOrVoid(
-        start, new Parser(listener)));
-
-    listener = new TypeInfoListener();
-    assertResult(simpleNullableTypeWith1Argument.parseTypeNotVoid(
-        start, new Parser(listener)));
-
-    listener = new TypeInfoListener();
-    assertResult(
-        simpleNullableTypeWith1Argument.parseType(start, new Parser(listener)));
-  }
-}
-
-@reflectiveTest
-class SimpleTypeTest {
+class SimpleTypeInfoTest {
   void test_compute() {
     expectInfo(simpleType, 'C', required: true);
     expectInfo(simpleType, 'C;', required: true);
@@ -455,7 +336,7 @@
     expectInfo(simpleType, 'C Function<T>(int x)', required: false);
   }
 
-  void test_simpleType() {
+  void test_simpleTypeInfo() {
     final Token start = scanString('before C ;').tokens;
     final Token expectedEnd = start.next;
 
@@ -937,9 +818,7 @@
         expectedErrors: [
           error(codeExpectedType, 2, 1)
         ]);
-  }
 
-  void test_computeType_statements() {
     // Statements that should not have a type
     expectInfo(noType, 'C<T ; T>U;', required: false);
     expectInfo(noType, 'C<T && T>U;', required: false);