Revert "[analyzer][cfe] Expand TypeAnalyzerOperations. Part 1"

This reverts commit a8cf0a08254bce394e16859a884de9ced5539b05.

Reason for revert: The CL broke a few places in google3.

Original change's description:
> [analyzer][cfe] Expand TypeAnalyzerOperations. Part 1
>
> This CL adds more of the type operations required in the subtype
> constraint gathering algorithm into the shared type operation
> class. The added operations are used in the constraint gathering
> algorithms in the Analyzer and the CFE.
>
> Part of https://github.com/dart-lang/sdk/issues/54902
>
> Change-Id: Ia895fc84bd7ab666330a4ab32b6e759f0977e750
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/346840
> Reviewed-by: Johnni Winther <johnniwinther@google.com>
> Reviewed-by: Paul Berry <paulberry@google.com>
> Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>

Change-Id: Ibf75bb6dda4a4f5f36a2265036703977b28a4333
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/353160
Auto-Submit: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/nullability_suffix.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/nullability_suffix.dart
deleted file mode 100644
index 4f7fffa..0000000
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/nullability_suffix.dart
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
-// 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.
-
-/// Suffix indicating the nullability of a type.
-///
-/// This enum describes whether a `?` or `*` would be used at the end of the
-/// canonical representation of a type.  It's subtly different the notions of
-/// "nullable", "non-nullable", "potentially nullable", and "potentially
-/// non-nullable" defined by the spec.  For example, the type `Null` is
-/// nullable, even though it lacks a trailing `?`.
-///
-/// This enum is exposed through the analyzer API, so it should not be modified
-/// without considering the impact on analyzer clients.
-enum NullabilitySuffix {
-  /// An indication that the canonical representation of the type under
-  /// consideration ends with `?`.  Types having this nullability suffix should
-  /// be interpreted as being unioned with the Null type.
-  question,
-
-  /// An indication that the canonical representation of the type under
-  /// consideration ends with `*`.  Types having this nullability suffix are
-  /// called "legacy types"; it has not yet been determined whether they should
-  /// be unioned with the Null type.
-  star,
-
-  /// An indication that the canonical representation of the type under
-  /// consideration does not end with either `?` or `*`.
-  none
-}
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 adb22c5..646a9c9 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
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import '../flow_analysis/flow_analysis_operations.dart';
-import 'nullability_suffix.dart';
 
 class RecordType<Type extends Object> {
   final List<Type> positional;
@@ -15,23 +14,6 @@
   });
 }
 
-/// Describes all possibility for a type to be derived from a declaration.
-///
-/// This enum is intended to exhaustively handle all possibilities for a type to
-/// be derived from a type declaration. Currently, there are two such kinds of
-/// declarations: declarations inducing interfaces for dynamic dispatch (such as
-/// classes, mixins, and enums), and extension types.
-enum TypeDeclarationKind {
-  /// Indication that the type is derived from a declaration inducing interface.
-  ///
-  /// An example of such declaration can be a class declaration, a mixin
-  /// declaration, or an enum declaration.
-  interfaceDeclaration,
-
-  /// Indication that the type is derived from an extension type declaration.
-  extensionTypeDeclaration,
-}
-
 /// Callback API used by the shared type analyzer to query and manipulate the
 /// client's representation of variables and types.
 abstract interface class TypeAnalyzerOperations<Variable extends Object,
@@ -52,15 +34,9 @@
   /// Returns the type `Never`.
   Type get neverType;
 
-  /// Returns the type `Null`.
-  Type get nullType;
-
   /// Returns the type `Object?`.
   Type get objectQuestionType;
 
-  /// Returns the type `Object`.
-  Type get objectType;
-
   /// Returns the unknown type schema (`_`) used in type inference.
   TypeSchema get unknownType;
 
@@ -70,29 +46,6 @@
   /// If [type] is a record type, returns it.
   RecordType<Type>? asRecordType(Type type);
 
-  /// Returns the nullability modifier of [type].
-  NullabilitySuffix getNullabilitySuffix(Type type);
-
-  /// If [type] was introduced by a class, mixin, enum, or extension type,
-  /// returns a [TypeDeclarationKind] indicating what kind of thing it was
-  /// introduced by. Otherwise, returns `null`.
-  ///
-  /// Examples of types derived from a class declarations are `A`, `A?`, `A*`,
-  /// `B<T, S>`, where `A` and `B` are the names of class declarations or
-  /// extension type declarations, `T` and `S` are types.
-  TypeDeclarationKind? getTypeDeclarationKind(Type type);
-
-  /// If at top level [typeSchema] describes a type that was introduced by a
-  /// class, mixin, enum, or extension type, returns a [TypeDeclarationKind]
-  /// indicating what kind of thing it was introduced by. Otherwise, returns
-  /// `null`.
-  ///
-  /// Examples of type schemas at top level describing types derived from a
-  /// declaration are `A`, `A?`, `A*`, `B<T, S>`, `B<_, B<_, _>>?`, where `A`
-  /// and `B` are class declarations or extension type declarations, `T` and
-  /// `S` are type schemas.
-  TypeDeclarationKind? getTypeSchemaDeclarationKind(TypeSchema typeSchema);
-
   /// Computes the greatest lower bound of [type1] and [type2].
   Type glb(Type type1, Type type2);
 
@@ -111,45 +64,14 @@
   bool isTypeSchemaSatisfied(
       {required TypeSchema typeSchema, required Type type});
 
-  /// Returns `true` if [type] is `F`, `F?`, or `F*` for some function type `F`.
-  bool isFunctionType(Type type);
-
-  /// If [type] takes the form `FutureOr<T>`, `FutureOr<T>?`, or `FutureOr<T>*`
-  /// for some `T`, returns the type `T`. Otherwise returns `null`.
-  Type? matchFutureOr(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.
-  bool isExtensionType(Type type);
-
-  /// Returns `true` if [type] is `A<T1, ..., Tn>`, `A<T1, ..., Tn>?`, or
-  /// `A<T1, ..., Tn>*` for some class, mixin, or enum A, some non-negative n,
-  /// and some types T1, ..., Tn. The method returns `false` if [type] is an
-  /// extension type, a type alias, `Null`, `Never`, or `FutureOr<X>` for any
-  /// type `X`.
-  bool isInterfaceType(Type type);
-
-  /// Returns `true` if [type] is `Null`.
-  bool isNull(Type Type);
-
-  /// Returns `true` if [type] is `Object` from `dart:core`. The method returns
-  /// `false` for `Object?` and `Object*`.
-  bool isObject(Type type);
-
-  /// Returns `true` if [type] is `R`, `R?`, or `R*` for some record type `R`.
-  bool isRecordType(Type type);
-
-  /// Returns `true` if [typeSchema] is the unknown type schema (`_`).
-  bool isUnknownType(TypeSchema typeSchema);
+  /// Returns `true` if [type] is the unknown type context (`_`).
+  bool isUnknownType(Type type);
 
   /// 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.
+  /// Returns the type schema `Iterable`, with type argument
+  /// [elementTypeSchema].
   TypeSchema iterableTypeSchema(TypeSchema elementTypeSchema);
 
   /// Returns the type `List`, with type argument [elementType].
@@ -225,7 +147,4 @@
 
   /// Converts a type into a corresponding type schema.
   TypeSchema typeToSchema(Type type);
-
-  /// Returns [type] suffixed with the [suffix].
-  Type withNullabilitySuffix(Type type, NullabilitySuffix suffix);
 }
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index ec34a04..9a5c2a3 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -19,7 +19,6 @@
         ThisPropertyTarget;
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis_operations.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/assigned_variables.dart';
-import 'package:_fe_analyzer_shared/src/type_inference/nullability_suffix.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart'
     as shared;
 import 'package:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart';
@@ -2679,9 +2678,6 @@
   late final Type objectQuestionType = Type('Object?');
 
   @override
-  late final Type objectType = Type('Object');
-
-  @override
   late final TypeSchema unknownType = TypeSchema('_');
 
   @override
@@ -2691,9 +2687,6 @@
   late final Type neverType = Type('Never');
 
   @override
-  late final Type nullType = Type('Null');
-
-  @override
   late final Type doubleType = Type('double');
 
   @override
@@ -2821,33 +2814,6 @@
   }
 
   @override
-  NullabilitySuffix getNullabilitySuffix(Type type) {
-    if (type is QuestionType) {
-      return NullabilitySuffix.question;
-    } else if (type is StarType) {
-      return NullabilitySuffix.star;
-    } else {
-      return NullabilitySuffix.none;
-    }
-  }
-
-  @override
-  TypeDeclarationKind? getTypeDeclarationKind(Type type) {
-    if (isInterfaceType(type)) {
-      return TypeDeclarationKind.interfaceDeclaration;
-    } else if (isExtensionType(type)) {
-      return TypeDeclarationKind.extensionTypeDeclaration;
-    } else {
-      return null;
-    }
-  }
-
-  @override
-  TypeDeclarationKind? getTypeSchemaDeclarationKind(TypeSchema typeSchema) {
-    return getTypeDeclarationKind(typeSchema.toType());
-  }
-
-  @override
   Type glb(Type type1, Type type2) {
     if (type1.type == type2.type) return type1;
     var typeNames = [type1.type, type2.type];
@@ -2876,63 +2842,19 @@
       type is PrimaryType && type.name == 'dynamic' && type.args.isEmpty;
 
   @override
-  bool isFunctionType(Type type) {
-    return withNullabilitySuffix(type, NullabilitySuffix.none) is FunctionType;
-  }
-
-  @override
-  Type? matchFutureOr(Type type) {
-    Type underlyingType = withNullabilitySuffix(type, NullabilitySuffix.none);
-    if (underlyingType is PrimaryType && underlyingType.args.length == 1) {
-      if (underlyingType.name == 'FutureOr') {
-        return underlyingType.args[0];
-      }
-    }
-    return null;
-  }
-
-  @override
   bool isError(Type type) =>
       type is PrimaryType && type.name == 'error' && type.args.isEmpty;
 
   @override
-  bool isExtensionType(Type type) {
-    // TODO(cstefantsova): Add the support for extension types in the mini ast
-    // testing framework.
-    return false;
-  }
-
-  @override
-  bool isInterfaceType(Type type) {
-    Type underlyingType = withNullabilitySuffix(type, NullabilitySuffix.none);
-    return underlyingType is PrimaryType && underlyingType.isInterfaceType;
-  }
-
-  @override
   bool isNever(Type type) {
     return type.type == 'Never';
   }
 
   @override
-  bool isNull(Type type) {
-    return type.type == 'Null';
-  }
-
-  @override
-  bool isObject(Type type) {
-    return type is PrimaryType && type.name == 'Object' && type.args.isEmpty;
-  }
-
-  @override
   bool isPropertyPromotable(covariant _PropertyElement property) =>
       property.isPromotable;
 
   @override
-  bool isRecordType(Type type) {
-    return withNullabilitySuffix(type, NullabilitySuffix.none) is RecordType;
-  }
-
-  @override
   bool isSameType(Type type1, Type type2) {
     return type1.type == type2.type;
   }
@@ -2951,7 +2873,7 @@
       isSubtypeOf(type, typeSchema.toType());
 
   @override
-  bool isUnknownType(TypeSchema typeSchema) => typeSchema is UnknownType;
+  bool isUnknownType(Type type) => type is UnknownType;
 
   @override
   bool isVariableFinal(Var node) {
@@ -2959,10 +2881,6 @@
   }
 
   @override
-  bool isVoid(Type type) =>
-      type is PrimaryType && type.name == 'void' && type.args.isEmpty;
-
-  @override
   TypeSchema iterableTypeSchema(TypeSchema elementTypeSchema) {
     return TypeSchema.fromType(
         PrimaryType('Iterable', args: [elementTypeSchema.toType()]));
@@ -3150,36 +3068,6 @@
   PropertyNonPromotabilityReason? whyPropertyIsNotPromotable(
           covariant _PropertyElement property) =>
       property.whyNotPromotable;
-
-  @override
-  Type withNullabilitySuffix(Type type, NullabilitySuffix modifier) {
-    switch (modifier) {
-      case NullabilitySuffix.none:
-        if (type is QuestionType) {
-          return type.innerType;
-        } else if (type is StarType) {
-          return type.innerType;
-        } else {
-          return type;
-        }
-      case NullabilitySuffix.question:
-        if (type is QuestionType) {
-          return type;
-        } else if (type is StarType) {
-          return QuestionType(type.innerType);
-        } else {
-          return QuestionType(type);
-        }
-      case NullabilitySuffix.star:
-        if (type is QuestionType) {
-          return StarType(type.innerType);
-        } else if (type is StarType) {
-          return type;
-        } else {
-          return StarType(type);
-        }
-    }
-  }
 }
 
 /// Representation of an expression or statement in the pseudo-Dart language
diff --git a/pkg/_fe_analyzer_shared/test/mini_types.dart b/pkg/_fe_analyzer_shared/test/mini_types.dart
index 1bafd10..8800c75 100644
--- a/pkg/_fe_analyzer_shared/test/mini_types.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_types.dart
@@ -60,14 +60,6 @@
 /// reference to a type parameter, or one of the special types whose name is a
 /// single word (e.g. `dynamic`).
 class PrimaryType extends Type {
-  /// Names of primary types not originating from a class, a mixin, or an enum.
-  static const List<String> namedNonInterfaceTypes = [
-    'FutureOr',
-    'Never',
-    'Null',
-    'dynamic',
-  ];
-
   /// The name of the type.
   final String name;
 
@@ -76,8 +68,6 @@
 
   PrimaryType(this.name, {this.args = const []}) : super._();
 
-  bool get isInterfaceType => !namedNonInterfaceTypes.contains(name);
-
   @override
   Type? recursivelyDemote({required bool covariant}) {
     List<Type>? newArgs = args.recursivelyDemote(covariant: covariant);
diff --git a/pkg/analyzer/lib/dart/element/nullability_suffix.dart b/pkg/analyzer/lib/dart/element/nullability_suffix.dart
index ac63891..59a7759 100644
--- a/pkg/analyzer/lib/dart/element/nullability_suffix.dart
+++ b/pkg/analyzer/lib/dart/element/nullability_suffix.dart
@@ -1,6 +1,27 @@
-// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
 // 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.
 
-export 'package:_fe_analyzer_shared/src/type_inference/nullability_suffix.dart'
-    show NullabilitySuffix;
+/// Suffix indicating the nullability of a type.
+///
+/// This enum describes whether a `?` or `*` would be used at the end of the
+/// canonical representation of a type.  It's subtly different the notions of
+/// "nullable", "non-nullable", "potentially nullable", and "potentially
+/// non-nullable" defined by the spec.  For example, the type `Null` is
+/// nullable, even though it lacks a trailing `?`.
+enum NullabilitySuffix {
+  /// An indication that the canonical representation of the type under
+  /// consideration ends with `?`.  Types having this nullability suffix should
+  /// be interpreted as being unioned with the Null type.
+  question,
+
+  /// An indication that the canonical representation of the type under
+  /// consideration ends with `*`.  Types having this nullability suffix are
+  /// called "legacy types"; it has not yet been determined whether they should
+  /// be unioned with the Null type.
+  star,
+
+  /// An indication that the canonical representation of the type under
+  /// consideration does not end with either `?` or `*`.
+  none
+}
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 d3804b9..4f4756c 100644
--- a/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
@@ -2,9 +2,8 @@
 // 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/type_inference/type_analyzer_operations.dart'
-    show TypeDeclarationKind;
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
@@ -103,21 +102,21 @@
 
     // If `P` is a type variable `X` in `L`, then the match holds:
     //   Under constraint `_ <: X <: Q`.
-    var P_nullability = _typeSystemOperations.getNullabilitySuffix(P);
-    if (_typeSystemOperations.isTypeParameterType(P) &&
+    var P_nullability = P.nullabilitySuffix;
+    if (P is TypeParameterType &&
         P_nullability == NullabilitySuffix.none &&
         _typeParameters.contains(P.element)) {
-      _addUpper(P.element as TypeParameterElement, Q);
+      _addUpper(P.element, Q);
       return true;
     }
 
     // If `Q` is a type variable `X` in `L`, then the match holds:
     //   Under constraint `P <: X <: _`.
-    var Q_nullability = _typeSystemOperations.getNullabilitySuffix(Q);
-    if (_typeSystemOperations.isTypeParameterType(Q) &&
+    var Q_nullability = Q.nullabilitySuffix;
+    if (Q is TypeParameterType &&
         Q_nullability == NullabilitySuffix.none &&
         _typeParameters.contains(Q.element)) {
-      _addLower(Q.element as TypeParameterElement, P);
+      _addLower(Q.element, P);
       return true;
     }
 
@@ -140,8 +139,8 @@
     if (Q_nullability == NullabilitySuffix.star) {
       // If `P` is `dynamic` or `void` and `P` is a subtype match
       // for `Q0` under constraint set `C`.
-      if (_typeSystemOperations.isDynamic(P) ||
-          _typeSystemOperations.isVoid(P)) {
+      if (identical(P, DynamicTypeImpl.instance) ||
+          identical(P, VoidTypeImpl.instance)) {
         var rewind = _constraints.length;
         var Q0 = (Q as TypeImpl).withNullability(NullabilitySuffix.none);
         if (trySubtypeMatch(P, Q0, leftSchema)) {
@@ -155,14 +154,18 @@
     }
 
     // If `Q` is `FutureOr<Q0>` the match holds under constraint set `C`:
-    if (_typeSystemOperations.matchFutureOr(Q) case var Q0?
-        when Q_nullability == NullabilitySuffix.none) {
+    if (Q_nullability == NullabilitySuffix.none &&
+        Q is InterfaceType &&
+        Q.isDartAsyncFutureOr) {
+      var Q0 = Q.typeArguments[0];
       var rewind = _constraints.length;
 
       // If `P` is `FutureOr<P0>` and `P0` is a subtype match for `Q0` under
       // constraint set `C`.
-      if (_typeSystemOperations.matchFutureOr(P) case var P0?
-          when P_nullability == NullabilitySuffix.none) {
+      if (P_nullability == NullabilitySuffix.none &&
+          P is InterfaceType &&
+          P.isDartAsyncFutureOr) {
+        var P0 = P.typeArguments[0];
         if (trySubtypeMatch(P0, Q0, leftSchema)) {
           return true;
         }
@@ -193,15 +196,13 @@
 
     // If `Q` is `Q0?` the match holds under constraint set `C`:
     if (Q_nullability == NullabilitySuffix.question) {
-      var Q0 = _typeSystemOperations.withNullabilitySuffix(
-          Q, NullabilitySuffix.none);
+      var Q0 = (Q as TypeImpl).withNullability(NullabilitySuffix.none);
       var rewind = _constraints.length;
 
       // If `P` is `P0?` and `P0` is a subtype match for `Q0` under
       // constraint set `C`.
       if (P_nullability == NullabilitySuffix.question) {
-        var P0 = _typeSystemOperations.withNullabilitySuffix(
-            P, NullabilitySuffix.none);
+        var P0 = (P as TypeImpl).withNullability(NullabilitySuffix.none);
         if (trySubtypeMatch(P0, Q0, leftSchema)) {
           return true;
         }
@@ -210,8 +211,8 @@
 
       // 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 (identical(P, DynamicTypeImpl.instance) ||
+          identical(P, VoidTypeImpl.instance)) {
         if (trySubtypeMatch(_typeSystem.objectNone, Q0, leftSchema)) {
           return true;
         }
@@ -240,8 +241,10 @@
     }
 
     // If `P` is `FutureOr<P0>` the match holds under constraint set `C1 + C2`:
-    if (_typeSystemOperations.matchFutureOr(P) case var P0?
-        when P_nullability == NullabilitySuffix.none) {
+    if (P_nullability == NullabilitySuffix.none &&
+        P is InterfaceType &&
+        P.isDartAsyncFutureOr) {
+      var P0 = P.typeArguments[0];
       var rewind = _constraints.length;
 
       // If `Future<P0>` is a subtype match for `Q` under constraint set `C1`.
@@ -257,8 +260,7 @@
 
     // If `P` is `P0?` the match holds under constraint set `C1 + C2`:
     if (P_nullability == NullabilitySuffix.question) {
-      var P0 = _typeSystemOperations.withNullabilitySuffix(
-          P, NullabilitySuffix.none);
+      var P0 = (P as TypeImpl).withNullability(NullabilitySuffix.none);
       var rewind = _constraints.length;
 
       // If `P0` is a subtype match for `Q` under constraint set `C1`.
@@ -273,27 +275,26 @@
 
     // If `Q` is `dynamic`, `Object?`, or `void` then the match holds under
     // no constraints.
-    if (_typeSystemOperations.isDynamic(Q) ||
-        _typeSystemOperations.isVoid(Q) ||
-        Q == _typeSystemOperations.objectQuestionType) {
+    if (identical(Q, DynamicTypeImpl.instance) ||
+        identical(Q, VoidTypeImpl.instance) ||
+        Q_nullability == NullabilitySuffix.question && Q.isDartCoreObject) {
       return true;
     }
 
     // If `P` is `Never` then the match holds under no constraints.
-    if (_typeSystemOperations.isNever(P)) {
+    if (identical(P, NeverTypeImpl.instance)) {
       return true;
     }
 
     // If `Q` is `Object`, then the match holds under no constraints:
     //  Only if `P` is non-nullable.
-    if (Q == _typeSystemOperations.objectType) {
+    if (Q_nullability == NullabilitySuffix.none && Q.isDartCoreObject) {
       return _typeSystem.isNonNullable(P);
     }
 
     // If `P` is `Null`, then the match holds under no constraints:
     //  Only if `Q` is nullable.
-    if (P_nullability == NullabilitySuffix.none &&
-        _typeSystemOperations.isNull(P)) {
+    if (P_nullability == NullabilitySuffix.none && P.isDartCoreNull) {
       return _typeSystem.isNullable(Q);
     }
 
@@ -310,70 +311,33 @@
       _constraints.length = rewind;
     }
 
-    TypeDeclarationKind? P_typeDeclarationKind =
-        _typeSystemOperations.getTypeDeclarationKind(P);
-    TypeDeclarationKind? Q_typeDeclarationKind =
-        _typeSystemOperations.getTypeDeclarationKind(Q);
-    if (P_typeDeclarationKind == TypeDeclarationKind.interfaceDeclaration &&
-        Q_typeDeclarationKind == TypeDeclarationKind.interfaceDeclaration) {
-      // If `P` is `C<M0, ..., Mk> and `Q` is `C<N0, ..., Nk>`, then the match
-      // holds under constraints `C0 + ... + Ck`:
-      //   If `Mi` is a subtype match for `Ni` with respect to L under
-      //   constraints `Ci`.
-      if (P.element == Q.element) {
-        if (!_interfaceType_arguments(
-            P as InterfaceType, Q as InterfaceType, leftSchema)) {
-          return false;
-        }
-        return true;
-      }
-      return _interfaceType(P as InterfaceType, Q as InterfaceType, leftSchema);
-    } else if (P_typeDeclarationKind ==
-            TypeDeclarationKind.extensionTypeDeclaration &&
-        Q_typeDeclarationKind == TypeDeclarationKind.extensionTypeDeclaration) {
-      // If `P` is `C<M0, ..., Mk> and `Q` is `C<N0, ..., Nk>`, then the match
-      // holds under constraints `C0 + ... + Ck`:
-      //   If `Mi` is a subtype match for `Ni` with respect to L under
-      //   constraints `Ci`.
-      if (P.element == Q.element) {
-        if (!_interfaceType_arguments(
-            P as InterfaceType, Q as InterfaceType, leftSchema)) {
-          return false;
-        }
-        return true;
-      }
-      return _interfaceType(P as InterfaceType, Q as InterfaceType, leftSchema);
-    }
-
-    if (P_typeDeclarationKind != null && Q_typeDeclarationKind != null) {
-      return _interfaceType(P as InterfaceType, Q as InterfaceType, leftSchema);
+    if (P is InterfaceType && Q is InterfaceType) {
+      return _interfaceType(P, Q, leftSchema);
     }
 
     // If `Q` is `Function` then the match holds under no constraints:
     //   If `P` is a function type.
     if (Q_nullability == NullabilitySuffix.none && Q.isDartCoreFunction) {
-      if (_typeSystemOperations.isFunctionType(P)) {
+      if (P is FunctionType) {
         return true;
       }
     }
 
-    if (_typeSystemOperations.isFunctionType(P) &&
-        _typeSystemOperations.isFunctionType(Q)) {
-      return _functionType(P as FunctionType, Q as FunctionType, leftSchema);
+    if (P is FunctionType && Q is FunctionType) {
+      return _functionType(P, Q, leftSchema);
     }
 
     // A type `P` is a subtype match for `Record` with respect to `L` under no
     // constraints:
     //   If `P` is a record type or `Record`.
     if (Q_nullability == NullabilitySuffix.none && Q.isDartCoreRecord) {
-      if (_typeSystemOperations.isRecordType(P)) {
+      if (P is RecordType) {
         return true;
       }
     }
 
-    if (_typeSystemOperations.isRecordType(P) &&
-        _typeSystemOperations.isRecordType(Q)) {
-      return _recordType(P as RecordTypeImpl, Q as RecordTypeImpl, leftSchema);
+    if (P is RecordTypeImpl && Q is RecordTypeImpl) {
+      return _recordType(P, Q, leftSchema);
     }
 
     return false;
@@ -584,6 +548,17 @@
       return false;
     }
 
+    // If `P` is `C<M0, ..., Mk> and `Q` is `C<N0, ..., Nk>`, then the match
+    // holds under constraints `C0 + ... + Ck`:
+    //   If `Mi` is a subtype match for `Ni` with respect to L under
+    //   constraints `Ci`.
+    if (P.element == Q.element) {
+      if (!_interfaceType_arguments(P, Q, leftSchema)) {
+        return false;
+      }
+      return true;
+    }
+
     // If `P` is `C0<M0, ..., Mk>` and `Q` is `C1<N0, ..., Nj>` then the match
     // holds with respect to `L` under constraints `C`:
     //   If `C1<B0, ..., Bj>` is a superinterface of `C0<M0, ..., Mk>` and
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart
index 2177237..446665f 100644
--- a/pkg/analyzer/lib/src/dart/element/type_system.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -7,6 +7,7 @@
 import 'package:analyzer/dart/ast/ast.dart' show AstNode;
 import 'package:analyzer/dart/ast/token.dart' show TokenType;
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
 import 'package:analyzer/dart/element/type_system.dart';
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 fdf2054..a4ed4af 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -23,9 +23,6 @@
 import 'package:analyzer/src/dart/element/type_system.dart' show TypeSystemImpl;
 import 'package:analyzer/src/generated/variable_type_provider.dart';
 
-export 'package:_fe_analyzer_shared/src/type_inference/nullability_suffix.dart'
-    show NullabilitySuffix;
-
 /// Data gathered by flow analysis, retained for testing purposes.
 class FlowAnalysisDataForTesting {
   /// The list of nodes, [Expression]s or [Statement]s, that cannot be reached,
@@ -404,15 +401,9 @@
   DartType get neverType => typeSystem.typeProvider.neverType;
 
   @override
-  DartType get nullType => typeSystem.typeProvider.nullType;
-
-  @override
   DartType get objectQuestionType => typeSystem.objectQuestion;
 
   @override
-  DartType get objectType => typeSystem.objectNone;
-
-  @override
   DartType get unknownType => UnknownInferredType.instance;
 
   @override
@@ -454,27 +445,6 @@
   }
 
   @override
-  NullabilitySuffix getNullabilitySuffix(DartType type) {
-    return type.nullabilitySuffix;
-  }
-
-  @override
-  TypeDeclarationKind? getTypeDeclarationKind(DartType type) {
-    if (isInterfaceType(type)) {
-      return TypeDeclarationKind.interfaceDeclaration;
-    } else if (isExtensionType(type)) {
-      return TypeDeclarationKind.extensionTypeDeclaration;
-    } else {
-      return null;
-    }
-  }
-
-  @override
-  TypeDeclarationKind? getTypeSchemaDeclarationKind(DartType typeSchema) {
-    return getTypeDeclarationKind(typeSchema);
-  }
-
-  @override
   DartType glb(DartType type1, DartType type2) {
     return typeSystem.greatestLowerBound(type1, type2);
   }
@@ -497,40 +467,11 @@
   bool isError(DartType type) => type is InvalidType;
 
   @override
-  bool isExtensionType(DartType type) {
-    return type is InterfaceType && type.element is ExtensionTypeElement;
-  }
-
-  @override
-  bool isFunctionType(DartType type) {
-    return type is FunctionType;
-  }
-
-  @override
-  bool isInterfaceType(DartType type) {
-    return type is InterfaceType &&
-        !type.isDartCoreNull &&
-        !type.isDartAsyncFutureOr &&
-        type.element is! ExtensionTypeElement;
-  }
-
-  @override
   bool isNever(DartType type) {
     return typeSystem.isBottom(type);
   }
 
   @override
-  bool isNull(DartType type) {
-    return type.isDartCoreNull;
-  }
-
-  @override
-  bool isObject(DartType type) {
-    return type.isDartCoreObject &&
-        type.nullabilitySuffix == NullabilitySuffix.none;
-  }
-
-  @override
   bool isPropertyPromotable(Object property) {
     if (property is! PropertyAccessorElement) return false;
     var field = property.variable;
@@ -539,9 +480,6 @@
   }
 
   @override
-  bool isRecordType(DartType type) => type is RecordType;
-
-  @override
   bool isSameType(covariant TypeImpl type1, covariant TypeImpl type2) {
     return type1 == type2;
   }
@@ -560,8 +498,8 @@
       isSubtypeOf(type, typeSchema);
 
   @override
-  bool isUnknownType(DartType typeSchema) {
-    return identical(typeSchema, UnknownInferredType.instance);
+  bool isUnknownType(DartType type) {
+    return identical(type, UnknownInferredType.instance);
   }
 
   @override
@@ -570,11 +508,6 @@
   }
 
   @override
-  bool isVoid(DartType type) {
-    return identical(type, VoidTypeImpl.instance);
-  }
-
-  @override
   DartType iterableTypeSchema(DartType elementTypeSchema) {
     return typeSystem.typeProvider.iterableType(elementTypeSchema);
   }
@@ -621,15 +554,6 @@
   }
 
   @override
-  DartType? matchFutureOr(DartType type) {
-    if (type is InterfaceType && type.isDartAsyncFutureOr) {
-      return type.typeArguments[0];
-    } else {
-      return null;
-    }
-  }
-
-  @override
   DartType? matchIterableType(DartType type) {
     var iterableElement = typeSystem.typeProvider.iterableElement;
     var listType = type.asInstanceOf(iterableElement);
@@ -751,11 +675,6 @@
     // declaration, or because field promotion is disabled.
     return null;
   }
-
-  @override
-  DartType withNullabilitySuffix(DartType type, NullabilitySuffix suffix) {
-    return (type as TypeImpl).withNullability(suffix);
-  }
 }
 
 /// The visitor that gathers local variables that are potentially assigned
diff --git a/pkg/analyzer/lib/src/dart/resolver/named_type_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/named_type_resolver.dart
index 305b8f3..90fe457 100644
--- a/pkg/analyzer/lib/src/dart/resolver/named_type_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/named_type_resolver.dart
@@ -5,6 +5,7 @@
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/scope.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/error.dart';
diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
index 82f3b50..e1de80e 100644
--- a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/scope.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
diff --git a/pkg/analyzer/lib/src/error/dead_code_verifier.dart b/pkg/analyzer/lib/src/error/dead_code_verifier.dart
index 8098e90..b9ae8164 100644
--- a/pkg/analyzer/lib/src/error/dead_code_verifier.dart
+++ b/pkg/analyzer/lib/src/error/dead_code_verifier.dart
@@ -6,6 +6,7 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 0cda82f..3e6c9e1 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -11,6 +11,7 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
 import 'package:analyzer/diagnostic/diagnostic.dart';
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 2d6f924..caea4d8 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -20,6 +20,7 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/scope.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
diff --git a/pkg/analyzer/lib/src/summary2/types_builder.dart b/pkg/analyzer/lib/src/summary2/types_builder.dart
index 1497a40..1599bac 100644
--- a/pkg/analyzer/lib/src/summary2/types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/types_builder.dart
@@ -4,6 +4,7 @@
 
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/extensions.dart';
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 50451e8..8259e27 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
@@ -2,12 +2,6 @@
 // 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/type_inference/nullability_suffix.dart'
-    show NullabilitySuffix;
-
-import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart'
-    show TypeDeclarationKind;
-
 import 'package:kernel/ast.dart';
 
 import 'package:kernel/type_algebra.dart';
@@ -260,6 +254,14 @@
     return true;
   }
 
+  bool _isNull(DartType type) {
+    // TODO(paulberry): would it be better to call this "_isBottom", and to have
+    // it return `true` for both Null and bottom types?  Revisit this once
+    // enough functionality is implemented that we can compare the behavior with
+    // the old analyzer-based implementation.
+    return type is NullType;
+  }
+
   /// Whether the [subtype] interface is a subtype of the [supertype] interface
   /// with respect to variance.
   ///
@@ -473,9 +475,12 @@
     // If P is a legacy type P0* then the match holds under constraint set C:
     //
     // Only if P0 is a subtype match for Q under constraint set C.
-    if (_typeOperations.getNullabilitySuffix(p) == NullabilitySuffix.star) {
+    if (isLegacyTypeConstructorApplication(p,
+        isNonNullableByDefault: _isNonNullableByDefault)) {
       return _isNullabilityAwareSubtypeMatch(
-          _typeOperations.withNullabilitySuffix(p, NullabilitySuffix.none), q,
+          computeTypeWithoutNullabilityMarker(p,
+              isNonNullableByDefault: _isNonNullableByDefault),
+          q,
           constrainSupertype: constrainSupertype);
     }
 
@@ -485,23 +490,24 @@
     // set C.
     // Or if P is not dynamic or void and P is a subtype match for Q0? under
     // constraint set C.
-    if (_typeOperations.getNullabilitySuffix(q) == NullabilitySuffix.star) {
+    if (isLegacyTypeConstructorApplication(q,
+        isNonNullableByDefault: _isNonNullableByDefault)) {
       final int baseConstraintCount = _protoConstraints.length;
 
-      if ((_typeOperations.isDynamic(p) || _typeOperations.isVoid(p)) &&
-          _isNullabilityAwareSubtypeMatch(p,
-              _typeOperations.withNullabilitySuffix(q, NullabilitySuffix.none),
+      if ((p is DynamicType || p is VoidType) &&
+          _isNullabilityAwareSubtypeMatch(
+              p,
+              computeTypeWithoutNullabilityMarker(q,
+                  isNonNullableByDefault: _isNonNullableByDefault),
               constrainSupertype: constrainSupertype)) {
         return true;
       }
       _protoConstraints.length = baseConstraintCount;
 
-      if (!_typeOperations.isDynamic(p) &&
-          !_typeOperations.isVoid(p) &&
+      if (p is! DynamicType &&
+          p is! VoidType &&
           _isNullabilityAwareSubtypeMatch(
-              p,
-              _typeOperations.withNullabilitySuffix(
-                  q, NullabilitySuffix.question),
+              p, q.withDeclaredNullability(Nullability.nullable),
               constrainSupertype: constrainSupertype)) {
         return true;
       }
@@ -515,21 +521,18 @@
     // constraint set C.  Or if P is a subtype match for Q0 under constraint set
     // C.  Or if P is a subtype match for Future<Q0> under empty constraint set
     // C.
-    if (_typeOperations.matchFutureOr(q) != null) {
+    if (q is FutureOrType) {
       final int baseConstraintCount = _protoConstraints.length;
 
       if (p is FutureOrType &&
-          _isNullabilityAwareSubtypeMatch(
-              p.typeArgument, (q as FutureOrType).typeArgument,
+          _isNullabilityAwareSubtypeMatch(p.typeArgument, q.typeArgument,
               constrainSupertype: constrainSupertype)) {
         return true;
       }
       _protoConstraints.length = baseConstraintCount;
 
       bool isMatchWithFuture = _isNullabilityAwareSubtypeMatch(
-          p,
-          _environment.futureType(
-              (q as FutureOrType).typeArgument, Nullability.nonNullable),
+          p, _environment.futureType(q.typeArgument, Nullability.nonNullable),
           constrainSupertype: constrainSupertype);
       bool matchWithFutureAddsConstraints =
           _protoConstraints.length != baseConstraintCount;
@@ -558,23 +561,23 @@
     // Or if P is a subtype match for Q0 under non-empty constraint set C.
     // Or if P is a subtype match for Null under constraint set C.
     // Or if P is a subtype match for Q0 under empty constraint set C.
-    if (_typeOperations.getNullabilitySuffix(q) == NullabilitySuffix.question) {
+    if (isNullableTypeConstructorApplication(q)) {
       final int baseConstraintCount = _protoConstraints.length;
-      final DartType rawP =
-          _typeOperations.withNullabilitySuffix(p, NullabilitySuffix.none);
-      final DartType rawQ =
-          _typeOperations.withNullabilitySuffix(q, NullabilitySuffix.none);
+      final DartType rawP = computeTypeWithoutNullabilityMarker(p,
+          isNonNullableByDefault: _isNonNullableByDefault);
+      final DartType rawQ = computeTypeWithoutNullabilityMarker(q,
+          isNonNullableByDefault: _isNonNullableByDefault);
 
-      if (_typeOperations.getNullabilitySuffix(p) ==
-              NullabilitySuffix.question &&
+      if (isNullableTypeConstructorApplication(p) &&
           _isNullabilityAwareSubtypeMatch(rawP, rawQ,
               constrainSupertype: constrainSupertype)) {
         return true;
       }
       _protoConstraints.length = baseConstraintCount;
 
-      if ((_typeOperations.isDynamic(p) || _typeOperations.isVoid(p)) &&
-          _isNullabilityAwareSubtypeMatch(_typeOperations.objectType, rawQ,
+      if ((p is DynamicType || p is VoidType) &&
+          _isNullabilityAwareSubtypeMatch(
+              _environment.coreTypes.objectNonNullableRawType, rawQ,
               constrainSupertype: constrainSupertype)) {
         return true;
       }
@@ -589,7 +592,7 @@
       }
       _protoConstraints.length = baseConstraintCount;
 
-      if (_isNullabilityAwareSubtypeMatch(p, _typeOperations.nullType,
+      if (_isNullabilityAwareSubtypeMatch(p, const NullType(),
           constrainSupertype: constrainSupertype)) {
         return true;
       }
@@ -605,11 +608,10 @@
     //
     // If Future<P0> is a subtype match for Q under constraint set C1.
     // And if P0 is a subtype match for Q under constraint set C2.
-    if (_typeOperations.matchFutureOr(p) != null) {
+    if (p is FutureOrType) {
       final int baseConstraintCount = _protoConstraints.length;
       if (_isNullabilityAwareSubtypeMatch(
-              _environment.futureType(
-                  (p as FutureOrType).typeArgument, Nullability.nonNullable),
+              _environment.futureType(p.typeArgument, Nullability.nonNullable),
               q,
               constrainSupertype: constrainSupertype) &&
           _isNullabilityAwareSubtypeMatch(p.typeArgument, q,
@@ -626,10 +628,11 @@
     if (isNullableTypeConstructorApplication(p)) {
       final int baseConstraintCount = _protoConstraints.length;
       if (_isNullabilityAwareSubtypeMatch(
-              _typeOperations.withNullabilitySuffix(p, NullabilitySuffix.none),
+              computeTypeWithoutNullabilityMarker(p,
+                  isNonNullableByDefault: _isNonNullableByDefault),
               q,
               constrainSupertype: constrainSupertype) &&
-          _isNullabilityAwareSubtypeMatch(_typeOperations.nullType, q,
+          _isNullabilityAwareSubtypeMatch(const NullType(), q,
               constrainSupertype: constrainSupertype)) {
         return true;
       }
@@ -638,29 +641,28 @@
 
     // If Q is dynamic, Object?, or void then the match holds under no
     // constraints.
-    if (_typeOperations.isDynamic(q) ||
-        _typeOperations.isVoid(q) ||
-        q == _typeOperations.objectQuestionType) {
+    if (q is DynamicType ||
+        q is VoidType ||
+        q == _environment.coreTypes.objectNullableRawType) {
       return true;
     }
 
     // If P is Never then the match holds under no constraints.
-    if (_typeOperations.isNever(p) &&
-        _typeOperations.getNullabilitySuffix(p) == NullabilitySuffix.none) {
+    if (p is NeverType && p.declaredNullability == Nullability.nonNullable) {
       return true;
     }
 
     // If Q is Object, then the match holds under no constraints:
     //
     // Only if P is non-nullable.
-    if (q == _typeOperations.objectType) {
-      return _typeOperations.getNullabilitySuffix(p) == NullabilitySuffix.none;
+    if (q == _environment.coreTypes.objectNonNullableRawType) {
+      return p.nullability == Nullability.nonNullable;
     }
 
     // If P is Null, then the match holds under no constraints:
     //
     // Only if Q is nullable.
-    if (_typeOperations.isNull(p)) {
+    if (p is NullType) {
       return q.nullability == Nullability.nullable;
     }
 
@@ -689,42 +691,34 @@
     // under constraints C0 + ... + Ck:
     //
     // If Mi is a subtype match for Ni with respect to L under constraints Ci.
-    TypeDeclarationKind? pTypeDeclarationKind =
-        _typeOperations.getTypeDeclarationKind(p);
-    TypeDeclarationKind? qTypeDeclarationKind =
-        _typeOperations.getTypeDeclarationKind(q);
-    if (pTypeDeclarationKind == TypeDeclarationKind.interfaceDeclaration &&
-        qTypeDeclarationKind == TypeDeclarationKind.interfaceDeclaration) {
-      if ((p as InterfaceType).classNode == (q as InterfaceType).classNode) {
-        assert(p.typeArguments.length == q.typeArguments.length);
+    if (p is InterfaceType &&
+        q is InterfaceType &&
+        p.classNode == q.classNode) {
+      assert(p.typeArguments.length == q.typeArguments.length);
 
-        final int baseConstraintCount = _protoConstraints.length;
-        bool isMatch = true;
-        for (int i = 0; isMatch && i < p.typeArguments.length; ++i) {
-          isMatch = _isNullabilityAwareInterfaceSubtypeMatch(p, q,
-              constrainSupertype: constrainSupertype);
-        }
-        if (isMatch) return true;
-        _protoConstraints.length = baseConstraintCount;
+      final int baseConstraintCount = _protoConstraints.length;
+      bool isMatch = true;
+      for (int i = 0; isMatch && i < p.typeArguments.length; ++i) {
+        isMatch = _isNullabilityAwareInterfaceSubtypeMatch(p, q,
+            constrainSupertype: constrainSupertype);
       }
-    } else if (pTypeDeclarationKind ==
-            TypeDeclarationKind.extensionTypeDeclaration &&
-        qTypeDeclarationKind == TypeDeclarationKind.extensionTypeDeclaration) {
-      if ((p as ExtensionType).extensionTypeDeclaration ==
-          (q as ExtensionType).extensionTypeDeclaration) {
-        assert(p.typeArguments.length == q.typeArguments.length);
+      if (isMatch) return true;
+      _protoConstraints.length = baseConstraintCount;
+    } else if (p is ExtensionType &&
+        q is ExtensionType &&
+        p.extensionTypeDeclaration == q.extensionTypeDeclaration) {
+      assert(p.typeArguments.length == q.typeArguments.length);
 
-        final int baseConstraintCount = _protoConstraints.length;
-        bool isMatch = true;
-        for (int i = 0; isMatch && i < p.typeArguments.length; ++i) {
-          isMatch = isMatch &&
-              _isNullabilityAwareSubtypeMatch(
-                  p.typeArguments[i], q.typeArguments[i],
-                  constrainSupertype: constrainSupertype);
-        }
-        if (isMatch) return true;
-        _protoConstraints.length = baseConstraintCount;
+      final int baseConstraintCount = _protoConstraints.length;
+      bool isMatch = true;
+      for (int i = 0; isMatch && i < p.typeArguments.length; ++i) {
+        isMatch = isMatch &&
+            _isNullabilityAwareSubtypeMatch(
+                p.typeArguments[i], q.typeArguments[i],
+                constrainSupertype: constrainSupertype);
       }
+      if (isMatch) return true;
+      _protoConstraints.length = baseConstraintCount;
     }
 
     // If P is C0<M0, ..., Mk> and Q is C1<N0, ..., Nj> then the match holds
@@ -733,9 +727,9 @@
     // If C1<B0, ..., Bj> is a superinterface of C0<M0, ..., Mk> and C1<B0, ...,
     // Bj> is a subtype match for C1<N0, ..., Nj> with respect to L under
     // constraints C.
-    if (pTypeDeclarationKind != null && qTypeDeclarationKind != null) {
-      final List<DartType>? sArguments = getTypeArgumentsAsInstanceOf(
-          p as TypeDeclarationType, (q as TypeDeclarationType).typeDeclaration);
+    if (p is TypeDeclarationType && q is TypeDeclarationType) {
+      final List<DartType>? sArguments =
+          getTypeArgumentsAsInstanceOf(p, q.typeDeclaration);
       if (sArguments != null) {
         assert(sArguments.length == q.typeArguments.length);
 
@@ -755,7 +749,7 @@
     //
     // If P is a function type.
     if (q == _environment.coreTypes.functionNonNullableRawType &&
-        _typeOperations.isFunctionType(p)) {
+        p is FunctionType) {
       return true;
     }
 
@@ -766,10 +760,10 @@
     // If R0 is a subtype match for a type R1 with respect to L under
     // constraints C.  If n <= k and r <= m.  And for i in 0...r, Ni is a
     // subtype match for Mi with respect to L under constraints Ci.
-    if (_typeOperations.isFunctionType(p) &&
-        _typeOperations.isFunctionType(q) &&
-        (p as FunctionType).typeParameters.isEmpty &&
-        (q as FunctionType).typeParameters.isEmpty &&
+    if (p is FunctionType &&
+        q is FunctionType &&
+        p.typeParameters.isEmpty &&
+        q.typeParameters.isEmpty &&
         p.namedParameters.isEmpty &&
         q.namedParameters.isEmpty &&
         p.requiredParameterCount <= q.requiredParameterCount &&
@@ -792,10 +786,10 @@
 
     // Function types with named parameters are treated analogously to the
     // positional parameter case above.
-    if (_typeOperations.isFunctionType(p) &&
-        _typeOperations.isFunctionType(q) &&
-        (p as FunctionType).typeParameters.isEmpty &&
-        (q as FunctionType).typeParameters.isEmpty &&
+    if (p is FunctionType &&
+        q is FunctionType &&
+        p.typeParameters.isEmpty &&
+        q.typeParameters.isEmpty &&
         p.positionalParameters.length == p.requiredParameterCount &&
         q.positionalParameters.length == q.requiredParameterCount &&
         p.requiredParameterCount == q.requiredParameterCount &&
@@ -845,10 +839,10 @@
     // with respect to L under constraints C0.  And C1 is C02 + ... + Cn2 + C0.
     // And C2 is C1 with each constraint replaced with its closure with respect
     // to [Z0, ..., Zn].
-    if (_typeOperations.isFunctionType(p) &&
-        _typeOperations.isFunctionType(q) &&
-        (p as FunctionType).typeParameters.isNotEmpty &&
-        (q as FunctionType).typeParameters.isNotEmpty &&
+    if (p is FunctionType &&
+        q is FunctionType &&
+        p.typeParameters.isNotEmpty &&
+        q.typeParameters.isNotEmpty &&
         p.typeParameters.length == q.typeParameters.length) {
       final int baseConstraintCount = _protoConstraints.length;
 
@@ -880,8 +874,8 @@
               new NullabilityAwareTypeVariableEliminator(
                   structuralEliminationTargets: p.typeParameters.toSet(),
                   nominalEliminationTargets: {},
-                  bottomType: _typeOperations.neverType,
-                  topType: _typeOperations.objectQuestionType,
+                  bottomType: const NeverType.nonNullable(),
+                  topType: _environment.coreTypes.objectNullableRawType,
                   topFunctionType:
                       _environment.coreTypes.functionNonNullableRawType,
                   unhandledTypeHandler: (DartType type, ignored) =>
@@ -918,10 +912,9 @@
     // respect to `L` under constraints `C0 + ... + Cm`
     // If for `i` in `0...m`, `Mi` is a subtype match for `Ni` with respect to
     // `L` under constraints `Ci`.
-    if (_typeOperations.isRecordType(p) &&
-        _typeOperations.isRecordType(q) &&
-        (p as RecordType).positional.length ==
-            (q as RecordType).positional.length &&
+    if (p is RecordType &&
+        q is RecordType &&
+        p.positional.length == q.positional.length &&
         p.named.length == q.named.length) {
       bool sameNames = true;
       for (int i = 0; sameNames && i < p.named.length; i++) {
@@ -961,10 +954,10 @@
       DartType subtype, DartType supertype) {
     // The unknown type `?` is a subtype match for any type `Q` with no
     // constraints.
-    if (_typeOperations.isUnknownType(subtype)) return true;
+    if (subtype is UnknownType) return true;
     // Any type `P` is a subtype match for the unknown type `?` with no
     // constraints.
-    if (_typeOperations.isUnknownType(supertype)) return true;
+    if (supertype is UnknownType) return true;
     // A type variable `T` in `L` is a subtype match for any type schema `Q`:
     // - Under constraint `T <: Q`.
 
@@ -1006,8 +999,8 @@
     if (identical(subtype, supertype)) return true;
 
     // Handle FutureOr<T> union type.
-    if (_typeOperations.matchFutureOr(subtype) != null) {
-      DartType subtypeArg = (subtype as FutureOrType).typeArgument;
+    if (subtype is FutureOrType) {
+      DartType subtypeArg = subtype.typeArgument;
       if (supertype is FutureOrType) {
         // `FutureOr<P>` is a subtype match for `FutureOr<Q>` with respect to
         // `L` under constraints `C`:
@@ -1034,7 +1027,7 @@
               .isSubtypeWhenUsingNullabilities();
     }
 
-    if (_typeOperations.matchFutureOr(supertype) != null) {
+    if (supertype is FutureOrType) {
       // `P` is a subtype match for `FutureOr<Q>` with respect to `L` under
       // constraints `C`:
       // - If `P` is a subtype match for `Future<Q>` with respect to `L` under
@@ -1056,8 +1049,7 @@
       // should be united.  Also, computeNullability is used to fetch the
       // nullability of the argument because it can be a FutureOr itself.
       Nullability unitedNullability = uniteNullabilities(
-          (supertype as FutureOrType).typeArgument.nullability,
-          supertype.nullability);
+          supertype.typeArgument.nullability, supertype.nullability);
       DartType supertypeArg =
           supertype.typeArgument.withDeclaredNullability(unitedNullability);
       DartType supertypeFuture =
@@ -1081,7 +1073,7 @@
     if (_isTop(supertype)) return true;
     // `Null` is a subtype match for any type `Q` under no constraints.
     // Note that nullable types will change this.
-    if (_typeOperations.isNull(subtype)) return true;
+    if (_isNull(subtype)) return true;
 
     // A type variable `T` not in `L` with bound `P` is a subtype match for the
     // same type variable `T` with bound `Q` with respect to `L` under
@@ -1121,17 +1113,15 @@
       return _isNullabilityObliviousSubtypeMatch(
           subtype.parameter.bound, supertype);
     }
-    if (_typeOperations.isInterfaceType(subtype) &&
-        _typeOperations.isInterfaceType(supertype)) {
-      return _isNullabilityObliviousInterfaceSubtypeMatch(
-          subtype as InterfaceType, supertype as InterfaceType);
+    if (subtype is InterfaceType && supertype is InterfaceType) {
+      return _isNullabilityObliviousInterfaceSubtypeMatch(subtype, supertype);
     }
-    if (_typeOperations.isFunctionType(subtype)) {
-      if (_typeOperations.isInterfaceType(supertype)) {
+    if (subtype is FunctionType) {
+      if (supertype is InterfaceType) {
         return supertype == _environment.coreTypes.functionLegacyRawType ||
             supertype == _environment.coreTypes.objectLegacyRawType;
       } else if (supertype is FunctionType) {
-        return _isFunctionSubtypeMatch(subtype as FunctionType, supertype);
+        return _isFunctionSubtypeMatch(subtype, supertype);
       }
     }
     // A type `P` is a subtype match for a type `Q` with respect to `L` under
@@ -1139,9 +1129,8 @@
     // - If `P` is an interface type which implements a call method of type `F`,
     //   and `F` is a subtype match for a type `Q` with respect to `L` under
     //   constraints `C`.
-    if (_typeOperations.isInterfaceType(subtype)) {
-      Member? callMember =
-          getInterfaceMember((subtype as InterfaceType).classNode, callName);
+    if (subtype is InterfaceType) {
+      Member? callMember = getInterfaceMember(subtype.classNode, callName);
       if (callMember is Procedure && !callMember.isGetter) {
         DartType callType = callMember.getterType;
         callType =
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 9cfeba1..cc583d6 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
@@ -4,7 +4,6 @@
 
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis_operations.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/assigned_variables.dart';
-import 'package:_fe_analyzer_shared/src/type_inference/nullability_suffix.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart'
     as shared;
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart'
@@ -14,7 +13,6 @@
     show ClassHierarchy, ClassHierarchyBase;
 import 'package:kernel/core_types.dart' show CoreTypes;
 import 'package:kernel/src/norm.dart';
-import 'package:kernel/type_algebra.dart';
 import 'package:kernel/type_environment.dart';
 
 import '../../base/instrumentation.dart' show Instrumentation;
@@ -512,16 +510,10 @@
   DartType get neverType => const NeverType.nonNullable();
 
   @override
-  DartType get nullType => const NullType();
-
-  @override
   DartType get objectQuestionType =>
       typeEnvironment.coreTypes.objectNullableRawType;
 
   @override
-  DartType get objectType => typeEnvironment.coreTypes.objectNonNullableRawType;
-
-  @override
   DartType get unknownType => const UnknownType();
 
   @override
@@ -553,20 +545,6 @@
   }
 
   @override
-  NullabilitySuffix getNullabilitySuffix(DartType type) {
-    if (isTypeWithoutNullabilityMarker(type,
-        isNonNullableByDefault: nullability == Nullability.nonNullable)) {
-      return NullabilitySuffix.none;
-    } else if (isNullableTypeConstructorApplication(type)) {
-      return NullabilitySuffix.question;
-    } else {
-      assert(isLegacyTypeConstructorApplication(type,
-          isNonNullableByDefault: nullability == Nullability.nonNullable));
-      return NullabilitySuffix.star;
-    }
-  }
-
-  @override
   DartType factor(DartType from, DartType what) {
     return factorType(typeEnvironment, from, what);
   }
@@ -577,33 +555,11 @@
   }
 
   @override
-  bool isExtensionType(DartType type) {
-    return type is ExtensionType;
-  }
-
-  @override
-  bool isInterfaceType(DartType type) {
-    return type is InterfaceType;
-  }
-
-  @override
   bool isNever(DartType type) {
     return typeEnvironment.coreTypes.isBottom(type);
   }
 
   @override
-  bool isNull(DartType type) {
-    return type is NullType;
-  }
-
-  @override
-  bool isObject(DartType type) {
-    return type is InterfaceType &&
-        type.classNode == typeEnvironment.objectClass &&
-        type.nullability == Nullability.nonNullable;
-  }
-
-  @override
   bool isPropertyPromotable(covariant Member property) {
     FieldNonPromotabilityInfo? fieldNonPromotabilityInfo =
         this.fieldNonPromotabilityInfo;
@@ -628,9 +584,6 @@
   }
 
   @override
-  bool isRecordType(DartType type) => type is RecordType;
-
-  @override
   PropertyNonPromotabilityReason? whyPropertyIsNotPromotable(
       covariant Member property) {
     FieldNonPromotabilityInfo? fieldNonPromotabilityInfo =
@@ -772,24 +725,12 @@
   bool isError(DartType type) => type is InvalidType;
 
   @override
-  bool isFunctionType(DartType type) => type is FunctionType;
-
-  @override
-  DartType? matchFutureOr(DartType type) {
-    if (type is! FutureOrType) {
-      return null;
-    } else {
-      return type.typeArgument;
-    }
-  }
-
-  @override
   bool isTypeSchemaSatisfied(
           {required DartType typeSchema, required DartType type}) =>
       isSubtypeOf(type, typeSchema);
 
   @override
-  bool isUnknownType(DartType typeSchema) => typeSchema is UnknownType;
+  bool isUnknownType(DartType type) => type is UnknownType;
 
   @override
   bool isVariableFinal(VariableDeclaration node) {
@@ -797,9 +738,6 @@
   }
 
   @override
-  bool isVoid(DartType type) => type is VoidType;
-
-  @override
   DartType iterableTypeSchema(DartType elementTypeSchema) {
     return new InterfaceType(typeEnvironment.coreTypes.iterableClass,
         Nullability.nonNullable, <DartType>[elementTypeSchema]);
@@ -967,38 +905,6 @@
 
   @override
   DartType typeToSchema(DartType type) => type;
-
-  @override
-  DartType withNullabilitySuffix(DartType type, NullabilitySuffix modifier) {
-    switch (modifier) {
-      case NullabilitySuffix.none:
-        return computeTypeWithoutNullabilityMarker(type,
-            isNonNullableByDefault: nullability == Nullability.nonNullable);
-      case NullabilitySuffix.question:
-        return type.withDeclaredNullability(Nullability.nullable);
-      case NullabilitySuffix.star:
-        return type.withDeclaredNullability(Nullability.legacy);
-    }
-  }
-
-  @override
-  TypeDeclarationKind? getTypeDeclarationKind(DartType type) {
-    if (type is TypeDeclarationType) {
-      switch (type) {
-        case InterfaceType():
-          return TypeDeclarationKind.interfaceDeclaration;
-        case ExtensionType():
-          return TypeDeclarationKind.extensionTypeDeclaration;
-      }
-    } else {
-      return null;
-    }
-  }
-
-  @override
-  TypeDeclarationKind? getTypeSchemaDeclarationKind(DartType typeSchema) {
-    return getTypeDeclarationKind(typeSchema);
-  }
 }
 
 /// Type inference results used for testing.
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index d40c04a..36fbd07 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -1480,7 +1480,6 @@
 immediate
 immediately
 immutable
-impact
 implement
 implementation
 implementations
@@ -1536,13 +1535,11 @@
 indicated
 indicates
 indicating
-indication
 indices
 indirect
 indirectly
 induce
 induced
-inducing
 infer
 inference
 inferrable
@@ -2064,7 +2061,6 @@
 notice
 noticed
 notifies
-notions
 now
 nowhere
 null
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index 499f14f..39fbe33 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -2282,6 +2282,7 @@
 
   @override
   bool visitExtensionType(ExtensionType node) {
+    assert(node.declaredNullability != Nullability.undetermined);
     return node.declaredNullability == Nullability.nullable ||
         node.declaredNullability == Nullability.legacy;
   }