Share more analyzer/CFE code related to types.

This commit builds on the work done in
https://dart-review.googlesource.com/c/sdk/+/362481, which established
the framework for sharing a class hierarchy between the analyzer and
CFE to represent types.

This commit introduces the following new classes:

- `SharedDynamicType`, which represents the common interface between
  the `DynamicType` classes in the analyzer and the CFE.

- `SharedInvalidType`, which represents the common interface between
  the `InvalidType` classes in the analyzer and the CFE.

- `SharedVoidType`, which represents the common interface between the
  `VoidType` classes in the analyzer and the CFE.

This allows 3 methods to be removed from the
`FlowAnalysisTypeOperations` class:

- `isDynamic`, which is no longer needed becasue `is
  SharedDynamicType` can be used instead.

- `isError`, which is no longer needed because `is SharedInvalidType`
  can be used instead.

- `isVoid`, which is no longer needed because `is SharedVoidType` can
  be used instead.

In addition, `getDisplayString` is removed from the
`TypeAnalyzerOperations` class, and replaced with a `getDisplayString`
method in `SharedType`. This does not increase the API surface area of
the analyzer, because the analyzer already has a
`DartType.getDisplayString` method.

Change-Id: Ib8d9d3a7699f3d1e8b9612ca9c8f4134fa19de77
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/365303
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index d4944ed..3e73406 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:meta/meta.dart';
 
 import '../type_inference/assigned_variables.dart';
@@ -5152,7 +5153,7 @@
       required Type knownType,
       bool matchFailsIfWrongType = true,
       bool matchMayFailEvenIfCorrectType = false}) {
-    if (operations.isError(knownType)) {
+    if (knownType is SharedInvalidType) {
       _unmatched = _join(_unmatched!, _current);
       return false;
     }
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis_operations.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis_operations.dart
index 6ade20a..5d5193f 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis_operations.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis_operations.dart
@@ -63,9 +63,6 @@
   /// consideration by an instance check.
   Type factor(Type from, Type what);
 
-  /// Returns `true` if [type] is the error type.
-  bool isError(Type type);
-
   /// Determines whether the given [type] is equivalent to the `Never` type.
   ///
   /// A type is equivalent to `Never` if it:
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
index 47b012a..d843002 100644
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
@@ -326,8 +326,8 @@
         'Assigned variables must only appear in irrefutable pattern contexts');
     Error? patternTypeMismatchInIrrefutableContextError;
     if (irrefutableContext != null &&
-        !operations.isDynamic(matchedValueType) &&
-        !operations.isError(matchedValueType) &&
+        matchedValueType is! SharedDynamicType &&
+        matchedValueType is! SharedInvalidType &&
         !operations.isSubtypeOf(matchedValueType, variableDeclaredType)) {
       patternTypeMismatchInIrrefutableContextError =
           errors.patternTypeMismatchInIrrefutableContext(
@@ -371,7 +371,7 @@
         knownType: requiredType,
         matchFailsIfWrongType: false);
     if (operations.isSubtypeOf(matchedValueType, requiredType) &&
-        !operations.isError(requiredType)) {
+        requiredType is! SharedInvalidType) {
       errors.matchedTypeIsSubtypeOfRequired(
         pattern: pattern,
         matchedType: matchedValueType,
@@ -488,8 +488,8 @@
     Node? irrefutableContext = context.irrefutableContext;
     Error? patternTypeMismatchInIrrefutableContextError;
     if (irrefutableContext != null &&
-        !operations.isDynamic(matchedValueType) &&
-        !operations.isError(matchedValueType) &&
+        matchedValueType is! SharedDynamicType &&
+        matchedValueType is! SharedInvalidType &&
         !operations.isSubtypeOf(matchedValueType, staticType)) {
       patternTypeMismatchInIrrefutableContextError =
           errors.patternTypeMismatchInIrrefutableContext(
@@ -774,9 +774,9 @@
       Type? listElementType = operations.matchListType(matchedValueType);
       if (listElementType != null) {
         valueType = listElementType;
-      } else if (operations.isDynamic(matchedValueType)) {
+      } else if (matchedValueType is SharedDynamicType) {
         valueType = operations.dynamicType;
-      } else if (operations.isError(matchedValueType)) {
+      } else if (matchedValueType is SharedInvalidType) {
         valueType = operations.errorType;
       } else {
         valueType = operations.objectQuestionType;
@@ -1040,11 +1040,11 @@
         keyType = typeArguments.keyType;
         valueType = typeArguments.valueType;
         keySchema = operations.typeToSchema(keyType);
-      } else if (operations.isDynamic(matchedValueType)) {
+      } else if (matchedValueType is SharedDynamicType) {
         keyType = operations.dynamicType;
         valueType = operations.dynamicType;
         keySchema = operations.unknownType;
-      } else if (operations.isError(matchedValueType)) {
+      } else if (matchedValueType is SharedInvalidType) {
         keyType = operations.errorType;
         valueType = operations.errorType;
         keySchema = operations.unknownType;
@@ -1258,8 +1258,8 @@
     // If the required type is `dynamic` or `Never`, then every getter is
     // treated as having the same type.
     (Object?, Type)? overridePropertyGetType;
-    if (operations.isDynamic(requiredType) ||
-        operations.isError(requiredType) ||
+    if (requiredType is SharedDynamicType ||
+        requiredType is SharedInvalidType ||
         operations.isNever(requiredType)) {
       overridePropertyGetType = (null, requiredType);
     }
@@ -1392,9 +1392,9 @@
         ? operations.matchStreamType(expressionType)
         : operations.matchIterableType(expressionType);
     if (elementType == null) {
-      if (operations.isDynamic(expressionType)) {
+      if (expressionType is SharedDynamicType) {
         elementType = operations.dynamicType;
-      } else if (operations.isError(expressionType)) {
+      } else if (expressionType is SharedInvalidType) {
         elementType = operations.errorType;
       } else {
         patternForInExpressionIsNotIterableError =
@@ -1558,9 +1558,9 @@
       } else {
         dispatchFields(operations.objectQuestionType);
       }
-    } else if (operations.isDynamic(matchedValueType)) {
+    } else if (matchedValueType is SharedDynamicType) {
       dispatchFields(operations.dynamicType);
-    } else if (operations.isError(matchedValueType)) {
+    } else if (matchedValueType is SharedInvalidType) {
       dispatchFields(operations.errorType);
     } else {
       dispatchFields(operations.objectQuestionType);
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart
index 8e476a8..214ad06 100644
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart
@@ -47,13 +47,6 @@
   /// [argumentType].
   Type futureType(Type argumentType);
 
-  /// Return the presentation of this type as it should appear when presented
-  /// to users in contexts such as error messages.
-  ///
-  /// Clients should not depend on the content of the returned value as it will
-  /// be changed if doing so would improve the UX.
-  String getDisplayString(Type type);
-
   /// Returns the nullability modifier of [type].
   NullabilitySuffix getNullabilitySuffix(Type type);
 
@@ -101,9 +94,6 @@
   /// returns `false` for `Object?` and `Object*`.
   bool isDartCoreFunction(Type type);
 
-  /// Returns `true` if [type] is the type `dynamic`.
-  bool isDynamic(Type type);
-
   /// Returns `true` if [type] is `E<T1, ..., Tn>`, `E<T1, ..., Tn>?`, or
   /// `E<T1, ..., Tn>*` for some extension type declaration E, some
   /// non-negative n, and some types T1, ..., Tn.
@@ -142,9 +132,6 @@
   /// Returns whether [node] is final.
   bool isVariableFinal(Variable node);
 
-  /// Returns `true` if [type] is the type `void`.
-  bool isVoid(Type type);
-
   /// Returns the type schema `Iterable`, with type argument.
   TypeSchema iterableTypeSchema(TypeSchema elementTypeSchema);
 
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart
index 550ebc5..12b3db3 100644
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart
@@ -251,10 +251,8 @@
 
     return [
       prefix,
-      "declared as     "
-          "'${typeAnalyzerOperations.getDisplayString(parameterType)}'",
-      "but argument is "
-          "'${typeAnalyzerOperations.getDisplayString(argumentType)}'."
+      "declared as     '${parameterType.getDisplayString()}'",
+      "but argument is '${argumentType.getDisplayString()}'."
     ];
   }
 }
@@ -293,8 +291,8 @@
       TypeAnalyzerOperations<Variable, Type, TypeSchema, InferableParameter,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
-    String boundStr = typeAnalyzerOperations.getDisplayString(boundType);
-    String extendsStr = typeAnalyzerOperations.getDisplayString(extendsType);
+    String boundStr = boundType.getDisplayString();
+    String extendsStr = extendsType.getDisplayString();
     return [
       "Type parameter '${typeParameterName}'",
       "is declared to extend '${boundStr}' producing '${extendsStr}'."
@@ -324,9 +322,8 @@
           typeAnalyzerOperations) {
     return [
       "Function type",
-      "declared as '${typeAnalyzerOperations.getDisplayString(functionType)}'",
-      "used where  '${typeAnalyzerOperations.getDisplayString(contextType)}' "
-          "is required."
+      "declared as '${functionType.getDisplayString()}'",
+      "used where  '${contextType.getDisplayString()}' is required."
     ];
   }
 }
@@ -353,9 +350,8 @@
           typeAnalyzerOperations) {
     return [
       "Return type",
-      "declared as '${typeAnalyzerOperations.getDisplayString(declaredType)}'",
-      "used where  '${typeAnalyzerOperations.getDisplayString(contextType)}' "
-          "is required."
+      "declared as '${declaredType.getDisplayString()}'",
+      "used where  '${contextType.getDisplayString()}' is required."
     ];
   }
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart b/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart
index c58d104..23b4270 100644
--- a/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart
@@ -3,6 +3,17 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /// Common interface for data structures used by the implementations to
+/// represent the type `dynamic`.
+abstract interface class SharedDynamicType implements SharedType {}
+
+/// Common interface for data structures used by the implementations to
+/// represent a type resulting from a compile-time error.
+///
+/// The implementations may choose to suppress further errors that arise from
+/// the use of this type.
+abstract interface class SharedInvalidType implements SharedType {}
+
+/// Common interface for data structures used by the implementations to
 /// represent a name/type pair.
 abstract interface class SharedNamedType<Type extends SharedType> {
   String get name;
@@ -21,9 +32,20 @@
 /// Common interface for data structures used by the implementations to
 /// represent a type.
 abstract interface class SharedType {
+  /// Return the presentation of this type as it should appear when presented
+  /// to users in contexts such as error messages.
+  ///
+  /// Clients should not depend on the content of the returned value as it will
+  /// be changed if doing so would improve the UX.
+  String getDisplayString();
+
   bool isStructurallyEqualTo(SharedType other);
 }
 
 /// Common interface for data structures used by the implementations to
 /// represent the unknown type schema (`_`).
 abstract interface class SharedUnknownType implements SharedType {}
+
+/// Common interface for data structures used by the implementations to
+/// represent the type `void`.
+abstract interface class SharedVoidType implements SharedType {}
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index 2452b8e..7529eca 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -2820,9 +2820,6 @@
   }
 
   @override
-  String getDisplayString(Type type) => type.type;
-
-  @override
   NullabilitySuffix getNullabilitySuffix(Type type) {
     if (type is QuestionType) {
       return NullabilitySuffix.question;
@@ -2892,12 +2889,6 @@
   }
 
   @override
-  bool isDynamic(Type type) => type is DynamicType;
-
-  @override
-  bool isError(Type type) => type is InvalidType;
-
-  @override
   bool isExtensionType(Type type) {
     // TODO(cstefantsova): Add the support for extension types in the mini ast
     // testing framework.
@@ -2977,9 +2968,6 @@
   }
 
   @override
-  bool isVoid(Type type) => type is VoidType;
-
-  @override
   TypeSchema iterableTypeSchema(TypeSchema elementTypeSchema) {
     return TypeSchema.fromType(
         PrimaryType('Iterable', args: [elementTypeSchema.toType()]));
diff --git a/pkg/_fe_analyzer_shared/test/mini_types.dart b/pkg/_fe_analyzer_shared/test/mini_types.dart
index 3c6c10a..1209ec3 100644
--- a/pkg/_fe_analyzer_shared/test/mini_types.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_types.dart
@@ -10,7 +10,7 @@
 
 /// Representation of the type `dynamic` suitable for unit testing of code in
 /// the `_fe_analyzer_shared` package.
-class DynamicType extends _SpecialSimpleType {
+class DynamicType extends _SpecialSimpleType implements SharedDynamicType {
   static final instance = DynamicType._();
 
   DynamicType._() : super._('dynamic');
@@ -91,7 +91,7 @@
 
 /// Representation of an invalid type suitable for unit testing of code in the
 /// `_fe_analyzer_shared` package.
-class InvalidType extends _SpecialSimpleType {
+class InvalidType extends _SpecialSimpleType implements SharedInvalidType {
   static final instance = InvalidType._();
 
   InvalidType._() : super._('error');
@@ -437,6 +437,9 @@
   Type? closureWithRespectToUnknown({required bool covariant});
 
   @override
+  String getDisplayString() => type;
+
+  @override
   bool isStructurallyEqualTo(SharedType other) => '$this' == '$other';
 
   /// Finds the nearest type that doesn't involve any type parameter promotion.
@@ -932,7 +935,7 @@
 
 /// Representation of the type `void` suitable for unit testing of code in the
 /// `_fe_analyzer_shared` package.
-class VoidType extends _SpecialSimpleType {
+class VoidType extends _SpecialSimpleType implements SharedVoidType {
   static final instance = VoidType._();
 
   VoidType._() : super._('void');
diff --git a/pkg/analyzer/lib/dart/element/type.dart b/pkg/analyzer/lib/dart/element/type.dart
index 19a7d8c..09d69a1 100644
--- a/pkg/analyzer/lib/dart/element/type.dart
+++ b/pkg/analyzer/lib/dart/element/type.dart
@@ -189,6 +189,7 @@
   ///
   /// Clients should not depend on the content of the returned value as it will
   /// be changed if doing so would improve the UX.
+  @override
   String getDisplayString({
     @Deprecated('Only non-nullable by default mode is supported')
     bool withNullability = true,
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 3bcd224..2c67653 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -31,7 +31,8 @@
 }
 
 /// The [Type] representing the type `dynamic`.
-class DynamicTypeImpl extends TypeImpl implements DynamicType {
+class DynamicTypeImpl extends TypeImpl
+    implements DynamicType, SharedDynamicType {
   /// The unique instance of this class.
   static final DynamicTypeImpl instance = DynamicTypeImpl._();
 
@@ -933,7 +934,8 @@
   }
 }
 
-class InvalidTypeImpl extends TypeImpl implements InvalidType {
+class InvalidTypeImpl extends TypeImpl
+    implements InvalidType, SharedInvalidType {
   /// The unique instance of this class.
   static final InvalidTypeImpl instance = InvalidTypeImpl._();
 
@@ -1544,7 +1546,7 @@
 }
 
 /// A concrete implementation of a [VoidType].
-class VoidTypeImpl extends TypeImpl implements VoidType {
+class VoidTypeImpl extends TypeImpl implements VoidType, SharedVoidType {
   /// The unique instance of this class, with indeterminate nullability.
   static final VoidTypeImpl instance = VoidTypeImpl._();
 
diff --git a/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart b/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
index e0e76c5..3ab8b5c 100644
--- a/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
@@ -178,8 +178,7 @@
 
       // Or if `P` is `dynamic` or `void` and `Object` is a subtype match
       // for `Q0` under constraint set `C`.
-      if (_typeSystemOperations.isDynamic(P) ||
-          _typeSystemOperations.isVoid(P)) {
+      if (P is SharedDynamicType || P is SharedVoidType) {
         if (trySubtypeMatch(_typeSystem.objectNone, Q0, leftSchema,
             nodeForTesting: nodeForTesting)) {
           return true;
@@ -246,8 +245,8 @@
 
     // If `Q` is `dynamic`, `Object?`, or `void` then the match holds under
     // no constraints.
-    if (_typeSystemOperations.isDynamic(Q) ||
-        _typeSystemOperations.isVoid(Q) ||
+    if (Q is SharedDynamicType ||
+        Q is SharedVoidType ||
         Q == _typeSystemOperations.objectQuestionType) {
       return true;
     }
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index bc0ce9f8..19c8cee 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -442,9 +442,6 @@
   }
 
   @override
-  String getDisplayString(DartType type) => type.getDisplayString();
-
-  @override
   NullabilitySuffix getNullabilitySuffix(DartType type) {
     return type.nullabilitySuffix;
   }
@@ -500,12 +497,6 @@
   }
 
   @override
-  bool isDynamic(DartType type) => type is DynamicType;
-
-  @override
-  bool isError(DartType type) => type is InvalidType;
-
-  @override
   bool isExtensionType(DartType type) {
     return type is InterfaceType && type.element is ExtensionTypeElement;
   }
@@ -574,11 +565,6 @@
   }
 
   @override
-  bool isVoid(DartType type) {
-    return identical(type, VoidTypeImpl.instance);
-  }
-
-  @override
   DartType iterableTypeSchema(DartType elementTypeSchema) {
     return typeSystem.typeProvider.iterableType(elementTypeSchema);
   }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
index 6d6c997..2324bb1 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
@@ -9,7 +9,7 @@
     as shared show TypeDeclarationKind, TypeDeclarationMatchResult, Variance;
 
 import 'package:_fe_analyzer_shared/src/types/shared_type.dart'
-    show SharedUnknownType;
+    show SharedDynamicType, SharedUnknownType, SharedVoidType;
 
 import 'package:kernel/ast.dart';
 
@@ -462,7 +462,7 @@
     if (qNullability == NullabilitySuffix.star) {
       final int baseConstraintCount = _protoConstraints.length;
 
-      if ((typeOperations.isDynamic(p) || typeOperations.isVoid(p)) &&
+      if ((p is SharedDynamicType || p is SharedVoidType) &&
           _isNullabilityAwareSubtypeMatch(p,
               typeOperations.withNullabilitySuffix(q, NullabilitySuffix.none),
               constrainSupertype: constrainSupertype,
@@ -471,8 +471,8 @@
       }
       _protoConstraints.length = baseConstraintCount;
 
-      if (!typeOperations.isDynamic(p) &&
-          !typeOperations.isVoid(p) &&
+      if (p is! SharedDynamicType &&
+          p is! SharedVoidType &&
           _isNullabilityAwareSubtypeMatch(
               p,
               typeOperations.withNullabilitySuffix(
@@ -550,7 +550,7 @@
       }
       _protoConstraints.length = baseConstraintCount;
 
-      if ((typeOperations.isDynamic(p) || typeOperations.isVoid(p)) &&
+      if ((p is SharedDynamicType || p is SharedVoidType) &&
           _isNullabilityAwareSubtypeMatch(typeOperations.objectType, rawQ,
               constrainSupertype: constrainSupertype,
               treeNodeForTesting: treeNodeForTesting)) {
@@ -619,8 +619,8 @@
 
     // If Q is dynamic, Object?, or void then the match holds under no
     // constraints.
-    if (typeOperations.isDynamic(q) ||
-        typeOperations.isVoid(q) ||
+    if (q is SharedDynamicType ||
+        q is SharedVoidType ||
         q == typeOperations.objectQuestionType) {
       return true;
     }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
index 3f5dc96..ea82a27 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
@@ -12,7 +12,6 @@
     show ClassHierarchy, ClassHierarchyBase;
 import 'package:kernel/core_types.dart' show CoreTypes;
 import 'package:kernel/src/norm.dart';
-import 'package:kernel/src/printer.dart';
 import 'package:kernel/type_algebra.dart';
 import 'package:kernel/type_environment.dart';
 
@@ -766,12 +765,6 @@
   }
 
   @override
-  bool isDynamic(DartType type) => type is DynamicType;
-
-  @override
-  bool isError(DartType type) => type is InvalidType;
-
-  @override
   bool isFunctionType(DartType type) => type is FunctionType;
 
   @override
@@ -794,9 +787,6 @@
   }
 
   @override
-  bool isVoid(DartType type) => type is VoidType;
-
-  @override
   DartType iterableTypeSchema(DartType elementTypeSchema) {
     return new InterfaceType(typeEnvironment.coreTypes.iterableClass,
         Nullability.nonNullable, <DartType>[elementTypeSchema]);
@@ -963,11 +953,6 @@
   DartType typeToSchema(DartType type) => type;
 
   @override
-  String getDisplayString(DartType type) {
-    return type.toText(const AstTextStrategy());
-  }
-
-  @override
   DartType typeSchemaLub(DartType typeSchema1, DartType typeSchema2) {
     return lub(typeSchema1, typeSchema2);
   }
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index ea9b610..c123c34 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -70,7 +70,13 @@
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart'
     show Variance;
 import 'package:_fe_analyzer_shared/src/types/shared_type.dart'
-    show SharedNamedType, SharedRecordType, SharedType;
+    show
+        SharedDynamicType,
+        SharedInvalidType,
+        SharedNamedType,
+        SharedRecordType,
+        SharedType,
+        SharedVoidType;
 
 import 'src/extension_type_erasure.dart';
 import 'visitor.dart';
@@ -11166,6 +11172,9 @@
   bool equals(Object other, Assumptions? assumptions);
 
   @override
+  String getDisplayString() => toText(const AstTextStrategy());
+
+  @override
   bool isStructurallyEqualTo(SharedType other) {
     // TODO(cstefantsova): Use the actual algorithm for structural equality.
     return this == other;
@@ -11214,7 +11223,7 @@
 ///
 /// Can usually be treated as 'dynamic', but should occasionally be handled
 /// differently, e.g. `x is ERROR` should evaluate to false.
-class InvalidType extends DartType {
+class InvalidType extends DartType implements SharedInvalidType {
   @override
   final int hashCode = 12345;
 
@@ -11267,7 +11276,7 @@
   }
 }
 
-class DynamicType extends DartType {
+class DynamicType extends DartType implements SharedDynamicType {
   @override
   final int hashCode = 54321;
 
@@ -11312,7 +11321,7 @@
   }
 }
 
-class VoidType extends DartType {
+class VoidType extends DartType implements SharedVoidType {
   @override
   final int hashCode = 123121;