[analyzer][cfe] Implement types and type schemas as extension types

This CL removes Type and TypeSchema type variables from the abstract
classes with shared code between the CFE and the analyzer. Extension
types SharedTypeView and SharedTypeSchemaView are declared to replace
the type variables.

The update propagates the discipline of distinguishing between types
and type schemas into the clients of the shared code. Now the code in
the CFE and the Analyzer that uses the shared code needs to statically
specify the interpretation of their type objects as either types or
type schemas.

Another benefit of the update is SharedTypeView and
SharedTypeSchemaView being less opaque than the Type and TypeSchema
type variables, which removes the necessity for some code duplication
in abstract methods for types and type schemas.

Finally, the update enables some further changes in the shared code
between the Analyzer and the CFE.

Change-Id: I88e8cfcd47d4f721974b4f2612521e85bb54c30f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/379302
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: 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 b21a283..6a6273a 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
@@ -5145,7 +5145,7 @@
       required Type knownType,
       bool matchFailsIfWrongType = true,
       bool matchMayFailEvenIfCorrectType = false}) {
-    if (knownType is SharedInvalidType) {
+    if (knownType is SharedInvalidTypeStructure) {
       _unmatched = _join(_unmatched!, _current);
       return false;
     }
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/shared_inference_log.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/shared_inference_log.dart
index d99c777..1ccdf14 100644
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/shared_inference_log.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/shared_inference_log.dart
@@ -121,7 +121,9 @@
 /// This class defines methods that the analyzer or CFE can use to instrument
 /// their type inference logic. The implementations are found in
 /// [SharedInferenceLogWriterImpl].
-abstract interface class SharedInferenceLogWriter<Type extends SharedType<Type>,
+abstract interface class SharedInferenceLogWriter<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Type extends SharedTypeStructure<Type>,
     TypeParameter extends Object> {
   /// If [inProgress] is `true`, verifies that generic type inference is in
   /// progress; otherwise, verifies that generic type inference is not in
@@ -238,7 +240,7 @@
   /// type schema to another.
   void recordGeneratedConstraint(
       TypeParameter parameter,
-      MergedTypeConstraint<Type, Type, TypeParameter, Object, Type, Object>
+      MergedTypeConstraint<TypeStructure, TypeParameter, Object, Type, Object>
           constraint);
 
   /// Records that type inference has resolved a method name.
@@ -266,9 +268,11 @@
 /// from classes derived from [SharedInferenceLogWriterImpl], but these methods
 /// are not exposed in [SharedInferenceLogWriter] so that they won't be called
 /// accidentally on their own.
-abstract class SharedInferenceLogWriterImpl<Type extends SharedType<Type>,
+abstract class SharedInferenceLogWriterImpl<
+        TypeStructure extends SharedTypeStructure<TypeStructure>,
+        Type extends SharedTypeStructure<Type>,
         TypeParameter extends Object>
-    implements SharedInferenceLogWriter<Type, TypeParameter> {
+    implements SharedInferenceLogWriter<TypeStructure, Type, TypeParameter> {
   /// A stack of [State] objects representing the calls that have been made to
   /// `enter...` methods without any matched `exit...` method.
   ///
@@ -685,7 +689,7 @@
   @override
   void recordGeneratedConstraint(
       TypeParameter parameter,
-      MergedTypeConstraint<Type, Type, TypeParameter, Object, Type, Object>
+      MergedTypeConstraint<TypeStructure, TypeParameter, Object, Type, Object>
           constraint) {
     checkCall(
         method: 'recordGeneratedConstraint',
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart
index 0c1030b..336b486 100644
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart
@@ -2,12 +2,14 @@
 // 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 '../types/shared_type.dart';
 import 'type_analyzer.dart';
 
 /// Result for analyzing an assigned variable pattern in
 /// [TypeAnalyzer.analyzeAssignedVariablePattern].
-class AssignedVariablePatternResult<Type extends Object, Error>
-    extends PatternResult<Type> {
+class AssignedVariablePatternResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Error> extends PatternResult<TypeStructure> {
   /// Error for when a variable was assigned multiple times within a pattern.
   final Error? duplicateAssignmentPatternVariableError;
 
@@ -23,10 +25,11 @@
 
 /// Result for analyzing a constant pattern in
 /// [TypeAnalyzer.analyzeConstantPattern].
-class ConstantPatternResult<Type extends Object, Error>
-    extends PatternResult<Type> {
+class ConstantPatternResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Error> extends PatternResult<TypeStructure> {
   /// The static type of the constant expression.
-  final Type expressionType;
+  final SharedTypeView<TypeStructure> expressionType;
 
   /// Error for when the pattern occurred in an irrefutable context.
   final Error? refutablePatternInIrrefutableContextError;
@@ -44,10 +47,11 @@
 
 /// Result for analyzing a declared variable pattern in
 /// [TypeAnalyzer.analyzeDeclaredVariablePattern].
-class DeclaredVariablePatternResult<Type extends Object, Error>
-    extends PatternResult<Type> {
+class DeclaredVariablePatternResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Error> extends PatternResult<TypeStructure> {
   /// The static type of the variable.
-  final Type staticType;
+  final SharedTypeView<TypeStructure> staticType;
 
   /// Error for when the matched value type is not assignable to the static
   /// type in an irrefutable context.
@@ -64,7 +68,8 @@
 /// This class keeps track of a provisional type of the expression (prior to
 /// resolving null shorting) as well as the information necessary to resolve
 /// null shorting.
-abstract class ExpressionTypeAnalysisResult<Type extends Object> {
+abstract class ExpressionTypeAnalysisResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>> {
   /// Type of the expression before resolving null shorting.
   ///
   /// For example, if `this` is the result of analyzing `(... as int?)?.isEven`,
@@ -72,7 +77,7 @@
   /// `bool`, and it is not yet known (until looking at the surrounding code)
   /// whether there will be additional selectors after `isEven` that should act
   /// on the `bool` type.
-  Type get provisionalType;
+  SharedTypeView<TypeStructure> get provisionalType;
 
   /// Resolves any pending null shorting.  For example, if `this` is the result
   /// of analyzing `(... as int?)?.isEven`, then calling [resolveShorting] will
@@ -81,21 +86,22 @@
   ///
   /// TODO(paulberry): document what calls back to the client might be made by
   /// invoking this method.
-  Type resolveShorting();
+  SharedTypeView<TypeStructure> resolveShorting();
 }
 
 /// Result for analyzing an if-case statement or element in
 /// [TypeAnalyzer.analyzeIfCaseStatement] and
 /// [TypeAnalyzer.analyzeIfCaseElement].
-class IfCaseStatementResult<Type extends Object, Error> {
+class IfCaseStatementResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>, Error> {
   /// The static type of the matched expression.
-  final Type matchedExpressionType;
+  final SharedTypeView<TypeStructure> matchedExpressionType;
 
   /// Error for when the guard has a non-bool type.
   final Error? nonBooleanGuardError;
 
   /// The type of the guard expression, if present.
-  final Type? guardType;
+  final SharedTypeView<TypeStructure>? guardType;
 
   IfCaseStatementResult(
       {required this.matchedExpressionType,
@@ -104,8 +110,9 @@
 }
 
 /// Container for the result of running type analysis on an integer literal.
-class IntTypeAnalysisResult<Type extends Object>
-    extends SimpleTypeAnalysisResult<Type> {
+class IntTypeAnalysisResult<
+        TypeStructure extends SharedTypeStructure<TypeStructure>>
+    extends SimpleTypeAnalysisResult<TypeStructure> {
   /// Whether the integer literal was converted to a double.
   final bool convertedToDouble;
 
@@ -113,10 +120,11 @@
 }
 
 /// Result for analyzing a list pattern in [TypeAnalyzer.analyzeListPattern].
-class ListPatternResult<Type extends Object, Error>
-    extends PatternResult<Type> {
+class ListPatternResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Error> extends PatternResult<TypeStructure> {
   /// The required type of the list pattern.
-  final Type requiredType;
+  final SharedTypeView<TypeStructure> requiredType;
 
   /// Errors for when multiple rest patterns occurred within the list pattern.
   ///
@@ -138,8 +146,9 @@
 
 /// Result for analyzing a logical or pattern in
 /// [TypeAnalyzer.analyzeLogicalOrPattern].
-class LogicalOrPatternResult<Type extends Object, Error>
-    extends PatternResult<Type> {
+class LogicalOrPatternResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Error> extends PatternResult<TypeStructure> {
   /// Error for when the pattern occurred in an irrefutable context.
   final Error? refutablePatternInIrrefutableContextError;
 
@@ -149,17 +158,18 @@
 }
 
 /// Result for analyzing a pattern in [TypeAnalyzer].
-class PatternResult<Type extends Object> {
+class PatternResult<TypeStructure extends SharedTypeStructure<TypeStructure>> {
   /// The matched value type that was used to type check the pattern.
-  final Type matchedValueType;
+  final SharedTypeView<TypeStructure> matchedValueType;
 
   PatternResult({required this.matchedValueType});
 }
 
 /// Result for analyzing a map pattern in [TypeAnalyzer.analyzeMapPattern].
-class MapPatternResult<Type extends Object, Error> extends PatternResult<Type> {
+class MapPatternResult<TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Error> extends PatternResult<TypeStructure> {
   /// The required type of the map pattern.
-  final Type requiredType;
+  final SharedTypeView<TypeStructure> requiredType;
 
   /// Error for when the matched value type is not assignable to the required
   /// type in an irrefutable context.
@@ -269,8 +279,9 @@
 
 /// Result for analyzing a null check or null assert pattern in
 /// [TypeAnalyzer.analyzeNullCheckOrAssertPattern].
-class NullCheckOrAssertPatternResult<Type extends Object, Error>
-    extends PatternResult<Type> {
+class NullCheckOrAssertPatternResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Error> extends PatternResult<TypeStructure> {
   /// Error for when the pattern occurred in an irrefutable context.
   final Error? refutablePatternInIrrefutableContextError;
 
@@ -285,10 +296,11 @@
 
 /// Result for analyzing an object pattern in
 /// [TypeAnalyzer.analyzeObjectPattern].
-class ObjectPatternResult<Type extends Object, Error>
-    extends PatternResult<Type> {
+class ObjectPatternResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Error> extends PatternResult<TypeStructure> {
   /// The required type of the object pattern.
-  final Type requiredType;
+  final SharedTypeView<TypeStructure> requiredType;
 
   /// Errors for when the same property name was used multiple times in the
   /// object pattern.
@@ -310,10 +322,11 @@
 }
 
 /// Container for the result of running type analysis on a pattern assignment.
-class PatternAssignmentAnalysisResult<Type extends Object,
-    TypeSchema extends Object> extends SimpleTypeAnalysisResult<Type> {
+class PatternAssignmentAnalysisResult<
+        TypeStructure extends SharedTypeStructure<TypeStructure>>
+    extends SimpleTypeAnalysisResult<TypeStructure> {
   /// The type schema of the pattern on the left hand size of the assignment.
-  final TypeSchema patternSchema;
+  final SharedTypeSchemaView<TypeStructure> patternSchema;
 
   PatternAssignmentAnalysisResult({
     required this.patternSchema,
@@ -323,13 +336,13 @@
 
 /// Container for the result of running type analysis on a pattern variable
 /// declaration.
-class PatternVariableDeclarationAnalysisResult<Type extends Object,
-    TypeSchema extends Object> {
+class PatternVariableDeclarationAnalysisResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>> {
   /// The type schema of the pattern on the left hand size of the declaration.
-  final TypeSchema patternSchema;
+  final SharedTypeSchemaView<TypeStructure> patternSchema;
 
   /// The type of the initializer expression.
-  final Type initializerType;
+  final SharedTypeView<TypeStructure> initializerType;
 
   PatternVariableDeclarationAnalysisResult({
     required this.patternSchema,
@@ -339,12 +352,13 @@
 
 /// Result for analyzing a pattern-for-in statement or element in
 /// [TypeAnalyzer.analyzePatternForIn].
-class PatternForInResult<Type extends Object, Error> {
+class PatternForInResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>, Error> {
   /// The static type of the elements of the for in expression.
-  final Type elementType;
+  final SharedTypeView<TypeStructure> elementType;
 
   /// The static type of the collection of elements of the for in expression.
-  final Type expressionType;
+  final SharedTypeView<TypeStructure> expressionType;
 
   /// Error for when the expression is not an iterable.
   final Error? patternForInExpressionIsNotIterableError;
@@ -357,10 +371,11 @@
 
 /// Result for analyzing a record pattern in
 /// [TypeAnalyzer.analyzeRecordPattern].
-class RecordPatternResult<Type extends Object, Error>
-    extends PatternResult<Type> {
+class RecordPatternResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Error> extends PatternResult<TypeStructure> {
   /// The required type of the record pattern.
-  final Type requiredType;
+  final SharedTypeView<TypeStructure> requiredType;
 
   /// Errors for when the same property name was used multiple times in the
   /// record pattern.
@@ -383,10 +398,11 @@
 
 /// Result for analyzing a relational pattern in
 /// [TypeAnalyzer.analyzeRelationalPattern].
-class RelationalPatternResult<Type extends Object, Error>
-    extends PatternResult<Type> {
+class RelationalPatternResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Error> extends PatternResult<TypeStructure> {
   /// The static type of the operand.
-  final Type operandType;
+  final SharedTypeView<TypeStructure> operandType;
 
   /// Error for when the pattern occurred in an irrefutable context.
   final Error? refutablePatternInIrrefutableContextError;
@@ -408,24 +424,26 @@
 
 /// Container for the result of running type analysis on an expression that does
 /// not contain any null shorting.
-class SimpleTypeAnalysisResult<Type extends Object>
-    implements ExpressionTypeAnalysisResult<Type> {
+class SimpleTypeAnalysisResult<
+        TypeStructure extends SharedTypeStructure<TypeStructure>>
+    implements ExpressionTypeAnalysisResult<TypeStructure> {
   /// The static type of the expression.
-  final Type type;
+  final SharedTypeView<TypeStructure> type;
 
   SimpleTypeAnalysisResult({required this.type});
 
   @override
-  Type get provisionalType => type;
+  SharedTypeView<TypeStructure> get provisionalType => type;
 
   @override
-  Type resolveShorting() => type;
+  SharedTypeView<TypeStructure> resolveShorting() => type;
 }
 
 /// Result for analyzing a switch expression in
 /// [TypeAnalyzer.analyzeSwitchExpression].
-class SwitchExpressionResult<Type extends Object, Error>
-    extends SimpleTypeAnalysisResult<Type> {
+class SwitchExpressionResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Error> extends SimpleTypeAnalysisResult<TypeStructure> {
   /// Errors for non-bool guards.
   ///
   /// The key is the case index of the erroneous guard.
@@ -438,7 +456,7 @@
   /// The key is the case index of the guard.
   ///
   /// This is `null` if no such guards where present.
-  final Map<int, Type>? guardTypes;
+  final Map<int, SharedTypeView<TypeStructure>>? guardTypes;
 
   SwitchExpressionResult(
       {required super.type,
@@ -447,7 +465,8 @@
 }
 
 /// Container for the result of running type analysis on an integer literal.
-class SwitchStatementTypeAnalysisResult<Type extends Object, Error> {
+class SwitchStatementTypeAnalysisResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>, Error> {
   /// Whether the switch statement had a `default` clause.
   final bool hasDefault;
 
@@ -466,7 +485,7 @@
   final bool requiresExhaustivenessValidation;
 
   /// The static type of the scrutinee expression.
-  final Type scrutineeType;
+  final SharedTypeView<TypeStructure> scrutineeType;
 
   /// Errors for the cases that don't complete normally.
   ///
@@ -485,7 +504,7 @@
   /// The keys of the maps are case and head indices of the guard.
   ///
   /// This is `null` if no such guards where present.
-  final Map<int, Map<int, Type>>? guardTypes;
+  final Map<int, Map<int, SharedTypeView<TypeStructure>>>? guardTypes;
 
   SwitchStatementTypeAnalysisResult({
     required this.hasDefault,
@@ -513,8 +532,9 @@
 
 /// Result for analyzing a wildcard pattern
 /// [TypeAnalyzer.analyzeWildcardPattern].
-class WildcardPatternResult<Type extends Object, Error>
-    extends PatternResult<Type> {
+class WildcardPatternResult<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Error> extends PatternResult<TypeStructure> {
   /// Error for when the matched value type is not assignable to the wildcard
   /// type in an irrefutable context.
   final Error? patternTypeMismatchInIrrefutableContextError;
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 93e847d..e41a822 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
@@ -130,10 +130,11 @@
 }
 
 /// Information about a relational operator.
-class RelationalOperatorResolution<Type extends SharedType<Type>> {
+class RelationalOperatorResolution<
+    TypeStructure extends SharedTypeStructure<TypeStructure>> {
   final RelationalOperatorKind kind;
-  final Type parameterType;
-  final Type returnType;
+  final SharedTypeView<TypeStructure> parameterType;
+  final SharedTypeView<TypeStructure> returnType;
 
   RelationalOperatorResolution({
     required this.kind,
@@ -261,26 +262,26 @@
 /// of each entry in order to verify that when an entity is popped, it has the
 /// expected kind.
 mixin TypeAnalyzer<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
     Node extends Object,
     Statement extends Node,
     Expression extends Node,
     Variable extends Object,
-    Type extends SharedType<Type>,
     Pattern extends Node,
     Error,
-    TypeSchema extends SharedType<TypeSchema>,
     InferableParameter extends Object,
     TypeDeclarationType extends Object,
     TypeDeclaration extends Object> {
-  TypeAnalyzerErrors<Node, Statement, Expression, Variable, Type, Pattern,
-      Error> get errors;
+  TypeAnalyzerErrors<Node, Statement, Expression, Variable,
+      SharedTypeView<TypeStructure>, Pattern, Error> get errors;
 
   /// Returns the client's [FlowAnalysis] object.
-  FlowAnalysis<Node, Statement, Expression, Variable, Type> get flow;
+  FlowAnalysis<Node, Statement, Expression, Variable,
+      SharedTypeView<TypeStructure>> get flow;
 
   /// The [TypeAnalyzerOperations], used to access types, check subtyping, and
   /// query variable types.
-  TypeAnalyzerOperations<Variable, Type, TypeSchema, InferableParameter,
+  TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
       TypeDeclarationType, TypeDeclaration> get operations;
 
   /// Options affecting the behavior of [TypeAnalyzer].
@@ -299,11 +300,14 @@
   /// [analyzeDeclaredVariablePattern] should be used instead.
   ///
   /// Stack effect: none.
-  AssignedVariablePatternResult<Type, Error> analyzeAssignedVariablePattern(
-      MatchContext<Node, Expression, Pattern, Type, Variable> context,
-      Pattern node,
-      Variable variable) {
-    Type matchedValueType = flow.getMatchedValueType();
+  AssignedVariablePatternResult<TypeStructure, Error>
+      analyzeAssignedVariablePattern(
+          MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+                  Variable>
+              context,
+          Pattern node,
+          Variable variable) {
+    SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
     Error? duplicateAssignmentPatternVariableError;
     Map<Variable, Pattern>? assignedVariables = context.assignedVariables;
     if (assignedVariables != null) {
@@ -320,14 +324,15 @@
       }
     }
 
-    Type variableDeclaredType = operations.variableType(variable);
+    SharedTypeView<TypeStructure> variableDeclaredType =
+        operations.variableType(variable);
     Node? irrefutableContext = context.irrefutableContext;
     assert(irrefutableContext != null,
         'Assigned variables must only appear in irrefutable pattern contexts');
     Error? patternTypeMismatchInIrrefutableContextError;
     if (irrefutableContext != null &&
-        matchedValueType is! SharedDynamicType &&
-        matchedValueType is! SharedInvalidType &&
+        matchedValueType is! SharedDynamicTypeStructure &&
+        matchedValueType is! SharedInvalidTypeStructure &&
         !operations.isSubtypeOf(matchedValueType, variableDeclaredType)) {
       patternTypeMismatchInIrrefutableContextError =
           errors.patternTypeMismatchInIrrefutableContext(
@@ -349,7 +354,8 @@
 
   /// Computes the type schema for a variable pattern appearing in an assignment
   /// context.  [variable] is the variable being referenced.
-  TypeSchema analyzeAssignedVariablePatternSchema(Variable variable) =>
+  SharedTypeSchemaView<TypeStructure> analyzeAssignedVariablePatternSchema(
+          Variable variable) =>
       operations.typeToSchema(
           flow.promotedType(variable) ?? operations.variableType(variable));
 
@@ -359,19 +365,21 @@
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (Pattern innerPattern).
-  PatternResult<Type> analyzeCastPattern({
-    required MatchContext<Node, Expression, Pattern, Type, Variable> context,
+  PatternResult<TypeStructure> analyzeCastPattern({
+    required MatchContext<Node, Expression, Pattern,
+            SharedTypeView<TypeStructure>, Variable>
+        context,
     required Pattern pattern,
     required Pattern innerPattern,
-    required Type requiredType,
+    required SharedTypeView<TypeStructure> requiredType,
   }) {
-    Type matchedValueType = flow.getMatchedValueType();
+    SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
     flow.promoteForPattern(
         matchedType: matchedValueType,
         knownType: requiredType,
         matchFailsIfWrongType: false);
     if (operations.isSubtypeOf(matchedValueType, requiredType) &&
-        requiredType is! SharedInvalidType) {
+        requiredType is! SharedInvalidTypeStructure) {
       errors.matchedTypeIsSubtypeOfRequired(
         pattern: pattern,
         matchedType: matchedValueType,
@@ -394,7 +402,8 @@
   /// Computes the type schema for a cast pattern.
   ///
   /// Stack effect: none.
-  TypeSchema analyzeCastPatternSchema() => operations.unknownType;
+  SharedTypeSchemaView<TypeStructure> analyzeCastPatternSchema() =>
+      operations.unknownType;
 
   /// Analyzes a constant pattern.  [node] is the pattern itself, and
   /// [expression] is the constant expression.  Depending on the client's
@@ -406,11 +415,13 @@
   /// and information about reported errors.
   ///
   /// Stack effect: pushes (Expression).
-  ConstantPatternResult<Type, Error> analyzeConstantPattern(
-      MatchContext<Node, Expression, Pattern, Type, Variable> context,
+  ConstantPatternResult<TypeStructure, Error> analyzeConstantPattern(
+      MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+              Variable>
+          context,
       Node node,
       Expression expression) {
-    Type matchedValueType = flow.getMatchedValueType();
+    SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
     // Stack: ()
     Node? irrefutableContext = context.irrefutableContext;
     Error? refutablePatternInIrrefutableContextError;
@@ -419,7 +430,7 @@
           errors.refutablePatternInIrrefutableContext(
               pattern: node, context: irrefutableContext);
     }
-    Type expressionType = analyzeExpression(
+    SharedTypeView<TypeStructure> expressionType = analyzeExpression(
         expression, operations.typeToSchema(matchedValueType));
     flow.constantPattern_end(expression, expressionType,
         patternsEnabled: options.patternsEnabled,
@@ -454,7 +465,7 @@
   /// Computes the type schema for a constant pattern.
   ///
   /// Stack effect: none.
-  TypeSchema analyzeConstantPatternSchema() {
+  SharedTypeSchemaView<TypeStructure> analyzeConstantPatternSchema() {
     // Constant patterns are only allowed in refutable contexts, and refutable
     // contexts don't propagate a type schema into the scrutinee.  So this
     // code path is only reachable if the user's code contains errors.
@@ -475,21 +486,24 @@
   /// variable (possibly inferred) and information about reported errors.
   ///
   /// Stack effect: none.
-  DeclaredVariablePatternResult<Type, Error> analyzeDeclaredVariablePattern(
-    MatchContext<Node, Expression, Pattern, Type, Variable> context,
+  DeclaredVariablePatternResult<TypeStructure, Error>
+      analyzeDeclaredVariablePattern(
+    MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+            Variable>
+        context,
     Pattern node,
     Variable variable,
     String variableName,
-    Type? declaredType,
+    SharedTypeView<TypeStructure>? declaredType,
   ) {
-    Type matchedValueType = flow.getMatchedValueType();
-    Type staticType =
+    SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
+    SharedTypeView<TypeStructure> staticType =
         declaredType ?? variableTypeFromInitializerType(matchedValueType);
     Node? irrefutableContext = context.irrefutableContext;
     Error? patternTypeMismatchInIrrefutableContextError;
     if (irrefutableContext != null &&
-        matchedValueType is! SharedDynamicType &&
-        matchedValueType is! SharedInvalidType &&
+        matchedValueType is! SharedDynamicTypeStructure &&
+        matchedValueType is! SharedInvalidTypeStructure &&
         !operations.isSubtypeOf(matchedValueType, staticType)) {
       patternTypeMismatchInIrrefutableContextError =
           errors.patternTypeMismatchInIrrefutableContext(
@@ -503,7 +517,8 @@
     // The promotion may have made the matched type even more specific than
     // either `matchedType` or `staticType`, so fetch it again and use that
     // in the call to `declaredVariablePattern` below.
-    Type promotedValueType = flow.getMatchedValueType();
+    SharedTypeView<TypeStructure> promotedValueType =
+        flow.getMatchedValueType();
     bool isImplicitlyTyped = declaredType == null;
     // TODO(paulberry): are we handling _isFinal correctly?
     int promotionKey = context.patternVariablePromotionKeys[variableName] =
@@ -528,7 +543,8 @@
   /// declared type (if present).
   ///
   /// Stack effect: none.
-  TypeSchema analyzeDeclaredVariablePatternSchema(Type? declaredType) {
+  SharedTypeSchemaView<TypeStructure> analyzeDeclaredVariablePatternSchema(
+      SharedTypeView<TypeStructure>? declaredType) {
     return declaredType == null
         ? operations.unknownType
         : operations.typeToSchema(declaredType);
@@ -538,12 +554,13 @@
   /// [schema] is the type schema which should be used for type inference.
   ///
   /// Stack effect: pushes (Expression).
-  Type analyzeExpression(Expression node, TypeSchema schema) {
+  SharedTypeView<TypeStructure> analyzeExpression(
+      Expression node, SharedTypeSchemaView<TypeStructure> schema) {
     // Stack: ()
-    if (schema is SharedDynamicType<TypeSchema>) {
+    if (schema is SharedDynamicTypeSchemaView<TypeStructure>) {
       schema = operations.unknownType;
     }
-    ExpressionTypeAnalysisResult<Type> result =
+    ExpressionTypeAnalysisResult<TypeStructure> result =
         dispatchExpression(node, schema);
     // Stack: (Expression)
     if (operations.isNever(result.provisionalType)) {
@@ -572,7 +589,7 @@
   /// `else` clause, the representation for `ifFalse` will be pushed by
   /// [handleNoCollectionElement].  If there is no guard, the representation
   /// for `guard` will be pushed by [handleNoGuard].
-  IfCaseStatementResult<Type, Error> analyzeIfCaseElement({
+  IfCaseStatementResult<TypeStructure, Error> analyzeIfCaseElement({
     required Node node,
     required Expression expression,
     required Pattern pattern,
@@ -584,7 +601,7 @@
   }) {
     // Stack: ()
     flow.ifCaseStatement_begin();
-    Type initializerType =
+    SharedTypeView<TypeStructure> initializerType =
         analyzeExpression(expression, operations.unknownType);
     flow.ifCaseStatement_afterExpression(expression, initializerType);
     // Stack: (Expression)
@@ -592,7 +609,8 @@
     Map<String, int> patternVariablePromotionKeys = {};
     // TODO(paulberry): rework handling of isFinal
     dispatchPattern(
-      new MatchContext<Node, Expression, Pattern, Type, Variable>(
+      new MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+          Variable>(
         isFinal: false,
         componentVariables: componentVariables,
         patternVariablePromotionKeys: patternVariablePromotionKeys,
@@ -604,7 +622,7 @@
         variables, componentVariables, patternVariablePromotionKeys,
         location: JoinedPatternVariableLocation.singlePattern);
     Error? nonBooleanGuardError;
-    Type? guardType;
+    SharedTypeView<TypeStructure>? guardType;
     if (guard != null) {
       guardType = analyzeExpression(
           guard, operations.typeToSchema(operations.boolType));
@@ -636,7 +654,7 @@
   /// representation for `ifFalse` will be pushed by [handleNoStatement].  If
   /// there is no guard, the representation for `guard` will be pushed by
   /// [handleNoGuard].
-  IfCaseStatementResult<Type, Error> analyzeIfCaseStatement(
+  IfCaseStatementResult<TypeStructure, Error> analyzeIfCaseStatement(
     Statement node,
     Expression expression,
     Pattern pattern,
@@ -647,7 +665,7 @@
   ) {
     // Stack: ()
     flow.ifCaseStatement_begin();
-    Type initializerType =
+    SharedTypeView<TypeStructure> initializerType =
         analyzeExpression(expression, operations.unknownType);
     flow.ifCaseStatement_afterExpression(expression, initializerType);
     // Stack: (Expression)
@@ -655,7 +673,8 @@
     Map<String, int> patternVariablePromotionKeys = {};
     // TODO(paulberry): rework handling of isFinal
     dispatchPattern(
-      new MatchContext<Node, Expression, Pattern, Type, Variable>(
+      new MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+          Variable>(
         isFinal: false,
         componentVariables: componentVariables,
         patternVariablePromotionKeys: patternVariablePromotionKeys,
@@ -673,7 +692,7 @@
     handle_ifCaseStatement_afterPattern(node: node);
     // Stack: (Expression, Pattern)
     Error? nonBooleanGuardError;
-    Type? guardType;
+    SharedTypeView<TypeStructure>? guardType;
     if (guard != null) {
       guardType = analyzeExpression(
           guard, operations.typeToSchema(operations.boolType));
@@ -741,13 +760,15 @@
   /// Analyzes an integer literal, given the type schema [schema].
   ///
   /// Stack effect: none.
-  IntTypeAnalysisResult<Type> analyzeIntLiteral(TypeSchema schema) {
+  IntTypeAnalysisResult<TypeStructure> analyzeIntLiteral(
+      SharedTypeSchemaView<TypeStructure> schema) {
     bool convertToDouble = !operations.isTypeSchemaSatisfied(
             type: operations.intType, typeSchema: schema) &&
         operations.isTypeSchemaSatisfied(
             type: operations.doubleType, typeSchema: schema);
-    Type type = convertToDouble ? operations.doubleType : operations.intType;
-    return new IntTypeAnalysisResult<Type>(
+    SharedTypeView<TypeStructure> type =
+        convertToDouble ? operations.doubleType : operations.intType;
+    return new IntTypeAnalysisResult<TypeStructure>(
         type: type, convertedToDouble: convertToDouble);
   }
 
@@ -761,28 +782,31 @@
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (n * Pattern) where n = elements.length.
-  ListPatternResult<Type, Error> analyzeListPattern(
-      MatchContext<Node, Expression, Pattern, Type, Variable> context,
+  ListPatternResult<TypeStructure, Error> analyzeListPattern(
+      MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+              Variable>
+          context,
       Pattern node,
-      {Type? elementType,
+      {SharedTypeView<TypeStructure>? elementType,
       required List<Node> elements}) {
-    Type matchedValueType = flow.getMatchedValueType();
-    Type valueType;
+    SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
+    SharedTypeView<TypeStructure> valueType;
     if (elementType != null) {
       valueType = elementType;
     } else {
-      Type? listElementType = operations.matchListType(matchedValueType);
+      SharedTypeView<TypeStructure>? listElementType =
+          operations.matchListType(matchedValueType);
       if (listElementType != null) {
         valueType = listElementType;
-      } else if (matchedValueType is SharedDynamicType) {
+      } else if (matchedValueType is SharedDynamicTypeStructure) {
         valueType = operations.dynamicType;
-      } else if (matchedValueType is SharedInvalidType) {
+      } else if (matchedValueType is SharedInvalidTypeStructure) {
         valueType = operations.errorType;
       } else {
         valueType = operations.objectQuestionType;
       }
     }
-    Type requiredType = operations.listType(valueType);
+    SharedTypeView<TypeStructure> requiredType = operations.listType(valueType);
     flow.promoteForPattern(
         matchedType: matchedValueType,
         knownType: requiredType,
@@ -804,7 +828,7 @@
         previousRestPattern = element;
         Pattern? subPattern = getRestPatternElementPattern(element);
         if (subPattern != null) {
-          Type subPatternMatchedType = requiredType;
+          SharedTypeView<TypeStructure> subPatternMatchedType = requiredType;
           flow.pushSubpattern(subPatternMatchedType);
           dispatchPattern(
               context.withUnnecessaryWildcardKind(null), subPattern);
@@ -842,8 +866,8 @@
   /// subpatterns.
   ///
   /// Stack effect: none.
-  TypeSchema analyzeListPatternSchema({
-    required Type? elementType,
+  SharedTypeSchemaView<TypeStructure> analyzeListPatternSchema({
+    required SharedTypeView<TypeStructure>? elementType,
     required List<Node> elements,
   }) {
     if (elementType != null) {
@@ -854,13 +878,14 @@
       return operations.listTypeSchema(operations.unknownType);
     }
 
-    TypeSchema? currentGLB;
+    SharedTypeSchemaView<TypeStructure>? currentGLB;
     for (Node element in elements) {
-      TypeSchema? typeToAdd;
+      SharedTypeSchemaView<TypeStructure>? typeToAdd;
       if (isRestPatternElement(element)) {
         Pattern? subPattern = getRestPatternElementPattern(element);
         if (subPattern != null) {
-          TypeSchema subPatternType = dispatchPatternSchema(subPattern);
+          SharedTypeSchemaView<TypeStructure> subPatternType =
+              dispatchPatternSchema(subPattern);
           typeToAdd = operations.matchIterableTypeSchema(subPatternType);
         }
       } else {
@@ -884,12 +909,14 @@
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (Pattern left, Pattern right)
-  PatternResult<Type> analyzeLogicalAndPattern(
-      MatchContext<Node, Expression, Pattern, Type, Variable> context,
+  PatternResult<TypeStructure> analyzeLogicalAndPattern(
+      MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+              Variable>
+          context,
       Pattern node,
       Node lhs,
       Node rhs) {
-    Type matchedValueType = flow.getMatchedValueType();
+    SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
     // Stack: ()
     dispatchPattern(
       context.withUnnecessaryWildcardKind(
@@ -912,7 +939,8 @@
   /// the left and right sides of the `&&` operator.
   ///
   /// Stack effect: none.
-  TypeSchema analyzeLogicalAndPatternSchema(Node lhs, Node rhs) {
+  SharedTypeSchemaView<TypeStructure> analyzeLogicalAndPatternSchema(
+      Node lhs, Node rhs) {
     return operations.typeSchemaGlb(
         dispatchPatternSchema(lhs), dispatchPatternSchema(rhs));
   }
@@ -925,12 +953,14 @@
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (Pattern left, Pattern right)
-  LogicalOrPatternResult<Type, Error> analyzeLogicalOrPattern(
-      MatchContext<Node, Expression, Pattern, Type, Variable> context,
+  LogicalOrPatternResult<TypeStructure, Error> analyzeLogicalOrPattern(
+      MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+              Variable>
+          context,
       Pattern node,
       Node lhs,
       Node rhs) {
-    Type matchedValueType = flow.getMatchedValueType();
+    SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
     Node? irrefutableContext = context.irrefutableContext;
     Error? refutablePatternInIrrefutableContextError;
     if (irrefutableContext != null) {
@@ -1002,7 +1032,8 @@
   /// the left and right sides of the `|` or `&` operator.
   ///
   /// Stack effect: none.
-  TypeSchema analyzeLogicalOrPatternSchema(Node lhs, Node rhs) {
+  SharedTypeSchemaView<TypeStructure> analyzeLogicalOrPatternSchema(
+      Node lhs, Node rhs) {
     // Logical-or patterns are only allowed in refutable contexts, and
     // refutable contexts don't propagate a type schema into the scrutinee.
     // So this code path is only reachable if the user's code contains errors.
@@ -1020,16 +1051,21 @@
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (n * MapPatternElement) where n = elements.length.
-  MapPatternResult<Type, Error> analyzeMapPattern(
-    MatchContext<Node, Expression, Pattern, Type, Variable> context,
+  MapPatternResult<TypeStructure, Error> analyzeMapPattern(
+    MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+            Variable>
+        context,
     Pattern node, {
-    required ({Type keyType, Type valueType})? typeArguments,
+    required ({
+      SharedTypeView<TypeStructure> keyType,
+      SharedTypeView<TypeStructure> valueType
+    })? typeArguments,
     required List<Node> elements,
   }) {
-    Type matchedValueType = flow.getMatchedValueType();
-    Type keyType;
-    Type valueType;
-    TypeSchema keySchema;
+    SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
+    SharedTypeView<TypeStructure> keyType;
+    SharedTypeView<TypeStructure> valueType;
+    SharedTypeSchemaView<TypeStructure> keySchema;
     if (typeArguments != null) {
       keyType = typeArguments.keyType;
       valueType = typeArguments.valueType;
@@ -1040,11 +1076,11 @@
         keyType = typeArguments.keyType;
         valueType = typeArguments.valueType;
         keySchema = operations.typeToSchema(keyType);
-      } else if (matchedValueType is SharedDynamicType) {
+      } else if (matchedValueType is SharedDynamicTypeStructure) {
         keyType = operations.dynamicType;
         valueType = operations.dynamicType;
         keySchema = operations.unknownType;
-      } else if (matchedValueType is SharedInvalidType) {
+      } else if (matchedValueType is SharedInvalidTypeStructure) {
         keyType = operations.errorType;
         valueType = operations.errorType;
         keySchema = operations.unknownType;
@@ -1054,7 +1090,7 @@
         keySchema = operations.unknownType;
       }
     }
-    Type requiredType = operations.mapType(
+    SharedTypeView<TypeStructure> requiredType = operations.mapType(
       keyType: keyType,
       valueType: valueType,
     );
@@ -1077,7 +1113,8 @@
       Node element = elements[i];
       MapPatternEntry<Expression, Pattern>? entry = getMapPatternEntry(element);
       if (entry != null) {
-        Type keyType = analyzeExpression(entry.key, keySchema);
+        SharedTypeView<TypeStructure> keyType =
+            analyzeExpression(entry.key, keySchema);
         flow.pushSubpattern(valueType);
         dispatchPattern(
           context.withUnnecessaryWildcardKind(null),
@@ -1130,8 +1167,11 @@
   /// subpatterns.
   ///
   /// Stack effect: none.
-  TypeSchema analyzeMapPatternSchema({
-    required ({Type keyType, Type valueType})? typeArguments,
+  SharedTypeSchemaView<TypeStructure> analyzeMapPatternSchema({
+    required ({
+      SharedTypeView<TypeStructure> keyType,
+      SharedTypeView<TypeStructure> valueType
+    })? typeArguments,
     required List<Node> elements,
   }) {
     if (typeArguments != null) {
@@ -1141,11 +1181,12 @@
       ));
     }
 
-    TypeSchema? valueType;
+    SharedTypeSchemaView<TypeStructure>? valueType;
     for (Node element in elements) {
       MapPatternEntry<Expression, Pattern>? entry = getMapPatternEntry(element);
       if (entry != null) {
-        TypeSchema entryValueType = dispatchPatternSchema(entry.value);
+        SharedTypeSchemaView<TypeStructure> entryValueType =
+            dispatchPatternSchema(entry.value);
         if (valueType == null) {
           valueType = entryValueType;
         } else {
@@ -1169,12 +1210,15 @@
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (Pattern innerPattern).
-  NullCheckOrAssertPatternResult<Type, Error> analyzeNullCheckOrAssertPattern(
-      MatchContext<Node, Expression, Pattern, Type, Variable> context,
-      Pattern node,
-      Pattern innerPattern,
-      {required bool isAssert}) {
-    Type matchedValueType = flow.getMatchedValueType();
+  NullCheckOrAssertPatternResult<TypeStructure, Error>
+      analyzeNullCheckOrAssertPattern(
+          MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+                  Variable>
+              context,
+          Pattern node,
+          Pattern innerPattern,
+          {required bool isAssert}) {
+    SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
     // Stack: ()
     Error? refutablePatternInIrrefutableContextError;
     Error? matchedTypeIsStrictlyNonNullableError;
@@ -1214,7 +1258,8 @@
   /// a null-check or a null-assert pattern.
   ///
   /// Stack effect: none.
-  TypeSchema analyzeNullCheckOrAssertPatternSchema(Pattern innerPattern,
+  SharedTypeSchemaView<TypeStructure> analyzeNullCheckOrAssertPatternSchema(
+      Pattern innerPattern,
       {required bool isAssert}) {
     if (isAssert) {
       return operations
@@ -1237,16 +1282,19 @@
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (n * Pattern) where n = fields.length.
-  ObjectPatternResult<Type, Error> analyzeObjectPattern(
-    MatchContext<Node, Expression, Pattern, Type, Variable> context,
+  ObjectPatternResult<TypeStructure, Error> analyzeObjectPattern(
+    MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+            Variable>
+        context,
     Pattern node, {
     required List<RecordPatternField<Node, Pattern>> fields,
   }) {
-    Type matchedValueType = flow.getMatchedValueType();
+    SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
     Map<int, Error>? duplicateRecordPatternFieldErrors =
         _reportDuplicateRecordPatternFields(node, fields);
 
-    Type requiredType = downwardInferObjectPatternRequiredType(
+    SharedTypeView<TypeStructure> requiredType =
+        downwardInferObjectPatternRequiredType(
       matchedType: matchedValueType,
       pattern: node,
     );
@@ -1255,9 +1303,9 @@
 
     // If the required type is `dynamic` or `Never`, then every getter is
     // treated as having the same type.
-    (Object?, Type)? overridePropertyGetType;
-    if (requiredType is SharedDynamicType ||
-        requiredType is SharedInvalidType ||
+    (Object?, SharedTypeView<TypeStructure>)? overridePropertyGetType;
+    if (requiredType is SharedDynamicTypeStructure ||
+        requiredType is SharedInvalidTypeStructure ||
         operations.isNever(requiredType)) {
       overridePropertyGetType = (null, requiredType);
     }
@@ -1277,20 +1325,23 @@
 
     // Stack: ()
     for (RecordPatternField<Node, Pattern> field in fields) {
-      var (Object? propertyMember, Type unpromotedPropertyType) =
-          overridePropertyGetType ??
-              resolveObjectPatternPropertyGet(
-                objectPattern: node,
-                receiverType: requiredType,
-                field: field,
-              );
+      var (
+        Object? propertyMember,
+        SharedTypeView<TypeStructure> unpromotedPropertyType
+      ) = overridePropertyGetType ??
+          resolveObjectPatternPropertyGet(
+            objectPattern: node,
+            receiverType: requiredType,
+            field: field,
+          );
       // Note: an object pattern field must always have a property name, but in
       // error recovery circumstances, one may be absent; when this happens, use
       // the empty string as a the property name to prevent a crash.
       String propertyName = field.name ?? '';
-      Type promotedPropertyType = flow.pushPropertySubpattern(
-              propertyName, propertyMember, unpromotedPropertyType) ??
-          unpromotedPropertyType;
+      SharedTypeView<TypeStructure> promotedPropertyType =
+          flow.pushPropertySubpattern(
+                  propertyName, propertyMember, unpromotedPropertyType) ??
+              unpromotedPropertyType;
       if (operations.isNever(promotedPropertyType)) {
         flow.handleExit();
       }
@@ -1314,7 +1365,8 @@
   /// specified with the object name, and with the type arguments applied.
   ///
   /// Stack effect: none.
-  TypeSchema analyzeObjectPatternSchema(Type type) {
+  SharedTypeSchemaView<TypeStructure> analyzeObjectPatternSchema(
+      SharedTypeView<TypeStructure> type) {
     return operations.typeToSchema(type);
   }
 
@@ -1324,17 +1376,20 @@
   /// the pattern, and [rhs] for the right hand side.
   ///
   /// Stack effect: pushes (Expression, Pattern).
-  PatternAssignmentAnalysisResult<Type, TypeSchema> analyzePatternAssignment(
+  PatternAssignmentAnalysisResult<TypeStructure> analyzePatternAssignment(
       Expression node, Pattern pattern, Expression rhs) {
     // Stack: ()
-    TypeSchema patternSchema = dispatchPatternSchema(pattern);
-    Type rhsType = analyzeExpression(rhs, patternSchema);
+    SharedTypeSchemaView<TypeStructure> patternSchema =
+        dispatchPatternSchema(pattern);
+    SharedTypeView<TypeStructure> rhsType =
+        analyzeExpression(rhs, patternSchema);
     // Stack: (Expression)
     flow.patternAssignment_afterRhs(rhs, rhsType);
     Map<String, List<Variable>> componentVariables = {};
     Map<String, int> patternVariablePromotionKeys = {};
     dispatchPattern(
-      new MatchContext<Node, Expression, Pattern, Type, Variable>(
+      new MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+          Variable>(
         isFinal: false,
         irrefutableContext: node,
         assignedVariables: <Variable, Pattern>{},
@@ -1350,7 +1405,7 @@
     }
     flow.patternAssignment_end();
     // Stack: (Expression, Pattern)
-    return new PatternAssignmentAnalysisResult<Type, TypeSchema>(
+    return new PatternAssignmentAnalysisResult<TypeStructure>(
       patternSchema: patternSchema,
       type: rhsType,
     );
@@ -1370,7 +1425,7 @@
   ///
   /// Note, however, that the caller is responsible for reporting an error if
   /// the static type of [expression] is potentially nullable.
-  PatternForInResult<Type, Error> analyzePatternForIn({
+  PatternForInResult<TypeStructure, Error> analyzePatternForIn({
     required Node node,
     required bool hasAwait,
     required Pattern pattern,
@@ -1378,21 +1433,23 @@
     required void Function() dispatchBody,
   }) {
     // Stack: ()
-    TypeSchema patternTypeSchema = dispatchPatternSchema(pattern);
-    TypeSchema expressionTypeSchema = hasAwait
+    SharedTypeSchemaView<TypeStructure> patternTypeSchema =
+        dispatchPatternSchema(pattern);
+    SharedTypeSchemaView<TypeStructure> expressionTypeSchema = hasAwait
         ? operations.streamTypeSchema(patternTypeSchema)
         : operations.iterableTypeSchema(patternTypeSchema);
-    Type expressionType = analyzeExpression(expression, expressionTypeSchema);
+    SharedTypeView<TypeStructure> expressionType =
+        analyzeExpression(expression, expressionTypeSchema);
     // Stack: (Expression)
 
     Error? patternForInExpressionIsNotIterableError;
-    Type? elementType = hasAwait
+    SharedTypeView<TypeStructure>? elementType = hasAwait
         ? operations.matchStreamType(expressionType)
         : operations.matchIterableType(expressionType);
     if (elementType == null) {
-      if (expressionType is SharedDynamicType) {
+      if (expressionType is SharedDynamicTypeStructure) {
         elementType = operations.dynamicType;
-      } else if (expressionType is SharedInvalidType) {
+      } else if (expressionType is SharedInvalidTypeStructure) {
         elementType = operations.errorType;
       } else {
         patternForInExpressionIsNotIterableError =
@@ -1409,7 +1466,8 @@
     Map<String, List<Variable>> componentVariables = {};
     Map<String, int> patternVariablePromotionKeys = {};
     dispatchPattern(
-      new MatchContext<Node, Expression, Pattern, Type, Variable>(
+      new MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+          Variable>(
         isFinal: false,
         irrefutableContext: node,
         componentVariables: componentVariables,
@@ -1442,20 +1500,23 @@
   /// type of the initializer and the type schema of the [pattern].
   ///
   /// Stack effect: pushes (Expression, Pattern).
-  PatternVariableDeclarationAnalysisResult<Type, TypeSchema>
+  PatternVariableDeclarationAnalysisResult<TypeStructure>
       analyzePatternVariableDeclaration(
           Node node, Pattern pattern, Expression initializer,
           {required bool isFinal}) {
     // Stack: ()
-    TypeSchema patternSchema = dispatchPatternSchema(pattern);
-    Type initializerType = analyzeExpression(initializer, patternSchema);
+    SharedTypeSchemaView<TypeStructure> patternSchema =
+        dispatchPatternSchema(pattern);
+    SharedTypeView<TypeStructure> initializerType =
+        analyzeExpression(initializer, patternSchema);
     // Stack: (Expression)
     flow.patternVariableDeclaration_afterInitializer(
         initializer, initializerType);
     Map<String, List<Variable>> componentVariables = {};
     Map<String, int> patternVariablePromotionKeys = {};
     dispatchPattern(
-      new MatchContext<Node, Expression, Pattern, Type, Variable>(
+      new MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+          Variable>(
         isFinal: isFinal,
         irrefutableContext: node,
         componentVariables: componentVariables,
@@ -1481,24 +1542,27 @@
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (n * Pattern) where n = fields.length.
-  RecordPatternResult<Type, Error> analyzeRecordPattern(
-    MatchContext<Node, Expression, Pattern, Type, Variable> context,
+  RecordPatternResult<TypeStructure, Error> analyzeRecordPattern(
+    MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+            Variable>
+        context,
     Pattern node, {
     required List<RecordPatternField<Node, Pattern>> fields,
   }) {
-    Type matchedValueType = flow.getMatchedValueType();
-    List<Type> demonstratedPositionalTypes = [];
-    List<(String, Type)> demonstratedNamedTypes = [];
+    SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
+    List<SharedTypeView<TypeStructure>> demonstratedPositionalTypes = [];
+    List<(String, SharedTypeView<TypeStructure>)> demonstratedNamedTypes = [];
     void dispatchField(
       RecordPatternField<Node, Pattern> field,
-      Type matchedType,
+      SharedTypeView<TypeStructure> matchedType,
     ) {
       flow.pushSubpattern(matchedType);
       dispatchPattern(
         context.withUnnecessaryWildcardKind(null),
         field.pattern,
       );
-      Type demonstratedType = flow.getMatchedValueType();
+      SharedTypeView<TypeStructure> demonstratedType =
+          flow.getMatchedValueType();
       String? name = field.name;
       if (name == null) {
         demonstratedPositionalTypes.add(demonstratedType);
@@ -1508,7 +1572,7 @@
       flow.popSubpattern();
     }
 
-    void dispatchFields(Type matchedType) {
+    void dispatchFields(SharedTypeView<TypeStructure> matchedType) {
       for (int i = 0; i < fields.length; i++) {
         dispatchField(fields[i], matchedType);
       }
@@ -1519,7 +1583,7 @@
 
     // Build the required type.
     int requiredTypePositionalCount = 0;
-    List<(String, Type)> requiredTypeNamedTypes = [];
+    List<(String, SharedTypeView<TypeStructure>)> requiredTypeNamedTypes = [];
     for (RecordPatternField<Node, Pattern> field in fields) {
       String? name = field.name;
       if (name == null) {
@@ -1530,7 +1594,7 @@
         );
       }
     }
-    Type requiredType = operations.recordType(
+    SharedTypeView<TypeStructure> requiredType = operations.recordType(
       positional: new List.filled(
         requiredTypePositionalCount,
         operations.objectQuestionType,
@@ -1541,8 +1605,9 @@
         matchedType: matchedValueType, knownType: requiredType);
 
     // Stack: ()
-    if (matchedValueType is SharedRecordType<Type>) {
-      List<Type>? fieldTypes = _matchRecordTypeShape(fields, matchedValueType);
+    if (matchedValueType is SharedRecordTypeView<TypeStructure>) {
+      List<SharedTypeView<TypeStructure>>? fieldTypes =
+          _matchRecordTypeShape(fields, matchedValueType);
       if (fieldTypes != null) {
         assert(fieldTypes.length == fields.length);
         for (int i = 0; i < fields.length; i++) {
@@ -1551,9 +1616,9 @@
       } else {
         dispatchFields(operations.objectQuestionType);
       }
-    } else if (matchedValueType is SharedDynamicType) {
+    } else if (matchedValueType is SharedDynamicTypeStructure) {
       dispatchFields(operations.dynamicType);
-    } else if (matchedValueType is SharedInvalidType) {
+    } else if (matchedValueType is SharedInvalidTypeStructure) {
       dispatchFields(operations.errorType);
     } else {
       dispatchFields(operations.objectQuestionType);
@@ -1573,7 +1638,7 @@
       );
     }
 
-    Type demonstratedType = operations.recordType(
+    SharedTypeView<TypeStructure> demonstratedType = operations.recordType(
         positional: demonstratedPositionalTypes, named: demonstratedNamedTypes);
     flow.promoteForPattern(
         matchedType: matchedValueType,
@@ -1590,13 +1655,14 @@
   /// Computes the type schema for a record pattern.
   ///
   /// Stack effect: none.
-  TypeSchema analyzeRecordPatternSchema({
+  SharedTypeSchemaView<TypeStructure> analyzeRecordPatternSchema({
     required List<RecordPatternField<Node, Pattern>> fields,
   }) {
-    List<TypeSchema> positional = [];
-    List<(String, TypeSchema)> named = [];
+    List<SharedTypeSchemaView<TypeStructure>> positional = [];
+    List<(String, SharedTypeSchemaView<TypeStructure>)> named = [];
     for (RecordPatternField<Node, Pattern> field in fields) {
-      TypeSchema fieldType = dispatchPatternSchema(field.pattern);
+      SharedTypeSchemaView<TypeStructure> fieldType =
+          dispatchPatternSchema(field.pattern);
       String? name = field.name;
       if (name != null) {
         named.add((name, fieldType));
@@ -1620,11 +1686,13 @@
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (Expression).
-  RelationalPatternResult<Type, Error> analyzeRelationalPattern(
-      MatchContext<Node, Expression, Pattern, Type, Variable> context,
+  RelationalPatternResult<TypeStructure, Error> analyzeRelationalPattern(
+      MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+              Variable>
+          context,
       Pattern node,
       Expression operand) {
-    Type matchedValueType = flow.getMatchedValueType();
+    SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
     // Stack: ()
     Error? refutablePatternInIrrefutableContextError;
     Node? irrefutableContext = context.irrefutableContext;
@@ -1633,9 +1701,9 @@
           errors.refutablePatternInIrrefutableContext(
               pattern: node, context: irrefutableContext);
     }
-    RelationalOperatorResolution<Type>? operator =
+    RelationalOperatorResolution<TypeStructure>? operator =
         resolveRelationalPatternOperator(node, matchedValueType);
-    Type? parameterType = operator?.parameterType;
+    SharedTypeView<TypeStructure>? parameterType = operator?.parameterType;
     bool isEquality = switch (operator?.kind) {
       RelationalOperatorKind.equals => true,
       RelationalOperatorKind.notEquals => true,
@@ -1644,7 +1712,7 @@
     if (isEquality && parameterType != null) {
       parameterType = operations.makeNullable(parameterType);
     }
-    Type operandType = analyzeExpression(
+    SharedTypeView<TypeStructure> operandType = analyzeExpression(
         operand,
         parameterType == null
             ? operations.unknownType
@@ -1691,7 +1759,7 @@
   /// Computes the type schema for a relational pattern.
   ///
   /// Stack effect: none.
-  TypeSchema analyzeRelationalPatternSchema() {
+  SharedTypeSchemaView<TypeStructure> analyzeRelationalPatternSchema() {
     // Relational patterns are only allowed in refutable contexts, and refutable
     // contexts don't propagate a type schema into the scrutinee.  So this
     // code path is only reachable if the user's code contains errors.
@@ -1706,8 +1774,11 @@
   ///
   /// Stack effect: pushes (Expression, n * ExpressionCase), where n is the
   /// number of cases.
-  SwitchExpressionResult<Type, Error> analyzeSwitchExpression(
-      Expression node, Expression scrutinee, int numCases, TypeSchema schema) {
+  SwitchExpressionResult<TypeStructure, Error> analyzeSwitchExpression(
+      Expression node,
+      Expression scrutinee,
+      int numCases,
+      SharedTypeSchemaView<TypeStructure> schema) {
     // Stack: ()
 
     // The static type of a switch expression `E` of the form `switch (e0) { p1
@@ -1715,15 +1786,16 @@
     // follows:
     //
     // - The scrutinee (`e0`) is first analyzed with context type `_`.
-    Type expressionType = analyzeExpression(scrutinee, operations.unknownType);
+    SharedTypeView<TypeStructure> expressionType =
+        analyzeExpression(scrutinee, operations.unknownType);
     // Stack: (Expression)
     handleSwitchScrutinee(expressionType);
     flow.switchStatement_expressionEnd(null, scrutinee, expressionType);
 
     // - If the switch expression has no cases, its static type is `Never`.
     Map<int, Error>? nonBooleanGuardErrors;
-    Map<int, Type>? guardTypes;
-    Type staticType;
+    Map<int, SharedTypeView<TypeStructure>>? guardTypes;
+    SharedTypeView<TypeStructure> staticType;
     if (numCases == 0) {
       staticType = operations.neverType;
     } else {
@@ -1732,8 +1804,8 @@
       // - Let `T` be the least upper bound of the static types of all the case
       //   expressions.
       // - Let `S` be the greatest closure of `K`.
-      Type? t;
-      Type s = operations.greatestClosure(schema);
+      SharedTypeView<TypeStructure>? t;
+      SharedTypeView<TypeStructure> s = operations.greatestClosure(schema);
       bool allCasesSatisfyContext = true;
       for (int i = 0; i < numCases; i++) {
         // Stack: (Expression, i * ExpressionCase)
@@ -1748,7 +1820,8 @@
           Map<String, List<Variable>> componentVariables = {};
           Map<String, int> patternVariablePromotionKeys = {};
           dispatchPattern(
-            new MatchContext<Node, Expression, Pattern, Type, Variable>(
+            new MatchContext<Node, Expression, Pattern,
+                SharedTypeView<TypeStructure>, Variable>(
               isFinal: false,
               switchScrutinee: scrutinee,
               componentVariables: componentVariables,
@@ -1766,7 +1839,7 @@
           guard = memberInfo.head.guard;
           bool hasGuard = guard != null;
           if (hasGuard) {
-            Type guardType = analyzeExpression(
+            SharedTypeView<TypeStructure> guardType = analyzeExpression(
                 guard, operations.typeToSchema(operations.boolType));
             Error? nonBooleanGuardError = _checkGuardType(guard, guardType);
             (guardTypes ??= {})[i] = guardType;
@@ -1785,7 +1858,8 @@
         flow.switchStatement_endAlternative(guard, {});
         flow.switchStatement_endAlternatives(null, hasLabels: false);
         // Stack: (Expression, i * ExpressionCase, CaseHead)
-        Type ti = analyzeExpression(memberInfo.expression, schema);
+        SharedTypeView<TypeStructure> ti =
+            analyzeExpression(memberInfo.expression, schema);
         if (allCasesSatisfyContext && !operations.isSubtypeOf(ti, s)) {
           allCasesSatisfyContext = false;
         }
@@ -1828,10 +1902,12 @@
   ///
   /// Stack effect: pushes (Expression, n * StatementCase), where n is the
   /// number of cases after merging together cases that share a body.
-  SwitchStatementTypeAnalysisResult<Type, Error> analyzeSwitchStatement(
-      Statement node, Expression scrutinee, final int numCases) {
+  SwitchStatementTypeAnalysisResult<TypeStructure, Error>
+      analyzeSwitchStatement(
+          Statement node, Expression scrutinee, final int numCases) {
     // Stack: ()
-    Type scrutineeType = analyzeExpression(scrutinee, operations.unknownType);
+    SharedTypeView<TypeStructure> scrutineeType =
+        analyzeExpression(scrutinee, operations.unknownType);
     // Stack: (Expression)
     handleSwitchScrutinee(scrutineeType);
     flow.switchStatement_expressionEnd(node, scrutinee, scrutineeType);
@@ -1839,7 +1915,7 @@
     bool lastCaseTerminates = true;
     Map<int, Error>? switchCaseCompletesNormallyErrors;
     Map<int, Map<int, Error>>? nonBooleanGuardErrors;
-    Map<int, Map<int, Type>>? guardTypes;
+    Map<int, Map<int, SharedTypeView<TypeStructure>>>? guardTypes;
     for (int caseIndex = 0; caseIndex < numCases; caseIndex++) {
       // Stack: (Expression, numExecutionPaths * StatementCase)
       flow.switchStatement_beginAlternatives();
@@ -1861,7 +1937,8 @@
           Map<String, List<Variable>> componentVariables = {};
           Map<String, int> patternVariablePromotionKeys = {};
           dispatchPattern(
-            new MatchContext<Node, Expression, Pattern, Type, Variable>(
+            new MatchContext<Node, Expression, Pattern,
+                SharedTypeView<TypeStructure>, Variable>(
               isFinal: false,
               switchScrutinee: scrutinee,
               componentVariables: componentVariables,
@@ -1879,7 +1956,7 @@
           //         numHeads * CaseHead, Pattern),
           guard = head.guard;
           if (guard != null) {
-            Type guardType = analyzeExpression(
+            SharedTypeView<TypeStructure> guardType = analyzeExpression(
                 guard, operations.typeToSchema(operations.boolType));
             Error? nonBooleanGuardError = _checkGuardType(guard, guardType);
             ((guardTypes ??= {})[caseIndex] ??= {})[headIndex] = guardType;
@@ -1971,10 +2048,11 @@
   /// Stack effect: none.
   ///
   /// Returns the inferred type of the variable.
-  Type analyzeUninitializedVariableDeclaration(
-      Node node, Variable variable, Type? declaredType,
+  SharedTypeView<TypeStructure> analyzeUninitializedVariableDeclaration(
+      Node node, Variable variable, SharedTypeView<TypeStructure>? declaredType,
       {required bool isFinal}) {
-    Type inferredType = declaredType ?? operations.dynamicType;
+    SharedTypeView<TypeStructure> inferredType =
+        declaredType ?? operations.dynamicType;
     setVariableType(variable, inferredType);
     flow.declare(variable, inferredType, initialized: false);
     return inferredType;
@@ -1987,12 +2065,14 @@
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: none.
-  WildcardPatternResult<Type, Error> analyzeWildcardPattern({
-    required MatchContext<Node, Expression, Pattern, Type, Variable> context,
+  WildcardPatternResult<TypeStructure, Error> analyzeWildcardPattern({
+    required MatchContext<Node, Expression, Pattern,
+            SharedTypeView<TypeStructure>, Variable>
+        context,
     required Pattern node,
-    required Type? declaredType,
+    required SharedTypeView<TypeStructure>? declaredType,
   }) {
-    Type matchedValueType = flow.getMatchedValueType();
+    SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
     Node? irrefutableContext = context.irrefutableContext;
     Error? patternTypeMismatchInIrrefutableContextError;
     if (irrefutableContext != null && declaredType != null) {
@@ -2033,8 +2113,8 @@
   /// explicitly declared type (if present).
   ///
   /// Stack effect: none.
-  TypeSchema analyzeWildcardPatternSchema({
-    required Type? declaredType,
+  SharedTypeSchemaView<TypeStructure> analyzeWildcardPatternSchema({
+    required SharedTypeView<TypeStructure>? declaredType,
   }) {
     return declaredType == null
         ? operations.unknownType
@@ -2058,8 +2138,8 @@
   /// [analyzeSwitchExpression].
   ///
   /// Stack effect: pushes (Expression).
-  ExpressionTypeAnalysisResult<Type> dispatchExpression(
-      Expression node, TypeSchema schema);
+  ExpressionTypeAnalysisResult<TypeStructure> dispatchExpression(
+      Expression node, SharedTypeSchemaView<TypeStructure> schema);
 
   /// Calls the appropriate `analyze` method according to the form of [pattern].
   ///
@@ -2068,15 +2148,17 @@
   /// and the information accumulated while matching previous patterns.
   ///
   /// Stack effect: pushes (Pattern).
-  PatternResult<Type> dispatchPattern(
-      MatchContext<Node, Expression, Pattern, Type, Variable> context,
+  PatternResult<TypeStructure> dispatchPattern(
+      MatchContext<Node, Expression, Pattern, SharedTypeView<TypeStructure>,
+              Variable>
+          context,
       Node pattern);
 
   /// Calls the appropriate `analyze...Schema` method according to the form of
   /// [pattern].
   ///
   /// Stack effect: none.
-  TypeSchema dispatchPatternSchema(Node pattern);
+  SharedTypeSchemaView<TypeStructure> dispatchPatternSchema(Node pattern);
 
   /// Calls the appropriate `analyze` method according to the form of
   /// [statement], and then adjusts the stack as needed to combine any
@@ -2089,8 +2171,8 @@
   void dispatchStatement(Statement statement);
 
   /// Infers the type for the [pattern], should be a subtype of [matchedType].
-  Type downwardInferObjectPatternRequiredType({
-    required Type matchedType,
+  SharedTypeView<TypeStructure> downwardInferObjectPatternRequiredType({
+    required SharedTypeView<TypeStructure> matchedType,
     required Pattern pattern,
   });
 
@@ -2107,7 +2189,7 @@
     required JoinedPatternVariableLocation location,
     required JoinedPatternVariableInconsistency inconsistency,
     required bool isFinal,
-    required Type type,
+    required SharedTypeView<TypeStructure> type,
   });
 
   /// If the [element] is a map pattern entry, returns it.
@@ -2203,8 +2285,8 @@
   /// Called after visiting an entry element in a map pattern.
   ///
   /// Stack effect: pushes (MapPatternElement).
-  void handleMapPatternEntry(
-      Pattern container, Node entryElement, Type keyType);
+  void handleMapPatternEntry(Pattern container, Node entryElement,
+      SharedTypeView<TypeStructure> keyType);
 
   /// Called after visiting a rest element in a map pattern.
   ///
@@ -2268,14 +2350,15 @@
   /// eliminate this method.
   ///
   /// Stack effect: none.
-  void handleSwitchScrutinee(Type type);
+  void handleSwitchScrutinee(SharedTypeView<TypeStructure> type);
 
   /// Queries whether the switch statement or expression represented by [node]
   /// was exhaustive.  [expressionType] is the static type of the scrutinee.
   ///
   /// Will only be called if the switch statement or expression lacks a
   /// `default` clause, and patterns support is disabled.
-  bool isLegacySwitchExhaustive(Node node, Type expressionType);
+  bool isLegacySwitchExhaustive(
+      Node node, SharedTypeView<TypeStructure> expressionType);
 
   /// Returns whether [node] is a rest element in a list or map pattern.
   bool isRestPatternElement(Node node);
@@ -2286,9 +2369,9 @@
   /// Returns the type of the property in [receiverType] that corresponds to
   /// the name of the [field].  If the property cannot be resolved, the client
   /// should report an error, and return `dynamic` for recovery.
-  (Object?, Type) resolveObjectPatternPropertyGet({
+  (Object?, SharedTypeView<TypeStructure>) resolveObjectPatternPropertyGet({
     required Pattern objectPattern,
-    required Type receiverType,
+    required SharedTypeView<TypeStructure> receiverType,
     required RecordPatternField<Node, Pattern> field,
   });
 
@@ -2298,17 +2381,18 @@
   /// If no operator is found, `null` should be returned.  (This could happen
   /// either because the code is invalid, or because [matchedValueType] is
   /// `dynamic`).
-  RelationalOperatorResolution<Type>? resolveRelationalPatternOperator(
-      Pattern node, Type matchedValueType);
+  RelationalOperatorResolution<TypeStructure>? resolveRelationalPatternOperator(
+      Pattern node, SharedTypeView<TypeStructure> matchedValueType);
 
   /// Records that type inference has assigned a [type] to a [variable].  This
   /// is called once per variable, regardless of whether the variable's type is
   /// explicit or inferred.
-  void setVariableType(Variable variable, Type type);
+  void setVariableType(Variable variable, SharedTypeView<TypeStructure> type);
 
   /// Computes the type that should be inferred for an implicitly typed variable
   /// whose initializer expression has static type [type].
-  Type variableTypeFromInitializerType(Type type);
+  SharedTypeView<TypeStructure> variableTypeFromInitializerType(
+      SharedTypeView<TypeStructure> type);
 
   /// Common functionality shared by [analyzeIfStatement] and
   /// [analyzeIfCaseStatement].
@@ -2354,7 +2438,8 @@
     // Stack: (CollectionElement ifTrue, CollectionElement ifFalse)
   }
 
-  Error? _checkGuardType(Expression expression, Type type) {
+  Error? _checkGuardType(
+      Expression expression, SharedTypeView<TypeStructure> type) {
     // TODO(paulberry): harmonize this with analyzer's checkForNonBoolExpression
     // TODO(paulberry): spec says the type must be `bool` or `dynamic`.  This
     // logic permits `T extends bool`, `T promoted to bool`, or `Never`.  What
@@ -2384,14 +2469,15 @@
       Variable? variable = variables[variableName];
       List<Variable> components = componentVariables[variableName] ?? [];
       bool isFirst = true;
-      Type? typeIfConsistent;
+      SharedTypeView<TypeStructure>? typeIfConsistent;
       bool? isFinalIfConsistent;
       bool isIdenticalToComponent = false;
       for (Variable component in components) {
         if (identical(variable, component)) {
           isIdenticalToComponent = true;
         }
-        Type componentType = operations.variableType(component);
+        SharedTypeView<TypeStructure> componentType =
+            operations.variableType(component);
         bool isComponentFinal = operations.isVariableFinal(component);
         if (isFirst) {
           typeIfConsistent = componentType;
@@ -2437,20 +2523,22 @@
   /// If the shape described by [fields] is the same as the shape of the
   /// [matchedType], returns matched types for each field in [fields].
   /// Otherwise returns `null`.
-  List<Type>? _matchRecordTypeShape(
+  List<SharedTypeView<TypeStructure>>? _matchRecordTypeShape(
     List<RecordPatternField<Node, Pattern>> fields,
-    SharedRecordType<Type> matchedType,
+    SharedRecordTypeView<TypeStructure> matchedType,
   ) {
-    Map<String, Type> matchedTypeNamed = {};
-    for (var SharedNamedType(:name, :type) in matchedType.namedTypes) {
+    Map<String, SharedTypeView<TypeStructure>> matchedTypeNamed = {};
+    for (var SharedNamedTypeView<TypeStructure>(:name, :type)
+        in matchedType.namedTypes) {
       matchedTypeNamed[name] = type;
     }
 
-    List<Type> result = [];
+    List<SharedTypeView<TypeStructure>> result = [];
     int namedCount = 0;
-    Iterator<Type> positionalIterator = matchedType.positionalTypes.iterator;
+    Iterator<SharedTypeView<TypeStructure>> positionalIterator =
+        matchedType.positionalTypes.iterator;
     for (RecordPatternField<Node, Pattern> field in fields) {
-      Type? fieldType;
+      SharedTypeView<TypeStructure>? fieldType;
       String? name = field.name;
       if (name != null) {
         fieldType = matchedTypeNamed[name];
@@ -2502,10 +2590,11 @@
     return errorResults;
   }
 
-  bool _structurallyEqualAfterNormTypes(Type type1, Type type2) {
-    Type norm1 = operations.normalize(type1);
-    Type norm2 = operations.normalize(type2);
-    return norm1.isStructurallyEqualTo(norm2);
+  bool _structurallyEqualAfterNormTypes(SharedTypeView<TypeStructure> type1,
+      SharedTypeView<TypeStructure> type2) {
+    SharedTypeView<TypeStructure> norm1 = operations.normalize(type1);
+    SharedTypeView<TypeStructure> norm2 = operations.normalize(type2);
+    return norm1.unwrapTypeView().isStructurallyEqualTo(norm2.unwrapTypeView());
   }
 }
 
@@ -2516,7 +2605,7 @@
     Statement extends Node,
     Expression extends Node,
     Variable extends Object,
-    Type extends SharedType<Type>,
+    Type extends Object,
     Pattern extends Node,
     Error> implements TypeAnalyzerErrorsBase {
   /// Called if pattern support is disabled and a case constant's static type
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 4dcba8f..739e7a7 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
@@ -8,48 +8,95 @@
 
 /// Callback API used by the shared type analyzer to query and manipulate the
 /// client's representation of variables and types.
+///
+/// Concrete classes that implement this class should also mix in
+/// [TypeAnalyzerOperationsMixin], which provides the implementations of the
+/// operations for types and type schemas using the related operations on type
+/// structures, implemented by the concrete class itself. For example,
+/// [TypeAnalyzerOperationsMixin] adds [TypeAnalyzerOperationsMixin.futureType]
+/// and [TypeAnalyzerOperationsMixin.futureTypeSchema] that are defined in terms
+/// of [TypeAnalyzerOperations.futureTypeInternal], so a concrete class
+/// implementing [TypeAnalyzerOperations] needs to implement only
+/// `futureTypeInternal` to receive the implementations of both `futureType` and
+/// `futureTypeSchema` by mixing in [TypeAnalyzerOperationsMixin].
 abstract interface class TypeAnalyzerOperations<
+        TypeStructure extends SharedTypeStructure<TypeStructure>,
         Variable extends Object,
-        Type extends SharedType<Type>,
-        TypeSchema extends SharedType<TypeSchema>,
         InferableParameter extends Object,
         TypeDeclarationType extends Object,
         TypeDeclaration extends Object>
-    implements FlowAnalysisOperations<Variable, Type> {
+    implements FlowAnalysisOperations<Variable, SharedTypeView<TypeStructure>> {
   /// Returns the type `double`.
-  Type get doubleType;
+  SharedTypeView<TypeStructure> get doubleType;
 
   /// Returns the type `dynamic`.
-  Type get dynamicType;
+  SharedTypeView<TypeStructure> get dynamicType;
 
   /// Returns the type used by the client in the case of errors.
-  Type get errorType;
+  SharedTypeView<TypeStructure> get errorType;
 
   /// Returns the type `int`.
-  Type get intType;
+  SharedTypeView<TypeStructure> get intType;
 
   /// Returns the type `Never`.
-  Type get neverType;
+  SharedTypeView<TypeStructure> get neverType;
 
   /// Returns the type `Null`.
-  Type get nullType;
+  SharedTypeView<TypeStructure> get nullType;
 
   /// Returns the type `Object?`.
-  Type get objectQuestionType;
+  SharedTypeView<TypeStructure> get objectQuestionType;
 
   /// Returns the type `Object`.
-  Type get objectType;
+  SharedTypeView<TypeStructure> get objectType;
 
   /// Returns the unknown type schema (`_`) used in type inference.
-  TypeSchema get unknownType;
+  SharedTypeSchemaView<TypeStructure> get unknownType;
 
   /// Returns the type `Future` with omitted nullability and type argument
   /// [argumentType].
-  Type futureType(Type argumentType);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [futureTypeInternal] to
+  /// receive a concrete implementation of [futureType] instead of implementing
+  /// [futureType] directly.
+  SharedTypeView<TypeStructure> futureType(
+      SharedTypeView<TypeStructure> argumentType);
 
   /// Returns the type schema `Future` with omitted nullability and type
   /// argument [argumentTypeSchema].
-  TypeSchema futureTypeSchema(TypeSchema argumentTypeSchema);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [futureTypeInternal] to
+  /// receive a concrete implementation of [futureTypeSchema] instead of
+  /// implementing [futureTypeSchema] directly.
+  SharedTypeSchemaView<TypeStructure> futureTypeSchema(
+      SharedTypeSchemaView<TypeStructure> argumentTypeSchema);
+
+  /// [futureTypeInternal] should be implemented by concrete classes
+  /// implementing [TypeAnalyzerOperations]. The implementations of [futureType]
+  /// and [futureTypeSchema] are provided by mixing in
+  /// [TypeAnalyzerOperationsMixin], which defines [futureType] and
+  /// [futureTypeSchema] in terms of [futureTypeInternal].
+  ///
+  /// The main purpose of this method is to avoid code duplication in the
+  /// concrete classes implementing [TypeAnalyzerOperations], so they can
+  /// implement only one member, in this case [futureTypeInternal], and receive
+  /// the implementation of both [futureType] and [futureTypeSchema] from the
+  /// mixin.
+  ///
+  /// The auxiliary purpose of [futureTypeInternal] is to facilitate the
+  /// development of the shared code at early stages. Sometimes the sharing of
+  /// the code starts by unifying the implementations of some concrete members
+  /// in the Analyzer and the CFE by bringing them in a form that looks
+  /// syntactically very similar in both tools, and then continues by
+  /// abstracting the two concrete members and using the shared abstracted one
+  /// instead of the two concrete methods existing previously. During the early
+  /// stages of unifying the two concrete members it can be beneficial to use
+  /// [futureTypeInternal] instead of the tool-specific ways of constructing a
+  /// future type, for the sake of uniformity, and to simplify the abstraction
+  /// step too.
+  TypeStructure futureTypeInternal(TypeStructure typeStructure);
 
   /// If [type] was introduced by a class, mixin, enum, or extension type,
   /// returns a [TypeDeclarationKind] indicating what kind of thing it was
@@ -58,7 +105,8 @@
   /// 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);
+  TypeDeclarationKind? getTypeDeclarationKind(
+      SharedTypeView<TypeStructure> type);
 
   /// Returns variance for of the type parameter at index [parameterIndex] in
   /// [typeDeclaration].
@@ -74,101 +122,332 @@
   /// 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);
+  TypeDeclarationKind? getTypeSchemaDeclarationKind(
+      SharedTypeSchemaView<TypeStructure> typeSchema);
+
+  TypeDeclarationKind? getTypeDeclarationKindInternal(TypeStructure type);
 
   /// Computes the greatest lower bound of [type1] and [type2].
-  Type glb(Type type1, Type type2);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [glbInternal] to receive a
+  /// concrete implementation of [glb] instead of implementing [glb] directly.
+  SharedTypeView<TypeStructure> glb(
+      SharedTypeView<TypeStructure> type1, SharedTypeView<TypeStructure> type2);
+
+  /// Computes the greatest lower bound of [typeSchema1] and [typeSchema2].
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [glbInternal] to receive a
+  /// concrete implementation of [typeSchemaGlb] instead of implementing
+  /// [typeSchemaGlb] directly.
+  SharedTypeSchemaView<TypeStructure> typeSchemaGlb(
+      SharedTypeSchemaView<TypeStructure> typeSchema1,
+      SharedTypeSchemaView<TypeStructure> typeSchema2);
+
+  /// [glbInternal] should be implemented by concrete classes implementing
+  /// [TypeAnalyzerOperations]. The implementations of [glb] and [typeSchemaGlb]
+  /// are provided by mixing in [TypeAnalyzerOperationsMixin], which defines
+  /// [glb] and [typeSchemaGlb] in terms of [glbInternal].
+  ///
+  /// The main purpose of this method is to avoid code duplication in the
+  /// concrete classes implementing [TypeAnalyzerOperations], so they can
+  /// implement only one member, in this case [glbInternal], and receive the
+  /// implementation of both [glb] and [typeSchemaGlb] from the mixin.
+  ///
+  /// The auxiliary purpose of [glbInternal] is to facilitate the development of
+  /// the shared code at early stages. Sometimes the sharing of the code starts
+  /// by unifying the implementations of some concrete members in the Analyzer
+  /// and the CFE by bringing them in a form that looks syntactically very
+  /// similar in both tools, and then continues by abstracting the two concrete
+  /// members and using the shared abstracted one instead of the two concrete
+  /// methods existing previously. During the early stages of unifying the two
+  /// concrete members it can be beneficial to use [glbInternal] instead of the
+  /// tool-specific ways of constructing a future type, for the sake of
+  /// uniformity, and to simplify the abstraction step too.
+  TypeStructure glbInternal(TypeStructure type1, TypeStructure type2);
 
   /// Returns the greatest closure of [schema] with respect to the unknown type
   /// (`_`).
-  Type greatestClosure(TypeSchema schema);
+  SharedTypeView<TypeStructure> greatestClosure(
+      SharedTypeSchemaView<TypeStructure> schema);
 
   /// Queries whether [type] is an "always-exhaustive" type (as defined in the
   /// patterns spec).  Exhaustive types are types for which the switch statement
   /// is required to be exhaustive when patterns support is enabled.
-  bool isAlwaysExhaustiveType(Type type);
+  bool isAlwaysExhaustiveType(SharedTypeView<TypeStructure> type);
 
   /// Returns `true` if [fromType] is assignable to [toType].
-  bool isAssignableTo(Type fromType, Type toType);
+  bool isAssignableTo(SharedTypeView<TypeStructure> fromType,
+      SharedTypeView<TypeStructure> toType);
 
   /// Returns `true` if [type] is `Function` from `dart:core`. The method
   /// returns `false` for `Object?` and `Object*`.
-  bool isDartCoreFunction(Type type);
+  bool isDartCoreFunction(SharedTypeView<TypeStructure> 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);
+  bool isExtensionType(SharedTypeView<TypeStructure> type);
 
   /// Returns `true` if [type] is `F`, `F?`, or `F*` for some function type `F`.
-  bool isFunctionType(Type type);
+  bool isFunctionType(SharedTypeView<TypeStructure> 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);
+  bool isInterfaceType(SharedTypeView<TypeStructure> type);
 
   /// Returns `true` if `Null` is not a subtype of all types matching
   /// [typeSchema].
   ///
   /// The predicate of [isNonNullable] could be computed directly with a subtype
   /// query, but the implementations can do that more efficiently.
-  bool isNonNullable(TypeSchema typeSchema);
+  bool isNonNullable(SharedTypeSchemaView<TypeStructure> typeSchema);
 
   /// Returns `true` if [type] is `Null`.
-  bool isNull(Type type);
+  bool isNull(SharedTypeView<TypeStructure> type);
 
   /// Returns `true` if [type] is `Object` from `dart:core`. The method returns
   /// `false` for `Object?` and `Object*`.
-  bool isObject(Type type);
+  bool isObject(SharedTypeView<TypeStructure> type);
 
   /// Returns `true` if the type [type] satisfies the type schema [typeSchema].
   bool isTypeSchemaSatisfied(
-      {required TypeSchema typeSchema, required Type type});
+      {required SharedTypeSchemaView<TypeStructure> typeSchema,
+      required SharedTypeView<TypeStructure> type});
 
   /// Returns whether [node] is final.
   bool isVariableFinal(Variable node);
 
   /// Returns the type schema `Iterable`, with type argument.
-  TypeSchema iterableTypeSchema(TypeSchema elementTypeSchema);
+  SharedTypeSchemaView<TypeStructure> iterableTypeSchema(
+      SharedTypeSchemaView<TypeStructure> elementTypeSchema);
 
   /// Returns the type `List`, with type argument [elementType].
-  Type listType(Type elementType);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [listTypeInternal] to receive
+  /// a concrete implementation of [listType] instead of implementing [listType]
+  /// directly.
+  SharedTypeView<TypeStructure> listType(
+      SharedTypeView<TypeStructure> elementType);
 
   /// Returns the type schema `List`, with type argument [elementTypeSchema].
-  TypeSchema listTypeSchema(TypeSchema elementTypeSchema);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [listTypeInternal] to receive
+  /// a concrete implementation of [listTypeSchema] instead of implementing
+  /// [listTypeSchema] directly.
+  SharedTypeSchemaView<TypeStructure> listTypeSchema(
+      SharedTypeSchemaView<TypeStructure> elementTypeSchema);
+
+  /// [listTypeInternal] should be implemented by concrete classes implementing
+  /// [TypeAnalyzerOperations]. The implementations of [listType] and
+  /// [listTypeSchema] are provided by mixing in [TypeAnalyzerOperationsMixin],
+  /// which defines [listType] and [listTypeSchema] in terms of
+  /// [listTypeInternal].
+  ///
+  /// The main purpose of this method is to avoid code duplication in the
+  /// concrete classes implementing [TypeAnalyzerOperations], so they can
+  /// implement only one member, in this case [listTypeInternal], and receive
+  /// the implementation of both [listType] and [listTypeSchema] from the mixin.
+  ///
+  /// The auxiliary purpose of [listTypeInternal] is to facilitate the
+  /// development of the shared code at early stages. Sometimes the sharing of
+  /// the code starts by unifying the implementations of some concrete members
+  /// in the Analyzer and the CFE by bringing them in a form that looks
+  /// syntactically very similar in both tools, and then continues by
+  /// abstracting the two concrete members and using the shared abstracted one
+  /// instead of the two concrete methods existing previously. During the early
+  /// stages of unifying the two concrete members it can be beneficial to use
+  /// [listTypeInternal] instead of the tool-specific ways of constructing a
+  /// future type, for the sake of uniformity, and to simplify the abstraction
+  /// step too.
+  TypeStructure listTypeInternal(TypeStructure elementType);
 
   /// Computes the least upper bound of [type1] and [type2].
-  Type lub(Type type1, Type type2);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [lubInternal] to receive a
+  /// concrete implementation of [lub] instead of implementing [lub] directly.
+  SharedTypeView<TypeStructure> lub(
+      SharedTypeView<TypeStructure> type1, SharedTypeView<TypeStructure> type2);
+
+  /// Computes the least upper bound of [typeSchema1] and [typeSchema2].
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [lubInternal] to receive a
+  /// concrete implementation of [typeSchemaLub] instead of implementing
+  /// [typeSchemaLub] directly.
+  SharedTypeSchemaView<TypeStructure> typeSchemaLub(
+      SharedTypeSchemaView<TypeStructure> typeSchema1,
+      SharedTypeSchemaView<TypeStructure> typeSchema2);
+
+  /// [lubInternal] should be implemented by concrete classes implementing
+  /// [TypeAnalyzerOperations]. The implementations of [lub] and [typeSchemaLub]
+  /// are provided by mixing in [TypeAnalyzerOperationsMixin], which defines
+  /// [lub] and [typeSchemaLub] in terms of [lubInternal].
+  ///
+  /// The main purpose of this method is to avoid code duplication in the
+  /// concrete classes implementing [TypeAnalyzerOperations], so they can
+  /// implement only one member, in this case [lubInternal], and receive the
+  /// implementation of both [lub] and [typeSchemaLub] from the mixin.
+  ///
+  /// The auxiliary purpose of [lubInternal] is to facilitate the development of
+  /// the shared code at early stages. Sometimes the sharing of the code starts
+  /// by unifying the implementations of some concrete members in the Analyzer
+  /// and the CFE by bringing them in a form that looks syntactically very
+  /// similar in both tools, and then continues by abstracting the two concrete
+  /// members and using the shared abstracted one instead of the two concrete
+  /// methods existing previously. During the early stages of unifying the two
+  /// concrete members it can be beneficial to use [lubInternal] instead of the
+  /// tool-specific ways of constructing a future type, for the sake of
+  /// uniformity, and to simplify the abstraction step too.
+  TypeStructure lubInternal(TypeStructure type1, TypeStructure type2);
 
   /// Computes the nullable form of [type], in other words the least upper bound
   /// of [type] and `Null`.
-  Type makeNullable(Type type);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [makeNullableInternal] to
+  /// receive a concrete implementation of [makeNullable] instead of
+  /// implementing [makeNullable] directly.
+  SharedTypeView<TypeStructure> makeNullable(
+      SharedTypeView<TypeStructure> type);
 
   /// Computes the nullable form of [typeSchema].
-  TypeSchema makeTypeSchemaNullable(TypeSchema typeSchema);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [makeNullableInternal] to
+  /// receive a concrete implementation of [makeTypeSchemaNullable] instead of
+  /// implementing [makeTypeSchemaNullable] directly.
+  SharedTypeSchemaView<TypeStructure> makeTypeSchemaNullable(
+      SharedTypeSchemaView<TypeStructure> typeSchema);
+
+  /// [makeNullableInternal] should be implemented by concrete classes
+  /// implementing [TypeAnalyzerOperations]. The implementations of
+  /// [makeNullable] and [makeTypeSchemaNullable] are provided by mixing in
+  /// [TypeAnalyzerOperationsMixin], which defines [makeNullable] and
+  /// [makeTypeSchemaNullable] in terms of [makeNullableInternal].
+  ///
+  /// The main purpose of this method is to avoid code duplication in the
+  /// concrete classes implementing [TypeAnalyzerOperations], so they can
+  /// implement only one member, in this case [makeNullableInternal], and
+  /// receive the implementation of both [makeNullable] and
+  /// [makeTypeSchemaNullable] from the mixin.
+  ///
+  /// The auxiliary purpose of [makeNullableInternal] is to facilitate the
+  /// development of the shared code at early stages. Sometimes the sharing of
+  /// the code starts by unifying the implementations of some concrete members
+  /// in the Analyzer and the CFE by bringing them in a form that looks
+  /// syntactically very similar in both tools, and then continues by
+  /// abstracting the two concrete members and using the shared abstracted one
+  /// instead of the two concrete methods existing previously. During the early
+  /// stages of unifying the two concrete members it can be beneficial to use
+  /// [makeNullableInternal] instead of the tool-specific ways of constructing a
+  /// future type, for the sake of uniformity, and to simplify the abstraction
+  /// step too.
+  TypeStructure makeNullableInternal(TypeStructure type);
 
   /// Returns the type `Map`, with type arguments.
-  Type mapType({
-    required Type keyType,
-    required Type valueType,
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [mapTypeInternal] to receive a
+  /// concrete implementation of [mapType] instead of implementing [mapType]
+  /// directly.
+  SharedTypeView<TypeStructure> mapType({
+    required SharedTypeView<TypeStructure> keyType,
+    required SharedTypeView<TypeStructure> valueType,
   });
 
   /// Returns the type schema `Map`, with type arguments [keyTypeSchema] and
   /// [valueTypeSchema].
-  TypeSchema mapTypeSchema(
-      {required TypeSchema keyTypeSchema, required TypeSchema valueTypeSchema});
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [mapTypeInternal] to receive a
+  /// concrete implementation of [makeTypeSchemaNullable] instead of
+  /// implementing [makeTypeSchemaNullable] directly.
+  SharedTypeSchemaView<TypeStructure> mapTypeSchema({
+    required SharedTypeSchemaView<TypeStructure> keyTypeSchema,
+    required SharedTypeSchemaView<TypeStructure> valueTypeSchema,
+  });
+
+  /// [mapTypeInternal] should be implemented by concrete classes implementing
+  /// [TypeAnalyzerOperations]. The implementations of [mapType] and
+  /// [makeTypeSchemaNullable] are provided by mixing in
+  /// [TypeAnalyzerOperationsMixin], which defines [mapType] and
+  /// [makeTypeSchemaNullable] in terms of [mapTypeInternal].
+  ///
+  /// The main purpose of this method is to avoid code duplication in the
+  /// concrete classes implementing [TypeAnalyzerOperations], so they can
+  /// implement only one member, in this case [mapTypeInternal], and receive the
+  /// implementation of both [mapType] and [makeTypeSchemaNullable] from the
+  /// mixin.
+  ///
+  /// The auxiliary purpose of [mapTypeInternal] is to facilitate the
+  /// development of the shared code at early stages. Sometimes the sharing of
+  /// the code starts by unifying the implementations of some concrete members
+  /// in the Analyzer and the CFE by bringing them in a form that looks
+  /// syntactically very similar in both tools, and then continues by
+  /// abstracting the two concrete members and using the shared abstracted one
+  /// instead of the two concrete methods existing previously. During the early
+  /// stages of unifying the two concrete members it can be beneficial to use
+  /// [mapTypeInternal] instead of the tool-specific ways of constructing a
+  /// future type, for the sake of uniformity, and to simplify the abstraction
+  /// step too.
+  TypeStructure mapTypeInternal({
+    required TypeStructure keyType,
+    required TypeStructure valueType,
+  });
 
   /// 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);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [matchFutureOrInternal] to
+  /// receive a concrete implementation of [matchFutureOr] instead of
+  /// implementing [matchFutureOr] directly.
+  SharedTypeView<TypeStructure>? matchFutureOr(
+      SharedTypeView<TypeStructure> type);
 
   /// If [typeSchema] takes the form `FutureOr<T>`, `FutureOr<T>?`, or
   /// `FutureOr<T>*` for some `T`, returns the type schema `T`. Otherwise
   /// returns `null`.
-  TypeSchema? matchTypeSchemaFutureOr(TypeSchema typeSchema);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [matchFutureOrInternal] to
+  /// receive a concrete implementation of [matchTypeSchemaFutureOr] instead of
+  /// implementing [matchTypeSchemaFutureOr] directly.
+  SharedTypeSchemaView<TypeStructure>? matchTypeSchemaFutureOr(
+      SharedTypeSchemaView<TypeStructure> typeSchema);
+
+  /// [matchFutureOrInternal] should be implemented by concrete classes
+  /// implementing [TypeAnalyzerOperations]. The implementations of
+  /// [matchFutureOr] and [matchTypeSchemaFutureOr] are provided by mixing in
+  /// [TypeAnalyzerOperationsMixin], which defines [matchFutureOr] and
+  /// [matchTypeSchemaFutureOr] in terms of [matchFutureOrInternal].
+  ///
+  /// The main purpose of this method is to avoid code duplication in the
+  /// concrete classes implementing [TypeAnalyzerOperations], so they can
+  /// implement only one member, in this case [matchFutureOrInternal], and
+  /// receive the implementation of both [matchFutureOr] and
+  /// [matchTypeSchemaFutureOr] from the mixin.
+  ///
+  /// The auxiliary purpose of [matchFutureOrInternal] is to facilitate the
+  /// development of the shared code at early stages. Sometimes the sharing of
+  /// the code starts by unifying the implementations of some concrete members
+  /// in the Analyzer and the CFE by bringing them in a form that looks
+  /// syntactically very similar in both tools, and then continues by
+  /// abstracting the two concrete members and using the shared abstracted one
+  /// instead of the two concrete methods existing previously. During the early
+  /// stages of unifying the two concrete members it can be beneficial to use
+  /// [matchFutureOrInternal] instead of the tool-specific ways of constructing
+  /// a future type, for the sake of uniformity, and to simplify the abstraction
+  /// step too.
+  TypeStructure? matchFutureOrInternal(TypeStructure type);
 
   /// If [type] is a parameter type that is of a kind used in type inference,
   /// returns the corresponding parameter.
@@ -179,27 +458,70 @@
   /// `foo`.
   ///
   ///   X foo<X>(bool c, X x1, X x2) => c ? x1 : x2;
-  InferableParameter? matchInferableParameter(Type type);
+  InferableParameter? matchInferableParameter(
+      SharedTypeView<TypeStructure> type);
 
   /// If [type] is a subtype of the type `Iterable<T>?` for some `T`, returns
   /// the type `T`.  Otherwise returns `null`.
-  Type? matchIterableType(Type type);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [matchIterableTypeInternal] to
+  /// receive a concrete implementation of [matchIterableType] instead of
+  /// implementing [matchIterableType] directly.
+  SharedTypeView<TypeStructure>? matchIterableType(
+      SharedTypeView<TypeStructure> type);
 
   /// If [typeSchema] is the type schema `Iterable<T>?` (or a subtype thereof),
   /// for some `T`, returns the type `T`. Otherwise returns `null`.
-  TypeSchema? matchIterableTypeSchema(TypeSchema typeSchema);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [matchIterableTypeInternal] to
+  /// receive a concrete implementation of [matchIterableTypeSchema] instead of
+  /// implementing [matchIterableTypeSchema] directly.
+  SharedTypeSchemaView<TypeStructure>? matchIterableTypeSchema(
+      SharedTypeSchemaView<TypeStructure> typeSchema);
+
+  /// [matchIterableTypeInternal] should be implemented by concrete classes
+  /// implementing [TypeAnalyzerOperations]. The implementations of
+  /// [matchIterableType] and [matchIterableTypeSchema] are provided by mixing
+  /// in [TypeAnalyzerOperationsMixin], which defines [matchIterableType] and
+  /// [matchIterableTypeSchema] in terms of [matchIterableTypeInternal].
+  ///
+  /// The main purpose of this method is to avoid code duplication in the
+  /// concrete classes implementing [TypeAnalyzerOperations], so they can
+  /// implement only one member, in this case [matchIterableTypeInternal], and
+  /// receive the implementation of both [matchIterableType] and
+  /// [matchIterableTypeSchema] from the mixin.
+  ///
+  /// The auxiliary purpose of [matchIterableTypeInternal] is to facilitate the
+  /// development of the shared code at early stages. Sometimes the sharing of
+  /// the code starts by unifying the implementations of some concrete members
+  /// in the Analyzer and the CFE by bringing them in a form that looks
+  /// syntactically very similar in both tools, and then continues by
+  /// abstracting the two concrete members and using the shared abstracted one
+  /// instead of the two concrete methods existing previously. During the early
+  /// stages of unifying the two concrete members it can be beneficial to use
+  /// [matchIterableTypeInternal] instead of the tool-specific ways of
+  /// constructing a future type, for the sake of uniformity, and to simplify
+  /// the abstraction step too.
+  TypeStructure? matchIterableTypeInternal(TypeStructure type);
 
   /// If [type] is a subtype of the type `List<T>?` for some `T`, returns the
   /// type `T`.  Otherwise returns `null`.
-  Type? matchListType(Type type);
+  SharedTypeView<TypeStructure>? matchListType(
+      SharedTypeView<TypeStructure> type);
 
   /// If [type] is a subtype of the type `Map<K, V>?` for some `K` and `V`,
   /// returns these `K` and `V`.  Otherwise returns `null`.
-  ({Type keyType, Type valueType})? matchMapType(Type type);
+  ({
+    SharedTypeView<TypeStructure> keyType,
+    SharedTypeView<TypeStructure> valueType
+  })? matchMapType(SharedTypeView<TypeStructure> type);
 
   /// If [type] is a subtype of the type `Stream<T>?` for some `T`, returns
   /// the type `T`.  Otherwise returns `null`.
-  Type? matchStreamType(Type type);
+  SharedTypeView<TypeStructure>? matchStreamType(
+      SharedTypeView<TypeStructure> type);
 
   /// If [type] was introduced by a class, mixin, enum, or extension type,
   /// returns an object of [TypeDeclarationMatchResult] describing the
@@ -207,24 +529,64 @@
   ///
   /// If [type] isn't introduced by a class, mixin, enum, or extension type,
   /// returns null.
-  TypeDeclarationMatchResult? matchTypeDeclarationType(Type type);
+  TypeDeclarationMatchResult? matchTypeDeclarationType(
+      SharedTypeView<TypeStructure> type);
 
   /// Computes `NORM` of [type].
   /// https://github.com/dart-lang/language
   /// See `resources/type-system/normalization.md`
-  Type normalize(Type type);
+  SharedTypeView<TypeStructure> normalize(SharedTypeView<TypeStructure> type);
 
   /// Builds the client specific record type.
-  Type recordType(
-      {required List<Type> positional, required List<(String, Type)> named});
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [recordTypeInternal] to
+  /// receive a concrete implementation of [recordType] instead of implementing
+  /// [recordType] directly.
+  SharedTypeView<TypeStructure> recordType(
+      {required List<SharedTypeView<TypeStructure>> positional,
+      required List<(String, SharedTypeView<TypeStructure>)> named});
 
   /// Builds the client specific record type schema.
-  TypeSchema recordTypeSchema(
-      {required List<TypeSchema> positional,
-      required List<(String, TypeSchema)> named});
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [recordTypeInternal] to
+  /// receive a concrete implementation of [recordTypeSchema] instead of
+  /// implementing [recordTypeSchema] directly.
+  SharedTypeSchemaView<TypeStructure> recordTypeSchema(
+      {required List<SharedTypeSchemaView<TypeStructure>> positional,
+      required List<(String, SharedTypeSchemaView<TypeStructure>)> named});
+
+  /// [recordTypeInternal] should be implemented by concrete classes
+  /// implementing [TypeAnalyzerOperations]. The implementations of [recordType]
+  /// and [recordTypeSchema] are provided by mixing in
+  /// [TypeAnalyzerOperationsMixin], which defines [recordType] and
+  /// [recordTypeSchema] in terms of [recordTypeInternal].
+  ///
+  /// The main purpose of this method is to avoid code duplication in the
+  /// concrete classes implementing [TypeAnalyzerOperations], so they can
+  /// implement only one member, in this case [recordTypeInternal], and receive
+  /// the implementation of both [recordType] and [recordTypeSchema] from the
+  /// mixin.
+  ///
+  /// The auxiliary purpose of [recordTypeInternal] is to facilitate the
+  /// development of the shared code at early stages. Sometimes the sharing of
+  /// the code starts by unifying the implementations of some concrete members
+  /// in the Analyzer and the CFE by bringing them in a form that looks
+  /// syntactically very similar in both tools, and then continues by
+  /// abstracting the two concrete members and using the shared abstracted one
+  /// instead of the two concrete methods existing previously. During the early
+  /// stages of unifying the two concrete members it can be beneficial to use
+  /// [recordTypeInternal] instead of the tool-specific ways of constructing a
+  /// future type, for the sake of uniformity, and to simplify the abstraction
+  /// step too.
+  TypeStructure recordTypeInternal(
+      {required List<TypeStructure> positional,
+      required List<(String, TypeStructure)> named});
 
   /// Returns the type schema `Stream`, with type argument [elementTypeSchema].
-  TypeSchema streamTypeSchema(TypeSchema elementTypeSchema);
+  SharedTypeSchemaView<TypeStructure> streamTypeSchema(
+      SharedTypeSchemaView<TypeStructure> elementTypeSchema);
 
   /// Returns `true` if [leftType] is a subtype of the greatest closure of
   /// [rightSchema].
@@ -234,10 +596,13 @@
   /// [leftType] via [isSubtypeOf]. However, that would mean at least two
   /// recursive descends over types. This method is supposed to have optimized
   /// implementations that only use one recursive descend.
-  bool typeIsSubtypeOfTypeSchema(Type leftType, TypeSchema rightSchema);
-
-  /// Computes the greatest lower bound of [typeSchema1] and [typeSchema2].
-  TypeSchema typeSchemaGlb(TypeSchema typeSchema1, TypeSchema typeSchema2);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should
+  /// implement [isSubtypeOfInternal] and mix in [TypeAnalyzerOperationsMixin]
+  /// to receive an implementation of [typeIsSubtypeOfTypeSchema] instead of
+  /// implementing it directly.
+  bool typeIsSubtypeOfTypeSchema(SharedTypeView<TypeStructure> leftType,
+      SharedTypeSchemaView<TypeStructure> rightSchema);
 
   /// Returns `true` if the least closure of [leftSchema] is a subtype of
   /// [rightType].
@@ -247,7 +612,13 @@
   /// [isSubtypeOf]. However, that would mean at least two recursive descends
   /// over types. This method is supposed to have optimized implementations
   /// that only use one recursive descend.
-  bool typeSchemaIsSubtypeOfType(TypeSchema leftSchema, Type rightType);
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should
+  /// implement [isSubtypeOfInternal] and mix in [TypeAnalyzerOperationsMixin]
+  /// to receive an implementation of [typeSchemaIsSubtypeOfType] instead of
+  /// implementing it directly.
+  bool typeSchemaIsSubtypeOfType(SharedTypeSchemaView<TypeStructure> leftSchema,
+      SharedTypeView<TypeStructure> rightType);
 
   /// Returns `true` if least closure of [leftSchema] is a subtype of
   /// the greatest closure of [rightSchema].
@@ -257,20 +628,236 @@
   /// the resulting types via [isSubtypeOf]. However, that would mean at least
   /// three recursive descends over types. This method is supposed to have
   /// optimized implementations that only use one recursive descend.
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should
+  /// implement [isSubtypeOfInternal] and mix in [TypeAnalyzerOperationsMixin]
+  /// to receive an implementation of [typeSchemaIsSubtypeOfTypeSchema] instead
+  /// of implementing it directly.
   bool typeSchemaIsSubtypeOfTypeSchema(
-      TypeSchema leftSchema, TypeSchema rightSchema);
+      SharedTypeSchemaView<TypeStructure> leftSchema,
+      SharedTypeSchemaView<TypeStructure> rightSchema);
 
-  /// Computes the least upper bound of [typeSchema1] and [typeSchema2].
-  TypeSchema typeSchemaLub(TypeSchema typeSchema1, TypeSchema typeSchema2);
-
-  /// Returns the nullability suffix of [typeSchema].
-  NullabilitySuffix typeSchemaNullabilitySuffix(TypeSchema typeSchema);
+  /// The concrete classes implementing [TypeAnalyzerOperations] should
+  /// implement [isSubtypeOfInternal] in order to receive the implementations of
+  /// [typeIsSubtypeOfTypeSchema], [typeSchemaIsSubtypeOfType], and
+  /// [typeSchemaIsSubtypeOfTypeSchema] by mixing in
+  /// [TypeAnalyzerOperationsMixin].
+  bool isSubtypeOfInternal(TypeStructure left, TypeStructure right);
 
   /// Converts a type into a corresponding type schema.
-  TypeSchema typeToSchema(Type type);
+  SharedTypeSchemaView<TypeStructure> typeToSchema(
+      SharedTypeView<TypeStructure> type);
 
   /// Returns [type] suffixed with the [suffix].
-  Type withNullabilitySuffix(Type type, NullabilitySuffix suffix);
+  SharedTypeView<TypeStructure> withNullabilitySuffix(
+      SharedTypeView<TypeStructure> type, NullabilitySuffix suffix);
+
+  @override
+  bool isNever(SharedTypeView<TypeStructure> type);
+
+  @override
+  bool isTypeParameterType(SharedTypeView<TypeStructure> type);
+
+  @override
+  SharedTypeView<TypeStructure> promoteToNonNull(
+      SharedTypeView<TypeStructure> type);
+
+  @override
+  SharedTypeView<TypeStructure>? tryPromoteToType(
+      SharedTypeView<TypeStructure> to, SharedTypeView<TypeStructure> from);
+}
+
+mixin TypeAnalyzerOperationsMixin<
+        TypeStructure extends SharedTypeStructure<TypeStructure>,
+        Variable extends Object,
+        InferableParameter extends Object,
+        TypeDeclarationType extends Object,
+        TypeDeclaration extends Object>
+    implements
+        TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
+            TypeDeclarationType, TypeDeclaration> {
+  @override
+  SharedTypeView<TypeStructure> futureType(
+      SharedTypeView<TypeStructure> argumentType) {
+    return new SharedTypeView(
+        futureTypeInternal(argumentType.unwrapTypeView()));
+  }
+
+  @override
+  SharedTypeSchemaView<TypeStructure> futureTypeSchema(
+      SharedTypeSchemaView<TypeStructure> argumentTypeSchema) {
+    return new SharedTypeSchemaView(
+        futureTypeInternal(argumentTypeSchema.unwrapTypeSchemaView()));
+  }
+
+  @override
+  TypeDeclarationKind? getTypeDeclarationKind(
+      SharedTypeView<TypeStructure> type) {
+    return getTypeDeclarationKindInternal(type.unwrapTypeView());
+  }
+
+  @override
+  TypeDeclarationKind? getTypeSchemaDeclarationKind(
+      SharedTypeSchemaView<TypeStructure> typeSchema) {
+    return getTypeDeclarationKindInternal(typeSchema.unwrapTypeSchemaView());
+  }
+
+  @override
+  SharedTypeView<TypeStructure> glb(SharedTypeView<TypeStructure> type1,
+      SharedTypeView<TypeStructure> type2) {
+    return new SharedTypeView(
+        glbInternal(type1.unwrapTypeView(), type2.unwrapTypeView()));
+  }
+
+  @override
+  SharedTypeSchemaView<TypeStructure> typeSchemaGlb(
+      SharedTypeSchemaView<TypeStructure> typeSchema1,
+      SharedTypeSchemaView<TypeStructure> typeSchema2) {
+    return new SharedTypeSchemaView(glbInternal(
+        typeSchema1.unwrapTypeSchemaView(),
+        typeSchema2.unwrapTypeSchemaView()));
+  }
+
+  @override
+  SharedTypeView<TypeStructure> listType(
+      SharedTypeView<TypeStructure> elementType) {
+    return new SharedTypeView(listTypeInternal(elementType.unwrapTypeView()));
+  }
+
+  @override
+  SharedTypeSchemaView<TypeStructure> listTypeSchema(
+      SharedTypeSchemaView<TypeStructure> elementTypeSchema) {
+    return new SharedTypeSchemaView(
+        listTypeInternal(elementTypeSchema.unwrapTypeSchemaView()));
+  }
+
+  @override
+  SharedTypeView<TypeStructure> lub(SharedTypeView<TypeStructure> type1,
+      SharedTypeView<TypeStructure> type2) {
+    return new SharedTypeView(
+        lubInternal(type1.unwrapTypeView(), type2.unwrapTypeView()));
+  }
+
+  @override
+  SharedTypeSchemaView<TypeStructure> typeSchemaLub(
+      SharedTypeSchemaView<TypeStructure> typeSchema1,
+      SharedTypeSchemaView<TypeStructure> typeSchema2) {
+    return new SharedTypeSchemaView(lubInternal(
+        typeSchema1.unwrapTypeSchemaView(),
+        typeSchema2.unwrapTypeSchemaView()));
+  }
+
+  @override
+  SharedTypeView<TypeStructure> makeNullable(
+      SharedTypeView<TypeStructure> type) {
+    return new SharedTypeView(makeNullableInternal(type.unwrapTypeView()));
+  }
+
+  @override
+  SharedTypeSchemaView<TypeStructure> makeTypeSchemaNullable(
+      SharedTypeSchemaView<TypeStructure> typeSchema) {
+    return new SharedTypeSchemaView(
+        makeNullableInternal(typeSchema.unwrapTypeSchemaView()));
+  }
+
+  @override
+  SharedTypeView<TypeStructure> mapType({
+    required SharedTypeView<TypeStructure> keyType,
+    required SharedTypeView<TypeStructure> valueType,
+  }) {
+    return new SharedTypeView(mapTypeInternal(
+        keyType: keyType.unwrapTypeView(),
+        valueType: valueType.unwrapTypeView()));
+  }
+
+  @override
+  SharedTypeSchemaView<TypeStructure> mapTypeSchema(
+      {required SharedTypeSchemaView<TypeStructure> keyTypeSchema,
+      required SharedTypeSchemaView<TypeStructure> valueTypeSchema}) {
+    return new SharedTypeSchemaView(mapTypeInternal(
+        keyType: keyTypeSchema.unwrapTypeSchemaView(),
+        valueType: valueTypeSchema.unwrapTypeSchemaView()));
+  }
+
+  @override
+  SharedTypeView<TypeStructure>? matchFutureOr(
+      SharedTypeView<TypeStructure> type) {
+    return matchFutureOrInternal(type.unwrapTypeView())?.wrapSharedTypeView();
+  }
+
+  @override
+  SharedTypeSchemaView<TypeStructure>? matchTypeSchemaFutureOr(
+      SharedTypeSchemaView<TypeStructure> typeSchema) {
+    return matchFutureOrInternal(typeSchema.unwrapTypeSchemaView())
+        ?.wrapSharedTypeSchemaView();
+  }
+
+  @override
+  SharedTypeView<TypeStructure>? matchIterableType(
+      SharedTypeView<TypeStructure> type) {
+    return matchIterableTypeInternal(type.unwrapTypeView())
+        ?.wrapSharedTypeView();
+  }
+
+  @override
+  SharedTypeSchemaView<TypeStructure>? matchIterableTypeSchema(
+      SharedTypeSchemaView<TypeStructure> typeSchema) {
+    return matchIterableTypeInternal(typeSchema.unwrapTypeSchemaView())
+        ?.wrapSharedTypeSchemaView();
+  }
+
+  @override
+  SharedTypeView<TypeStructure> recordType(
+      {required List<SharedTypeView<TypeStructure>> positional,
+      required List<(String, SharedTypeView<TypeStructure>)> named}) {
+    return new SharedTypeView(recordTypeInternal(
+        positional: positional.cast<TypeStructure>(),
+        named: named.cast<(String, TypeStructure)>()));
+  }
+
+  @override
+  SharedTypeSchemaView<TypeStructure> recordTypeSchema(
+      {required List<SharedTypeSchemaView<TypeStructure>> positional,
+      required List<(String, SharedTypeSchemaView<TypeStructure>)> named}) {
+    return new SharedTypeSchemaView(recordTypeInternal(
+        positional: positional.cast<TypeStructure>(),
+        named: named.cast<(String, TypeStructure)>()));
+  }
+
+  @override
+  bool isSubtypeOf(SharedTypeView<TypeStructure> leftType,
+      SharedTypeView<TypeStructure> rightType) {
+    return isSubtypeOfInternal(
+        leftType.unwrapTypeView(), rightType.unwrapTypeView());
+  }
+
+  @override
+  bool typeIsSubtypeOfTypeSchema(SharedTypeView<TypeStructure> leftType,
+      SharedTypeSchemaView<TypeStructure> rightSchema) {
+    return isSubtypeOfInternal(
+        leftType.unwrapTypeView(), rightSchema.unwrapTypeSchemaView());
+  }
+
+  @override
+  bool typeSchemaIsSubtypeOfType(SharedTypeSchemaView<TypeStructure> leftSchema,
+      SharedTypeView<TypeStructure> rightType) {
+    return isSubtypeOfInternal(
+        leftSchema.unwrapTypeSchemaView(), rightType.unwrapTypeView());
+  }
+
+  @override
+  bool typeSchemaIsSubtypeOfTypeSchema(
+      SharedTypeSchemaView<TypeStructure> leftSchema,
+      SharedTypeSchemaView<TypeStructure> rightSchema) {
+    return isSubtypeOfInternal(
+        leftSchema.unwrapTypeSchemaView(), rightSchema.unwrapTypeSchemaView());
+  }
+
+  @override
+  SharedTypeSchemaView<TypeStructure> typeToSchema(
+      SharedTypeView<TypeStructure> type) {
+    return new SharedTypeSchemaView(type.unwrapTypeView());
+  }
 }
 
 /// Describes all possibility for a type to be derived from a declaration.
@@ -456,9 +1043,8 @@
 
 /// Abstract interface of a type constraint generator.
 abstract class TypeConstraintGenerator<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
     Variable extends Object,
-    Type extends SharedType<Type>,
-    TypeSchema extends SharedType<TypeSchema>,
     InferableParameter extends Object,
     TypeDeclarationType extends Object,
     TypeDeclaration extends Object,
@@ -477,7 +1063,7 @@
   void restoreState(TypeConstraintGeneratorState state);
 
   /// Abstract type operations to be used in the matching methods.
-  TypeAnalyzerOperations<Variable, Type, TypeSchema, InferableParameter,
+  TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
       TypeDeclarationType, TypeDeclaration> get typeAnalyzerOperations;
 
   /// True if FutureOr types are required to have the empty [NullabilitySuffix]
@@ -503,7 +1089,8 @@
   ///
   /// The algorithm for subtype constraint generation is described in
   /// https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md#subtype-constraint-generation
-  bool performSubtypeConstraintGenerationRightSchema(Type p, TypeSchema q,
+  bool performSubtypeConstraintGenerationRightSchema(
+      SharedTypeView<TypeStructure> p, SharedTypeSchemaView<TypeStructure> q,
       {required AstNode? astNodeForTesting});
 
   /// Matches type schema [p] against type [q] as a subtype against supertype,
@@ -520,7 +1107,8 @@
   ///
   /// The algorithm for subtype constraint generation is described in
   /// https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md#subtype-constraint-generation
-  bool performSubtypeConstraintGenerationLeftSchema(TypeSchema p, Type q,
+  bool performSubtypeConstraintGenerationLeftSchema(
+      SharedTypeSchemaView<TypeStructure> p, SharedTypeView<TypeStructure> q,
       {required AstNode? astNodeForTesting});
 
   /// Matches type [p] against type schema [q] as a subtype against supertype
@@ -537,18 +1125,19 @@
   /// supposed to restore the generator to the prior state in case of a
   /// mismatch, taking that responsibility away from the caller.
   bool performSubtypeConstraintGenerationForFutureOrRightSchema(
-      Type p, TypeSchema q,
+      SharedTypeView<TypeStructure> p, SharedTypeSchemaView<TypeStructure> q,
       {required AstNode? astNodeForTesting}) {
     // If `Q` is `FutureOr<Q0>` the match holds under constraint set `C`:
-    if (typeAnalyzerOperations.matchTypeSchemaFutureOr(q) case TypeSchema q0?
+    if (typeAnalyzerOperations.matchTypeSchemaFutureOr(q)
+        case SharedTypeSchemaView<TypeStructure> q0?
         when enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr ||
-            typeAnalyzerOperations.typeSchemaNullabilitySuffix(q) ==
-                NullabilitySuffix.none) {
+            q.nullabilitySuffix == NullabilitySuffix.none) {
       final TypeConstraintGeneratorState state = currentState;
 
       // If `P` is `FutureOr<P0>` and `P0` is a subtype match for `Q0` under
       // constraint set `C`.
-      if (typeAnalyzerOperations.matchFutureOr(p) case Type p0?
+      if (typeAnalyzerOperations.matchFutureOr(p)
+          case SharedTypeView<TypeStructure> p0?
           when enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr ||
               p.nullabilitySuffix == NullabilitySuffix.none) {
         if (performSubtypeConstraintGenerationRightSchema(p0, q0,
@@ -600,20 +1189,21 @@
   /// supposed to restore the generator to the prior state in case of a
   /// mismatch, taking that responsibility away from the caller.
   bool performSubtypeConstraintGenerationForFutureOrLeftSchema(
-      TypeSchema p, Type q,
+      SharedTypeSchemaView<TypeStructure> p, SharedTypeView<TypeStructure> q,
       {required AstNode? astNodeForTesting}) {
     // If `Q` is `FutureOr<Q0>` the match holds under constraint set `C`:
-    if (typeAnalyzerOperations.matchFutureOr(q) case Type q0?
+    if (typeAnalyzerOperations.matchFutureOr(q)
+        case SharedTypeView<TypeStructure> q0?
         when enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr ||
             q.nullabilitySuffix == NullabilitySuffix.none) {
       final TypeConstraintGeneratorState state = currentState;
 
       // If `P` is `FutureOr<P0>` and `P0` is a subtype match for `Q0` under
       // constraint set `C`.
-      if (typeAnalyzerOperations.matchTypeSchemaFutureOr(p) case TypeSchema p0?
+      if (typeAnalyzerOperations.matchTypeSchemaFutureOr(p)
+          case SharedTypeSchemaView<TypeStructure> p0?
           when enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr ||
-              typeAnalyzerOperations.typeSchemaNullabilitySuffix(p) ==
-                  NullabilitySuffix.none) {
+              p.nullabilitySuffix == NullabilitySuffix.none) {
         if (performSubtypeConstraintGenerationLeftSchema(p0, q0,
             astNodeForTesting: astNodeForTesting)) {
           return true;
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 e77394e..32e8e68 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
@@ -9,13 +9,15 @@
 ///
 /// We require that `typeParameter <: constraint` if `isUpper` is true, and
 /// `constraint <: typeParameter` otherwise.
-class GeneratedTypeConstraint<Type extends Object, TypeSchema extends Object,
-    TypeParameter extends Object, Variable extends Object> {
+class GeneratedTypeConstraint<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    TypeParameter extends Object,
+    Variable extends Object> {
   /// The type parameter that is constrained by [constraint].
   final TypeParameter typeParameter;
 
   /// The type schema constraining the type parameter.
-  final TypeSchema constraint;
+  final SharedTypeSchemaView<TypeStructure> constraint;
 
   /// True if `typeParameter <: constraint`, and false otherwise.
   ///
@@ -37,8 +39,7 @@
 
 /// A constraint on a type parameter that we're inferring.
 class MergedTypeConstraint<
-    Type extends SharedType<Type>,
-    TypeSchema extends SharedType<TypeSchema>,
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
     TypeParameter extends Object,
     Variable extends Object,
     TypeDeclarationType extends Object,
@@ -62,7 +63,7 @@
   /// In the example above `num` is chosen as the greatest upper bound between
   /// `int` and `double`, so the resulting constraint is equal or stronger than
   /// either of the two.
-  TypeSchema lower;
+  SharedTypeSchemaView<TypeStructure> lower;
 
   /// The upper bound of the type being constrained.  The type being constrained
   /// must be a subtype of this bound. In other words, T <: upperBound.
@@ -86,10 +87,10 @@
   ///
   /// Here the [lower] will be `String` and the upper bound will be `num`,
   /// which cannot be satisfied, so this is ill typed.
-  TypeSchema upper;
+  SharedTypeSchemaView<TypeStructure> upper;
 
   /// Where this constraint comes from, used for error messages.
-  TypeConstraintOrigin<Type, TypeSchema, Variable, TypeParameter,
+  TypeConstraintOrigin<TypeStructure, Variable, TypeParameter,
       TypeDeclarationType, TypeDeclaration> origin;
 
   MergedTypeConstraint(
@@ -97,9 +98,9 @@
 
   MergedTypeConstraint.fromExtends(
       {required String typeParameterName,
-      required Type boundType,
-      required Type extendsType,
-      required TypeAnalyzerOperations<Variable, Type, TypeSchema, TypeParameter,
+      required SharedTypeView<TypeStructure> boundType,
+      required SharedTypeView<TypeStructure> extendsType,
+      required TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations})
       : this(
@@ -111,21 +112,22 @@
             upper: typeAnalyzerOperations.typeToSchema(extendsType),
             lower: typeAnalyzerOperations.unknownType);
 
-  MergedTypeConstraint<Type, TypeSchema, TypeParameter, Variable,
+  MergedTypeConstraint<TypeStructure, TypeParameter, Variable,
       TypeDeclarationType, TypeDeclaration> clone() {
     return new MergedTypeConstraint(lower: lower, upper: upper, origin: origin);
   }
 
   bool isEmpty(
-      TypeAnalyzerOperations<Variable, Type, TypeSchema, TypeParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
-    return lower is SharedUnknownType && upper is SharedUnknownType;
+    return lower is SharedUnknownTypeStructure &&
+        upper is SharedUnknownTypeStructure;
   }
 
   bool isSatisfiedBy(
-      Type type,
-      TypeAnalyzerOperations<Variable, Type, TypeSchema, TypeParameter,
+      SharedTypeView<TypeStructure> type,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     return typeAnalyzerOperations.typeIsSubtypeOfTypeSchema(type, upper) &&
@@ -133,9 +135,9 @@
   }
 
   void mergeIn(
-      GeneratedTypeConstraint<Type, TypeSchema, TypeParameter, Variable>
+      GeneratedTypeConstraint<TypeStructure, TypeParameter, Variable>
           generatedTypeConstraint,
-      TypeAnalyzerOperations<Variable, Type, TypeSchema, TypeParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     if (generatedTypeConstraint.isUpper) {
@@ -148,16 +150,16 @@
   }
 
   void mergeInTypeSchemaUpper(
-      TypeSchema constraint,
-      TypeAnalyzerOperations<Variable, Type, TypeSchema, TypeParameter,
+      SharedTypeSchemaView<TypeStructure> constraint,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     upper = typeAnalyzerOperations.typeSchemaGlb(upper, constraint);
   }
 
   void mergeInTypeSchemaLower(
-      TypeSchema constraint,
-      TypeAnalyzerOperations<Variable, Type, TypeSchema, TypeParameter,
+      SharedTypeSchemaView<TypeStructure> constraint,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     lower = typeAnalyzerOperations.typeSchemaLub(lower, constraint);
@@ -173,8 +175,7 @@
 /// readable error message during type inference as well as determining whether
 /// the constraint was used to fix the type parameter or not.
 abstract class TypeConstraintOrigin<
-    Type extends SharedType<Type>,
-    TypeSchema extends SharedType<TypeSchema>,
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
     Variable extends Object,
     TypeParameter extends Object,
     TypeDeclarationType extends Object,
@@ -182,25 +183,24 @@
   const TypeConstraintOrigin();
 
   List<String> formatError(
-      TypeAnalyzerOperations<Variable, Type, TypeSchema, TypeParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations);
 }
 
 class UnknownTypeConstraintOrigin<
-        Type extends SharedType<Type>,
-        TypeSchema extends SharedType<TypeSchema>,
+        TypeStructure extends SharedTypeStructure<TypeStructure>,
         Variable extends Object,
         InferableParameter extends Object,
         TypeDeclarationType extends Object,
         TypeDeclaration extends Object>
-    extends TypeConstraintOrigin<Type, TypeSchema, Variable, InferableParameter,
+    extends TypeConstraintOrigin<TypeStructure, Variable, InferableParameter,
         TypeDeclarationType, TypeDeclaration> {
   const UnknownTypeConstraintOrigin();
 
   @override
   List<String> formatError(
-      TypeAnalyzerOperations<Variable, Type, TypeSchema, InferableParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     return <String>[];
@@ -208,16 +208,15 @@
 }
 
 class TypeConstraintFromArgument<
-        Type extends SharedType<Type>,
-        TypeSchema extends SharedType<TypeSchema>,
+        TypeStructure extends SharedTypeStructure<TypeStructure>,
         Variable extends Object,
         InferableParameter extends Object,
         TypeDeclarationType extends Object,
         TypeDeclaration extends Object>
-    extends TypeConstraintOrigin<Type, TypeSchema, Variable, InferableParameter,
+    extends TypeConstraintOrigin<TypeStructure, Variable, InferableParameter,
         TypeDeclarationType, TypeDeclaration> {
-  final Type argumentType;
-  final Type parameterType;
+  final SharedTypeView<TypeStructure> argumentType;
+  final SharedTypeView<TypeStructure> parameterType;
   final String parameterName;
   final String? genericClassName;
   final bool isGenericClassInDartCore;
@@ -231,7 +230,7 @@
 
   @override
   List<String> formatError(
-      TypeAnalyzerOperations<Variable, Type, TypeSchema, InferableParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     // TODO(cstefantsova): we should highlight the span. That would be more
@@ -258,13 +257,12 @@
 }
 
 class TypeConstraintFromExtendsClause<
-        Type extends SharedType<Type>,
-        TypeSchema extends SharedType<TypeSchema>,
+        TypeStructure extends SharedTypeStructure<TypeStructure>,
         Variable extends Object,
         InferableParameter extends Object,
         TypeDeclarationType extends Object,
         TypeDeclaration extends Object>
-    extends TypeConstraintOrigin<Type, TypeSchema, Variable, InferableParameter,
+    extends TypeConstraintOrigin<TypeStructure, Variable, InferableParameter,
         TypeDeclarationType, TypeDeclaration> {
   /// Name of the type parameter with the extends clause.
   final String typeParameterName;
@@ -273,13 +271,13 @@
   /// this clause only when it is not `null`.
   ///
   /// For example `Iterable<T>` for `<T, E extends Iterable<T>>`.
-  final Type boundType;
+  final SharedTypeView<TypeStructure> boundType;
 
   /// [boundType] in which type parameters are substituted with inferred
   /// type arguments.
   ///
   /// For example `Iterable<int>` if `T` inferred to `int`.
-  final Type extendsType;
+  final SharedTypeView<TypeStructure> extendsType;
 
   TypeConstraintFromExtendsClause(
       {required this.typeParameterName,
@@ -288,7 +286,7 @@
 
   @override
   List<String> formatError(
-      TypeAnalyzerOperations<Variable, Type, TypeSchema, InferableParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     String boundStr = boundType.getDisplayString();
@@ -301,13 +299,14 @@
 }
 
 class TypeConstraintFromFunctionContext<
-        Type extends SharedType<Type>,
-        TypeSchema extends SharedType<TypeSchema>,
+        TypeStructure extends SharedTypeStructure<TypeStructure>,
+        Type extends SharedTypeStructure<Type>,
+        TypeSchema extends SharedTypeStructure<TypeSchema>,
         Variable extends Object,
         InferableParameter extends Object,
         TypeDeclarationType extends Object,
         TypeDeclaration extends Object>
-    extends TypeConstraintOrigin<Type, TypeSchema, Variable, InferableParameter,
+    extends TypeConstraintOrigin<TypeStructure, Variable, InferableParameter,
         TypeDeclarationType, TypeDeclaration> {
   final Type contextType;
   final Type functionType;
@@ -317,7 +316,7 @@
 
   @override
   List<String> formatError(
-      TypeAnalyzerOperations<Variable, Type, TypeSchema, InferableParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     return [
@@ -329,13 +328,14 @@
 }
 
 class TypeConstraintFromReturnType<
-        Type extends SharedType<Type>,
-        TypeSchema extends SharedType<TypeSchema>,
+        TypeStructure extends SharedTypeStructure<TypeStructure>,
+        Type extends SharedTypeStructure<Type>,
+        TypeSchema extends SharedTypeStructure<TypeSchema>,
         Variable extends Object,
         InferableParameter extends Object,
         TypeDeclarationType extends Object,
         TypeDeclaration extends Object>
-    extends TypeConstraintOrigin<Type, TypeSchema, Variable, InferableParameter,
+    extends TypeConstraintOrigin<TypeStructure, Variable, InferableParameter,
         TypeDeclarationType, TypeDeclaration> {
   final Type contextType;
   final Type declaredType;
@@ -345,7 +345,7 @@
 
   @override
   List<String> formatError(
-      TypeAnalyzerOperations<Variable, Type, TypeSchema, InferableParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     return [
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 4bd057a..c775ee0 100644
--- a/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart
@@ -6,56 +6,224 @@
 
 /// Common interface for data structures used by the implementations to
 /// represent the type `dynamic`.
-abstract interface class SharedDynamicType<Type extends SharedType<Type>>
-    implements SharedType<Type> {}
+abstract interface class SharedDynamicTypeStructure<
+        TypeStructure extends SharedTypeStructure<TypeStructure>>
+    implements SharedTypeStructure<TypeStructure> {}
 
 /// 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<Type extends SharedType<Type>>
-    implements SharedType<Type> {}
+abstract interface class SharedInvalidTypeStructure<
+        TypeStructure extends SharedTypeStructure<TypeStructure>>
+    implements SharedTypeStructure<TypeStructure> {}
 
 /// Common interface for data structures used by the implementations to
 /// represent a name/type pair.
-abstract interface class SharedNamedType<Type extends SharedType<Type>> {
+abstract interface class SharedNamedTypeStructure<
+    TypeStructure extends SharedTypeStructure<TypeStructure>> {
   String get name;
-  Type get type;
+  TypeStructure get type;
 }
 
 /// Common interface for data structures used by the implementations to
 /// represent a record type.
-abstract interface class SharedRecordType<Type extends SharedType<Type>>
-    implements SharedType<Type> {
-  List<SharedNamedType<Type>> get namedTypes;
+abstract interface class SharedRecordTypeStructure<
+        TypeStructure extends SharedTypeStructure<TypeStructure>>
+    implements SharedTypeStructure<TypeStructure> {
+  List<SharedNamedTypeStructure<TypeStructure>> get namedTypes;
 
-  List<Type> get positionalTypes;
+  List<TypeStructure> get positionalTypes;
 }
 
 /// Common interface for data structures used by the implementations to
 /// represent a type.
-abstract interface class SharedType<Type extends SharedType<Type>> {
+abstract interface class SharedTypeStructure<
+    TypeStructure extends SharedTypeStructure<TypeStructure>> {
   /// If this type ends in a suffix (`?` or `*`), the suffix it ends with;
   /// otherwise [NullabilitySuffix.none].
   NullabilitySuffix get nullabilitySuffix;
 
-  /// Return the presentation of this type as it should appear when presented
-  /// to users in contexts such as error messages.
+  /// 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<Type> other);
+  bool isStructurallyEqualTo(SharedTypeStructure<TypeStructure> other);
 }
 
 /// Common interface for data structures used by the implementations to
 /// represent the unknown type schema (`_`).
-abstract interface class SharedUnknownType<Type extends SharedType<Type>>
-    implements SharedType<Type> {}
+///
+/// Note below that there is no `SharedUnknownTypeView`, only
+/// [SharedUnknownTypeSchemaView], since we want to restrict
+/// [SharedUnknownTypeStructure] from appearing in type views.
+abstract interface class SharedUnknownTypeStructure<
+        TypeStructure extends SharedTypeStructure<TypeStructure>>
+    implements SharedTypeStructure<TypeStructure> {}
 
 /// Common interface for data structures used by the implementations to
 /// represent the type `void`.
-abstract interface class SharedVoidType<Type extends SharedType<Type>>
-    implements SharedType<Type> {}
+abstract interface class SharedVoidTypeStructure<
+        TypeStructure extends SharedTypeStructure<TypeStructure>>
+    implements SharedTypeStructure<TypeStructure> {}
+
+extension type SharedTypeView<
+        TypeStructure extends SharedTypeStructure<TypeStructure>>(
+    SharedTypeStructure<TypeStructure> _typeStructure) implements Object {
+  TypeStructure unwrapTypeView() => _typeStructure as TypeStructure;
+
+  NullabilitySuffix get nullabilitySuffix => _typeStructure.nullabilitySuffix;
+
+  String getDisplayString() => _typeStructure.getDisplayString();
+}
+
+extension type SharedDynamicTypeView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedDynamicTypeStructure<TypeStructure> _typeStructure)
+    implements SharedTypeView<TypeStructure> {}
+
+extension type SharedInvalidTypeView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedInvalidTypeStructure<TypeStructure> _typeStructure)
+    implements SharedTypeView<TypeStructure> {}
+
+extension type SharedNamedTypeView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedNamedTypeStructure<TypeStructure> _namedTypeStructure)
+    implements Object {
+  SharedTypeView<TypeStructure> get type =>
+      new SharedTypeView(_namedTypeStructure.type);
+
+  String get name => _namedTypeStructure.name;
+}
+
+extension type SharedRecordTypeView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedRecordTypeStructure<TypeStructure> _typeStructure)
+    implements SharedTypeView<TypeStructure> {
+  List<SharedNamedTypeView<TypeStructure>> get namedTypes {
+    return _typeStructure.namedTypes
+        as List<SharedNamedTypeView<TypeStructure>>;
+  }
+
+  List<SharedTypeView<TypeStructure>> get positionalTypes {
+    return _typeStructure.positionalTypes
+        as List<SharedTypeView<TypeStructure>>;
+  }
+}
+
+extension type SharedVoidTypeView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedVoidTypeStructure<TypeStructure> _typeStructure)
+    implements SharedTypeView<TypeStructure> {}
+
+extension type SharedTypeSchemaView<
+        TypeStructure extends SharedTypeStructure<TypeStructure>>(
+    SharedTypeStructure<TypeStructure> _typeStructure) implements Object {
+  TypeStructure unwrapTypeSchemaView() => _typeStructure as TypeStructure;
+
+  NullabilitySuffix get nullabilitySuffix => _typeStructure.nullabilitySuffix;
+
+  String getDisplayString() => _typeStructure.getDisplayString();
+}
+
+extension type SharedDynamicTypeSchemaView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedDynamicTypeStructure<TypeStructure> _typeStructure)
+    implements SharedTypeSchemaView<TypeStructure> {}
+
+extension type SharedInvalidTypeSchemaView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedInvalidTypeStructure<TypeStructure> _typeStructure)
+    implements SharedTypeSchemaView<TypeStructure> {}
+
+extension type SharedNamedTypeSchemaView<
+        TypeStructure extends SharedTypeStructure<TypeStructure>>(
+    SharedNamedTypeStructure<TypeStructure> _typeStructure) implements Object {}
+
+extension type SharedRecordTypeSchemaView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedRecordTypeStructure<TypeStructure> _typeStructure)
+    implements SharedTypeSchemaView<TypeStructure> {
+  List<SharedNamedTypeSchemaView<TypeStructure>> get namedTypes {
+    return _typeStructure.namedTypes
+        as List<SharedNamedTypeSchemaView<TypeStructure>>;
+  }
+
+  List<SharedTypeSchemaView<TypeStructure>> get positionalTypes {
+    return _typeStructure.positionalTypes
+        as List<SharedTypeSchemaView<TypeStructure>>;
+  }
+}
+
+/// Note that there is no `SharedUnknownTypeView`, only
+/// [SharedUnknownTypeSchemaView], since we want to restrict
+/// [SharedUnknownTypeStructure] from appearing in type views and allow it to
+/// appear only in type schema views.
+extension type SharedUnknownTypeSchemaView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedUnknownTypeStructure<TypeStructure> _typeStructure)
+    implements SharedTypeSchemaView<TypeStructure> {}
+
+extension type SharedVoidTypeSchemaView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedVoidTypeStructure<TypeStructure> _typeStructure)
+    implements SharedTypeSchemaView<TypeStructure> {}
+
+/// Extension methods of [SharedTypeStructureExtension] are intended to avoid
+/// explicit null-testing on types before wrapping them into [SharedTypeView] or
+/// [SharedTypeSchemaView].
+///
+/// Consider the following code:
+///     DartType? type = e.foo();
+///     return type == null ? null : SharedTypeView(type);
+///
+/// In the example above we want to wrap the result of the evaluation of
+/// `e.foo()` in `SharedTypeView` if it's not null. For that we need to store it
+/// into a variable to enable promotion in the ternary operator that will
+/// perform the wrapping.
+///
+/// This code can be rewritten in a more concise way using
+/// [SharedTypeStructureExtension] as follows:
+///     return e.foo()?.wrapSharedTypeView();
+extension SharedTypeStructureExtension<
+        TypeStructure extends SharedTypeStructure<TypeStructure>>
+    on SharedTypeStructure<TypeStructure> {
+  SharedTypeView<TypeStructure> wrapSharedTypeView() {
+    return new SharedTypeView(this);
+  }
+
+  SharedTypeSchemaView<TypeStructure> wrapSharedTypeSchemaView() {
+    return new SharedTypeSchemaView(this);
+  }
+}
+
+extension SharedTypeStructureMapEntryExtension<
+    TypeStructure extends SharedTypeStructure<TypeStructure>> on ({
+  SharedTypeStructure<TypeStructure> keyType,
+  SharedTypeStructure<TypeStructure> valueType
+}) {
+  ({
+    SharedTypeView<TypeStructure> keyType,
+    SharedTypeView<TypeStructure> valueType
+  }) wrapSharedTypeMapEntryView() {
+    return (
+      keyType: new SharedTypeView(this.keyType),
+      valueType: new SharedTypeView(this.valueType)
+    );
+  }
+
+  ({
+    SharedTypeSchemaView<TypeStructure> keyType,
+    SharedTypeSchemaView<TypeStructure> valueType
+  }) wrapSharedTypeSchemaMapEntryView() {
+    return (
+      keyType: new SharedTypeSchemaView(this.keyType),
+      valueType: new SharedTypeSchemaView(this.valueType)
+    );
+  }
+}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
index efe460f..537738b 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
@@ -6,6 +6,7 @@
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis_operations.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/promotion_key_store.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 
 import '../mini_ast.dart';
 import '../mini_ir.dart';
@@ -17,41 +18,46 @@
 Expression getSsaNodes(void Function(SsaNodeHarness) callback) =>
     new _GetSsaNodes(callback, location: computeLocation());
 
-Expression implicitThis_whyNotPromoted(String staticType,
-        void Function(Map<Type, NonPromotionReason>) callback) =>
+Expression implicitThis_whyNotPromoted(
+        String staticType,
+        void Function(Map<SharedTypeView<Type>, NonPromotionReason>)
+            callback) =>
     new _WhyNotPromoted_ImplicitThis(Type(staticType), callback,
         location: computeLocation());
 
 /// Test harness for creating flow analysis tests.  This class provides all
 /// the [FlowAnalysisOperations] needed by flow analysis, as well as other
 /// methods needed for testing.
-class FlowAnalysisTestHarness extends Harness with FlowModelHelper<Type> {
+class FlowAnalysisTestHarness extends Harness
+    with FlowModelHelper<SharedTypeView<Type>> {
   @override
   final PromotionKeyStore<Var> promotionKeyStore = PromotionKeyStore();
 
   @override
-  final Type boolType = Type('bool');
+  final SharedTypeView<Type> boolType = SharedTypeView(Type('bool'));
 
   @override
-  FlowAnalysisOperations<Var, Type> get typeOperations =>
+  FlowAnalysisOperations<Var, SharedTypeView<Type>> get typeOperations =>
       typeAnalyzer.operations;
 }
 
 /// Helper class allowing tests to examine the values of variables' SSA nodes.
 class SsaNodeHarness {
-  final FlowAnalysis<Node, Statement, Expression, Var, Type> _flow;
+  final FlowAnalysis<Node, Statement, Expression, Var, SharedTypeView<Type>>
+      _flow;
 
   SsaNodeHarness(this._flow);
 
   /// Gets the SSA node associated with [variable] at the current point in
   /// control flow, or `null` if the variable has been write captured.
-  SsaNode<Type>? operator [](Var variable) => _flow.ssaNodeForTesting(variable);
+  SsaNode<SharedTypeView<Type>>? operator [](Var variable) =>
+      _flow.ssaNodeForTesting(variable);
 }
 
 class _GetExpressionInfo extends Expression {
   final Expression target;
 
-  final void Function(ExpressionInfo<Type>?) callback;
+  final void Function(ExpressionInfo<SharedTypeView<Type>>?) callback;
 
   _GetExpressionInfo(this.target, this.callback, {required super.location});
 
@@ -61,7 +67,8 @@
   }
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var type =
         h.typeAnalyzer.analyzeExpression(target, h.operations.unknownType);
     h.flow.forwardExpression(this, target);
@@ -79,17 +86,19 @@
   void preVisit(PreVisitor visitor) {}
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     callback(SsaNodeHarness(h.flow));
     h.irBuilder.atom('null', Kind.expression, location: location);
-    return SimpleTypeAnalysisResult(type: h.typeAnalyzer.nullType);
+    return SimpleTypeAnalysisResult(
+        type: SharedTypeView(h.typeAnalyzer.nullType));
   }
 }
 
 class _WhyNotPromoted extends Expression {
   final Expression target;
 
-  final void Function(Map<Type, NonPromotionReason>) callback;
+  final void Function(Map<SharedTypeView<Type>, NonPromotionReason>) callback;
 
   _WhyNotPromoted(this.target, this.callback, {required super.location});
 
@@ -102,7 +111,8 @@
   String toString() => '$target (whyNotPromoted)';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var type =
         h.typeAnalyzer.analyzeExpression(target, h.operations.unknownType);
     h.flow.forwardExpression(this, target);
@@ -114,7 +124,7 @@
 class _WhyNotPromoted_ImplicitThis extends Expression {
   final Type staticType;
 
-  final void Function(Map<Type, NonPromotionReason>) callback;
+  final void Function(Map<SharedTypeView<Type>, NonPromotionReason>) callback;
 
   _WhyNotPromoted_ImplicitThis(this.staticType, this.callback,
       {required super.location});
@@ -126,10 +136,12 @@
   String toString() => 'implicit this (whyNotPromoted)';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
-    callback(h.flow.whyNotPromotedImplicitThis(staticType)());
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
+    callback(h.flow.whyNotPromotedImplicitThis(SharedTypeView(staticType))());
     h.irBuilder.atom('noop', Kind.expression, location: location);
-    return SimpleTypeAnalysisResult(type: h.typeAnalyzer.nullType);
+    return SimpleTypeAnalysisResult(
+        type: SharedTypeView(h.typeAnalyzer.nullType));
   }
 }
 
@@ -139,7 +151,8 @@
   /// [ExpressionInfo] associated with it.  If the expression has no flow
   /// analysis information associated with it, `null` will be passed to
   /// [callback].
-  Expression getExpressionInfo(void Function(ExpressionInfo<Type>?) callback) {
+  Expression getExpressionInfo(
+      void Function(ExpressionInfo<SharedTypeView<Type>>?) callback) {
     var location = computeLocation();
     return new _GetExpressionInfo(asExpression(location: location), callback,
         location: location);
@@ -150,7 +163,7 @@
   /// non-promotion info associated with it.  If the expression has no
   /// non-promotion info, an empty map will be passed to [callback].
   Expression whyNotPromoted(
-      void Function(Map<Type, NonPromotionReason>) callback) {
+      void Function(Map<SharedTypeView<Type>, NonPromotionReason>) callback) {
     var location = computeLocation();
     return new _WhyNotPromoted(asExpression(location: location), callback,
         location: location);
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index 91a182b..4a4d073 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -9,6 +9,7 @@
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis_operations.dart';
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_link.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/assigned_variables.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:test/test.dart';
 
 import '../mini_ast.dart';
@@ -25,7 +26,7 @@
   group('API', () {
     test('asExpression_end promotes variables', () {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforePromotion;
+      late SsaNode<SharedTypeView<Type>> ssaBeforePromotion;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
@@ -201,7 +202,7 @@
 
     test('equalityOp(x != null) promotes true branch', () {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforePromotion;
+      late SsaNode<SharedTypeView<Type>> ssaBeforePromotion;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
@@ -265,7 +266,7 @@
 
     test('equalityOp(x == null) promotes false branch', () {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforePromotion;
+      late SsaNode<SharedTypeView<Type>> ssaBeforePromotion;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
@@ -297,7 +298,7 @@
 
     test('equalityOp(null != x) promotes true branch', () {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforePromotion;
+      late SsaNode<SharedTypeView<Type>> ssaBeforePromotion;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
@@ -325,7 +326,7 @@
 
     test('equalityOp(null == x) promotes false branch', () {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforePromotion;
+      late SsaNode<SharedTypeView<Type>> ssaBeforePromotion;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
@@ -437,7 +438,7 @@
 
     test('doStatement_bodyBegin() un-promotes', () {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforeLoop;
+      late SsaNode<SharedTypeView<Type>> ssaBeforeLoop;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         x.as_('int'),
@@ -592,10 +593,11 @@
     test('finish checks proper nesting', () {
       var e = expr('Null');
       var s = if_(e, []);
-      var flow = FlowAnalysis<Node, Statement, Expression, Var, Type>(
-          h.typeOperations, AssignedVariables<Node, Var>(),
-          respectImplicitlyTypedVarInitializers: true,
-          fieldPromotionEnabled: true);
+      var flow =
+          FlowAnalysis<Node, Statement, Expression, Var, SharedTypeView<Type>>(
+              h.typeOperations, AssignedVariables<Node, Var>(),
+              respectImplicitlyTypedVarInitializers: true,
+              fieldPromotionEnabled: true);
       flow.ifStatement_conditionBegin();
       flow.ifStatement_thenBegin(e, s);
       expect(() => flow.finish(), _asserts);
@@ -603,7 +605,7 @@
 
     test('for_conditionBegin() un-promotes', () {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforeLoop;
+      late SsaNode<SharedTypeView<Type>> ssaBeforeLoop;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         x.as_('int'),
@@ -737,8 +739,8 @@
     test('for_end() with break updates Ssa of modified vars', () {
       var x = Var('x');
       var y = Var('y');
-      late SsaNode<Type> xSsaInsideLoop;
-      late SsaNode<Type> ySsaInsideLoop;
+      late SsaNode<SharedTypeView<Type>> xSsaInsideLoop;
+      late SsaNode<SharedTypeView<Type>> ySsaInsideLoop;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
@@ -765,8 +767,8 @@
         'tested', () {
       var x = Var('x');
       var y = Var('y');
-      late SsaNode<Type> xSsaInsideLoop;
-      late SsaNode<Type> ySsaInsideLoop;
+      late SsaNode<SharedTypeView<Type>> xSsaInsideLoop;
+      late SsaNode<SharedTypeView<Type>> ySsaInsideLoop;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
@@ -791,7 +793,7 @@
 
     test('forEach_bodyBegin() un-promotes', () {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforeLoop;
+      late SsaNode<SharedTypeView<Type>> ssaBeforeLoop;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         x.as_('int'),
@@ -944,7 +946,7 @@
     test('functionExpression_begin() cancels promotions of written vars', () {
       var x = Var('x');
       var y = Var('y');
-      late SsaNode<Type> ssaBeforeFunction;
+      late SsaNode<SharedTypeView<Type>> ssaBeforeFunction;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
@@ -1263,7 +1265,7 @@
       var x = Var('x');
       var y = Var('y');
       var z = Var('z');
-      late SsaNode<Type> xSsaNodeBeforeIf;
+      late SsaNode<SharedTypeView<Type>> xSsaNodeBeforeIf;
       h.run([
         declare(w, type: 'Object', initializer: expr('Object')),
         declare(x, type: 'bool', initializer: expr('bool')),
@@ -1291,7 +1293,7 @@
         'ifStatement_end() ignores non-matching SSA info from "then" path if '
         'unreachable', () {
       var x = Var('x');
-      late SsaNode<Type> xSsaNodeBeforeIf;
+      late SsaNode<SharedTypeView<Type>> xSsaNodeBeforeIf;
       h.run([
         declare(x, type: 'Object', initializer: expr('Object')),
         getSsaNodes((nodes) {
@@ -1311,7 +1313,7 @@
         'ifStatement_end() ignores non-matching SSA info from "else" path if '
         'unreachable', () {
       var x = Var('x');
-      late SsaNode<Type> xSsaNodeBeforeIf;
+      late SsaNode<SharedTypeView<Type>> xSsaNodeBeforeIf;
       h.run([
         declare(x, type: 'Object', initializer: expr('Object')),
         getSsaNodes((nodes) {
@@ -1428,6 +1430,7 @@
                   .get(h, key)!
                   .promotedTypes!
                   .single
+                  .unwrapTypeView()
                   .type,
               'int');
         }),
@@ -1517,7 +1520,7 @@
         String? expectedPromotedTypeThen, String? expectedPromotedTypeElse,
         {bool inverted = false}) {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforePromotion;
+      late SsaNode<SharedTypeView<Type>> ssaBeforePromotion;
       h.run([
         declare(x, type: declaredType, initializer: expr(declaredType)),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
@@ -1788,7 +1791,7 @@
 
     test('nonNullAssert_end(x) promotes', () {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforePromotion;
+      late SsaNode<SharedTypeView<Type>> ssaBeforePromotion;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
@@ -1810,7 +1813,7 @@
 
     test('nullAwareAccess temporarily promotes', () {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforePromotion;
+      late SsaNode<SharedTypeView<Type>> ssaBeforePromotion;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
@@ -2132,7 +2135,7 @@
 
     test('switchStatement_beginCase(true) un-promotes', () {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforeSwitch;
+      late SsaNode<SharedTypeView<Type>> ssaBeforeSwitch;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         x.as_('int'),
@@ -2296,7 +2299,7 @@
     test('tryCatchStatement_bodyEnd() un-promotes variables assigned in body',
         () {
       var x = Var('x');
-      late SsaNode<Type> ssaAfterTry;
+      late SsaNode<SharedTypeView<Type>> ssaAfterTry;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         x.as_('int'),
@@ -2427,8 +2430,8 @@
         'tryFinallyStatement_finallyBegin() un-promotes variables assigned in '
         'body', () {
       var x = Var('x');
-      late SsaNode<Type> ssaAtStartOfTry;
-      late SsaNode<Type> ssaAfterTry;
+      late SsaNode<SharedTypeView<Type>> ssaAtStartOfTry;
+      late SsaNode<SharedTypeView<Type>> ssaAfterTry;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         x.as_('int'),
@@ -2497,8 +2500,8 @@
         'variables assigned in finally', () {
       var x = Var('x');
       var y = Var('y');
-      late SsaNode<Type> xSsaAtEndOfFinally;
-      late SsaNode<Type> ySsaAtEndOfFinally;
+      late SsaNode<SharedTypeView<Type>> xSsaAtEndOfFinally;
+      late SsaNode<SharedTypeView<Type>> ySsaAtEndOfFinally;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
@@ -2536,10 +2539,10 @@
           'is sound to do so', () {
         var x = Var('x');
         var y = Var('y');
-        late SsaNode<Type> xSsaAtEndOfTry;
-        late SsaNode<Type> ySsaAtEndOfTry;
-        late SsaNode<Type> xSsaAtEndOfFinally;
-        late SsaNode<Type> ySsaAtEndOfFinally;
+        late SsaNode<SharedTypeView<Type>> xSsaAtEndOfTry;
+        late SsaNode<SharedTypeView<Type>> ySsaAtEndOfTry;
+        late SsaNode<SharedTypeView<Type>> xSsaAtEndOfFinally;
+        late SsaNode<SharedTypeView<Type>> ySsaAtEndOfFinally;
         h.run([
           declare(x, type: 'int?', initializer: expr('int?')),
           declare(y, type: 'int?', initializer: expr('int?')),
@@ -2999,7 +3002,7 @@
 
     test('whileStatement_conditionBegin() un-promotes', () {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforeLoop;
+      late SsaNode<SharedTypeView<Type>> ssaBeforeLoop;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         x.as_('int'),
@@ -3078,8 +3081,8 @@
     test('whileStatement_end() with break updates Ssa of modified vars', () {
       var x = Var('x');
       var y = Var('y');
-      late SsaNode<Type> xSsaInsideLoop;
-      late SsaNode<Type> ySsaInsideLoop;
+      late SsaNode<SharedTypeView<Type>> xSsaInsideLoop;
+      late SsaNode<SharedTypeView<Type>> ySsaInsideLoop;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
@@ -3106,8 +3109,8 @@
         'types were tested', () {
       var x = Var('x');
       var y = Var('y');
-      late SsaNode<Type> xSsaInsideLoop;
-      late SsaNode<Type> ySsaInsideLoop;
+      late SsaNode<SharedTypeView<Type>> xSsaInsideLoop;
+      late SsaNode<SharedTypeView<Type>> ySsaInsideLoop;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
@@ -3133,8 +3136,8 @@
     test('write() de-promotes and updates Ssa of a promoted variable', () {
       var x = Var('x');
       var y = Var('y');
-      late SsaNode<Type> ssaBeforeWrite;
-      late ExpressionInfo<Type> writtenValueInfo;
+      late SsaNode<SharedTypeView<Type>> ssaBeforeWrite;
+      late ExpressionInfo<SharedTypeView<Type>> writtenValueInfo;
       h.run([
         declare(x, type: 'Object', initializer: expr('Object')),
         declare(y, type: 'int?', initializer: expr('int?')),
@@ -3156,8 +3159,8 @@
     test('write() updates Ssa', () {
       var x = Var('x');
       var y = Var('y');
-      late SsaNode<Type> ssaBeforeWrite;
-      late ExpressionInfo<Type> writtenValueInfo;
+      late SsaNode<SharedTypeView<Type>> ssaBeforeWrite;
+      late ExpressionInfo<SharedTypeView<Type>> writtenValueInfo;
       h.run([
         declare(x, type: 'Object', initializer: expr('Object')),
         declare(y, type: 'int?', initializer: expr('int?')),
@@ -3188,8 +3191,8 @@
 
       var x = Var('x');
       var y = Var('y');
-      late SsaNode<Type> xSsaBeforeWrite;
-      late SsaNode<Type> ySsa;
+      late SsaNode<SharedTypeView<Type>> xSsaBeforeWrite;
+      late SsaNode<SharedTypeView<Type>> ySsa;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
@@ -3208,7 +3211,7 @@
     test('write() does not store expressionInfo for trivial expressions', () {
       var x = Var('x');
       var y = Var('y');
-      late SsaNode<Type> ssaBeforeWrite;
+      late SsaNode<SharedTypeView<Type>> ssaBeforeWrite;
       h.run([
         declare(x, type: 'Object', initializer: expr('Object')),
         declare(y, type: 'int?', initializer: expr('int?')),
@@ -3230,7 +3233,7 @@
 
     test('write() permits expression to be null', () {
       var x = Var('x');
-      late SsaNode<Type> ssaBeforeWrite;
+      late SsaNode<SharedTypeView<Type>> ssaBeforeWrite;
       h.run([
         declare(x, type: 'Object', initializer: expr('Object')),
         getSsaNodes((nodes) => ssaBeforeWrite = nodes[x]!),
@@ -3443,14 +3446,15 @@
     var nullVar = Var('x')..type = Type('Null');
 
     group('setUnreachable', () {
-      var unreachable = FlowModel<Type>(Reachability.initial.setUnreachable());
-      var reachable = FlowModel<Type>(Reachability.initial);
+      var unreachable = FlowModel<SharedTypeView<Type>>(
+          Reachability.initial.setUnreachable());
+      var reachable = FlowModel<SharedTypeView<Type>>(Reachability.initial);
       test('unchanged', () {
         expect(unreachable.setUnreachable(), same(unreachable));
       });
 
       test('changed', () {
-        void _check(FlowModel<Type> initial) {
+        void _check(FlowModel<SharedTypeView<Type>> initial) {
           var s = initial.setUnreachable();
           expect(s, isNot(same(initial)));
           expect(s.reachable.overallReachable, false);
@@ -3462,33 +3466,33 @@
     });
 
     test('split', () {
-      var s1 = FlowModel<Type>(Reachability.initial);
+      var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
       var s2 = s1.split();
       expect(s2.reachable.parent, same(s1.reachable));
     });
 
     test('unsplit', () {
-      var s1 = FlowModel<Type>(Reachability.initial.split());
+      var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial.split());
       var s2 = s1.unsplit();
       expect(s2.reachable, same(Reachability.initial));
     });
 
     group('unsplitTo', () {
       test('no change', () {
-        var s1 = FlowModel<Type>(Reachability.initial.split());
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial.split());
         var result = s1.unsplitTo(s1.reachable.parent!);
         expect(result, same(s1));
       });
 
       test('unsplit once, reachable', () {
-        var s1 = FlowModel<Type>(Reachability.initial.split());
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial.split());
         var s2 = s1.split();
         var result = s2.unsplitTo(s1.reachable.parent!);
         expect(result.reachable, same(s1.reachable));
       });
 
       test('unsplit once, unreachable', () {
-        var s1 = FlowModel<Type>(Reachability.initial.split());
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial.split());
         var s2 = s1.split().setUnreachable();
         var result = s2.unsplitTo(s1.reachable.parent!);
         expect(result.reachable.locallyReachable, false);
@@ -3496,7 +3500,7 @@
       });
 
       test('unsplit twice, reachable', () {
-        var s1 = FlowModel<Type>(Reachability.initial.split());
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial.split());
         var s2 = s1.split();
         var s3 = s2.split();
         var result = s3.unsplitTo(s1.reachable.parent!);
@@ -3504,7 +3508,7 @@
       });
 
       test('unsplit twice, top unreachable', () {
-        var s1 = FlowModel<Type>(Reachability.initial.split());
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial.split());
         var s2 = s1.split();
         var s3 = s2.split().setUnreachable();
         var result = s3.unsplitTo(s1.reachable.parent!);
@@ -3513,7 +3517,7 @@
       });
 
       test('unsplit twice, previous unreachable', () {
-        var s1 = FlowModel<Type>(Reachability.initial.split());
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial.split());
         var s2 = s1.split().setUnreachable();
         var s3 = s2.split();
         var result = s3.unsplitTo(s1.reachable.parent!);
@@ -3524,25 +3528,25 @@
 
     group('tryPromoteForTypeCheck', () {
       test('unpromoted -> unchanged (same)', () {
-        var s1 = FlowModel<Type>(Reachability.initial);
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s2 = s1._tryPromoteForTypeCheck(h, intVar, 'int').ifTrue;
         expect(s2, same(s1));
       });
 
       test('unpromoted -> unchanged (supertype)', () {
-        var s1 = FlowModel<Type>(Reachability.initial);
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s2 = s1._tryPromoteForTypeCheck(h, intVar, 'Object').ifTrue;
         expect(s2, same(s1));
       });
 
       test('unpromoted -> unchanged (unrelated)', () {
-        var s1 = FlowModel<Type>(Reachability.initial);
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s2 = s1._tryPromoteForTypeCheck(h, intVar, 'String').ifTrue;
         expect(s2, same(s1));
       });
 
       test('unpromoted -> subtype', () {
-        var s1 = FlowModel<Type>(Reachability.initial);
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s2 = s1._tryPromoteForTypeCheck(h, intQVar, 'int').ifTrue;
         expect(s2.reachable.overallReachable, true);
         expect(s2.promotionInfo.unwrap(h), {
@@ -3552,7 +3556,7 @@
       });
 
       test('promoted -> unchanged (same)', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
         var s2 = s1._tryPromoteForTypeCheck(h, objectQVar, 'int').ifTrue;
@@ -3560,7 +3564,7 @@
       });
 
       test('promoted -> unchanged (supertype)', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
         var s2 = s1._tryPromoteForTypeCheck(h, objectQVar, 'Object').ifTrue;
@@ -3568,7 +3572,7 @@
       });
 
       test('promoted -> unchanged (unrelated)', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
         var s2 = s1._tryPromoteForTypeCheck(h, objectQVar, 'String').ifTrue;
@@ -3576,7 +3580,7 @@
       });
 
       test('promoted -> subtype', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
             .ifTrue;
         var s2 = s1._tryPromoteForTypeCheck(h, objectQVar, 'int').ifTrue;
@@ -3594,8 +3598,12 @@
       test('without declaration', () {
         // This should not happen in valid code, but test that we don't crash.
 
-        var s = FlowModel<Type>(Reachability.initial)._write(
-            h, null, objectQVar, Type('Object?'), new SsaNode<Type>(null));
+        var s = FlowModel<SharedTypeView<Type>>(Reachability.initial)._write(
+            h,
+            null,
+            objectQVar,
+            SharedTypeView(Type('Object?')),
+            new SsaNode<SharedTypeView<Type>>(null));
         expect(
             s.promotionInfo
                 ?.get(h, h.promotionKeyStore.keyForVariable(objectQVar)),
@@ -3603,10 +3611,10 @@
       });
 
       test('unchanged', () {
-        var s1 =
-            FlowModel<Type>(Reachability.initial)._declare(h, objectQVar, true);
-        var s2 = s1._write(
-            h, null, objectQVar, Type('Object?'), new SsaNode<Type>(null));
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
+            ._declare(h, objectQVar, true);
+        var s2 = s1._write(h, null, objectQVar, SharedTypeView(Type('Object?')),
+            new SsaNode<SharedTypeView<Type>>(null));
         expect(s2, isNot(same(s1)));
         expect(s2.reachable, same(s1.reachable));
         expect(
@@ -3619,10 +3627,10 @@
       });
 
       test('marks as assigned', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._declare(h, objectQVar, false);
-        var s2 = s1._write(
-            h, null, objectQVar, Type('int?'), new SsaNode<Type>(null));
+        var s2 = s1._write(h, null, objectQVar, SharedTypeView(Type('int?')),
+            new SsaNode<SharedTypeView<Type>>(null));
         expect(s2.reachable.overallReachable, true);
         expect(
             s2._infoFor(h, objectQVar),
@@ -3634,14 +3642,18 @@
       });
 
       test('un-promotes fully', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._declare(h, objectQVar, true)
             ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
         expect(s1.promotionInfo.unwrap(h),
             contains(h.promotionKeyStore.keyForVariable(objectQVar)));
-        var s2 = s1._write(h, _MockNonPromotionReason(), objectQVar,
-            Type('int?'), new SsaNode<Type>(null));
+        var s2 = s1._write(
+            h,
+            _MockNonPromotionReason(),
+            objectQVar,
+            SharedTypeView(Type('int?')),
+            new SsaNode<SharedTypeView<Type>>(null));
         expect(s2.reachable.overallReachable, true);
         expect(s2.promotionInfo.unwrap(h), {
           h.promotionKeyStore.keyForVariable(objectQVar): _matchVariableModel(
@@ -3653,7 +3665,7 @@
       });
 
       test('un-promotes partially, when no exact match', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._declare(h, objectQVar, true)
             ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
             .ifTrue
@@ -3666,8 +3678,12 @@
               assigned: true,
               unassigned: false)
         });
-        var s2 = s1._write(h, _MockNonPromotionReason(), objectQVar,
-            Type('num'), new SsaNode<Type>(null));
+        var s2 = s1._write(
+            h,
+            _MockNonPromotionReason(),
+            objectQVar,
+            SharedTypeView(Type('num')),
+            new SsaNode<SharedTypeView<Type>>(null));
         expect(s2.reachable.overallReachable, true);
         expect(s2.promotionInfo.unwrap(h), {
           h.promotionKeyStore.keyForVariable(objectQVar): _matchVariableModel(
@@ -3679,7 +3695,7 @@
       });
 
       test('un-promotes partially, when exact match', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._declare(h, objectQVar, true)
             ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
             .ifTrue
@@ -3694,8 +3710,12 @@
               assigned: true,
               unassigned: false)
         });
-        var s2 = s1._write(h, _MockNonPromotionReason(), objectQVar,
-            Type('num'), new SsaNode<Type>(null));
+        var s2 = s1._write(
+            h,
+            _MockNonPromotionReason(),
+            objectQVar,
+            SharedTypeView(Type('num')),
+            new SsaNode<SharedTypeView<Type>>(null));
         expect(s2.reachable.overallReachable, true);
         expect(s2.promotionInfo.unwrap(h), {
           h.promotionKeyStore.keyForVariable(objectQVar): _matchVariableModel(
@@ -3707,7 +3727,7 @@
       });
 
       test('leaves promoted, when exact match', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._declare(h, objectQVar, true)
             ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
             .ifTrue
@@ -3720,8 +3740,8 @@
               assigned: true,
               unassigned: false)
         });
-        var s2 = s1._write(
-            h, null, objectQVar, Type('num'), new SsaNode<Type>(null));
+        var s2 = s1._write(h, null, objectQVar, SharedTypeView(Type('num')),
+            new SsaNode<SharedTypeView<Type>>(null));
         expect(s2.reachable.overallReachable, true);
         expect(s2.promotionInfo, isNot(same(s1.promotionInfo)));
         expect(s2.promotionInfo.unwrap(h), {
@@ -3734,7 +3754,7 @@
       });
 
       test('leaves promoted, when writing a subtype', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._declare(h, objectQVar, true)
             ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
             .ifTrue
@@ -3747,8 +3767,8 @@
               assigned: true,
               unassigned: false)
         });
-        var s2 = s1._write(
-            h, null, objectQVar, Type('int'), new SsaNode<Type>(null));
+        var s2 = s1._write(h, null, objectQVar, SharedTypeView(Type('int')),
+            new SsaNode<SharedTypeView<Type>>(null));
         expect(s2.reachable.overallReachable, true);
         expect(s2.promotionInfo, isNot(same(s1.promotionInfo)));
         expect(s2.promotionInfo.unwrap(h), {
@@ -3764,13 +3784,15 @@
         test('when declared type', () {
           var x = Var('x')..type = Type('int?');
 
-          var s1 = FlowModel<Type>(Reachability.initial)._declare(h, x, true);
+          var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
+              ._declare(h, x, true);
           expect(s1.promotionInfo.unwrap(h), {
             h.promotionKeyStore.keyForVariable(x):
                 _matchVariableModel(chain: null),
           });
 
-          var s2 = s1._write(h, null, x, Type('int'), new SsaNode<Type>(null));
+          var s2 = s1._write(h, null, x, SharedTypeView(Type('int')),
+              new SsaNode<SharedTypeView<Type>>(null));
           expect(s2.promotionInfo.unwrap(h), {
             h.promotionKeyStore.keyForVariable(x):
                 _matchVariableModel(chain: ['int']),
@@ -3780,7 +3802,8 @@
         test('when declared type, if write-captured', () {
           var x = Var('x')..type = Type('int?');
 
-          var s1 = FlowModel<Type>(Reachability.initial)._declare(h, x, true);
+          var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
+              ._declare(h, x, true);
           expect(s1.promotionInfo.unwrap(h), {
             h.promotionKeyStore.keyForVariable(x):
                 _matchVariableModel(chain: null),
@@ -3793,7 +3816,8 @@
           });
 
           // 'x' is write-captured, so not promoted
-          var s3 = s2._write(h, null, x, Type('int'), new SsaNode<Type>(null));
+          var s3 = s2._write(h, null, x, SharedTypeView(Type('int')),
+              new SsaNode<SharedTypeView<Type>>(null));
           expect(s3.promotionInfo.unwrap(h), {
             h.promotionKeyStore.keyForVariable(x):
                 _matchVariableModel(chain: null, writeCaptured: true),
@@ -3801,7 +3825,7 @@
         });
 
         test('when promoted', () {
-          var s1 = FlowModel<Type>(Reachability.initial)
+          var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
               ._declare(h, objectQVar, true)
               ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
               .ifTrue;
@@ -3811,8 +3835,8 @@
               ofInterest: ['int?'],
             ),
           });
-          var s2 = s1._write(
-              h, null, objectQVar, Type('int'), new SsaNode<Type>(null));
+          var s2 = s1._write(h, null, objectQVar, SharedTypeView(Type('int')),
+              new SsaNode<SharedTypeView<Type>>(null));
           expect(s2.promotionInfo.unwrap(h), {
             h.promotionKeyStore.keyForVariable(objectQVar): _matchVariableModel(
               chain: ['int?', 'int'],
@@ -3822,7 +3846,7 @@
         });
 
         test('when not promoted', () {
-          var s1 = FlowModel<Type>(Reachability.initial)
+          var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
               ._declare(h, objectQVar, true)
               ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
               .ifFalse;
@@ -3832,8 +3856,8 @@
               ofInterest: ['int?'],
             ),
           });
-          var s2 = s1._write(
-              h, null, objectQVar, Type('int'), new SsaNode<Type>(null));
+          var s2 = s1._write(h, null, objectQVar, SharedTypeView(Type('int')),
+              new SsaNode<SharedTypeView<Type>>(null));
           expect(s2.promotionInfo.unwrap(h), {
             h.promotionKeyStore.keyForVariable(objectQVar): _matchVariableModel(
               chain: ['Object', 'int'],
@@ -3844,7 +3868,7 @@
       });
 
       test('Promotes to type of interest when not previously promoted', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._declare(h, objectQVar, true)
             ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
             .ifFalse;
@@ -3854,8 +3878,12 @@
             ofInterest: ['num?'],
           ),
         });
-        var s2 = s1._write(h, _MockNonPromotionReason(), objectQVar,
-            Type('num?'), new SsaNode<Type>(null));
+        var s2 = s1._write(
+            h,
+            _MockNonPromotionReason(),
+            objectQVar,
+            SharedTypeView(Type('num?')),
+            new SsaNode<SharedTypeView<Type>>(null));
         expect(s2.promotionInfo.unwrap(h), {
           h.promotionKeyStore.keyForVariable(objectQVar): _matchVariableModel(
             chain: ['num?'],
@@ -3865,7 +3893,7 @@
       });
 
       test('Promotes to type of interest when previously promoted', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._declare(h, objectQVar, true)
             ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
             .ifTrue
@@ -3877,8 +3905,12 @@
             ofInterest: ['num?', 'int?'],
           ),
         });
-        var s2 = s1._write(h, _MockNonPromotionReason(), objectQVar,
-            Type('int?'), new SsaNode<Type>(null));
+        var s2 = s1._write(
+            h,
+            _MockNonPromotionReason(),
+            objectQVar,
+            SharedTypeView(Type('int?')),
+            new SsaNode<SharedTypeView<Type>>(null));
         expect(s2.promotionInfo.unwrap(h), {
           h.promotionKeyStore.keyForVariable(objectQVar): _matchVariableModel(
             chain: ['num?', 'int?'],
@@ -3902,7 +3934,7 @@
           test('; first', () {
             var x = Var('x')..type = Type('Object?');
 
-            var s1 = FlowModel<Type>(Reachability.initial)
+            var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
                 ._declare(h, x, true)
                 ._tryPromoteForTypeCheck(h, x, 'B?')
                 .ifFalse
@@ -3915,7 +3947,8 @@
               ),
             });
 
-            var s2 = s1._write(h, null, x, Type('C'), new SsaNode<Type>(null));
+            var s2 = s1._write(h, null, x, SharedTypeView(Type('C')),
+                new SsaNode<SharedTypeView<Type>>(null));
             expect(s2.promotionInfo.unwrap(h), {
               h.promotionKeyStore.keyForVariable(x): _matchVariableModel(
                 chain: ['Object', 'B'],
@@ -3927,7 +3960,7 @@
           test('; second', () {
             var x = Var('x')..type = Type('Object?');
 
-            var s1 = FlowModel<Type>(Reachability.initial)
+            var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
                 ._declare(h, x, true)
                 ._tryPromoteForTypeCheck(h, x, 'A?')
                 .ifFalse
@@ -3940,7 +3973,8 @@
               ),
             });
 
-            var s2 = s1._write(h, null, x, Type('C'), new SsaNode<Type>(null));
+            var s2 = s1._write(h, null, x, SharedTypeView(Type('C')),
+                new SsaNode<SharedTypeView<Type>>(null));
             expect(s2.promotionInfo.unwrap(h), {
               h.promotionKeyStore.keyForVariable(x): _matchVariableModel(
                 chain: ['Object', 'B'],
@@ -3952,7 +3986,7 @@
           test('; nullable and non-nullable', () {
             var x = Var('x')..type = Type('Object?');
 
-            var s1 = FlowModel<Type>(Reachability.initial)
+            var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
                 ._declare(h, x, true)
                 ._tryPromoteForTypeCheck(h, x, 'A')
                 .ifFalse
@@ -3965,7 +3999,8 @@
               ),
             });
 
-            var s2 = s1._write(h, null, x, Type('B'), new SsaNode<Type>(null));
+            var s2 = s1._write(h, null, x, SharedTypeView(Type('B')),
+                new SsaNode<SharedTypeView<Type>>(null));
             expect(s2.promotionInfo.unwrap(h), {
               h.promotionKeyStore.keyForVariable(x): _matchVariableModel(
                 chain: ['Object', 'A'],
@@ -3977,7 +4012,7 @@
 
         group('; ambiguous', () {
           test('; no promotion', () {
-            var s1 = FlowModel<Type>(Reachability.initial)
+            var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
                 ._declare(h, objectQVar, true)
                 ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
                 .ifFalse
@@ -3990,8 +4025,8 @@
                 ofInterest: ['num?', 'num*'],
               ),
             });
-            var s2 = s1._write(
-                h, null, objectQVar, Type('int'), new SsaNode<Type>(null));
+            var s2 = s1._write(h, null, objectQVar, SharedTypeView(Type('int')),
+                new SsaNode<SharedTypeView<Type>>(null));
             // It's ambiguous whether to promote to num? or num*, so we don't
             // promote.
             expect(s2, isNot(same(s1)));
@@ -4006,7 +4041,7 @@
         });
 
         test('exact match', () {
-          var s1 = FlowModel<Type>(Reachability.initial)
+          var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
               ._declare(h, objectQVar, true)
               ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
               .ifFalse
@@ -4018,8 +4053,12 @@
               ofInterest: ['num?', 'num*'],
             ),
           });
-          var s2 = s1._write(h, _MockNonPromotionReason(), objectQVar,
-              Type('num?'), new SsaNode<Type>(null));
+          var s2 = s1._write(
+              h,
+              _MockNonPromotionReason(),
+              objectQVar,
+              SharedTypeView(Type('num?')),
+              new SsaNode<SharedTypeView<Type>>(null));
           // It's ambiguous whether to promote to num? or num*, but since the
           // written type is exactly num?, we use that.
           expect(s2.promotionInfo.unwrap(h), {
@@ -4036,7 +4075,7 @@
       test('when promoted via test', () {
         var x = Var('x')..type = Type('Object?');
 
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._declare(h, x, true)
             ._tryPromoteForTypeCheck(h, x, 'num?')
             .ifTrue
@@ -4049,8 +4088,12 @@
           ),
         });
 
-        var s2 = s1._write(h, _MockNonPromotionReason(), x, Type('double'),
-            new SsaNode<Type>(null));
+        var s2 = s1._write(
+            h,
+            _MockNonPromotionReason(),
+            x,
+            SharedTypeView(Type('double')),
+            new SsaNode<SharedTypeView<Type>>(null));
         expect(s2.promotionInfo.unwrap(h), {
           h.promotionKeyStore.keyForVariable(x): _matchVariableModel(
             chain: ['num?', 'num'],
@@ -4064,8 +4107,8 @@
       var objectQVar = Var('x')..type = Type('Object?');
 
       test('initialized', () {
-        var s =
-            FlowModel<Type>(Reachability.initial)._declare(h, objectQVar, true);
+        var s = FlowModel<SharedTypeView<Type>>(Reachability.initial)
+            ._declare(h, objectQVar, true);
         expect(s.promotionInfo.unwrap(h), {
           h.promotionKeyStore.keyForVariable(objectQVar):
               _matchVariableModel(assigned: true, unassigned: false),
@@ -4073,7 +4116,7 @@
       });
 
       test('not initialized', () {
-        var s = FlowModel<Type>(Reachability.initial)
+        var s = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._declare(h, objectQVar, false);
         expect(s.promotionInfo.unwrap(h), {
           h.promotionKeyStore.keyForVariable(objectQVar):
@@ -4084,13 +4127,13 @@
 
     group('markNonNullable', () {
       test('unpromoted -> unchanged', () {
-        var s1 = FlowModel<Type>(Reachability.initial);
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s2 = s1._tryMarkNonNullable(h, intVar).ifTrue;
         expect(s2, same(s1));
       });
 
       test('unpromoted -> promoted', () {
-        var s1 = FlowModel<Type>(Reachability.initial);
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s2 = s1._tryMarkNonNullable(h, intQVar).ifTrue;
         expect(s2.reachable.overallReachable, true);
         expect(s2._infoFor(h, intQVar),
@@ -4098,7 +4141,7 @@
       });
 
       test('promoted -> unchanged', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
         var s2 = s1._tryMarkNonNullable(h, objectQVar).ifTrue;
@@ -4106,7 +4149,7 @@
       });
 
       test('promoted -> re-promoted', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
             .ifTrue;
         var s2 = s1._tryMarkNonNullable(h, objectQVar).ifTrue;
@@ -4118,7 +4161,7 @@
       });
 
       test('promote to Never', () {
-        var s1 = FlowModel<Type>(Reachability.initial);
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s2 = s1._tryMarkNonNullable(h, nullVar).ifTrue;
         expect(s2.reachable.overallReachable, true);
         expect(s2._infoFor(h, nullVar),
@@ -4128,7 +4171,7 @@
 
     group('conservativeJoin', () {
       test('unchanged', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._declare(h, intQVar, true)
             ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
@@ -4144,7 +4187,7 @@
       });
 
       test('written', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue
             ._tryPromoteForTypeCheck(h, intQVar, 'int')
@@ -4160,7 +4203,7 @@
       });
 
       test('write captured', () {
-        var s1 = FlowModel<Type>(Reachability.initial)
+        var s1 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue
             ._tryPromoteForTypeCheck(h, intQVar, 'int')
@@ -4178,7 +4221,7 @@
 
     group('rebaseForward', () {
       test('reachability', () {
-        var reachable = FlowModel<Type>(Reachability.initial);
+        var reachable = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var unreachable = reachable.setUnreachable();
         expect(reachable.rebaseForward(h, reachable), same(reachable));
         expect(reachable.rebaseForward(h, unreachable), same(unreachable));
@@ -4195,17 +4238,21 @@
         var b = Var('b')..type = Type('int');
         var c = Var('c')..type = Type('int');
         var d = Var('d')..type = Type('int');
-        var s0 = FlowModel<Type>(Reachability.initial)
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._declare(h, a, false)
             ._declare(h, b, false)
             ._declare(h, c, false)
             ._declare(h, d, false);
         var s1 = s0
-            ._write(h, null, a, Type('int'), new SsaNode<Type>(null))
-            ._write(h, null, b, Type('int'), new SsaNode<Type>(null));
+            ._write(h, null, a, SharedTypeView(Type('int')),
+                new SsaNode<SharedTypeView<Type>>(null))
+            ._write(h, null, b, SharedTypeView(Type('int')),
+                new SsaNode<SharedTypeView<Type>>(null));
         var s2 = s0
-            ._write(h, null, a, Type('int'), new SsaNode<Type>(null))
-            ._write(h, null, c, Type('int'), new SsaNode<Type>(null));
+            ._write(h, null, a, SharedTypeView(Type('int')),
+                new SsaNode<SharedTypeView<Type>>(null))
+            ._write(h, null, c, SharedTypeView(Type('int')),
+                new SsaNode<SharedTypeView<Type>>(null));
         var result = s1.rebaseForward(h, s2);
         expect(result._infoFor(h, a).assigned, true);
         expect(result._infoFor(h, b).assigned, true);
@@ -4218,7 +4265,7 @@
         var b = Var('b')..type = Type('int');
         var c = Var('c')..type = Type('int');
         var d = Var('d')..type = Type('int');
-        var s0 = FlowModel<Type>(Reachability.initial)
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
             ._declare(h, a, false)
             ._declare(h, b, false)
             ._declare(h, c, false)
@@ -4247,7 +4294,8 @@
 
       test('write captured and promoted', () {
         var a = Var('a')..type = Type('num');
-        var s0 = FlowModel<Type>(Reachability.initial)._declare(h, a, false);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
+            ._declare(h, a, false);
         // In s1, a is write captured.  In s2 it's promoted.
         var s1 = s0._conservativeJoin(h, [a], [a]);
         var s2 = s0._tryPromoteForTypeCheck(h, a, 'int').ifTrue;
@@ -4265,11 +4313,12 @@
         void _check(String? thisType, String? otherType, bool unsafe,
             List<String>? expectedChain) {
           var x = Var('x')..type = Type('Object?');
-          var s0 = FlowModel<Type>(Reachability.initial)._declare(h, x, true);
+          var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
+              ._declare(h, x, true);
           var s1 = s0;
           if (unsafe) {
-            s1 =
-                s1._write(h, null, x, Type('Object?'), new SsaNode<Type>(null));
+            s1 = s1._write(h, null, x, SharedTypeView(Type('Object?')),
+                new SsaNode<SharedTypeView<Type>>(null));
           }
           if (thisType != null) {
             s1 = s1._tryPromoteForTypeCheck(h, x, thisType).ifTrue;
@@ -4287,7 +4336,7 @@
                 result
                     ._infoFor(h, x)
                     .promotedTypes!
-                    .map((t) => t.type)
+                    .map((t) => t.unwrapTypeView().type)
                     .toList(),
                 expectedChain);
           }
@@ -4310,8 +4359,11 @@
       test('promotion chains', () {
         // Verify that the given promotion chain matches the expected list of
         // strings.
-        void _checkChain(List<Type>? chain, List<String> expected) {
-          var strings = (chain ?? <Type>[]).map((t) => t.type).toList();
+        void _checkChain(
+            List<SharedTypeView<Type>>? chain, List<String> expected) {
+          var strings = (chain ?? <SharedTypeView<Type>>[])
+              .map((t) => t.unwrapTypeView().type)
+              .toList();
           expect(strings, expected);
         }
 
@@ -4328,7 +4380,8 @@
             List<String> inFinally, List<String> expectedResult) {
           var x = Var('x')..type = Type('Object?');
           var initialModel =
-              FlowModel<Type>(Reachability.initial)._declare(h, x, true);
+              FlowModel<SharedTypeView<Type>>(Reachability.initial)
+                  ._declare(h, x, true);
           for (var t in before) {
             initialModel = initialModel._tryPromoteForTypeCheck(h, x, t).ifTrue;
           }
@@ -4384,7 +4437,8 @@
 
       test('types of interest', () {
         var a = Var('a')..type = Type('Object');
-        var s0 = FlowModel<Type>(Reachability.initial)._declare(h, a, false);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial)
+            ._declare(h, a, false);
         var s1 = s0._tryPromoteForTypeCheck(h, a, 'int').ifFalse;
         var s2 = s0._tryPromoteForTypeCheck(h, a, 'String').ifFalse;
         expect(
@@ -4399,7 +4453,7 @@
 
       test('variable present in one state but not the other', () {
         var x = Var('x')..type = Type('Object?');
-        var s0 = FlowModel<Type>(Reachability.initial);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s1 = s0._declare(h, x, true);
         expect(s1.rebaseForward(h, s0), same(s1));
         expect(s0.rebaseForward(h, s1), same(s1));
@@ -4433,12 +4487,21 @@
 
     test('should return common prefix if there are common types', () {
       expect(
-          PromotionModel.joinPromotedTypes([objectType, intType],
-              [objectType, doubleType], h.typeOperations),
+          PromotionModel.joinPromotedTypes(
+              [SharedTypeView(objectType), SharedTypeView(intType)],
+              [SharedTypeView(objectType), SharedTypeView(doubleType)],
+              h.typeOperations),
           _matchPromotionChain(['Object']));
       expect(
-          PromotionModel.joinPromotedTypes([objectType, numType, intType],
-              [objectType, numType, doubleType], h.typeOperations),
+          PromotionModel.joinPromotedTypes([
+            SharedTypeView(objectType),
+            SharedTypeView(numType),
+            SharedTypeView(intType)
+          ], [
+            SharedTypeView(objectType),
+            SharedTypeView(numType),
+            SharedTypeView(doubleType)
+          ], h.typeOperations),
           _matchPromotionChain(['Object', 'num']));
     });
 
@@ -4483,7 +4546,8 @@
       h.addSuperInterfaces('B', (_) => [Type('A'), Type('Object')]);
       h.addSuperInterfaces('A', (_) => [Type('Object')]);
 
-      void check(List<Type> chain1, List<Type> chain2, Matcher matcher) {
+      void check(List<SharedTypeView<Type>> chain1,
+          List<SharedTypeView<Type>> chain2, Matcher matcher) {
         expect(
           PromotionModel.joinPromotedTypes(chain1, chain2, h.typeOperations),
           matcher,
@@ -4496,38 +4560,68 @@
       }
 
       {
-        var chain1 = [A, B, C];
-        var chain2 = [A, C];
+        var chain1 = [SharedTypeView(A), SharedTypeView(B), SharedTypeView(C)];
+        var chain2 = [SharedTypeView(A), SharedTypeView(C)];
         check(chain1, chain2, same(chain2));
       }
 
       check(
-        [A, B, C, F],
-        [A, D, E, F],
+        [
+          SharedTypeView(A),
+          SharedTypeView(B),
+          SharedTypeView(C),
+          SharedTypeView(F)
+        ],
+        [
+          SharedTypeView(A),
+          SharedTypeView(D),
+          SharedTypeView(E),
+          SharedTypeView(F)
+        ],
         _matchPromotionChain(['A', 'F']),
       );
 
       check(
-        [A, B, E, F],
-        [A, C, D, F],
+        [
+          SharedTypeView(A),
+          SharedTypeView(B),
+          SharedTypeView(E),
+          SharedTypeView(F)
+        ],
+        [
+          SharedTypeView(A),
+          SharedTypeView(C),
+          SharedTypeView(D),
+          SharedTypeView(F)
+        ],
         _matchPromotionChain(['A', 'F']),
       );
 
       check(
-        [A, C, E],
-        [B, C, D],
+        [SharedTypeView(A), SharedTypeView(C), SharedTypeView(E)],
+        [SharedTypeView(B), SharedTypeView(C), SharedTypeView(D)],
         _matchPromotionChain(['C']),
       );
 
       check(
-        [A, C, E, F],
-        [B, C, D, F],
+        [
+          SharedTypeView(A),
+          SharedTypeView(C),
+          SharedTypeView(E),
+          SharedTypeView(F)
+        ],
+        [
+          SharedTypeView(B),
+          SharedTypeView(C),
+          SharedTypeView(D),
+          SharedTypeView(F)
+        ],
         _matchPromotionChain(['C', 'F']),
       );
 
       check(
-        [A, B, C],
-        [A, B, D],
+        [SharedTypeView(A), SharedTypeView(B), SharedTypeView(C)],
+        [SharedTypeView(A), SharedTypeView(B), SharedTypeView(D)],
         _matchPromotionChain(['A', 'B']),
       );
     });
@@ -4587,25 +4681,27 @@
       w = h.promotionKeyStore.keyForVariable(Var('w')..type = Type('Object?'));
     });
 
-    PromotionModel<Type> model(List<Type>? promotionChain,
-            {List<Type>? typesOfInterest, bool assigned = false}) =>
-        PromotionModel<Type>(
+    PromotionModel<SharedTypeView<Type>> model(
+            List<SharedTypeView<Type>>? promotionChain,
+            {List<SharedTypeView<Type>>? typesOfInterest,
+            bool assigned = false}) =>
+        PromotionModel<SharedTypeView<Type>>(
             promotedTypes: promotionChain,
             tested: typesOfInterest ?? promotionChain ?? [],
             assigned: assigned,
             unassigned: !assigned,
-            ssaNode: new SsaNode<Type>(null));
+            ssaNode: new SsaNode<SharedTypeView<Type>>(null));
 
     group('without input reuse', () {
       test('promoted with unpromoted', () {
-        var s0 = FlowModel<Type>(Reachability.initial);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s1 = s0._setInfo(h, {
-          x: model([intType]),
+          x: model([SharedTypeView(intType)]),
           y: model(null)
         });
         var s2 = s0._setInfo(h, {
           x: model(null),
-          y: model([intType])
+          y: model([SharedTypeView(intType)])
         });
         expect(FlowModel.joinPromotionInfo(h, s1, s2).promotionInfo.unwrap(h), {
           x: _matchVariableModel(chain: null, ofInterest: ['int']),
@@ -4615,19 +4711,19 @@
     });
     group('should re-use an input if possible', () {
       test('identical inputs', () {
-        var s0 = FlowModel<Type>(Reachability.initial);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s1 = s0._setInfo(h, {
-          x: model([intType]),
-          y: model([stringType])
+          x: model([SharedTypeView(intType)]),
+          y: model([SharedTypeView(stringType)])
         });
         expect(FlowModel.joinPromotionInfo(h, s1, s1), same(s1));
       });
 
       test('one input empty', () {
-        var s0 = FlowModel<Type>(Reachability.initial);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s1 = s0._setInfo(h, {
-          x: model([intType]),
-          y: model([stringType])
+          x: model([SharedTypeView(intType)]),
+          y: model([SharedTypeView(stringType)])
         });
         var s2 = s0;
         const Null expected = null;
@@ -4638,9 +4734,9 @@
       });
 
       test('promoted with unpromoted', () {
-        var s0 = FlowModel<Type>(Reachability.initial);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s1 = s0._setInfo(h, {
-          x: model([intType])
+          x: model([SharedTypeView(intType)])
         });
         var s2 = s0._setInfo(h, {x: model(null)});
         var expected = {
@@ -4653,12 +4749,12 @@
       });
 
       test('related type chains', () {
-        var s0 = FlowModel<Type>(Reachability.initial);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s1 = s0._setInfo(h, {
-          x: model([intQType, intType])
+          x: model([SharedTypeView(intQType), SharedTypeView(intType)])
         });
         var s2 = s0._setInfo(h, {
-          x: model([intQType])
+          x: model([SharedTypeView(intQType)])
         });
         var expected = {
           x: _matchVariableModel(chain: ['int?'], ofInterest: ['int?', 'int'])
@@ -4670,12 +4766,12 @@
       });
 
       test('unrelated type chains', () {
-        var s0 = FlowModel<Type>(Reachability.initial);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s1 = s0._setInfo(h, {
-          x: model([intType])
+          x: model([SharedTypeView(intType)])
         });
         var s2 = s0._setInfo(h, {
-          x: model([stringType])
+          x: model([SharedTypeView(stringType)])
         });
         var expected = {
           x: _matchVariableModel(chain: null, ofInterest: ['String', 'int'])
@@ -4687,11 +4783,11 @@
       });
 
       test('sub-map', () {
-        var s0 = FlowModel<Type>(Reachability.initial);
-        var xModel = model([intType]);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
+        var xModel = model([SharedTypeView(intType)]);
         var s1 = s0._setInfo(h, {
           x: xModel,
-          y: model([stringType])
+          y: model([SharedTypeView(stringType)])
         });
         var s2 = s0._setInfo(h, {x: xModel});
         var expected = {x: xModel};
@@ -4702,13 +4798,13 @@
       });
 
       test('sub-map with matched subtype', () {
-        var s0 = FlowModel<Type>(Reachability.initial);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s1 = s0._setInfo(h, {
-          x: model([intQType, intType]),
-          y: model([stringType])
+          x: model([SharedTypeView(intQType), SharedTypeView(intType)]),
+          y: model([SharedTypeView(stringType)])
         });
         var s2 = s0._setInfo(h, {
-          x: model([intQType])
+          x: model([SharedTypeView(intQType)])
         });
         var expected = {
           x: _matchVariableModel(chain: ['int?'], ofInterest: ['int?', 'int'])
@@ -4720,13 +4816,13 @@
       });
 
       test('sub-map with mismatched subtype', () {
-        var s0 = FlowModel<Type>(Reachability.initial);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var s1 = s0._setInfo(h, {
-          x: model([intQType]),
-          y: model([stringType])
+          x: model([SharedTypeView(intQType)]),
+          y: model([SharedTypeView(stringType)])
         });
         var s2 = s0._setInfo(h, {
-          x: model([intQType, intType])
+          x: model([SharedTypeView(intQType), SharedTypeView(intType)])
         });
         var expected = {
           x: _matchVariableModel(chain: ['int?'], ofInterest: ['int?', 'int'])
@@ -4738,7 +4834,7 @@
       });
 
       test('assigned', () {
-        var s0 = FlowModel<Type>(Reachability.initial);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
         var unassigned = model(null, assigned: false);
         var assigned = model(null, assigned: true);
         var s1 = s0._setInfo(
@@ -4757,8 +4853,8 @@
       });
 
       test('write captured', () {
-        var s0 = FlowModel<Type>(Reachability.initial);
-        var intQModel = model([intQType]);
+        var s0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
+        var intQModel = model([SharedTypeView(intQType)]);
         var writeCapturedModel = intQModel.writeCapture();
         var s1 = s0._setInfo(h, {
           x: writeCapturedModel,
@@ -4792,42 +4888,43 @@
       x = h.promotionKeyStore.keyForVariable(Var('x')..type = Type('Object?'));
     });
 
-    PromotionModel<Type> model(List<Type> typesOfInterest) =>
-        PromotionModel<Type>(
+    PromotionModel<SharedTypeView<Type>> model(
+            List<SharedTypeView<Type>> typesOfInterest) =>
+        PromotionModel<SharedTypeView<Type>>(
             promotedTypes: null,
             tested: typesOfInterest,
             assigned: true,
             unassigned: false,
-            ssaNode: new SsaNode<Type>(null));
+            ssaNode: new SsaNode<SharedTypeView<Type>>(null));
 
     test('inherits types of interest from other', () {
-      var m0 = FlowModel<Type>(Reachability.initial);
+      var m0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
       var m1 = m0._setInfo(h, {
-        x: model([intType])
+        x: model([SharedTypeView(intType)])
       });
       var m2 = m0._setInfo(h, {
-        x: model([stringType])
+        x: model([SharedTypeView(stringType)])
       });
       expect(m1.inheritTested(h, m2).promotionInfo!.get(h, x)!.tested,
           _matchOfInterestSet(['int', 'String']));
     });
 
     test('handles variable missing from other', () {
-      var m0 = FlowModel<Type>(Reachability.initial);
+      var m0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
       var m1 = m0._setInfo(h, {
-        x: model([intType])
+        x: model([SharedTypeView(intType)])
       });
       var m2 = m0;
       expect(m1.inheritTested(h, m2), same(m1));
     });
 
     test('returns identical model when no changes', () {
-      var m0 = FlowModel<Type>(Reachability.initial);
+      var m0 = FlowModel<SharedTypeView<Type>>(Reachability.initial);
       var m1 = m0._setInfo(h, {
-        x: model([intType])
+        x: model([SharedTypeView(intType)])
       });
       var m2 = m0._setInfo(h, {
-        x: model([intType])
+        x: model([SharedTypeView(intType)])
       });
       expect(m1.inheritTested(h, m2), same(m1));
     });
@@ -5656,7 +5753,10 @@
         checkNotPromoted(x),
         x.whyNotPromoted((reasons) {
           expect(reasons.keys, unorderedEquals([Type('int'), Type('int?')]));
-          for (var type in [Type('int'), Type('int?')]) {
+          for (var type in [
+            SharedTypeView(Type('int')),
+            SharedTypeView(Type('int?'))
+          ]) {
             var nonPromotionReason =
                 reasons[type] as DemoteViaExplicitWrite<Var>;
             expect(nonPromotionReason.node, same(writeExpression));
@@ -5730,8 +5830,8 @@
         ]),
         checkPromoted(x, 'num'),
         x.whyNotPromoted((reasons) {
-          var nonPromotionReason =
-              reasons[Type('int')] as DemoteViaExplicitWrite<Var>;
+          var nonPromotionReason = reasons[SharedTypeView(Type('int'))]
+              as DemoteViaExplicitWrite<Var>;
           expect(nonPromotionReason.node, same(writeExpression));
           expect(nonPromotionReason.documentationLink,
               NonPromotionDocumentationLink.write);
@@ -11046,16 +11146,16 @@
 
 Matcher _matchOfInterestSet(List<String> expectedTypes) {
   return predicate(
-      (List<Type> x) => unorderedEquals(expectedTypes)
-          .matches(x.map((t) => t.type).toList(), {}),
+      (List<SharedTypeView<Type>> x) => unorderedEquals(expectedTypes)
+          .matches(x.map((t) => t.unwrapTypeView().type).toList(), {}),
       'interest set $expectedTypes');
 }
 
 Matcher _matchPromotionChain(List<String>? expectedTypes) {
   if (expectedTypes == null) return isNull;
   return predicate(
-      (List<Type> x) =>
-          equals(expectedTypes).matches(x.map((t) => t.type).toList(), {}),
+      (List<SharedTypeView<Type>> x) => equals(expectedTypes)
+          .matches(x.map((t) => t.unwrapTypeView().type).toList(), {}),
       'promotion chain $expectedTypes');
 }
 
@@ -11078,7 +11178,7 @@
   Matcher assignedMatcher = wrapMatcher(assigned);
   Matcher unassignedMatcher = wrapMatcher(unassigned);
   Matcher writeCapturedMatcher = wrapMatcher(writeCaptured);
-  return predicate((PromotionModel<Type> model) {
+  return predicate((PromotionModel<SharedTypeView<Type>> model) {
     if (!chainMatcher.matches(model.promotedTypes, {})) return false;
     if (!ofInterestMatcher.matches(model.tested, {})) return false;
     if (!assignedMatcher.matches(model.assigned, {})) return false;
@@ -11108,8 +11208,8 @@
       fail('Unexpected call to accept');
 }
 
-extension on FlowModel<Type> {
-  FlowModel<Type> _conservativeJoin(FlowAnalysisTestHarness h,
+extension on FlowModel<SharedTypeView<Type>> {
+  FlowModel<SharedTypeView<Type>> _conservativeJoin(FlowAnalysisTestHarness h,
           Iterable<Var> writtenVariables, Iterable<Var> capturedVariables) =>
       conservativeJoin(h, [
         for (Var v in writtenVariables) h.promotionKeyStore.keyForVariable(v)
@@ -11117,17 +11217,18 @@
         for (Var v in capturedVariables) h.promotionKeyStore.keyForVariable(v)
       ]);
 
-  FlowModel<Type> _declare(
+  FlowModel<SharedTypeView<Type>> _declare(
           FlowAnalysisTestHarness h, Var variable, bool initialized) =>
       this.declare(
           h, h.promotionKeyStore.keyForVariable(variable), initialized);
 
-  PromotionModel<Type> _infoFor(FlowAnalysisTestHarness h, Var variable) =>
+  PromotionModel<SharedTypeView<Type>> _infoFor(
+          FlowAnalysisTestHarness h, Var variable) =>
       infoFor(h, h.promotionKeyStore.keyForVariable(variable),
           ssaNode: new SsaNode(null));
 
-  FlowModel<Type> _setInfo(
-      FlowAnalysisTestHarness h, Map<int, PromotionModel<Type>> newInfo) {
+  FlowModel<SharedTypeView<Type>> _setInfo(FlowAnalysisTestHarness h,
+      Map<int, PromotionModel<SharedTypeView<Type>>> newInfo) {
     var result = this;
     for (var core.MapEntry(:key, :value) in newInfo.entries) {
       if (result.promotionInfo?.get(h, key) != value) {
@@ -11137,43 +11238,46 @@
     return result;
   }
 
-  ExpressionInfo<Type> _tryMarkNonNullable(
+  ExpressionInfo<SharedTypeView<Type>> _tryMarkNonNullable(
           FlowAnalysisTestHarness h, Var variable) =>
       tryMarkNonNullable(h, _varRefWithType(h, variable));
 
-  ExpressionInfo<Type> _tryPromoteForTypeCheck(
+  ExpressionInfo<SharedTypeView<Type>> _tryPromoteForTypeCheck(
           FlowAnalysisTestHarness h, Var variable, String type) =>
-      tryPromoteForTypeCheck(h, _varRefWithType(h, variable), Type(type));
+      tryPromoteForTypeCheck(
+          h, _varRefWithType(h, variable), SharedTypeView(Type(type)));
 
   int _varRef(FlowAnalysisTestHarness h, Var variable) =>
       h.promotionKeyStore.keyForVariable(variable);
 
-  TrivialVariableReference<Type> _varRefWithType(
+  TrivialVariableReference<SharedTypeView<Type>> _varRefWithType(
           FlowAnalysisTestHarness h, Var variable) =>
-      new TrivialVariableReference<Type>(
+      new TrivialVariableReference<SharedTypeView<Type>>(
           promotionKey: _varRef(h, variable),
           after: this,
           type: promotionInfo
                   ?.get(h, h.promotionKeyStore.keyForVariable(variable))
                   ?.promotedTypes
                   ?.last ??
-              variable.type,
+              SharedTypeView(variable.type),
           isThisOrSuper: false,
           ssaNode: SsaNode(null));
 
-  FlowModel<Type> _write(
+  FlowModel<SharedTypeView<Type>> _write(
           FlowAnalysisTestHarness h,
           NonPromotionReason? nonPromotionReason,
           Var variable,
-          Type writtenType,
-          SsaNode<Type> newSsaNode) =>
+          SharedTypeView<Type> writtenType,
+          SsaNode<SharedTypeView<Type>> newSsaNode) =>
       write(h, nonPromotionReason, h.promotionKeyStore.keyForVariable(variable),
           writtenType, newSsaNode, h.typeOperations,
-          unpromotedType: variable.type);
+          unpromotedType: SharedTypeView(variable.type));
 }
 
-extension on PromotionInfo<Type>? {
-  Map<int, PromotionModel<Type>> unwrap(FlowAnalysisTestHarness h) => {
+extension on PromotionInfo<SharedTypeView<Type>>? {
+  Map<int, PromotionModel<SharedTypeView<Type>>> unwrap(
+          FlowAnalysisTestHarness h) =>
+      {
         for (var FlowLinkDiffEntry(:int key, right: second!)
             in h.reader.diff(null, this).entries)
           key: second.model
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index 4eec09d..f2fd58e 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -529,7 +529,7 @@
 }
 
 typedef SharedMatchContext
-    = shared.MatchContext<Node, Expression, Pattern, Type, Var>;
+    = shared.MatchContext<Node, Expression, Pattern, SharedTypeView<Type>, Var>;
 
 typedef SharedRecordPatternField = shared.RecordPatternField<Node, Pattern>;
 
@@ -548,7 +548,8 @@
   String toString() => '$target as $type';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     return h.typeAnalyzer.analyzeTypeCast(this, target, type);
   }
 }
@@ -618,10 +619,11 @@
   String toString() => '$value';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var type = h.typeAnalyzer.analyzeBoolLiteral(this, value);
     h.irBuilder.atom('$value', Kind.expression, location: location);
-    return new SimpleTypeAnalysisResult<Type>(type: type);
+    return new SimpleTypeAnalysisResult<Type>(type: SharedTypeView(type));
   }
 }
 
@@ -710,7 +712,8 @@
   }
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     // Form the IR for evaluating the LHS
     var targetType =
         h.typeAnalyzer.dispatchExpression(target, schema).resolveShorting();
@@ -721,7 +724,8 @@
         h.typeAnalyzer._currentCascadeTargetIR = h.irBuilder.allocateTmp();
     h.typeAnalyzer._currentCascadeTargetType = h.flow
         .cascadeExpression_afterTarget(target, targetType,
-            isNullAware: isNullAware);
+            isNullAware: isNullAware)
+        .unwrapTypeView();
     if (isNullAware) {
       h.flow.nullAwareAccess_rightBegin(target, targetType);
       // Push `targetTmp == null` and `targetTmp` on the IR builder stack,
@@ -785,11 +789,12 @@
   }
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     h.irBuilder
         .readTmp(h.typeAnalyzer._currentCascadeTargetIR!, location: location);
     return SimpleTypeAnalysisResult(
-        type: h.typeAnalyzer._currentCascadeTargetType!);
+        type: SharedTypeView(h.typeAnalyzer._currentCascadeTargetType!));
   }
 }
 
@@ -801,7 +806,7 @@
   CastPattern(this.inner, this.type, {required super.location}) : super._();
 
   @override
-  TypeSchema computeSchema(Harness h) =>
+  SharedTypeSchemaView<Type> computeSchema(Harness h) =>
       h.typeAnalyzer.analyzeCastPatternSchema();
 
   @override
@@ -816,9 +821,9 @@
       context: context,
       pattern: this,
       innerPattern: inner,
-      requiredType: type,
+      requiredType: SharedTypeView(type),
     );
-    var matchedType = analysisResult.matchedValueType;
+    var matchedType = analysisResult.matchedValueType.unwrapTypeView();
     h.irBuilder.atom(type.type, Kind.type, location: location);
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.apply(
@@ -877,11 +882,13 @@
   }
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     expect(h.flow.isAssigned(variable), expectedAssignedState,
         reason: 'at $location');
     h.irBuilder.atom('null', Kind.expression, location: location);
-    return SimpleTypeAnalysisResult(type: h.typeAnalyzer.nullType);
+    return SimpleTypeAnalysisResult(
+        type: SharedTypeView(h.typeAnalyzer.nullType));
   }
 }
 
@@ -924,7 +931,8 @@
   String toString() => '$inner (should produce IR $expectedIR)';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var result =
         h.typeAnalyzer.analyzeParenthesizedExpression(this, inner, schema);
     h.irBuilder.check(expectedIR, Kind.expression, location: location);
@@ -949,8 +957,9 @@
   String toString() => '$inner (should be in schema $expectedSchema)';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
-    expect(schema.typeString, expectedSchema);
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
+    expect(schema.unwrapTypeSchemaView().type, expectedSchema);
     var result =
         h.typeAnalyzer.analyzeParenthesizedExpression(this, inner, schema);
     return result;
@@ -973,10 +982,12 @@
   String toString() => '$target (expected type: $expectedType)';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var result =
         h.typeAnalyzer.analyzeParenthesizedExpression(this, target, schema);
-    expect(result.type.type, expectedType, reason: 'at $location');
+    expect(result.type.unwrapTypeView().type, expectedType,
+        reason: 'at $location');
     return result;
   }
 }
@@ -1002,10 +1013,11 @@
   }
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var promotedType = promotable._getPromotedType(h);
     expect(promotedType?.type, expectedTypeStr, reason: 'at $location');
-    return SimpleTypeAnalysisResult(type: NullType.instance);
+    return SimpleTypeAnalysisResult(type: SharedTypeView(NullType.instance));
   }
 }
 
@@ -1021,10 +1033,12 @@
   String toString() => 'check reachable';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     expect(h.flow.isReachable, expectedReachable, reason: 'at $location');
     h.irBuilder.atom('null', Kind.expression, location: location);
-    return new SimpleTypeAnalysisResult(type: NullType.instance);
+    return new SimpleTypeAnalysisResult(
+        type: SharedTypeView(NullType.instance));
   }
 }
 
@@ -1067,11 +1081,13 @@
   }
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     expect(h.flow.isUnassigned(variable), expectedUnassignedState,
         reason: 'at $location');
     h.irBuilder.atom('null', Kind.expression, location: location);
-    return SimpleTypeAnalysisResult(type: h.typeAnalyzer.nullType);
+    return SimpleTypeAnalysisResult(
+        type: SharedTypeView(h.typeAnalyzer.nullType));
   }
 }
 
@@ -1107,7 +1123,7 @@
 }
 
 class CollectionElementContextType extends CollectionElementContext {
-  final TypeSchema elementTypeSchema;
+  final SharedTypeSchemaView<Type> elementTypeSchema;
 
   CollectionElementContextType._(this.elementTypeSchema);
 }
@@ -1133,7 +1149,8 @@
   String toString() => '$condition ? $ifTrue : $ifFalse';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var result = h.typeAnalyzer
         .analyzeConditionalExpression(this, condition, ifTrue, ifFalse);
     h.irBuilder.apply('if', [Kind.expression, Kind.expression, Kind.expression],
@@ -1149,7 +1166,7 @@
   ConstantPattern(this.constant, {required super.location}) : super._();
 
   @override
-  TypeSchema computeSchema(Harness h) =>
+  SharedTypeSchemaView<Type> computeSchema(Harness h) =>
       h.typeAnalyzer.analyzeConstantPatternSchema();
 
   @override
@@ -1162,7 +1179,7 @@
   PatternResult<Type> visit(Harness h, SharedMatchContext context) {
     var analysisResult =
         h.typeAnalyzer.analyzeConstantPattern(context, this, constant);
-    var matchedType = analysisResult.matchedValueType;
+    var matchedType = analysisResult.matchedValueType.unwrapTypeView();
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.apply('const', [Kind.expression, Kind.type], Kind.pattern,
         names: ['matchedType'], location: location);
@@ -1256,24 +1273,28 @@
       if (initializer == null) {
         // Use the shared logic for analyzing uninitialized variable
         // declarations.
-        staticType = h.typeAnalyzer.analyzeUninitializedVariableDeclaration(
-            this, pattern.variable, pattern.declaredType,
-            isFinal: isFinal);
+        staticType = h.typeAnalyzer
+            .analyzeUninitializedVariableDeclaration(
+                this, pattern.variable, declaredType?.wrapSharedTypeView(),
+                isFinal: isFinal)
+            .unwrapTypeView();
         irName = 'declare';
         argKinds = [Kind.variable];
       } else {
         // There's no shared logic for analyzing initialized late variable
         // declarations, so analyze the declaration directly.
         h.flow.lateInitializer_begin(this);
-        var initializerType = h.typeAnalyzer.analyzeExpression(
-            initializer,
-            declaredType == null
-                ? h.operations.unknownType
-                : h.operations.typeToSchema(declaredType));
+        var initializerType = h.typeAnalyzer
+            .analyzeExpression(
+                initializer,
+                declaredType?.wrapSharedTypeSchemaView() ??
+                    h.operations.unknownType)
+            .unwrapTypeView();
         h.flow.lateInitializer_end();
         staticType = variable.type = declaredType ?? initializerType;
-        h.flow.declare(variable, staticType, initialized: true);
-        h.flow.initialize(variable, initializerType, initializer,
+        h.flow.declare(variable, SharedTypeView(staticType), initialized: true);
+        h.flow.initialize(
+            variable, SharedTypeView(initializerType), initializer,
             isFinal: isFinal,
             isLate: true,
             isImplicitlyTyped: declaredType == null);
@@ -1291,9 +1312,12 @@
       }
     } else if (initializer == null) {
       var pattern = this.pattern as VariablePattern;
-      var staticType = h.typeAnalyzer.analyzeUninitializedVariableDeclaration(
-          this, pattern.variable, pattern.declaredType,
-          isFinal: isFinal);
+      var declaredType = pattern.declaredType;
+      var staticType = h.typeAnalyzer
+          .analyzeUninitializedVariableDeclaration(
+              this, pattern.variable, declaredType?.wrapSharedTypeView(),
+              isFinal: isFinal)
+          .unwrapTypeView();
       h.typeAnalyzer.handleDeclaredVariablePattern(pattern,
           matchedType: staticType, staticType: staticType);
       irName = 'declare';
@@ -1356,7 +1380,8 @@
   String toString() => '$lhs ${isInverted ? '!=' : '=='} $rhs';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var operatorName = isInverted ? '!=' : '==';
     var result =
         h.typeAnalyzer.analyzeBinaryExpression(this, lhs, operatorName, rhs);
@@ -1382,7 +1407,8 @@
 
   void preVisit(PreVisitor visitor);
 
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema);
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema);
 }
 
 /// Representation of a single case clause in a switch expression.  Use
@@ -1431,9 +1457,10 @@
 
   @override
   void visit(Harness h, CollectionElementContext context) {
-    TypeSchema typeSchema = context is CollectionElementContextType
-        ? context.elementTypeSchema
-        : h.operations.unknownType;
+    SharedTypeSchemaView<Type> typeSchema =
+        context is CollectionElementContextType
+            ? context.elementTypeSchema
+            : h.operations.unknownType;
     h.typeAnalyzer.dispatchExpression(expression, typeSchema);
     h.irBuilder.apply('celt', [Kind.expression], Kind.collectionElement,
         location: location);
@@ -1443,7 +1470,7 @@
 class ExpressionInTypeSchema extends Statement {
   final Expression expr;
 
-  final TypeSchema typeSchema;
+  final SharedTypeSchemaView<Type> typeSchema;
 
   ExpressionInTypeSchema._(this.expr, this.typeSchema,
       {required super.location});
@@ -1595,12 +1622,13 @@
 
   @override
   void visit(Harness h) {
-    var iteratedType = h._getIteratedType(
-        h.typeAnalyzer.analyzeExpression(iterable, h.operations.unknownType));
+    var iteratedType = h._getIteratedType(h.typeAnalyzer
+        .analyzeExpression(iterable, h.operations.unknownType)
+        .unwrapTypeView());
     h.flow.forEach_bodyBegin(this);
     var variable = this.variable;
     if (variable != null && !declaresVariable) {
-      h.flow.write(this, variable, iteratedType, null);
+      h.flow.write(this, variable, SharedTypeView(iteratedType), null);
     }
     h.typeAnalyzer._visitLoopBody(this, body);
     h.flow.forEach_end();
@@ -1639,7 +1667,8 @@
 
   bool _started = false;
 
-  late final FlowAnalysis<Node, Statement, Expression, Var, Type> flow;
+  late final FlowAnalysis<Node, Statement, Expression, Var,
+      SharedTypeView<Type>> flow;
 
   bool? _inferenceUpdate3Enabled;
 
@@ -1814,8 +1843,8 @@
           kind: operator == '=='
               ? RelationalOperatorKind.equals
               : RelationalOperatorKind.notEquals,
-          parameterType: Type('Object'),
-          returnType: Type('bool'));
+          parameterType: SharedTypeView(Type('Object')),
+          returnType: SharedTypeView(Type('bool')));
     }
     var member = getMember(matchedValueType, operator);
     if (member == null) return null;
@@ -1831,8 +1860,8 @@
     }
     return RelationalOperatorResolution(
         kind: RelationalOperatorKind.other,
-        parameterType: memberType.positionalParameters[0],
-        returnType: memberType.returnType);
+        parameterType: SharedTypeView(memberType.positionalParameters[0]),
+        returnType: SharedTypeView(memberType.returnType));
   }
 
   /// Runs the given [statements] through flow analysis, checking any assertions
@@ -1848,10 +1877,11 @@
       var b = Block._(statements, location: computeLocation());
       b.preVisit(visitor);
       flow = operations.legacy
-          ? FlowAnalysis<Node, Statement, Expression, Var, Type>.legacy(
+          ? FlowAnalysis<Node, Statement, Expression, Var,
+                  SharedTypeView<Type>>.legacy(
               operations, visitor._assignedVariables)
-          : FlowAnalysis<Node, Statement, Expression, Var, Type>(
-              operations, visitor._assignedVariables,
+          : FlowAnalysis<Node, Statement, Expression, Var,
+                  SharedTypeView<Type>>(operations, visitor._assignedVariables,
               respectImplicitlyTypedVarInitializers:
                   _respectImplicitlyTypedVarInitializers,
               fieldPromotionEnabled: _fieldPromotionEnabled);
@@ -2106,7 +2136,8 @@
   String toString() => '$lhs ?? $rhs';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var result = h.typeAnalyzer.analyzeIfNullExpression(this, lhs, rhs);
     h.irBuilder.apply(
         'ifNull', [Kind.expression, Kind.expression], Kind.expression,
@@ -2133,7 +2164,8 @@
   String toString() => '$value';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var result = h.typeAnalyzer.analyzeIntLiteral(schema);
     if (expectConversionToDouble != null) {
       expect(result.convertedToDouble, expectConversionToDouble);
@@ -2174,7 +2206,8 @@
       '$target.$methodName(${[for (var arg in arguments) arg].join(', ')})';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     return h.typeAnalyzer.analyzeMethodInvocation(this,
         target is CascadePlaceholder ? null : target, methodName, arguments);
   }
@@ -2196,7 +2229,8 @@
   String toString() => '$target is${isInverted ? '!' : ''} $type';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     return h.typeAnalyzer
         .analyzeTypeTest(this, target, type, isInverted: isInverted);
   }
@@ -2253,15 +2287,17 @@
   }
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     for (var element in elements) {
       element.visit(
-          h, CollectionElementContextType._(TypeSchema.fromType(elementType)));
+          h, CollectionElementContextType._(SharedTypeSchemaView(elementType)));
     }
     h.irBuilder.apply('list', [for (var _ in elements) Kind.collectionElement],
         Kind.expression,
         location: location);
-    return SimpleTypeAnalysisResult(type: h.operations.listType(elementType));
+    return SimpleTypeAnalysisResult(
+        type: h.operations.listType(SharedTypeView(elementType)));
   }
 }
 
@@ -2283,8 +2319,9 @@
       : super._();
 
   @override
-  TypeSchema computeSchema(Harness h) => h.typeAnalyzer
-      .analyzeListPatternSchema(elementType: elementType, elements: elements);
+  SharedTypeSchemaView<Type> computeSchema(Harness h) =>
+      h.typeAnalyzer.analyzeListPatternSchema(
+          elementType: elementType?.wrapSharedTypeView(), elements: elements);
 
   @override
   void preVisit(PreVisitor visitor, VariableBinder<Node, Var> variableBinder,
@@ -2297,9 +2334,9 @@
   @override
   PatternResult<Type> visit(Harness h, SharedMatchContext context) {
     var listPatternResult = h.typeAnalyzer.analyzeListPattern(context, this,
-        elementType: elementType, elements: elements);
-    var matchedType = listPatternResult.matchedValueType;
-    var requiredType = listPatternResult.requiredType;
+        elementType: elementType?.wrapSharedTypeView(), elements: elements);
+    var matchedType = listPatternResult.matchedValueType.unwrapTypeView();
+    var requiredType = listPatternResult.requiredType.unwrapTypeView();
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.atom(requiredType.type, Kind.type, location: location);
     h.irBuilder.apply(
@@ -2342,13 +2379,14 @@
   String toString() => '() $body';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     h.flow.functionExpression_begin(this);
     h.typeAnalyzer.dispatchStatement(body);
     h.flow.functionExpression_end();
     h.irBuilder.apply('localFunction', [Kind.statement], Kind.expression,
         location: location);
-    return SimpleTypeAnalysisResult(type: type);
+    return SimpleTypeAnalysisResult(type: SharedTypeView(type));
   }
 }
 
@@ -2371,7 +2409,8 @@
   String toString() => '$lhs ${isAnd ? '&&' : '||'} $rhs';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var operatorName = isAnd ? '&&' : '||';
     var result =
         h.typeAnalyzer.analyzeBinaryExpression(this, lhs, operatorName, rhs);
@@ -2391,7 +2430,7 @@
       : super._();
 
   @override
-  TypeSchema computeSchema(Harness h) =>
+  SharedTypeSchemaView<Type> computeSchema(Harness h) =>
       h.typeAnalyzer.analyzeLogicalAndPatternSchema(lhs, rhs);
 
   @override
@@ -2405,7 +2444,7 @@
   PatternResult<Type> visit(Harness h, SharedMatchContext context) {
     var analysisResult =
         h.typeAnalyzer.analyzeLogicalAndPattern(context, this, lhs, rhs);
-    var matchedType = analysisResult.matchedValueType;
+    var matchedType = analysisResult.matchedValueType.unwrapTypeView();
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.apply('logicalAndPattern',
         [Kind.pattern, Kind.pattern, Kind.type], Kind.pattern,
@@ -2429,7 +2468,7 @@
   LogicalOrPattern(this.lhs, this.rhs, {required super.location}) : super._();
 
   @override
-  TypeSchema computeSchema(Harness h) =>
+  SharedTypeSchemaView<Type> computeSchema(Harness h) =>
       h.typeAnalyzer.analyzeLogicalOrPatternSchema(lhs, rhs);
 
   @override
@@ -2446,7 +2485,7 @@
   PatternResult<Type> visit(Harness h, SharedMatchContext context) {
     var analysisResult =
         h.typeAnalyzer.analyzeLogicalOrPattern(context, this, lhs, rhs);
-    var matchedType = analysisResult.matchedValueType;
+    var matchedType = analysisResult.matchedValueType.unwrapTypeView();
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.apply('logicalOrPattern',
         [Kind.pattern, Kind.pattern, Kind.type], Kind.pattern,
@@ -2501,12 +2540,12 @@
 
   @override
   void visit(Harness h, CollectionElementContext context) {
-    TypeSchema keySchema;
-    TypeSchema valueSchema;
+    SharedTypeSchemaView<Type> keySchema;
+    SharedTypeSchemaView<Type> valueSchema;
     switch (context) {
       case CollectionElementContextMapEntry(:var keyType, :var valueType):
-        keySchema = TypeSchema.fromType(keyType);
-        valueSchema = TypeSchema.fromType(valueType);
+        keySchema = SharedTypeSchemaView(keyType);
+        valueSchema = SharedTypeSchemaView(valueType);
       default:
         keySchema = valueSchema = h.operations.unknownType;
     }
@@ -2536,7 +2575,8 @@
   }
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var context = CollectionElementContextMapEntry._(keyType, valueType);
     for (var element in elements) {
       element.visit(h, context);
@@ -2545,7 +2585,9 @@
         Kind.expression,
         location: location);
     return SimpleTypeAnalysisResult(
-        type: h.operations.mapType(keyType: keyType, valueType: valueType));
+        type: h.operations.mapType(
+            keyType: SharedTypeView(keyType),
+            valueType: SharedTypeView(valueType)));
   }
 }
 
@@ -2558,8 +2600,10 @@
       : super._();
 
   @override
-  TypeSchema computeSchema(Harness h) => h.typeAnalyzer.analyzeMapPatternSchema(
-      typeArguments: typeArguments, elements: elements);
+  SharedTypeSchemaView<Type> computeSchema(Harness h) =>
+      h.typeAnalyzer.analyzeMapPatternSchema(
+          typeArguments: typeArguments?.wrapSharedTypeMapEntryView(),
+          elements: elements);
 
   @override
   void preVisit(PreVisitor visitor, VariableBinder<Node, Var> variableBinder,
@@ -2572,9 +2616,10 @@
   @override
   PatternResult<Type> visit(Harness h, SharedMatchContext context) {
     var mapPatternResult = h.typeAnalyzer.analyzeMapPattern(context, this,
-        typeArguments: typeArguments, elements: elements);
-    var matchedType = mapPatternResult.matchedValueType;
-    var requiredType = mapPatternResult.requiredType;
+        typeArguments: typeArguments?.wrapSharedTypeMapEntryView(),
+        elements: elements);
+    var matchedType = mapPatternResult.matchedValueType.unwrapTypeView();
+    var requiredType = mapPatternResult.requiredType.unwrapTypeView();
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.atom(requiredType.type, Kind.type, location: location);
     h.irBuilder.apply(
@@ -2623,9 +2668,12 @@
 }
 
 class MiniAstOperations
+    with
+        TypeAnalyzerOperationsMixin<Type, Var, PromotedTypeVariableType, Type,
+            String>
     implements
-        TypeAnalyzerOperations<Var, Type, TypeSchema, PromotedTypeVariableType,
-            Type, String> {
+        TypeAnalyzerOperations<Type, Var, PromotedTypeVariableType, Type,
+            String> {
   static const Map<String, bool> _coreExhaustiveness = const {
     '()': true,
     '(int, int?)': false,
@@ -2696,19 +2744,21 @@
   };
 
   @override
-  late final Type objectQuestionType = Type('Object?');
+  late final SharedTypeView<Type> objectQuestionType =
+      SharedTypeView(Type('Object?'));
 
   @override
-  late final Type objectType = Type('Object');
+  late final SharedTypeView<Type> objectType = SharedTypeView(Type('Object'));
 
   @override
-  late final TypeSchema unknownType = TypeSchema('_');
+  late final SharedTypeSchemaView<Type> unknownType =
+      SharedTypeSchemaView(Type('_'));
 
   @override
-  late final Type intType = Type('int');
+  late final SharedTypeView<Type> intType = SharedTypeView(Type('int'));
 
   @override
-  late final Type doubleType = Type('double');
+  late final SharedTypeView<Type> doubleType = SharedTypeView(Type('double'));
 
   bool? _legacy;
 
@@ -2730,13 +2780,13 @@
   final TypeSystem _typeSystem = TypeSystem();
 
   @override
-  final Type boolType = Type('bool');
+  final SharedTypeView<Type> boolType = SharedTypeView(Type('bool'));
 
   @override
-  Type get dynamicType => DynamicType.instance;
+  SharedTypeView<Type> get dynamicType => SharedTypeView(DynamicType.instance);
 
   @override
-  Type get errorType => InvalidType.instance;
+  SharedTypeView<Type> get errorType => SharedTypeView(InvalidType.instance);
 
   bool get legacy => _legacy ?? false;
 
@@ -2745,10 +2795,10 @@
   }
 
   @override
-  Type get neverType => NeverType.instance;
+  SharedTypeView<Type> get neverType => SharedTypeView(NeverType.instance);
 
   @override
-  Type get nullType => NullType.instance;
+  SharedTypeView<Type> get nullType => SharedTypeView(NullType.instance);
 
   /// Updates the harness with a new result for [downwardInfer].
   void addDownwardInfer({
@@ -2790,10 +2840,10 @@
   }
 
   @override
-  TypeClassification classifyType(Type type) {
-    if (isSubtypeOf(type, Type('Object'))) {
+  TypeClassification classifyType(SharedTypeView<Type> type) {
+    if (isSubtypeOfInternal(type.unwrapTypeView(), Type('Object'))) {
       return TypeClassification.nonNullable;
-    } else if (isSubtypeOf(type, NullType.instance)) {
+    } else if (isSubtypeOfInternal(type.unwrapTypeView(), NullType.instance)) {
       return TypeClassification.nullOrEquivalent;
     } else {
       return TypeClassification.potentiallyNullable;
@@ -2809,26 +2859,29 @@
   }
 
   @override
-  Type extensionTypeErasure(Type type) {
-    var query = '$type';
-    return _extensionTypeErasure[query] ?? type;
+  SharedTypeView<Type> extensionTypeErasure(SharedTypeView<Type> type) {
+    var query = '${type.unwrapTypeView()}';
+    return SharedTypeView(
+        _extensionTypeErasure[query] ?? type.unwrapTypeView());
   }
 
   @override
-  Type factor(Type from, Type what) {
-    return _typeSystem.factor(from, what);
+  SharedTypeView<Type> factor(
+      SharedTypeView<Type> from, SharedTypeView<Type> what) {
+    return SharedTypeView(
+        _typeSystem.factor(from.unwrapTypeView(), what.unwrapTypeView()));
   }
 
   @override
-  Type futureType(Type argumentType) {
+  Type futureTypeInternal(Type argumentType) {
     return PrimaryType('Future', args: [argumentType]);
   }
 
   @override
-  TypeDeclarationKind? getTypeDeclarationKind(Type type) {
-    if (isInterfaceType(type)) {
+  TypeDeclarationKind? getTypeDeclarationKindInternal(Type type) {
+    if (isInterfaceType(SharedTypeView(type))) {
       return TypeDeclarationKind.interfaceDeclaration;
-    } else if (isExtensionType(type)) {
+    } else if (isExtensionType(SharedTypeView(type))) {
       return TypeDeclarationKind.extensionTypeDeclaration;
     } else {
       return null;
@@ -2843,12 +2896,7 @@
   }
 
   @override
-  TypeDeclarationKind? getTypeSchemaDeclarationKind(TypeSchema typeSchema) {
-    return getTypeDeclarationKind(typeSchema.toType());
-  }
-
-  @override
-  Type glb(Type type1, Type type2) {
+  Type glbInternal(Type type1, Type type2) {
     if (type1.type == type2.type) return type1;
     var typeNames = [type1.type, type2.type];
     typeNames.sort();
@@ -2857,83 +2905,102 @@
   }
 
   @override
-  Type greatestClosure(TypeSchema schema) {
-    var type = schema.toType();
-    return type.closureWithRespectToUnknown(covariant: true) ?? type;
+  SharedTypeView<Type> greatestClosure(SharedTypeSchemaView<Type> schema) {
+    return SharedTypeView(schema
+            .unwrapTypeSchemaView()
+            .closureWithRespectToUnknown(covariant: true) ??
+        schema.unwrapTypeSchemaView());
   }
 
   @override
-  bool isAlwaysExhaustiveType(Type type) {
-    var query = type.type;
+  bool isAlwaysExhaustiveType(SharedTypeView<Type> type) {
+    var query = type.unwrapTypeView().type;
     return _exhaustiveness[query] ??
         fail('Unknown exhaustiveness query: $query');
   }
 
   @override
-  bool isAssignableTo(Type fromType, Type toType) {
-    if (legacy && isSubtypeOf(toType, fromType)) return true;
+  bool isAssignableTo(
+      SharedTypeView<Type> fromType, SharedTypeView<Type> toType) {
+    if (legacy &&
+        isSubtypeOfInternal(
+            toType.unwrapTypeView(), fromType.unwrapTypeView())) {
+      return true;
+    }
     if (fromType is DynamicType) return true;
     if (fromType is InvalidType) return true;
-    return isSubtypeOf(fromType, toType);
+    return isSubtypeOfInternal(
+        fromType.unwrapTypeView(), toType.unwrapTypeView());
   }
 
   @override
-  bool isDartCoreFunction(Type type) {
-    return type is PrimaryType &&
-        type.nullabilitySuffix == NullabilitySuffix.none &&
-        type.name == 'Function' &&
-        type.args.isEmpty;
+  bool isDartCoreFunction(SharedTypeView<Type> type) {
+    Type unwrappedType = type.unwrapTypeView();
+    return unwrappedType is PrimaryType &&
+        unwrappedType.nullabilitySuffix == NullabilitySuffix.none &&
+        unwrappedType.name == 'Function' &&
+        unwrappedType.args.isEmpty;
   }
 
   @override
-  bool isExtensionType(Type type) {
+  bool isExtensionType(SharedTypeView<Type> type) {
     // TODO(cstefantsova): Add the support for extension types in the mini ast
     // testing framework.
     return false;
   }
 
   @override
-  bool isFunctionType(Type type) => type is FunctionType;
+  bool isFunctionType(SharedTypeView<Type> type) {
+    return type.unwrapTypeView() is FunctionType;
+  }
 
   @override
-  bool isInterfaceType(Type type) =>
-      type is PrimaryType && type.isInterfaceType;
+  bool isInterfaceType(SharedTypeView<Type> type) {
+    Type unwrappedType = type.unwrapTypeView();
+    return unwrappedType is PrimaryType && unwrappedType.isInterfaceType;
+  }
 
   @override
-  bool isNever(Type type) =>
-      type is NeverType && type.nullabilitySuffix == NullabilitySuffix.none;
+  bool isNever(SharedTypeView<Type> type) {
+    Type unwrappedType = type.unwrapTypeView();
+    return unwrappedType is NeverType &&
+        unwrappedType.nullabilitySuffix == NullabilitySuffix.none;
+  }
 
   @override
-  bool isNonNullable(TypeSchema typeSchema) {
-    Type type = typeSchema.toType();
-    if (type is DynamicType ||
-        typeSchema is SharedUnknownType ||
-        type is VoidType ||
-        type is NullType) {
+  bool isNonNullable(SharedTypeSchemaView<Type> type) {
+    Type unwrappedType = type.unwrapTypeSchemaView();
+    if (unwrappedType is DynamicType ||
+        unwrappedType is SharedUnknownTypeStructure ||
+        unwrappedType is VoidType ||
+        unwrappedType is NullType) {
       return false;
-    } else if (type is PromotedTypeVariableType &&
-        type.nullabilitySuffix == NullabilitySuffix.none) {
-      return isNonNullable(typeToSchema(type.promotion));
+    } else if (unwrappedType is PromotedTypeVariableType &&
+        unwrappedType.nullabilitySuffix == NullabilitySuffix.none) {
+      return isNonNullable(SharedTypeSchemaView(unwrappedType.promotion));
     } else if (type.nullabilitySuffix == NullabilitySuffix.question) {
       return false;
-    } else if (matchFutureOr(type) case Type typeArgument?) {
-      return isNonNullable(typeToSchema(typeArgument));
+    } else if (matchFutureOrInternal(unwrappedType) case Type typeArgument?) {
+      return isNonNullable(SharedTypeSchemaView(typeArgument));
     }
     // TODO(cstefantsova): Update to a fast-pass implementation when the
     // mini-ast testing framework supports looking up superinterfaces of
     // extension types or looking up bounds of type parameters.
-    return _typeSystem.isSubtype(NullType.instance, type);
+    return _typeSystem.isSubtype(NullType.instance, unwrappedType);
   }
 
   @override
-  bool isNull(Type type) => type is NullType;
+  bool isNull(SharedTypeView<Type> type) {
+    return type.unwrapTypeView() is NullType;
+  }
 
   @override
-  bool isObject(Type type) {
-    return type is PrimaryType &&
-        type.nullabilitySuffix == NullabilitySuffix.none &&
-        type.name == 'Object' &&
-        type.args.isEmpty;
+  bool isObject(SharedTypeView<Type> type) {
+    Type unwrappedType = type.unwrapTypeView();
+    return unwrappedType is PrimaryType &&
+        unwrappedType.nullabilitySuffix == NullabilitySuffix.none &&
+        unwrappedType.name == 'Object' &&
+        unwrappedType.args.isEmpty;
   }
 
   @override
@@ -2941,19 +3008,24 @@
       property.isPromotable;
 
   @override
-  bool isSubtypeOf(Type leftType, Type rightType) {
+  bool isSubtypeOfInternal(Type leftType, Type rightType) {
     return _typeSystem.isSubtype(leftType, rightType);
   }
 
   @override
-  bool isTypeParameterType(Type type) =>
-      type is PromotedTypeVariableType &&
-      type.nullabilitySuffix == NullabilitySuffix.none;
+  bool isTypeParameterType(SharedTypeView<Type> type) {
+    Type unwrappedType = type.unwrapTypeView();
+    return unwrappedType is PromotedTypeVariableType &&
+        unwrappedType.nullabilitySuffix == NullabilitySuffix.none;
+  }
 
   @override
   bool isTypeSchemaSatisfied(
-          {required TypeSchema typeSchema, required Type type}) =>
-      isSubtypeOf(type, typeSchema.toType());
+      {required SharedTypeSchemaView<Type> typeSchema,
+      required SharedTypeView<Type> type}) {
+    return isSubtypeOfInternal(
+        type.unwrapTypeView(), typeSchema.unwrapTypeSchemaView());
+  }
 
   @override
   bool isVariableFinal(Var node) {
@@ -2961,31 +3033,33 @@
   }
 
   @override
-  TypeSchema iterableTypeSchema(TypeSchema elementTypeSchema) {
-    return TypeSchema.fromType(
-        PrimaryType('Iterable', args: [elementTypeSchema.toType()]));
+  SharedTypeSchemaView<Type> iterableTypeSchema(
+      SharedTypeSchemaView<Type> elementTypeSchema) {
+    return SharedTypeSchemaView(PrimaryType('Iterable',
+        args: [elementTypeSchema.unwrapTypeSchemaView()]));
   }
 
   @override
-  Type listType(Type elementType) => PrimaryType('List', args: [elementType]);
+  Type listTypeInternal(Type elementType) {
+    return PrimaryType('List', args: [elementType]);
+  }
 
   @override
-  TypeSchema listTypeSchema(TypeSchema elementTypeSchema) =>
-      TypeSchema.fromType(
-          PrimaryType('List', args: [elementTypeSchema.toType()]));
-
-  @override
-  Type lub(Type type1, Type type2) {
+  Type lubInternal(Type type1, Type type2) {
     if (type1 == type2) {
       return type1;
-    } else if (promoteToNonNull(type1) == type2) {
+    } else if (promoteToNonNull(SharedTypeView(type1)) ==
+        SharedTypeView(type2)) {
       return type1;
-    } else if (promoteToNonNull(type2) == type1) {
+    } else if (promoteToNonNull(SharedTypeView(type2)) ==
+        SharedTypeView(type1)) {
       return type2;
-    } else if (type1 is NullType && promoteToNonNull(type2) != type2) {
+    } else if (type1 is NullType &&
+        promoteToNonNull(SharedTypeView(type2)) != SharedTypeView(type2)) {
       // type2 is already nullable
       return type2;
-    } else if (type2 is NullType && promoteToNonNull(type1) != type1) {
+    } else if (type2 is NullType &&
+        promoteToNonNull(SharedTypeView(type1)) != SharedTypeView(type1)) {
       // type1 is already nullable
       return type1;
     } else if (type1 is NeverType &&
@@ -3003,14 +3077,10 @@
   }
 
   @override
-  Type makeNullable(Type type) => lub(type, NullType.instance);
+  Type makeNullableInternal(Type type) => lubInternal(type, NullType.instance);
 
   @override
-  TypeSchema makeTypeSchemaNullable(TypeSchema typeSchema) =>
-      TypeSchema.fromType(lub(typeSchema.toType(), NullType.instance));
-
-  @override
-  Type mapType({
+  Type mapTypeInternal({
     required Type keyType,
     required Type valueType,
   }) {
@@ -3018,15 +3088,7 @@
   }
 
   @override
-  TypeSchema mapTypeSchema(
-      {required TypeSchema keyTypeSchema,
-      required TypeSchema valueTypeSchema}) {
-    return TypeSchema.fromType(PrimaryType('Map',
-        args: [keyTypeSchema.toType(), valueTypeSchema.toType()]));
-  }
-
-  @override
-  Type? matchFutureOr(Type type) {
+  Type? matchFutureOrInternal(Type type) {
     if (type is FutureOrType) {
       return type.typeArgument;
     }
@@ -3034,22 +3096,13 @@
   }
 
   @override
-  TypeSchema? matchTypeSchemaFutureOr(TypeSchema typeSchema) {
-    Type type = typeSchema.toType();
-    if (type is FutureOrType) {
-      return TypeSchema.fromType(type.typeArgument);
-    }
-    return null;
-  }
-
-  @override
-  PromotedTypeVariableType? matchInferableParameter(Type type) {
+  PromotedTypeVariableType? matchInferableParameter(SharedTypeView<Type> type) {
     // TODO(cstefantsova): Add support for type parameter objects in Mini AST.
     return null;
   }
 
   @override
-  Type? matchIterableType(Type type) {
+  Type? matchIterableTypeInternal(Type type) {
     if (type is PrimaryType &&
         type.nullabilitySuffix == NullabilitySuffix.none &&
         type.args.length == 1) {
@@ -3061,88 +3114,90 @@
   }
 
   @override
-  TypeSchema? matchIterableTypeSchema(TypeSchema typeSchema) =>
-      switch (matchIterableType(typeSchema.toType())) {
-        null => null,
-        var t => TypeSchema.fromType(t)
-      };
-
-  @override
-  Type? matchListType(Type type) {
-    if (type is PrimaryType &&
-        type.nullabilitySuffix == NullabilitySuffix.none &&
-        type.name == 'List' &&
-        type.args.length == 1) {
-      return type.args[0];
+  SharedTypeView<Type>? matchListType(SharedTypeView<Type> type) {
+    Type unwrappedType = type.unwrapTypeView();
+    if (unwrappedType is PrimaryType &&
+        unwrappedType.nullabilitySuffix == NullabilitySuffix.none &&
+        unwrappedType.name == 'List' &&
+        unwrappedType.args.length == 1) {
+      return SharedTypeView(unwrappedType.args[0]);
     }
     return null;
   }
 
   @override
-  ({Type keyType, Type valueType})? matchMapType(Type type) {
-    if (type is PrimaryType &&
-        type.nullabilitySuffix == NullabilitySuffix.none &&
-        type.name == 'Map' &&
-        type.args.length == 2) {
+  ({SharedTypeView<Type> keyType, SharedTypeView<Type> valueType})?
+      matchMapType(SharedTypeView<Type> type) {
+    Type unwrappedType = type.unwrapTypeView();
+    if (unwrappedType is PrimaryType &&
+        unwrappedType.nullabilitySuffix == NullabilitySuffix.none &&
+        unwrappedType.name == 'Map' &&
+        unwrappedType.args.length == 2) {
       return (
-        keyType: type.args[0],
-        valueType: type.args[1],
+        keyType: SharedTypeView(unwrappedType.args[0]),
+        valueType: SharedTypeView(unwrappedType.args[1]),
       );
     }
     return null;
   }
 
   @override
-  Type? matchStreamType(Type type) {
-    if (type is PrimaryType &&
-        type.nullabilitySuffix == NullabilitySuffix.none &&
-        type.args.length == 1) {
-      if (type.name == 'Stream') {
-        return type.args[0];
+  SharedTypeView<Type>? matchStreamType(SharedTypeView<Type> type) {
+    Type unwrappedType = type.unwrapTypeView();
+    if (unwrappedType is PrimaryType &&
+        unwrappedType.nullabilitySuffix == NullabilitySuffix.none &&
+        unwrappedType.args.length == 1) {
+      if (unwrappedType.name == 'Stream') {
+        return SharedTypeView(unwrappedType.args[0]);
       }
     }
     return null;
   }
 
   @override
-  TypeDeclarationMatchResult? matchTypeDeclarationType(Type type) {
-    if (type is! PrimaryType) return null;
-    if (type.isInterfaceType) {
+  TypeDeclarationMatchResult? matchTypeDeclarationType(
+      SharedTypeView<Type> type) {
+    Type unwrappedType = type.unwrapTypeView();
+    if (unwrappedType is! PrimaryType) return null;
+    if (unwrappedType.isInterfaceType) {
       return new TypeDeclarationMatchResult(
           typeDeclarationKind: TypeDeclarationKind.interfaceDeclaration,
-          typeDeclaration: type.type,
-          typeDeclarationType: type,
-          typeArguments: type.args);
+          typeDeclaration: unwrappedType.type,
+          typeDeclarationType: unwrappedType,
+          typeArguments: unwrappedType.args);
     } else if (isExtensionType(type)) {
       return new TypeDeclarationMatchResult(
           typeDeclarationKind: TypeDeclarationKind.extensionTypeDeclaration,
-          typeDeclaration: type.type,
-          typeDeclarationType: type,
-          typeArguments: type.args);
+          typeDeclaration: unwrappedType.type,
+          typeDeclarationType: unwrappedType,
+          typeArguments: unwrappedType.args);
     } else {
       return null;
     }
   }
 
   @override
-  Type normalize(Type type) {
-    var query = '$type';
-    return _normalizeResults[query] ?? fail('Unknown query: $query');
+  SharedTypeView<Type> normalize(SharedTypeView<Type> type) {
+    var query = '${type.unwrapTypeView()}';
+    return SharedTypeView(
+        _normalizeResults[query] ?? fail('Unknown query: $query'));
   }
 
   @override
-  Type promoteToNonNull(Type type) {
-    if (type.nullabilitySuffix == NullabilitySuffix.question) {
-      return type.withNullability(NullabilitySuffix.none);
-    } else if (type is NullType) {
-      return NeverType.instance;
+  SharedTypeView<Type> promoteToNonNull(SharedTypeView<Type> type) {
+    Type unwrappedType = type.unwrapTypeView();
+    if (unwrappedType.nullabilitySuffix == NullabilitySuffix.question) {
+      return SharedTypeView(
+          unwrappedType.withNullability(NullabilitySuffix.none));
+    } else if (unwrappedType is NullType) {
+      return SharedTypeView(NeverType.instance);
     } else {
       return type;
     }
   }
 
   @override
-  RecordType recordType(
+  RecordType recordTypeInternal(
       {required List<Type> positional, required List<(String, Type)> named}) {
     return RecordType(
       positionalTypes: positional,
@@ -3153,28 +3208,21 @@
   }
 
   @override
-  TypeSchema recordTypeSchema(
-          {required List<TypeSchema> positional,
-          required List<(String, TypeSchema)> named}) =>
-      TypeSchema.fromType(recordType(positional: [
-        for (var t in positional) t.toType()
-      ], named: [
-        for (var (name, typeSchema) in named) (name, typeSchema.toType())
-      ]));
-
-  @override
-  TypeSchema streamTypeSchema(TypeSchema elementTypeSchema) {
-    return TypeSchema.fromType(
-        PrimaryType('Stream', args: [elementTypeSchema.toType()]));
+  SharedTypeSchemaView<Type> streamTypeSchema(
+      SharedTypeSchemaView<Type> elementTypeSchema) {
+    return SharedTypeSchemaView(PrimaryType('Stream',
+        args: [elementTypeSchema.unwrapTypeSchemaView()]));
   }
 
   @override
-  Type? tryPromoteToType(Type to, Type from) {
-    var exception = (_promotionExceptions[from.type] ?? {})[to.type];
+  SharedTypeView<Type>? tryPromoteToType(
+      SharedTypeView<Type> to, SharedTypeView<Type> from) {
+    var exception = (_promotionExceptions[from.unwrapTypeView().type] ??
+        {})[to.unwrapTypeView().type];
     if (exception != null) {
-      return Type(exception);
+      return SharedTypeView(Type(exception));
     }
-    if (isSubtypeOf(to, from)) {
+    if (isSubtypeOfInternal(to.unwrapTypeView(), from.unwrapTypeView())) {
       return to;
     } else {
       return null;
@@ -3182,35 +3230,12 @@
   }
 
   @override
-  bool typeIsSubtypeOfTypeSchema(Type leftType, TypeSchema rightSchema) {
-    return isSubtypeOf(leftType, rightSchema.toType());
-  }
+  SharedTypeSchemaView<Type> typeToSchema(SharedTypeView<Type> type) =>
+      SharedTypeSchemaView(type.unwrapTypeView());
 
   @override
-  TypeSchema typeSchemaGlb(TypeSchema typeSchema1, TypeSchema typeSchema2) =>
-      TypeSchema.fromType(glb(typeSchema1.toType(), typeSchema2.toType()));
-
-  @override
-  bool typeSchemaIsSubtypeOfType(TypeSchema leftSchema, Type rightType) {
-    return isSubtypeOf(leftSchema.toType(), rightType);
-  }
-
-  @override
-  bool typeSchemaIsSubtypeOfTypeSchema(
-      TypeSchema leftSchema, TypeSchema rightSchema) {
-    return isSubtypeOf(leftSchema.toType(), rightSchema.toType());
-  }
-
-  @override
-  TypeSchema typeSchemaLub(TypeSchema typeSchema1, TypeSchema typeSchema2) =>
-      TypeSchema.fromType(lub(typeSchema1.toType(), typeSchema2.toType()));
-
-  @override
-  TypeSchema typeToSchema(Type type) => TypeSchema.fromType(type);
-
-  @override
-  Type variableType(Var variable) {
-    return variable.type;
+  SharedTypeView<Type> variableType(Var variable) {
+    return SharedTypeView(variable.type);
   }
 
   @override
@@ -3219,18 +3244,9 @@
       property.whyNotPromotable;
 
   @override
-  Type withNullabilitySuffix(Type type, NullabilitySuffix modifier) =>
-      type.withNullability(modifier);
-
-  @override
-  NullabilitySuffix typeSchemaNullabilitySuffix(TypeSchema typeSchema) {
-    return typeSchema.toType().nullabilitySuffix;
-  }
-
-  @override
-  TypeSchema futureTypeSchema(TypeSchema argumentTypeSchema) {
-    return TypeSchema.fromType(
-        PrimaryType('Future', args: [argumentTypeSchema.toType()]));
+  SharedTypeView<Type> withNullabilitySuffix(
+      SharedTypeView<Type> type, NullabilitySuffix modifier) {
+    return SharedTypeView(type.unwrapTypeView().withNullability(modifier));
   }
 }
 
@@ -3285,7 +3301,8 @@
   String toString() => '$operand!';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     return h.typeAnalyzer.analyzeNonNullAssert(this, operand);
   }
 }
@@ -3304,7 +3321,8 @@
   String toString() => '!$operand';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     return h.typeAnalyzer.analyzeLogicalNot(this, operand);
   }
 }
@@ -3329,14 +3347,15 @@
   String toString() => '$lhs?.${isCascaded ? '.' : ''}($rhs)';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var lhsType =
         h.typeAnalyzer.analyzeExpression(lhs, h.operations.unknownType);
     h.flow.nullAwareAccess_rightBegin(isCascaded ? null : lhs, lhsType);
     var rhsType =
         h.typeAnalyzer.analyzeExpression(rhs, h.operations.unknownType);
     h.flow.nullAwareAccess_end();
-    var type = h.operations.lub(rhsType, NullType.instance);
+    var type = h.operations.lub(rhsType, SharedTypeView(NullType.instance));
     h.irBuilder.apply(
         _fakeMethodName, [Kind.expression, Kind.expression], Kind.expression,
         location: location);
@@ -3354,7 +3373,7 @@
       : super._();
 
   @override
-  TypeSchema computeSchema(Harness h) => h.typeAnalyzer
+  SharedTypeSchemaView<Type> computeSchema(Harness h) => h.typeAnalyzer
       .analyzeNullCheckOrAssertPatternSchema(inner, isAssert: isAssert);
 
   @override
@@ -3368,7 +3387,7 @@
     var analysisResult = h.typeAnalyzer.analyzeNullCheckOrAssertPattern(
         context, this, inner,
         isAssert: isAssert);
-    var matchedType = analysisResult.matchedValueType;
+    var matchedType = analysisResult.matchedValueType.unwrapTypeView();
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.apply(isAssert ? 'nullAssertPattern' : 'nullCheckPattern',
         [Kind.pattern, Kind.type], Kind.pattern,
@@ -3391,7 +3410,8 @@
   String toString() => 'null';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var result = h.typeAnalyzer.analyzeNullLiteral(this);
     h.irBuilder.atom('null', Kind.expression, location: location);
     return result;
@@ -3409,8 +3429,9 @@
   }) : super._();
 
   @override
-  TypeSchema computeSchema(Harness h) {
-    return h.typeAnalyzer.analyzeObjectPatternSchema(requiredType);
+  SharedTypeSchemaView<Type> computeSchema(Harness h) {
+    return h.typeAnalyzer
+        .analyzeObjectPatternSchema(SharedTypeView(requiredType));
   }
 
   @override
@@ -3426,8 +3447,8 @@
   PatternResult<Type> visit(Harness h, SharedMatchContext context) {
     var objectPatternResult =
         h.typeAnalyzer.analyzeObjectPattern(context, this, fields: fields);
-    var matchedType = objectPatternResult.matchedValueType;
-    var requiredType = objectPatternResult.requiredType;
+    var matchedType = objectPatternResult.matchedValueType.unwrapTypeView();
+    var requiredType = objectPatternResult.requiredType.unwrapTypeView();
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.atom(requiredType.type, Kind.type, location: location);
     h.irBuilder.apply(
@@ -3465,7 +3486,8 @@
   String toString() => '($expr)';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     return h.typeAnalyzer.analyzeParenthesizedExpression(this, expr, schema);
   }
 }
@@ -3476,7 +3498,7 @@
   ParenthesizedPattern._(this.inner, {required super.location}) : super._();
 
   @override
-  TypeSchema computeSchema(Harness h) => inner.computeSchema(h);
+  SharedTypeSchemaView<Type> computeSchema(Harness h) => inner.computeSchema(h);
 
   @override
   void preVisit(PreVisitor visitor, VariableBinder<Node, Var> variableBinder,
@@ -3529,7 +3551,7 @@
         location: location);
   }
 
-  TypeSchema computeSchema(Harness h);
+  SharedTypeSchemaView<Type> computeSchema(Harness h);
 
   Pattern or(Pattern other) =>
       LogicalOrPattern(this, other, location: computeLocation());
@@ -3573,7 +3595,8 @@
   }
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var result = h.typeAnalyzer.analyzePatternAssignment(this, lhs, rhs);
     h.irBuilder.apply(
         'patternAssignment', [Kind.expression, Kind.pattern], Kind.expression,
@@ -3755,10 +3778,11 @@
   String toString() => '(expr with type $type)';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     h.irBuilder.atom(type.type, Kind.type, location: location);
     h.irBuilder.apply('expr', [Kind.type], Kind.expression, location: location);
-    return new SimpleTypeAnalysisResult<Type>(type: type);
+    return new SimpleTypeAnalysisResult<Type>(type: SharedTypeView(type));
   }
 }
 
@@ -3842,18 +3866,22 @@
   String toString() => '$target.$propertyName';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     return h.typeAnalyzer.analyzePropertyGet(
         this, target is CascadePlaceholder ? null : target, propertyName);
   }
 
   @override
   Type? _getPromotedType(Harness h) {
-    var receiverType =
-        h.typeAnalyzer.analyzeExpression(target, h.operations.unknownType);
+    var receiverType = h.typeAnalyzer
+        .analyzeExpression(target, h.operations.unknownType)
+        .unwrapTypeView();
     var member = h.typeAnalyzer._lookupMember(receiverType, propertyName);
-    return h.flow.promotedPropertyType(
-        ExpressionPropertyTarget(target), propertyName, member, member!._type);
+    return h.flow
+        .promotedPropertyType(ExpressionPropertyTarget(target), propertyName,
+            member, SharedTypeView(member!._type))
+        ?.unwrapTypeView();
   }
 
   @override
@@ -4037,8 +4065,8 @@
   /// a type schema of [typeSchema].
   Statement inTypeSchema(String typeSchema) {
     var location = computeLocation();
-    return ExpressionInTypeSchema._(
-        asExpression(location: location), TypeSchema(typeSchema),
+    return ExpressionInTypeSchema._(asExpression(location: location),
+        SharedTypeSchemaView(Type(typeSchema)),
         location: location);
   }
 
@@ -4164,7 +4192,7 @@
   RecordPattern._(this.fields, {required super.location}) : super._();
 
   @override
-  TypeSchema computeSchema(Harness h) {
+  SharedTypeSchemaView<Type> computeSchema(Harness h) {
     return h.typeAnalyzer.analyzeRecordPatternSchema(
       fields: fields,
     );
@@ -4183,8 +4211,8 @@
   PatternResult<Type> visit(Harness h, SharedMatchContext context) {
     var recordPatternResult =
         h.typeAnalyzer.analyzeRecordPattern(context, this, fields: fields);
-    var matchedType = recordPatternResult.matchedValueType;
-    var requiredType = recordPatternResult.requiredType;
+    var matchedType = recordPatternResult.matchedValueType.unwrapTypeView();
+    var requiredType = recordPatternResult.requiredType.unwrapTypeView();
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.atom(requiredType.type, Kind.type, location: location);
     h.irBuilder.apply(
@@ -4233,7 +4261,7 @@
       : super._();
 
   @override
-  TypeSchema computeSchema(Harness h) =>
+  SharedTypeSchemaView<Type> computeSchema(Harness h) =>
       h.typeAnalyzer.analyzeRelationalPatternSchema();
 
   @override
@@ -4246,7 +4274,7 @@
   PatternResult<Type> visit(Harness h, SharedMatchContext context) {
     var analysisResult =
         h.typeAnalyzer.analyzeRelationalPattern(context, this, operand);
-    var matchedType = analysisResult.matchedValueType;
+    var matchedType = analysisResult.matchedValueType.unwrapTypeView();
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.apply(operator, [Kind.expression, Kind.type], Kind.pattern,
         names: ['matchedType'], location: location);
@@ -4316,7 +4344,8 @@
   String toString() => 'second($first, $second)';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     h.typeAnalyzer.analyzeExpression(first, h.operations.unknownType);
     var type = h.typeAnalyzer.analyzeExpression(second, schema);
     h.irBuilder.apply(
@@ -4374,7 +4403,8 @@
   }
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var result = h.typeAnalyzer
         .analyzeSwitchExpression(this, scrutinee, cases.length, schema);
     h.irBuilder.apply(
@@ -4491,7 +4521,8 @@
         expectLastCaseTerminates ?? anything);
     expect(analysisResult.requiresExhaustivenessValidation,
         expectRequiresExhaustivenessValidation ?? anything);
-    expect(analysisResult.scrutineeType.type, expectScrutineeType ?? anything);
+    expect(analysisResult.scrutineeType.unwrapTypeView().type,
+        expectScrutineeType ?? anything);
     h.irBuilder.apply(
       'switch',
       [
@@ -4561,7 +4592,8 @@
   String toString() => 'this';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var result = h.typeAnalyzer.analyzeThis(this);
     h.irBuilder.atom('this', Kind.expression, location: location);
     return result;
@@ -4581,7 +4613,8 @@
       {_LValueDisposition disposition = _LValueDisposition.read}) {}
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var result = h.typeAnalyzer.analyzeThisOrSuperPropertyGet(
         this, propertyName,
         isSuperAccess: isSuperAccess);
@@ -4597,13 +4630,15 @@
     h.irBuilder.atom('$thisOrSuper.$propertyName', Kind.expression,
         location: location);
     var member = h.typeAnalyzer._lookupMember(h._thisType!, propertyName);
-    return h.flow.promotedPropertyType(
-        isSuperAccess
-            ? SuperPropertyTarget.singleton
-            : ThisPropertyTarget.singleton,
-        propertyName,
-        member,
-        member!._type);
+    return h.flow
+        .promotedPropertyType(
+            isSuperAccess
+                ? SuperPropertyTarget.singleton
+                : ThisPropertyTarget.singleton,
+            propertyName,
+            member,
+            SharedTypeView(member!._type))
+        ?.unwrapTypeView();
   }
 
   @override
@@ -4627,7 +4662,8 @@
   String toString() => 'throw ...';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     return h.typeAnalyzer.analyzeThrow(this, operand);
   }
 }
@@ -4807,7 +4843,7 @@
   @override
   Type? _getPromotedType(Harness h) {
     h.irBuilder.atom(name, Kind.expression, location: location);
-    return h.flow.promotedType(this);
+    return h.flow.promotedType(this)?.unwrapTypeView();
   }
 }
 
@@ -4825,11 +4861,12 @@
       : super._();
 
   @override
-  TypeSchema computeSchema(Harness h) {
+  SharedTypeSchemaView<Type> computeSchema(Harness h) {
     if (isAssignedVariable) {
       return h.typeAnalyzer.analyzeAssignedVariablePatternSchema(variable);
     } else {
-      return h.typeAnalyzer.analyzeDeclaredVariablePatternSchema(declaredType);
+      return h.typeAnalyzer.analyzeDeclaredVariablePatternSchema(
+          declaredType?.wrapSharedTypeView());
     }
   }
 
@@ -4856,10 +4893,12 @@
       return analysisResult;
     } else {
       var declaredVariablePatternResult = h.typeAnalyzer
-          .analyzeDeclaredVariablePattern(
-              context, this, variable, variable.name, declaredType);
-      var matchedType = declaredVariablePatternResult.matchedValueType;
-      var staticType = declaredVariablePatternResult.staticType;
+          .analyzeDeclaredVariablePattern(context, this, variable,
+              variable.name, declaredType?.wrapSharedTypeView());
+      var matchedType =
+          declaredVariablePatternResult.matchedValueType.unwrapTypeView();
+      var staticType =
+          declaredVariablePatternResult.staticType.unwrapTypeView();
       h.typeAnalyzer.handleDeclaredVariablePattern(this,
           matchedType: matchedType, staticType: staticType);
       return declaredVariablePatternResult;
@@ -4900,7 +4939,8 @@
   String toString() => variable.name;
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var result = h.typeAnalyzer.analyzeVariableGet(this, variable, callback);
     h.irBuilder.atom(variable.name, Kind.expression, location: location);
     return result;
@@ -4909,7 +4949,8 @@
   @override
   void _visitWrite(Harness h, Expression assignmentExpression, Type writtenType,
       Expression? rhs) {
-    h.flow.write(assignmentExpression, variable, writtenType, rhs);
+    h.flow.write(
+        assignmentExpression, variable, SharedTypeView(writtenType), rhs);
   }
 }
 
@@ -4951,9 +4992,9 @@
       : super._();
 
   @override
-  TypeSchema computeSchema(Harness h) {
+  SharedTypeSchemaView<Type> computeSchema(Harness h) {
     return h.typeAnalyzer.analyzeWildcardPatternSchema(
-      declaredType: declaredType,
+      declaredType: declaredType?.wrapSharedTypeView(),
     );
   }
 
@@ -4966,9 +5007,9 @@
     var analysisResult = h.typeAnalyzer.analyzeWildcardPattern(
       context: context,
       node: this,
-      declaredType: declaredType,
+      declaredType: declaredType?.wrapSharedTypeView(),
     );
-    var matchedType = analysisResult.matchedValueType;
+    var matchedType = analysisResult.matchedValueType.unwrapTypeView();
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.apply('wildcardPattern', [Kind.type], Kind.pattern,
         names: ['matchedType'], location: location);
@@ -5017,7 +5058,8 @@
   }
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     late MiniIRTmp beforeTmp;
     if (before != null) {
       h.typeAnalyzer.dispatchStatement(before!);
@@ -5063,19 +5105,24 @@
   String toString() => '$lhs = $rhs';
 
   @override
-  ExpressionTypeAnalysisResult<Type> visit(Harness h, TypeSchema schema) {
+  ExpressionTypeAnalysisResult<Type> visit(
+      Harness h, SharedTypeSchemaView<Type> schema) {
     var rhs = this.rhs;
     Type type;
     if (rhs == null) {
       // We are simulating an increment/decrement operation.
       // TODO(paulberry): Make a separate node type for this.
-      type = h.typeAnalyzer.analyzeExpression(lhs, h.operations.unknownType);
+      type = h.typeAnalyzer
+          .analyzeExpression(lhs, h.operations.unknownType)
+          .unwrapTypeView();
     } else {
-      type = h.typeAnalyzer.analyzeExpression(rhs, h.operations.unknownType);
+      type = h.typeAnalyzer
+          .analyzeExpression(rhs, h.operations.unknownType)
+          .unwrapTypeView();
     }
     lhs._visitWrite(h, this, type, rhs);
     // TODO(paulberry): null shorting
-    return new SimpleTypeAnalysisResult<Type>(type: type);
+    return new SimpleTypeAnalysisResult<Type>(type: SharedTypeView(type));
   }
 }
 
@@ -5097,8 +5144,8 @@
 
 class _MiniAstErrors
     implements
-        TypeAnalyzerErrors<Node, Statement, Expression, Var, Type, Pattern,
-            void>,
+        TypeAnalyzerErrors<Node, Statement, Expression, Var,
+            SharedTypeView<Type>, Pattern, void>,
         VariableBinderErrors<Node, Var> {
   final Set<String> _accumulatedErrors = {};
 
@@ -5119,8 +5166,8 @@
   void caseExpressionTypeMismatch(
       {required Expression scrutinee,
       required Expression caseExpression,
-      required Type scrutineeType,
-      required Type caseExpressionType,
+      required SharedTypeView<Type> scrutineeType,
+      required SharedTypeView<Type> caseExpressionType,
       required bool nullSafetyEnabled}) {
     _recordError('caseExpressionTypeMismatch', {
       'scrutinee': scrutinee,
@@ -5223,7 +5270,7 @@
   @override
   void matchedTypeIsStrictlyNonNullable({
     required Pattern pattern,
-    required Type matchedType,
+    required SharedTypeView<Type> matchedType,
   }) {
     _recordError('matchedTypeIsStrictlyNonNullable', {
       'pattern': pattern,
@@ -5234,8 +5281,8 @@
   @override
   void matchedTypeIsSubtypeOfRequired({
     required Pattern pattern,
-    required Type matchedType,
-    required Type requiredType,
+    required SharedTypeView<Type> matchedType,
+    required SharedTypeView<Type> requiredType,
   }) {
     _recordError('matchedTypeIsSubtypeOfRequired', {
       'pattern': pattern,
@@ -5253,7 +5300,7 @@
   void patternForInExpressionIsNotIterable({
     required Node node,
     required Expression expression,
-    required Type expressionType,
+    required SharedTypeView<Type> expressionType,
   }) {
     _recordError('patternForInExpressionIsNotIterable', {
       'node': node,
@@ -5266,8 +5313,8 @@
   void patternTypeMismatchInIrrefutableContext(
       {required Node pattern,
       required Node context,
-      required Type matchedType,
-      required Type requiredType}) {
+      required SharedTypeView<Type> matchedType,
+      required SharedTypeView<Type> requiredType}) {
     _recordError('patternTypeMismatchInIrrefutableContext', {
       'pattern': pattern,
       'context': context,
@@ -5286,8 +5333,8 @@
   @override
   void relationalPatternOperandTypeNotAssignable({
     required Pattern pattern,
-    required Type operandType,
-    required Type parameterType,
+    required SharedTypeView<Type> operandType,
+    required SharedTypeView<Type> parameterType,
   }) {
     _recordError('relationalPatternOperandTypeNotAssignable', {
       'pattern': pattern,
@@ -5299,7 +5346,7 @@
   @override
   void relationalPatternOperatorReturnTypeNotAssignableToBool({
     required Pattern pattern,
-    required Type returnType,
+    required SharedTypeView<Type> returnType,
   }) {
     _recordError('relationalPatternOperatorReturnTypeNotAssignableToBool', {
       'pattern': pattern,
@@ -5362,8 +5409,8 @@
 
 class _MiniAstTypeAnalyzer
     with
-        TypeAnalyzer<Node, Statement, Expression, Var, Type, Pattern, void,
-            TypeSchema, PromotedTypeVariableType, Type, String> {
+        TypeAnalyzer<Type, Node, Statement, Expression, Var, Pattern, void,
+            PromotedTypeVariableType, Type, String> {
   final Harness _harness;
 
   @override
@@ -5391,8 +5438,8 @@
   _MiniAstTypeAnalyzer(this._harness, this.options);
 
   @override
-  FlowAnalysis<Node, Statement, Expression, Var, Type> get flow =>
-      _harness.flow;
+  FlowAnalysis<Node, Statement, Expression, Var, SharedTypeView<Type>>
+      get flow => _harness.flow;
 
   Type get nullType => NullType.instance;
 
@@ -5448,7 +5495,7 @@
       flow.logicalBinaryOp_begin();
     }
     var leftType = analyzeExpression(lhs, operations.unknownType);
-    ExpressionInfo<Type>? leftInfo;
+    ExpressionInfo<SharedTypeView<Type>>? leftInfo;
     if (isEquals) {
       leftInfo = flow.equalityOperand_end(lhs, leftType);
     } else if (isLogical) {
@@ -5473,7 +5520,7 @@
 
   Type analyzeBoolLiteral(Expression node, bool value) {
     flow.booleanLiteral(node, value);
-    return operations.boolType;
+    return operations.boolType.unwrapTypeView();
   }
 
   void analyzeBreakStatement(Statement? target) {
@@ -5556,14 +5603,15 @@
           arguments[i],
           methodType is FunctionType &&
                   methodType.nullabilitySuffix == NullabilitySuffix.none
-              ? operations.typeToSchema(methodType.positionalParameters[i])
+              ? operations.typeToSchema(
+                  SharedTypeView(methodType.positionalParameters[i]))
               : operations.unknownType);
     }
     // Form the IR for the member invocation.
     _harness.irBuilder.apply(methodName, inputKinds, Kind.expression,
         location: node.location);
     // TODO(paulberry): handle null shorting
-    return new SimpleTypeAnalysisResult<Type>(type: methodType);
+    return new SimpleTypeAnalysisResult<Type>(type: SharedTypeView(methodType));
   }
 
   SimpleTypeAnalysisResult<Type> analyzeNonNullAssert(
@@ -5575,12 +5623,12 @@
   }
 
   SimpleTypeAnalysisResult<Type> analyzeNullLiteral(Expression node) {
-    flow.nullLiteral(node, nullType);
-    return new SimpleTypeAnalysisResult<Type>(type: nullType);
+    flow.nullLiteral(node, SharedTypeView(nullType));
+    return new SimpleTypeAnalysisResult<Type>(type: SharedTypeView(nullType));
   }
 
-  SimpleTypeAnalysisResult<Type> analyzeParenthesizedExpression(
-      Expression node, Expression expression, TypeSchema schema) {
+  SimpleTypeAnalysisResult<Type> analyzeParenthesizedExpression(Expression node,
+      Expression expression, SharedTypeSchemaView<Type> schema) {
     var type = analyzeExpression(expression, schema);
     flow.parenthesizedExpression(node, expression);
     return new SimpleTypeAnalysisResult<Type>(type: type);
@@ -5602,7 +5650,8 @@
     // Build the property get IR.
     _harness.irBuilder.propertyGet(propertyName, location: node.location);
     // TODO(paulberry): handle null shorting
-    return new SimpleTypeAnalysisResult<Type>(type: propertyType);
+    return new SimpleTypeAnalysisResult<Type>(
+        type: SharedTypeView(propertyType));
   }
 
   void analyzeReturnStatement() {
@@ -5611,24 +5660,27 @@
 
   SimpleTypeAnalysisResult<Type> analyzeThis(Expression node) {
     var thisType = this.thisType;
-    flow.thisOrSuper(node, thisType, isSuper: false);
-    return new SimpleTypeAnalysisResult<Type>(type: thisType);
+    flow.thisOrSuper(node, SharedTypeView(thisType), isSuper: false);
+    return new SimpleTypeAnalysisResult<Type>(type: SharedTypeView(thisType));
   }
 
   SimpleTypeAnalysisResult<Type> analyzeThisOrSuperPropertyGet(
       Expression node, String propertyName,
       {required bool isSuperAccess}) {
     var member = _lookupMember(thisType, propertyName);
-    var memberType = member?._type ?? operations.dynamicType;
-    var promotedType = flow.propertyGet(
-        node,
-        isSuperAccess
-            ? SuperPropertyTarget.singleton
-            : ThisPropertyTarget.singleton,
-        propertyName,
-        member,
-        memberType);
-    return new SimpleTypeAnalysisResult<Type>(type: promotedType ?? memberType);
+    var memberType = member?._type ?? operations.dynamicType.unwrapTypeView();
+    var promotedType = flow
+        .propertyGet(
+            node,
+            isSuperAccess
+                ? SuperPropertyTarget.singleton
+                : ThisPropertyTarget.singleton,
+            propertyName,
+            member,
+            SharedTypeView(memberType))
+        ?.unwrapTypeView();
+    return new SimpleTypeAnalysisResult<Type>(
+        type: SharedTypeView(promotedType ?? memberType));
   }
 
   SimpleTypeAnalysisResult<Type> analyzeThrow(
@@ -5669,24 +5721,24 @@
   SimpleTypeAnalysisResult<Type> analyzeTypeCast(
       Expression node, Expression expression, Type type) {
     analyzeExpression(expression, operations.unknownType);
-    flow.asExpression_end(expression, type);
-    return new SimpleTypeAnalysisResult<Type>(type: type);
+    flow.asExpression_end(expression, SharedTypeView(type));
+    return new SimpleTypeAnalysisResult<Type>(type: SharedTypeView(type));
   }
 
   SimpleTypeAnalysisResult<Type> analyzeTypeTest(
       Expression node, Expression expression, Type type,
       {bool isInverted = false}) {
     analyzeExpression(expression, operations.unknownType);
-    flow.isExpression_end(node, expression, isInverted, type);
+    flow.isExpression_end(node, expression, isInverted, SharedTypeView(type));
     return new SimpleTypeAnalysisResult<Type>(type: operations.boolType);
   }
 
   SimpleTypeAnalysisResult<Type> analyzeVariableGet(
       Expression node, Var variable, void Function(Type?)? callback) {
     var promotedType = flow.variableRead(node, variable);
-    callback?.call(promotedType);
+    callback?.call(promotedType?.unwrapTypeView());
     return new SimpleTypeAnalysisResult<Type>(
-        type: promotedType ?? variable.type);
+        type: promotedType ?? SharedTypeView(variable.type));
   }
 
   void analyzeWhileLoop(Statement node, Expression condition, Statement body) {
@@ -5707,7 +5759,7 @@
 
   @override
   ExpressionTypeAnalysisResult<Type> dispatchExpression(
-          Expression expression, TypeSchema schema) =>
+          Expression expression, SharedTypeSchemaView<Type> schema) =>
       _irBuilder.guard(expression, () => expression.visit(_harness, schema));
 
   @override
@@ -5717,7 +5769,7 @@
   }
 
   @override
-  TypeSchema dispatchPatternSchema(covariant Pattern node) {
+  SharedTypeSchemaView<Type> dispatchPatternSchema(covariant Pattern node) {
     return node.computeSchema(_harness);
   }
 
@@ -5726,15 +5778,16 @@
       _irBuilder.guard(statement, () => statement.visit(_harness));
 
   @override
-  Type downwardInferObjectPatternRequiredType({
-    required Type matchedType,
+  SharedTypeView<Type> downwardInferObjectPatternRequiredType({
+    required SharedTypeView<Type> matchedType,
     required covariant ObjectPattern pattern,
   }) {
     var requiredType = pattern.requiredType;
     if (requiredType.args.isNotEmpty) {
-      return requiredType;
+      return SharedTypeView(requiredType);
     } else {
-      return operations.downwardInfer(requiredType.name, matchedType);
+      return SharedTypeView(operations.downwardInfer(
+          requiredType.name, matchedType.unwrapTypeView()));
     }
   }
 
@@ -5755,10 +5808,10 @@
     required JoinedPatternVariableLocation location,
     required JoinedPatternVariableInconsistency inconsistency,
     required bool isFinal,
-    required Type type,
+    required SharedTypeView<Type> type,
   }) {
     variable.isFinal = isFinal;
-    variable.type = type;
+    variable.type = type.unwrapTypeView();
     variable.inconsistency = variable.inconsistency.maxWith(inconsistency);
   }
 
@@ -5913,7 +5966,7 @@
 
   @override
   void handleMapPatternEntry(
-      Pattern container, Node entryElement, Type keyType) {
+      Pattern container, Node entryElement, SharedTypeView<Type> keyType) {
     _irBuilder.apply('mapPatternEntry', [Kind.expression, Kind.pattern],
         Kind.mapPatternElement,
         location: entryElement.location);
@@ -5985,11 +6038,11 @@
   }) {}
 
   @override
-  void handleSwitchScrutinee(Type type) {}
+  void handleSwitchScrutinee(SharedTypeView<Type> type) {}
 
   @override
   bool isLegacySwitchExhaustive(
-      covariant SwitchStatement node, Type expressionType) {
+      covariant SwitchStatement node, SharedTypeView<Type> expressionType) {
     return node.isLegacyExhaustive!;
   }
 
@@ -6007,32 +6060,38 @@
   }
 
   @override
-  (_PropertyElement?, Type) resolveObjectPatternPropertyGet({
+  (_PropertyElement?, SharedTypeView<Type>) resolveObjectPatternPropertyGet({
     required Pattern objectPattern,
-    required Type receiverType,
+    required SharedTypeView<Type> receiverType,
     required shared.RecordPatternField<Node, Pattern> field,
   }) {
-    var propertyMember = _harness.getMember(receiverType, field.name!);
-    return (propertyMember, propertyMember?._type ?? operations.dynamicType);
+    var propertyMember =
+        _harness.getMember(receiverType.unwrapTypeView(), field.name!);
+    return (
+      propertyMember,
+      SharedTypeView(
+          propertyMember?._type ?? operations.dynamicType.unwrapTypeView())
+    );
   }
 
   @override
   RelationalOperatorResolution<Type>? resolveRelationalPatternOperator(
-      covariant RelationalPattern node, Type matchedValueType) {
+      covariant RelationalPattern node, SharedTypeView<Type> matchedValueType) {
     return _harness.resolveRelationalPatternOperator(
-        matchedValueType, node.operator);
+        matchedValueType.unwrapTypeView(), node.operator);
   }
 
   @override
-  void setVariableType(Var variable, Type type) {
-    variable.type = type;
+  void setVariableType(Var variable, SharedTypeView<Type> type) {
+    variable.type = type.unwrapTypeView();
   }
 
   @override
   String toString() => _irBuilder.toString();
 
   @override
-  Type variableTypeFromInitializerType(Type type) {
+  SharedTypeView<Type> variableTypeFromInitializerType(
+      SharedTypeView<Type> type) {
     // Variables whose initializer has type `Null` receive the inferred type
     // `dynamic`.
     if (_harness.operations.classifyType(type) ==
@@ -6044,7 +6103,9 @@
     // (e.g. `T&int` is demoted to `T`).
     // TODO(paulberry): add language tests to verify that the behavior of
     // `type.recursivelyDemote` matches what the analyzer and CFE do.
-    return type.recursivelyDemote(covariant: true) ?? type;
+    return SharedTypeView(
+        type.unwrapTypeView().recursivelyDemote(covariant: true) ??
+            type.unwrapTypeView());
   }
 
   /// Analyzes the target of a property get or method invocation, looks up the
@@ -6071,13 +6132,16 @@
       targetType = _currentCascadeTargetType!;
     } else {
       propertyTarget = ExpressionPropertyTarget(target);
-      targetType = analyzeExpression(target, operations.unknownType);
+      targetType =
+          analyzeExpression(target, operations.unknownType).unwrapTypeView();
     }
     // Look up the type of the member, applying type promotion if necessary.
     var member = _lookupMember(targetType, propertyName);
-    var memberType = member?._type ?? operations.dynamicType;
-    return flow.propertyGet(propertyGetNode, propertyTarget, propertyName,
-            member, memberType) ??
+    var memberType = member?._type ?? operations.dynamicType.unwrapTypeView();
+    return flow
+            .propertyGet(propertyGetNode, propertyTarget, propertyName, member,
+                SharedTypeView(memberType))
+            ?.unwrapTypeView() ??
         memberType;
   }
 
diff --git a/pkg/_fe_analyzer_shared/test/mini_types.dart b/pkg/_fe_analyzer_shared/test/mini_types.dart
index 204fa8e..b6abb1d 100644
--- a/pkg/_fe_analyzer_shared/test/mini_types.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_types.dart
@@ -16,7 +16,7 @@
 /// Representation of the type `dynamic` suitable for unit testing of code in
 /// the `_fe_analyzer_shared` package.
 class DynamicType extends _SpecialSimpleType
-    implements SharedDynamicType<Type> {
+    implements SharedDynamicTypeStructure<Type> {
   static final instance = DynamicType._();
 
   DynamicType._()
@@ -111,7 +111,7 @@
 /// Representation of an invalid type suitable for unit testing of code in the
 /// `_fe_analyzer_shared` package.
 class InvalidType extends _SpecialSimpleType
-    implements SharedInvalidType<Type> {
+    implements SharedInvalidTypeStructure<Type> {
   static final instance = InvalidType._();
 
   InvalidType._() : super._('error', nullabilitySuffix: NullabilitySuffix.none);
@@ -120,7 +120,7 @@
   Type withNullability(NullabilitySuffix suffix) => this;
 }
 
-class NamedType implements SharedNamedType<Type> {
+class NamedType implements SharedNamedTypeStructure<Type> {
   @override
   final String name;
 
@@ -272,7 +272,7 @@
           '${promotion.toString(parenthesizeIfComplex: true)}');
 }
 
-class RecordType extends Type implements SharedRecordType<Type> {
+class RecordType extends Type implements SharedRecordTypeStructure<Type> {
   @override
   final List<Type> positionalTypes;
 
@@ -385,7 +385,7 @@
 
 /// Representation of a type suitable for unit testing of code in the
 /// `_fe_analyzer_shared` package.
-abstract class Type implements SharedType<Type> {
+abstract class Type implements SharedTypeStructure<Type> {
   @override
   final NullabilitySuffix nullabilitySuffix;
 
@@ -412,7 +412,7 @@
   String getDisplayString() => type;
 
   @override
-  bool isStructurallyEqualTo(SharedType other) => '$this' == '$other';
+  bool isStructurallyEqualTo(SharedTypeStructure other) => '$this' == '$other';
 
   /// Finds the nearest type that doesn't involve any type parameter promotion.
   /// If `covariant` is `true`, a supertype will be returned (replacing promoted
@@ -461,37 +461,6 @@
   String _toStringWithoutSuffix({required bool parenthesizeIfComplex});
 }
 
-class TypeSchema implements SharedType<TypeSchema> {
-  final Type _type;
-
-  TypeSchema(String typeString) : _type = Type(typeString);
-
-  TypeSchema.fromType(this._type);
-
-  String get typeString => _type.type;
-
-  Type toType() => _type;
-
-  @override
-  String getDisplayString() {
-    throw UnsupportedError("TypeSchema.getDisplayString");
-  }
-
-  @override
-  bool isStructurallyEqualTo(SharedType<TypeSchema> other) {
-    throw UnsupportedError("TypeSchema.isStructurallyEqualTo");
-  }
-
-  @override
-  // TODO: implement nullabilitySuffix
-  NullabilitySuffix get nullabilitySuffix => throw UnimplementedError();
-}
-
-class DynamicTypeSchema extends TypeSchema
-    implements SharedDynamicType<TypeSchema> {
-  DynamicTypeSchema() : super.fromType(DynamicType.instance);
-}
-
 class TypeSystem {
   static final Map<String, List<Type> Function(List<Type>)>
       _coreSuperInterfaceTemplates = {
@@ -969,7 +938,7 @@
 
 /// Representation of the unknown type suitable for unit testing of code in the
 /// `_fe_analyzer_shared` package.
-class UnknownType extends Type implements SharedUnknownType<Type> {
+class UnknownType extends Type implements SharedUnknownTypeStructure<Type> {
   const UnknownType({super.nullabilitySuffix = NullabilitySuffix.none})
       : super._();
 
@@ -990,7 +959,8 @@
 
 /// Representation of the type `void` suitable for unit testing of code in the
 /// `_fe_analyzer_shared` package.
-class VoidType extends _SpecialSimpleType implements SharedVoidType<Type> {
+class VoidType extends _SpecialSimpleType
+    implements SharedVoidTypeStructure<Type> {
   static final instance = VoidType._();
 
   VoidType._() : super._('void', nullabilitySuffix: NullabilitySuffix.none);
diff --git a/pkg/analyzer/lib/dart/element/type.dart b/pkg/analyzer/lib/dart/element/type.dart
index 9abc61b..ebc008e 100644
--- a/pkg/analyzer/lib/dart/element/type.dart
+++ b/pkg/analyzer/lib/dart/element/type.dart
@@ -30,7 +30,7 @@
 /// The type associated with elements in the element model.
 ///
 /// Clients may not extend, implement or mix-in this class.
-abstract class DartType implements SharedType<DartType> {
+abstract class DartType implements SharedTypeStructure<DartType> {
   /// If this type is an instantiation of a type alias, information about
   /// the alias element, and the type arguments.
   /// Otherwise return `null`.
@@ -466,7 +466,8 @@
 /// The type of a record literal or a record type annotation.
 ///
 /// Clients may not extend, implement or mix-in this class.
-abstract class RecordType implements DartType, SharedRecordType<DartType> {
+abstract class RecordType
+    implements DartType, SharedRecordTypeStructure<DartType> {
   /// Creates a record type from of [positional] and [named] fields.
   factory RecordType({
     required List<DartType> positional,
@@ -500,7 +501,7 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class RecordTypeNamedField
-    implements RecordTypeField, SharedNamedType<DartType> {
+    implements RecordTypeField, SharedNamedTypeStructure<DartType> {
   /// The name of the field.
   @override
   String get name;
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index f97cb56..3a77a16 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -7,6 +7,7 @@
 
 import 'package:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/doc_comment.dart';
 import 'package:analyzer/dart/ast/precedence.dart';
@@ -784,9 +785,11 @@
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
     var element = this.element;
     if (element is PromotableElement) {
-      return resolverVisitor.analyzeAssignedVariablePatternSchema(element);
+      return resolverVisitor
+          .analyzeAssignedVariablePatternSchema(element)
+          .unwrapTypeSchemaView();
     }
-    return resolverVisitor.operations.unknownType;
+    return resolverVisitor.operations.unknownType.unwrapTypeSchemaView();
   }
 
   @override
@@ -2382,7 +2385,7 @@
 
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
-    return resolverVisitor.analyzeCastPatternSchema();
+    return resolverVisitor.analyzeCastPatternSchema().unwrapTypeSchemaView();
   }
 
   @override
@@ -2398,14 +2401,14 @@
       context: context,
       pattern: this,
       innerPattern: pattern,
-      requiredType: requiredType,
+      requiredType: SharedTypeView(requiredType),
     );
 
     resolverVisitor.checkPatternNeverMatchesValueType(
       context: context,
       pattern: this,
       requiredType: requiredType,
-      matchedValueType: analysisResult.matchedValueType,
+      matchedValueType: analysisResult.matchedValueType.unwrapTypeView(),
     );
     inferenceLogWriter?.exitPattern(this);
 
@@ -3988,7 +3991,9 @@
 
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
-    return resolverVisitor.analyzeConstantPatternSchema();
+    return resolverVisitor
+        .analyzeConstantPatternSchema()
+        .unwrapTypeSchemaView();
   }
 
   @override
@@ -4921,7 +4926,9 @@
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
     return resolverVisitor
-        .analyzeDeclaredVariablePatternSchema(type?.typeOrThrow);
+        .analyzeDeclaredVariablePatternSchema(
+            type?.typeOrThrow.wrapSharedTypeView())
+        .unwrapTypeSchemaView();
   }
 
   @override
@@ -4930,15 +4937,19 @@
     SharedMatchContext context,
   ) {
     inferenceLogWriter?.enterPattern(this);
-    var result = resolverVisitor.analyzeDeclaredVariablePattern(context, this,
-        declaredElement!, declaredElement!.name, type?.typeOrThrow);
-    declaredElement!.type = result.staticType;
+    var result = resolverVisitor.analyzeDeclaredVariablePattern(
+        context,
+        this,
+        declaredElement!,
+        declaredElement!.name,
+        type?.typeOrThrow.wrapSharedTypeView());
+    declaredElement!.type = result.staticType.unwrapTypeView();
 
     resolverVisitor.checkPatternNeverMatchesValueType(
       context: context,
       pattern: this,
-      requiredType: result.staticType,
-      matchedValueType: result.matchedValueType,
+      requiredType: result.staticType.unwrapTypeView(),
+      matchedValueType: result.matchedValueType.unwrapTypeView(),
     );
     inferenceLogWriter?.exitPattern(this);
 
@@ -6065,7 +6076,9 @@
   void resolveElement(
       ResolverVisitor resolver, CollectionLiteralContext? context) {
     resolver.analyzeExpression(
-        this, context?.elementType ?? UnknownInferredType.instance);
+        this,
+        SharedTypeSchemaView(
+            context?.elementType ?? UnknownInferredType.instance));
   }
 
   /// Dispatches this expression to the [resolver], with the given [contextType]
@@ -10995,10 +11008,12 @@
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
     var elementType = typeArguments?.arguments.elementAtOrNull(0)?.typeOrThrow;
-    return resolverVisitor.analyzeListPatternSchema(
-      elementType: elementType,
-      elements: elements,
-    );
+    return resolverVisitor
+        .analyzeListPatternSchema(
+          elementType: elementType?.wrapSharedTypeView(),
+          elements: elements,
+        )
+        .unwrapTypeSchemaView();
   }
 
   @override
@@ -11100,8 +11115,9 @@
 
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
-    return resolverVisitor.analyzeLogicalAndPatternSchema(
-        leftOperand, rightOperand);
+    return resolverVisitor
+        .analyzeLogicalAndPatternSchema(leftOperand, rightOperand)
+        .unwrapTypeSchemaView();
   }
 
   @override
@@ -11178,8 +11194,9 @@
 
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
-    return resolverVisitor.analyzeLogicalOrPatternSchema(
-        leftOperand, rightOperand);
+    return resolverVisitor
+        .analyzeLogicalOrPatternSchema(leftOperand, rightOperand)
+        .unwrapTypeSchemaView();
   }
 
   @override
@@ -11438,18 +11455,23 @@
 
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
-    ({DartType keyType, DartType valueType})? typeArguments;
     var typeArgumentNodes = this.typeArguments?.arguments;
+    ({
+      SharedTypeView<DartType> keyType,
+      SharedTypeView<DartType> valueType
+    })? typeArguments;
     if (typeArgumentNodes != null && typeArgumentNodes.length == 2) {
       typeArguments = (
-        keyType: typeArgumentNodes[0].typeOrThrow,
-        valueType: typeArgumentNodes[1].typeOrThrow,
+        keyType: SharedTypeView(typeArgumentNodes[0].typeOrThrow),
+        valueType: SharedTypeView(typeArgumentNodes[1].typeOrThrow),
       );
     }
-    return resolverVisitor.analyzeMapPatternSchema(
-      typeArguments: typeArguments,
-      elements: elements,
-    );
+    return resolverVisitor
+        .analyzeMapPatternSchema(
+          typeArguments: typeArguments,
+          elements: elements,
+        )
+        .unwrapTypeSchemaView();
   }
 
   @override
@@ -12704,10 +12726,12 @@
 
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
-    return resolverVisitor.analyzeNullCheckOrAssertPatternSchema(
-      pattern,
-      isAssert: true,
-    );
+    return resolverVisitor
+        .analyzeNullCheckOrAssertPatternSchema(
+          pattern,
+          isAssert: true,
+        )
+        .unwrapTypeSchemaView();
   }
 
   @override
@@ -12838,10 +12862,12 @@
 
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
-    return resolverVisitor.analyzeNullCheckOrAssertPatternSchema(
-      pattern,
-      isAssert: false,
-    );
+    return resolverVisitor
+        .analyzeNullCheckOrAssertPatternSchema(
+          pattern,
+          isAssert: false,
+        )
+        .unwrapTypeSchemaView();
   }
 
   @override
@@ -13016,7 +13042,9 @@
 
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
-    return resolverVisitor.analyzeObjectPatternSchema(type.typeOrThrow);
+    return resolverVisitor
+        .analyzeObjectPatternSchema(SharedTypeView(type.typeOrThrow))
+        .unwrapTypeSchemaView();
   }
 
   @override
@@ -13037,8 +13065,8 @@
     resolverVisitor.checkPatternNeverMatchesValueType(
       context: context,
       pattern: this,
-      requiredType: result.requiredType,
-      matchedValueType: result.matchedValueType,
+      requiredType: result.requiredType.unwrapTypeView(),
+      matchedValueType: result.matchedValueType.unwrapTypeView(),
     );
     inferenceLogWriter?.exitPattern(this);
 
@@ -13201,7 +13229,9 @@
 
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
-    return resolverVisitor.dispatchPatternSchema(pattern);
+    return resolverVisitor
+        .dispatchPatternSchema(pattern)
+        .unwrapTypeSchemaView();
   }
 
   @override
@@ -14315,12 +14345,14 @@
 
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
-    return resolverVisitor.analyzeRecordPatternSchema(
-      fields: resolverVisitor.buildSharedPatternFields(
-        fields,
-        mustBeNamed: false,
-      ),
-    );
+    return resolverVisitor
+        .analyzeRecordPatternSchema(
+          fields: resolverVisitor.buildSharedPatternFields(
+            fields,
+            mustBeNamed: false,
+          ),
+        )
+        .unwrapTypeSchemaView();
   }
 
   @override
@@ -14342,8 +14374,8 @@
       resolverVisitor.checkPatternNeverMatchesValueType(
         context: context,
         pattern: this,
-        requiredType: result.requiredType,
-        matchedValueType: result.matchedValueType,
+        requiredType: result.requiredType.unwrapTypeView(),
+        matchedValueType: result.matchedValueType.unwrapTypeView(),
       );
     }
     inferenceLogWriter?.exitPattern(this);
@@ -14750,7 +14782,9 @@
 
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
-    return resolverVisitor.analyzeRelationalPatternSchema();
+    return resolverVisitor
+        .analyzeRelationalPatternSchema()
+        .unwrapTypeSchemaView();
   }
 
   @override
@@ -16680,8 +16714,10 @@
     inferenceLogWriter?.enterExpression(this, contextType);
     var previousExhaustiveness = resolver.legacySwitchExhaustiveness;
     var staticType = resolver
-        .analyzeSwitchExpression(this, expression, cases.length, contextType)
-        .type;
+        .analyzeSwitchExpression(
+            this, expression, cases.length, SharedTypeSchemaView(contextType))
+        .type
+        .unwrapTypeView();
     recordStaticType(staticType, resolver: resolver);
     resolver.popRewrite();
     resolver.legacySwitchExhaustiveness = previousExhaustiveness;
@@ -18364,7 +18400,9 @@
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
     return resolverVisitor
-        .analyzeDeclaredVariablePatternSchema(type?.typeOrThrow);
+        .analyzeDeclaredVariablePatternSchema(
+            type?.typeOrThrow.wrapSharedTypeView())
+        .unwrapTypeSchemaView();
   }
 
   @override
@@ -18376,7 +18414,7 @@
     var analysisResult = resolverVisitor.analyzeWildcardPattern(
       context: context,
       node: this,
-      declaredType: declaredType,
+      declaredType: declaredType?.wrapSharedTypeView(),
     );
 
     if (declaredType != null) {
@@ -18384,7 +18422,7 @@
         context: context,
         pattern: this,
         requiredType: declaredType,
-        matchedValueType: analysisResult.matchedValueType,
+        matchedValueType: analysisResult.matchedValueType.unwrapTypeView(),
       );
     }
 
diff --git a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
index 969285a..54944dc 100644
--- a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
+++ b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
@@ -6,6 +6,7 @@
 
 import 'package:_fe_analyzer_shared/src/type_inference/shared_inference_log.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/type_constraint.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/ast/ast.dart'
     show
         Annotation,
@@ -64,7 +65,6 @@
       List<
           MergedTypeConstraint<
               DartType,
-              DartType,
               TypeParameterElement,
               PromotableElement,
               InterfaceType,
@@ -153,15 +153,10 @@
   void constrainArgument(
       DartType argumentType, DartType parameterType, String parameterName,
       {InterfaceElement? genericClass, required AstNode? nodeForTesting}) {
-    var origin = TypeConstraintFromArgument<
-        DartType,
-        DartType,
-        PromotableElement,
-        TypeParameterElement,
-        InterfaceType,
-        InterfaceElement>(
-      argumentType: argumentType,
-      parameterType: parameterType,
+    var origin = TypeConstraintFromArgument<DartType, PromotableElement,
+        TypeParameterElement, InterfaceType, InterfaceElement>(
+      argumentType: SharedTypeView(argumentType),
+      parameterType: SharedTypeView(parameterType),
       parameterName: parameterName,
       genericClassName: genericClass?.name,
       isGenericClassInDartCore: genericClass?.library.isDartCore ?? false,
@@ -201,6 +196,7 @@
     var origin = TypeConstraintFromFunctionContext<
         DartType,
         DartType,
+        DartType,
         PromotableElement,
         TypeParameterElement,
         InterfaceType,
@@ -230,6 +226,7 @@
     var origin = TypeConstraintFromReturnType<
         DartType,
         DartType,
+        DartType,
         PromotableElement,
         TypeParameterElement,
         InterfaceType,
@@ -254,8 +251,8 @@
       var constraints = _constraints[parameter]!;
 
       var inferred = inferredTypes[i];
-      bool success = constraints
-          .every((c) => c.isSatisfiedBy(inferred, _typeSystemOperations));
+      bool success = constraints.every((c) =>
+          c.isSatisfiedBy(SharedTypeView(inferred), _typeSystemOperations));
 
       // If everything else succeeded, check the `extends` constraint.
       if (success) {
@@ -266,19 +263,18 @@
                   .substituteType(parameterBoundRaw);
           var extendsConstraint = MergedTypeConstraint<
               DartType,
-              DartType,
               TypeParameterElement,
               PromotableElement,
               InterfaceType,
               InterfaceElement>.fromExtends(
             typeParameterName: parameter.name,
-            boundType: parameterBoundRaw,
-            extendsType: parameterBound,
+            boundType: SharedTypeView(parameterBoundRaw),
+            extendsType: SharedTypeView(parameterBound),
             typeAnalyzerOperations: _typeSystemOperations,
           );
           constraints.add(extendsConstraint);
-          success =
-              extendsConstraint.isSatisfiedBy(inferred, _typeSystemOperations);
+          success = extendsConstraint.isSatisfiedBy(
+              SharedTypeView(inferred), _typeSystemOperations);
         }
       }
 
@@ -444,7 +440,7 @@
   /// lower bound for normally covariant type parameters.
   DartType _chooseTypeFromConstraints(
       Iterable<
-              MergedTypeConstraint<DartType, DartType, TypeParameterElement,
+              MergedTypeConstraint<DartType, TypeParameterElement,
                   PromotableElement, InterfaceType, InterfaceElement>>
           constraints,
       {bool toKnownType = false,
@@ -465,8 +461,10 @@
       //
       // This resulting constraint may be unsatisfiable; in that case inference
       // will fail.
-      upper = _typeSystem.greatestLowerBound(upper, constraint.upper);
-      lower = _typeSystem.leastUpperBound(lower, constraint.lower);
+      upper = _typeSystem.greatestLowerBound(
+          upper, constraint.upper.unwrapTypeSchemaView());
+      lower = _typeSystem.leastUpperBound(
+          lower, constraint.lower.unwrapTypeSchemaView());
     }
 
     // Prefer the known bound, if any.
@@ -514,21 +512,17 @@
       // TODO(kallentu): : Clean up TypeParameterElementImpl casting once
       // variance is added to the interface.
       var typeParam = _typeFormals[i] as TypeParameterElementImpl;
-      MergedTypeConstraint<DartType, DartType, TypeParameterElement,
-          PromotableElement, InterfaceType, InterfaceElement>? extendsClause;
+      MergedTypeConstraint<DartType, TypeParameterElement, PromotableElement,
+          InterfaceType, InterfaceElement>? extendsClause;
       var bound = typeParam.bound;
       if (bound != null) {
-        extendsClause = MergedTypeConstraint<
-            DartType,
-            DartType,
-            TypeParameterElement,
-            PromotableElement,
-            InterfaceType,
-            InterfaceElement>.fromExtends(
+        extendsClause = MergedTypeConstraint<DartType, TypeParameterElement,
+            PromotableElement, InterfaceType, InterfaceElement>.fromExtends(
           typeParameterName: typeParam.name,
-          boundType: bound,
-          extendsType: Substitution.fromPairs(_typeFormals, inferredTypes)
-              .substituteType(bound),
+          boundType: SharedTypeView(bound),
+          extendsType: SharedTypeView(
+              Substitution.fromPairs(_typeFormals, inferredTypes)
+                  .substituteType(bound)),
           typeAnalyzerOperations: _typeSystemOperations,
         );
       }
@@ -570,22 +564,17 @@
       TypeParameterElement typeParam,
       DartType inferred,
       Iterable<
-              MergedTypeConstraint<DartType, DartType, TypeParameterElement,
+              MergedTypeConstraint<DartType, TypeParameterElement,
                   PromotableElement, InterfaceType, InterfaceElement>>
           constraints) {
     var inferredStr = inferred.getDisplayString();
     var intro = "Tried to infer '$inferredStr' for '${typeParam.name}'"
         " which doesn't work:";
 
-    var constraintsByOrigin = <TypeConstraintOrigin<
-            DartType,
-            DartType,
-            PromotableElement,
-            TypeParameterElement,
-            InterfaceType,
-            InterfaceElement>,
+    var constraintsByOrigin = <TypeConstraintOrigin<DartType, PromotableElement,
+            TypeParameterElement, InterfaceType, InterfaceElement>,
         List<
-            MergedTypeConstraint<DartType, DartType, TypeParameterElement,
+            MergedTypeConstraint<DartType, TypeParameterElement,
                 PromotableElement, InterfaceType, InterfaceElement>>>{};
     for (var c in constraints) {
       constraintsByOrigin.putIfAbsent(c.origin, () => []).add(c);
@@ -593,18 +582,14 @@
 
     // Only report unique constraint origins.
     Iterable<
-        MergedTypeConstraint<
-            DartType,
-            DartType,
-            TypeParameterElement,
-            PromotableElement,
-            InterfaceType,
-            InterfaceElement>> isSatisfied(bool expected) => constraintsByOrigin
-        .values
-        .where((l) =>
-            l.every((c) => c.isSatisfiedBy(inferred, _typeSystemOperations)) ==
-            expected)
-        .flattenedToList;
+        MergedTypeConstraint<DartType, TypeParameterElement, PromotableElement,
+            InterfaceType, InterfaceElement>> isSatisfied(bool expected) =>
+        constraintsByOrigin.values
+            .where((l) =>
+                l.every((c) => c.isSatisfiedBy(
+                    SharedTypeView(inferred), _typeSystemOperations)) ==
+                expected)
+            .flattenedToList;
 
     String unsatisfied =
         _formatConstraints(isSatisfied(false), _typeSystemOperations);
@@ -622,11 +607,11 @@
 
   DartType _inferTypeParameterFromAll(
       List<
-              MergedTypeConstraint<DartType, DartType, TypeParameterElement,
+              MergedTypeConstraint<DartType, TypeParameterElement,
                   PromotableElement, InterfaceType, InterfaceElement>>
           constraints,
-      MergedTypeConstraint<DartType, DartType, TypeParameterElement,
-              PromotableElement, InterfaceType, InterfaceElement>?
+      MergedTypeConstraint<DartType, TypeParameterElement, PromotableElement,
+              InterfaceType, InterfaceElement>?
           extendsClause,
       {required bool isContravariant}) {
     if (extendsClause != null) {
@@ -640,11 +625,11 @@
 
   DartType _inferTypeParameterFromContext(
       Iterable<
-              MergedTypeConstraint<DartType, DartType, TypeParameterElement,
+              MergedTypeConstraint<DartType, TypeParameterElement,
                   PromotableElement, InterfaceType, InterfaceElement>>
           constraints,
-      MergedTypeConstraint<DartType, DartType, TypeParameterElement,
-              PromotableElement, InterfaceType, InterfaceElement>?
+      MergedTypeConstraint<DartType, TypeParameterElement, PromotableElement,
+              InterfaceType, InterfaceElement>?
           extendsClause,
       {required bool isContravariant}) {
     DartType t = _chooseTypeFromConstraints(constraints,
@@ -757,8 +742,8 @@
   bool _tryMatchSubtypeOf(
       DartType t1,
       DartType t2,
-      TypeConstraintOrigin<DartType, DartType, PromotableElement,
-              TypeParameterElement, InterfaceType, InterfaceElement>
+      TypeConstraintOrigin<DartType, PromotableElement, TypeParameterElement,
+              InterfaceType, InterfaceElement>
           origin,
       {required bool covariant,
       required AstNode? nodeForTesting}) {
@@ -790,14 +775,13 @@
 
   static String _formatConstraints(
       Iterable<
-              MergedTypeConstraint<DartType, DartType, TypeParameterElement,
+              MergedTypeConstraint<DartType, TypeParameterElement,
                   PromotableElement, InterfaceType, InterfaceElement>>
           constraints,
       TypeSystemOperations typeSystemOperations) {
     List<List<String>> lineParts = Set<
             TypeConstraintOrigin<
                 DartType,
-                DartType,
                 PromotableElement,
                 TypeParameterElement,
                 InterfaceType,
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 76f359b..7c2f2d1 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -32,7 +32,7 @@
 
 /// The [Type] representing the type `dynamic`.
 class DynamicTypeImpl extends TypeImpl
-    implements DynamicType, SharedDynamicType<DartType> {
+    implements DynamicType, SharedDynamicTypeStructure<DartType> {
   /// The unique instance of this class.
   static final DynamicTypeImpl instance = DynamicTypeImpl._();
 
@@ -936,7 +936,7 @@
 }
 
 class InvalidTypeImpl extends TypeImpl
-    implements InvalidType, SharedInvalidType<DartType> {
+    implements InvalidType, SharedInvalidTypeStructure<DartType> {
   /// The unique instance of this class.
   static final InvalidTypeImpl instance = InvalidTypeImpl._();
 
@@ -1132,7 +1132,7 @@
   String? get name => null;
 
   @override
-  List<SharedNamedType<DartType>> get namedTypes => namedFields;
+  List<SharedNamedTypeStructure<DartType>> get namedTypes => namedFields;
 
   @override
   bool operator ==(Object other) {
@@ -1355,7 +1355,7 @@
   }
 
   @override
-  bool isStructurallyEqualTo(SharedType other) => this == other;
+  bool isStructurallyEqualTo(SharedTypeStructure other) => this == other;
 
   /// Returns true if this type references any of the [parameters].
   bool referencesAny(Set<TypeParameterElement> parameters) {
@@ -1550,7 +1550,7 @@
 
 /// A concrete implementation of a [VoidType].
 class VoidTypeImpl extends TypeImpl
-    implements VoidType, SharedVoidType<DartType> {
+    implements VoidType, SharedVoidTypeStructure<DartType> {
   /// 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 88b4c83..0337427 100644
--- a/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
@@ -25,9 +25,8 @@
 /// Creates sets of [TypeConstraint]s for type parameters, based on an attempt
 /// to make one type schema a subtype of another.
 class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
+    DartType,
     PromotableElement,
-    DartType,
-    DartType,
     TypeParameterElement,
     InterfaceType,
     InterfaceElement,
@@ -35,7 +34,7 @@
   final TypeSystemImpl _typeSystem;
   final Set<TypeParameterElement> _typeParameters = Set.identity();
   final List<
-      GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
+      GeneratedTypeConstraint<DartType, TypeParameterElement,
           PromotableElement>> _constraints = [];
   final TypeSystemOperations _typeSystemOperations;
   final TypeConstraintGenerationDataForTesting? dataForTesting;
@@ -66,26 +65,16 @@
   /// Returns the set of type constraints that was gathered.
   Map<
       TypeParameterElement,
-      MergedTypeConstraint<
-          DartType,
-          DartType,
-          TypeParameterElement,
-          PromotableElement,
-          InterfaceType,
-          InterfaceElement>> computeConstraints() {
+      MergedTypeConstraint<DartType, TypeParameterElement, PromotableElement,
+          InterfaceType, InterfaceElement>> computeConstraints() {
     var result = <TypeParameterElement,
-        MergedTypeConstraint<DartType, DartType, TypeParameterElement,
-            PromotableElement, InterfaceType, InterfaceElement>>{};
+        MergedTypeConstraint<DartType, TypeParameterElement, PromotableElement,
+            InterfaceType, InterfaceElement>>{};
     for (var parameter in _typeParameters) {
-      result[parameter] = MergedTypeConstraint<
-          DartType,
-          DartType,
-          TypeParameterElement,
-          PromotableElement,
-          InterfaceType,
-          InterfaceElement>(
-        lower: UnknownInferredType.instance,
-        upper: UnknownInferredType.instance,
+      result[parameter] = MergedTypeConstraint<DartType, TypeParameterElement,
+          PromotableElement, InterfaceType, InterfaceElement>(
+        lower: SharedTypeSchemaView(UnknownInferredType.instance),
+        upper: SharedTypeSchemaView(UnknownInferredType.instance),
         origin: const UnknownTypeConstraintOrigin(),
       );
     }
@@ -101,16 +90,20 @@
   }
 
   @override
-  bool performSubtypeConstraintGenerationLeftSchema(DartType p, DartType q,
+  bool performSubtypeConstraintGenerationLeftSchema(
+      SharedTypeSchemaView<DartType> p, SharedTypeView<DartType> q,
       {required AstNode? astNodeForTesting}) {
-    return trySubtypeMatch(p, q, /* leftSchema */ true,
+    return trySubtypeMatch(
+        p.unwrapTypeSchemaView(), q.unwrapTypeView(), /* leftSchema */ true,
         nodeForTesting: astNodeForTesting);
   }
 
   @override
-  bool performSubtypeConstraintGenerationRightSchema(DartType p, DartType q,
+  bool performSubtypeConstraintGenerationRightSchema(
+      SharedTypeView<DartType> p, SharedTypeSchemaView<DartType> q,
       {required AstNode? astNodeForTesting}) {
-    return trySubtypeMatch(p, q, /* leftSchema */ false,
+    return trySubtypeMatch(
+        p.unwrapTypeView(), q.unwrapTypeSchemaView(), /* leftSchema */ false,
         nodeForTesting: astNodeForTesting);
   }
 
@@ -127,19 +120,20 @@
   bool trySubtypeMatch(DartType P, DartType Q, bool leftSchema,
       {required AstNode? nodeForTesting}) {
     // If `P` is `_` then the match holds with no constraints.
-    if (P is SharedUnknownType) {
+    if (P is SharedUnknownTypeStructure) {
       return true;
     }
 
     // If `Q` is `_` then the match holds with no constraints.
-    if (Q is SharedUnknownType) {
+    if (Q is SharedUnknownTypeStructure) {
       return true;
     }
 
     // If `P` is a type variable `X` in `L`, then the match holds:
     //   Under constraint `_ <: X <: Q`.
     var P_nullability = P.nullabilitySuffix;
-    if (_typeSystemOperations.matchInferableParameter(P) case var P_element?
+    if (_typeSystemOperations.matchInferableParameter(SharedTypeView(P))
+        case var P_element?
         when P_nullability == NullabilitySuffix.none &&
             _typeParameters.contains(P_element)) {
       _addUpper(P_element, Q, nodeForTesting: nodeForTesting);
@@ -149,7 +143,8 @@
     // If `Q` is a type variable `X` in `L`, then the match holds:
     //   Under constraint `P <: X <: _`.
     var Q_nullability = Q.nullabilitySuffix;
-    if (_typeSystemOperations.matchInferableParameter(Q) case var Q_element?
+    if (_typeSystemOperations.matchInferableParameter(SharedTypeView(Q))
+        case var Q_element?
         when Q_nullability == NullabilitySuffix.none &&
             _typeParameters.contains(Q_element)) {
       _addLower(Q_element, P, nodeForTesting: nodeForTesting);
@@ -167,24 +162,28 @@
     // [performSubtypeConstraintGenerationForFutureOr] handles the rewinding of
     // the state itself.
     if (leftSchema
-        ? performSubtypeConstraintGenerationForFutureOrLeftSchema(P, Q,
+        ? performSubtypeConstraintGenerationForFutureOrLeftSchema(
+            SharedTypeSchemaView(P), SharedTypeView(Q),
             astNodeForTesting: nodeForTesting)
-        : performSubtypeConstraintGenerationForFutureOrRightSchema(P, Q,
+        : performSubtypeConstraintGenerationForFutureOrRightSchema(
+            SharedTypeView(P), SharedTypeSchemaView(Q),
             astNodeForTesting: nodeForTesting)) {
       return true;
     }
 
     // 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 = _typeSystemOperations
+          .withNullabilitySuffix(SharedTypeView(Q), NullabilitySuffix.none)
+          .unwrapTypeView();
       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 = _typeSystemOperations
+            .withNullabilitySuffix(SharedTypeView(P), NullabilitySuffix.none)
+            .unwrapTypeView();
         if (trySubtypeMatch(P0, Q0, leftSchema,
             nodeForTesting: nodeForTesting)) {
           return true;
@@ -194,7 +193,7 @@
 
       // Or if `P` is `dynamic` or `void` and `Object` is a subtype match
       // for `Q0` under constraint set `C`.
-      if (P is SharedDynamicType || P is SharedVoidType) {
+      if (P is SharedDynamicTypeStructure || P is SharedVoidTypeStructure) {
         if (trySubtypeMatch(_typeSystem.objectNone, Q0, leftSchema,
             nodeForTesting: nodeForTesting)) {
           return true;
@@ -226,13 +225,13 @@
     }
 
     // If `P` is `FutureOr<P0>` the match holds under constraint set `C1 + C2`:
-    if (_typeSystemOperations.matchFutureOr(P) case var P0?
+    if (_typeSystemOperations.matchFutureOrInternal(P) case var P0?
         when P_nullability == NullabilitySuffix.none) {
       var rewind = _constraints.length;
 
       // 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`.
-      var future_P0 = _typeSystemOperations.futureType(P0);
+      var future_P0 = _typeSystemOperations.futureTypeInternal(P0);
       if (trySubtypeMatch(future_P0, Q, leftSchema,
               nodeForTesting: nodeForTesting) &&
           trySubtypeMatch(P0, Q, leftSchema, nodeForTesting: nodeForTesting)) {
@@ -244,8 +243,9 @@
 
     // 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 = _typeSystemOperations
+          .withNullabilitySuffix(SharedTypeView(P), NullabilitySuffix.none)
+          .unwrapTypeView();
       var rewind = _constraints.length;
 
       // If `P0` is a subtype match for `Q` under constraint set `C1`.
@@ -261,27 +261,27 @@
 
     // If `Q` is `dynamic`, `Object?`, or `void` then the match holds under
     // no constraints.
-    if (Q is SharedDynamicType ||
-        Q is SharedVoidType ||
-        Q == _typeSystemOperations.objectQuestionType) {
+    if (Q is SharedDynamicTypeStructure ||
+        Q is SharedVoidTypeStructure ||
+        Q == _typeSystemOperations.objectQuestionType.unwrapTypeView()) {
       return true;
     }
 
     // If `P` is `Never` then the match holds under no constraints.
-    if (_typeSystemOperations.isNever(P)) {
+    if (_typeSystemOperations.isNever(SharedTypeView(P))) {
       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 == _typeSystemOperations.objectType.unwrapTypeView()) {
       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)) {
+        _typeSystemOperations.isNull(SharedTypeView(P))) {
       return _typeSystem.isNullable(Q);
     }
 
@@ -300,8 +300,8 @@
     }
 
     switch ((
-      _typeSystemOperations.matchTypeDeclarationType(P),
-      _typeSystemOperations.matchTypeDeclarationType(Q)
+      _typeSystemOperations.matchTypeDeclarationType(SharedTypeView(P)),
+      _typeSystemOperations.matchTypeDeclarationType(SharedTypeView(Q))
     )) {
       // If `P` is `C<M0, ..., Mk> and `Q` is `C<N0, ..., Nk>`, then the match
       // holds under constraints `C0 + ... + Ck`:
@@ -349,14 +349,14 @@
 
     // If `Q` is `Function` then the match holds under no constraints:
     //   If `P` is a function type.
-    if (_typeSystemOperations.isDartCoreFunction(Q)) {
-      if (_typeSystemOperations.isFunctionType(P)) {
+    if (_typeSystemOperations.isDartCoreFunction(SharedTypeView(Q))) {
+      if (_typeSystemOperations.isFunctionType(SharedTypeView(P))) {
         return true;
       }
     }
 
-    if (_typeSystemOperations.isFunctionType(P) &&
-        _typeSystemOperations.isFunctionType(Q)) {
+    if (_typeSystemOperations.isFunctionType(SharedTypeView(P)) &&
+        _typeSystemOperations.isFunctionType(SharedTypeView(Q))) {
       return _functionType(P as FunctionType, Q as FunctionType, leftSchema,
           nodeForTesting: nodeForTesting);
     }
@@ -365,12 +365,13 @@
     // constraints:
     //   If `P` is a record type or `Record`.
     if (Q_nullability == NullabilitySuffix.none && Q.isDartCoreRecord) {
-      if (P is SharedRecordType<DartType>) {
+      if (P is SharedRecordTypeStructure<DartType>) {
         return true;
       }
     }
 
-    if (P is SharedRecordType<DartType> && Q is SharedRecordType<DartType>) {
+    if (P is SharedRecordTypeStructure<DartType> &&
+        Q is SharedRecordTypeStructure<DartType>) {
       return _recordType(P as RecordTypeImpl, Q as RecordTypeImpl, leftSchema,
           nodeForTesting: nodeForTesting);
     }
@@ -380,10 +381,11 @@
 
   void _addLower(TypeParameterElement element, DartType lower,
       {required AstNode? nodeForTesting}) {
-    GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
-            PromotableElement> generatedTypeConstraint =
-        GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
-            PromotableElement>.lower(element, lower);
+    GeneratedTypeConstraint<DartType, TypeParameterElement, PromotableElement>
+        generatedTypeConstraint = GeneratedTypeConstraint<
+            DartType,
+            TypeParameterElement,
+            PromotableElement>.lower(element, SharedTypeSchemaView(lower));
     _constraints.add(generatedTypeConstraint);
     if (dataForTesting != null && nodeForTesting != null) {
       (dataForTesting!.generatedTypeConstraints[nodeForTesting] ??= [])
@@ -393,10 +395,11 @@
 
   void _addUpper(TypeParameterElement element, DartType upper,
       {required AstNode? nodeForTesting}) {
-    GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
-            PromotableElement> generatedTypeConstraint =
-        GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
-            PromotableElement>.upper(element, upper);
+    GeneratedTypeConstraint<DartType, TypeParameterElement, PromotableElement>
+        generatedTypeConstraint = GeneratedTypeConstraint<
+            DartType,
+            TypeParameterElement,
+            PromotableElement>.upper(element, SharedTypeSchemaView(upper));
     _constraints.add(generatedTypeConstraint);
     if (dataForTesting != null && nodeForTesting != null) {
       (dataForTesting!.generatedTypeConstraints[nodeForTesting] ??= [])
@@ -725,7 +728,7 @@
   final Map<
       AstNode,
       List<
-          GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
+          GeneratedTypeConstraint<DartType, TypeParameterElement,
               PromotableElement>>> generatedTypeConstraints = {};
 
   /// Merges [other] into the receiver, combining the constraints.
@@ -737,7 +740,7 @@
   void mergeIn(TypeConstraintGenerationDataForTesting other) {
     for (AstNode node in other.generatedTypeConstraints.keys) {
       List<
-          GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
+          GeneratedTypeConstraint<DartType, TypeParameterElement,
               PromotableElement>>? constraints = generatedTypeConstraints[node];
       if (constraints != null) {
         constraints.addAll(other.generatedTypeConstraints[node]!);
diff --git a/pkg/analyzer/lib/src/dart/element/type_schema.dart b/pkg/analyzer/lib/src/dart/element/type_schema.dart
index 711910c..47f97fb 100644
--- a/pkg/analyzer/lib/src/dart/element/type_schema.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_schema.dart
@@ -19,7 +19,7 @@
 /// example `List<_>`. This is distinct from `List<dynamic>`. These types will
 /// never appear in the final resolved AST.
 class UnknownInferredType extends TypeImpl
-    implements SharedUnknownType<DartType> {
+    implements SharedUnknownTypeStructure<DartType> {
   static const UnknownInferredType instance = UnknownInferredType._();
 
   const UnknownInferredType._();
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index 64a30e5..0c93d46 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -89,10 +90,10 @@
 
     var flow = _resolver.flowAnalysis.flow;
     if (flow != null && isIfNull) {
-      flow.ifNullExpression_rightBegin(left, node.readType!);
+      flow.ifNullExpression_rightBegin(left, SharedTypeView(node.readType!));
     }
 
-    _resolver.analyzeExpression(right, rhsContext);
+    _resolver.analyzeExpression(right, SharedTypeSchemaView(rhsContext));
     right = _resolver.popRewrite()!;
     var whyNotPromoted = flow?.whyNotPromoted(right);
 
@@ -101,8 +102,8 @@
 
     if (flow != null) {
       if (writeElement is PromotableElement) {
-        flow.write(
-            node, writeElement, node.typeOrThrow, hasRead ? null : right);
+        flow.write(node, writeElement, SharedTypeView(node.typeOrThrow),
+            hasRead ? null : right);
       }
       if (isIfNull) {
         flow.ifNullExpression_end();
@@ -116,7 +117,8 @@
     DartType writeType,
     Expression right,
     DartType rightType, {
-    required Map<DartType, NonPromotionReason> Function()? whyNotPromoted,
+    required Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+        whyNotPromoted,
   }) {
     if (writeType is! VoidType && _checkForUseOfVoidResult(right)) {
       return;
@@ -254,7 +256,8 @@
   }
 
   void _resolveTypes(AssignmentExpressionImpl node,
-      {required Map<DartType, NonPromotionReason> Function()? whyNotPromoted,
+      {required Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted,
       required DartType contextType}) {
     DartType assignedType;
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index 67d7656..f51627a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/ast/token.dart';
@@ -78,7 +79,8 @@
   }
 
   void _checkNonBoolOperand(Expression operand, String operator,
-      {required Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
+      {required Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted}) {
     _resolver.boolExpressionVerifier.checkForNonBoolExpression(
       operand,
       errorCode: CompileTimeErrorCode.NON_BOOL_OPERAND,
@@ -88,25 +90,27 @@
   }
 
   void _resolveEqual(BinaryExpressionImpl node, {required bool notEqual}) {
-    _resolver.analyzeExpression(node.leftOperand, UnknownInferredType.instance);
+    _resolver.analyzeExpression(
+        node.leftOperand, SharedTypeSchemaView(UnknownInferredType.instance));
     var left = _resolver.popRewrite()!;
 
     var flowAnalysis = _resolver.flowAnalysis;
     var flow = flowAnalysis.flow;
-    ExpressionInfo<DartType>? leftInfo;
+    ExpressionInfo<SharedTypeView<DartType>>? leftInfo;
     var leftExtensionOverride = left is ExtensionOverride;
     if (!leftExtensionOverride) {
-      leftInfo = flow?.equalityOperand_end(left, left.typeOrThrow);
+      leftInfo =
+          flow?.equalityOperand_end(left, SharedTypeView(left.typeOrThrow));
     }
 
     _resolver.analyzeExpression(
-        node.rightOperand, UnknownInferredType.instance);
+        node.rightOperand, SharedTypeSchemaView(UnknownInferredType.instance));
     var right = _resolver.popRewrite()!;
     var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(right);
 
     if (!leftExtensionOverride) {
-      flow?.equalityOperation_end(
-          node, leftInfo, flow.equalityOperand_end(right, right.typeOrThrow),
+      flow?.equalityOperation_end(node, leftInfo,
+          flow.equalityOperand_end(right, SharedTypeView(right.typeOrThrow)),
           notEqual: notEqual);
     }
 
@@ -156,7 +160,8 @@
     // analyzed as follows:
     //
     // - Let `T1` be the type of `e1` inferred with context type `K?`.
-    _resolver.analyzeExpression(left, _typeSystem.makeNullable(contextType));
+    _resolver.analyzeExpression(
+        left, SharedTypeSchemaView(_typeSystem.makeNullable(contextType)));
     left = _resolver.popRewrite()!;
     var t1 = left.typeOrThrow;
 
@@ -172,8 +177,8 @@
     {
       j = contextType;
     }
-    flow?.ifNullExpression_rightBegin(left, t1);
-    _resolver.analyzeExpression(right, j);
+    flow?.ifNullExpression_rightBegin(left, SharedTypeView(t1));
+    _resolver.analyzeExpression(right, SharedTypeSchemaView(j));
     right = _resolver.popRewrite()!;
     flow?.ifNullExpression_end();
     var t2 = right.typeOrThrow;
@@ -217,14 +222,16 @@
     var flow = _resolver.flowAnalysis.flow;
 
     flow?.logicalBinaryOp_begin();
-    _resolver.analyzeExpression(left, _typeProvider.boolType);
+    _resolver.analyzeExpression(
+        left, SharedTypeSchemaView(_typeProvider.boolType));
     left = _resolver.popRewrite()!;
     var leftWhyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(left);
 
     flow?.logicalBinaryOp_rightBegin(left, node, isAnd: true);
     _resolver.checkUnreachableNode(right);
 
-    _resolver.analyzeExpression(right, _typeProvider.boolType);
+    _resolver.analyzeExpression(
+        right, SharedTypeSchemaView(_typeProvider.boolType));
     right = _resolver.popRewrite()!;
     var rightWhyNotPromoted =
         _resolver.flowAnalysis.flow?.whyNotPromoted(right);
@@ -244,14 +251,16 @@
     var flow = _resolver.flowAnalysis.flow;
 
     flow?.logicalBinaryOp_begin();
-    _resolver.analyzeExpression(left, _typeProvider.boolType);
+    _resolver.analyzeExpression(
+        left, SharedTypeSchemaView(_typeProvider.boolType));
     left = _resolver.popRewrite()!;
     var leftWhyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(left);
 
     flow?.logicalBinaryOp_rightBegin(left, node, isAnd: false);
     _resolver.checkUnreachableNode(right);
 
-    _resolver.analyzeExpression(right, _typeProvider.boolType);
+    _resolver.analyzeExpression(
+        right, SharedTypeSchemaView(_typeProvider.boolType));
     right = _resolver.popRewrite()!;
     var rightWhyNotPromoted =
         _resolver.flowAnalysis.flow?.whyNotPromoted(right);
@@ -283,7 +292,8 @@
       rightContextType = UnknownInferredType.instance;
     }
 
-    _resolver.analyzeExpression(node.rightOperand, rightContextType);
+    _resolver.analyzeExpression(
+        node.rightOperand, SharedTypeSchemaView(rightContextType));
     var right = _resolver.popRewrite()!;
     var whyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(right);
 
@@ -311,14 +321,15 @@
       return;
     }
 
-    _resolver.analyzeExpression(node.leftOperand, UnknownInferredType.instance);
+    _resolver.analyzeExpression(
+        node.leftOperand, SharedTypeSchemaView(UnknownInferredType.instance));
     left = _resolver.popRewrite()!;
 
     if (left is SuperExpressionImpl) {
       if (SuperContext.of(left) != SuperContext.valid) {
         _resolver.analyzeExpression(
           node.rightOperand,
-          InvalidTypeImpl.instance,
+          SharedTypeSchemaView(InvalidTypeImpl.instance),
         );
         _resolver.popRewrite();
         node.recordStaticType(InvalidTypeImpl.instance, resolver: _resolver);
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 16fd38d..210a986 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -6,6 +6,7 @@
 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/type_analyzer_operations.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/ast/token.dart';
@@ -87,8 +88,8 @@
   final bool fieldPromotionEnabled;
 
   /// The current flow, when resolving a function body, or `null` otherwise.
-  FlowAnalysis<AstNode, Statement, Expression, PromotableElement, DartType>?
-      flow;
+  FlowAnalysis<AstNode, Statement, Expression, PromotableElement,
+      SharedTypeView<DartType>>? flow;
 
   FlowAnalysisHelper(bool retainDataForTesting, FeatureSet featureSet,
       {required TypeSystemOperations typeSystemOperations})
@@ -115,14 +116,16 @@
     var expression = node.expression;
     var typeAnnotation = node.type;
 
-    flow!.asExpression_end(expression, typeAnnotation.typeOrThrow);
+    flow!.asExpression_end(
+        expression, SharedTypeView(typeAnnotation.typeOrThrow));
   }
 
   void assignmentExpression(AssignmentExpression node) {
     if (flow == null) return;
 
     if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
-      flow!.ifNullExpression_rightBegin(node.leftHandSide, node.readType!);
+      flow!.ifNullExpression_rightBegin(
+          node.leftHandSide, SharedTypeView(node.readType!));
     }
   }
 
@@ -168,7 +171,7 @@
         var declaredElement = parameter.declaredElement!;
         // TODO(paulberry): `skipDuplicateCheck` is currently needed to work
         // around a failure in duplicate_definition_test.dart; fix this.
-        flow!.declare(declaredElement, declaredElement.type,
+        flow!.declare(declaredElement, SharedTypeView(declaredElement.type),
             initialized: true, skipDuplicateCheck: true);
       }
     }
@@ -231,7 +234,7 @@
       node,
       expression,
       node.notOperator != null,
-      typeAnnotation.typeOrThrow,
+      SharedTypeView(typeAnnotation.typeOrThrow),
     );
   }
 
@@ -258,12 +261,13 @@
     }
     flow = isNonNullableByDefault
         ? FlowAnalysis<AstNode, Statement, Expression, PromotableElement,
-                DartType>(typeOperations, assignedVariables!,
+                SharedTypeView<DartType>>(typeOperations, assignedVariables!,
             respectImplicitlyTypedVarInitializers:
                 respectImplicitlyTypedVarInitializers,
             fieldPromotionEnabled: fieldPromotionEnabled)
         : FlowAnalysis<AstNode, Statement, Expression, PromotableElement,
-            DartType>.legacy(typeOperations, assignedVariables!);
+                SharedTypeView<DartType>>.legacy(
+            typeOperations, assignedVariables!);
   }
 
   void topLevelDeclaration_exit() {
@@ -296,7 +300,7 @@
       for (var i = 0; i < variables.length; ++i) {
         var variable = variables[i];
         var declaredElement = variable.declaredElement as PromotableElement;
-        flow!.declare(declaredElement, declaredElement.type,
+        flow!.declare(declaredElement, SharedTypeView(declaredElement.type),
             initialized: variable.initializer != null);
       }
     }
@@ -377,8 +381,11 @@
 }
 
 class TypeSystemOperations
+    with
+        TypeAnalyzerOperationsMixin<DartType, PromotableElement,
+            TypeParameterElement, InterfaceType, InterfaceElement>
     implements
-        TypeAnalyzerOperations<PromotableElement, DartType, DartType,
+        TypeAnalyzerOperations<DartType, PromotableElement,
             TypeParameterElement, InterfaceType, InterfaceElement> {
   final bool strictCasts;
   final TypeSystemImpl typeSystem;
@@ -386,40 +393,62 @@
   TypeSystemOperations(this.typeSystem, {required this.strictCasts});
 
   @override
-  DartType get boolType => typeSystem.typeProvider.boolType;
+  SharedTypeView<DartType> get boolType {
+    return SharedTypeView(typeSystem.typeProvider.boolType);
+  }
 
   @override
-  DartType get doubleType => throw UnimplementedError('TODO(paulberry)');
+  SharedTypeView<DartType> get doubleType {
+    throw UnimplementedError('TODO(paulberry)');
+  }
 
   @override
-  DartType get dynamicType => typeSystem.typeProvider.dynamicType;
+  SharedTypeView<DartType> get dynamicType {
+    return SharedTypeView(typeSystem.typeProvider.dynamicType);
+  }
 
   @override
-  DartType get errorType => InvalidTypeImpl.instance;
+  SharedTypeView<DartType> get errorType {
+    return SharedTypeView(InvalidTypeImpl.instance);
+  }
 
   @override
-  DartType get intType => throw UnimplementedError('TODO(paulberry)');
+  SharedTypeView<DartType> get intType {
+    throw UnimplementedError('TODO(paulberry)');
+  }
 
   @override
-  DartType get neverType => typeSystem.typeProvider.neverType;
+  SharedTypeView<DartType> get neverType {
+    return SharedTypeView(typeSystem.typeProvider.neverType);
+  }
 
   @override
-  DartType get nullType => typeSystem.typeProvider.nullType;
+  SharedTypeView<DartType> get nullType {
+    return SharedTypeView(typeSystem.typeProvider.nullType);
+  }
 
   @override
-  DartType get objectQuestionType => typeSystem.objectQuestion;
+  SharedTypeView<DartType> get objectQuestionType {
+    return SharedTypeView(typeSystem.objectQuestion);
+  }
 
   @override
-  DartType get objectType => typeSystem.objectNone;
+  SharedTypeView<DartType> get objectType {
+    return SharedTypeView(typeSystem.objectNone);
+  }
 
   @override
-  DartType get unknownType => UnknownInferredType.instance;
+  SharedTypeSchemaView<DartType> get unknownType {
+    return SharedTypeSchemaView(UnknownInferredType.instance);
+  }
 
   @override
-  TypeClassification classifyType(DartType type) {
-    if (isSubtypeOf(type, typeSystem.typeProvider.objectType)) {
+  TypeClassification classifyType(SharedTypeView<DartType> type) {
+    DartType unwrapped = type.unwrapTypeView();
+    if (isSubtypeOfInternal(unwrapped, typeSystem.typeProvider.objectType)) {
       return TypeClassification.nonNullable;
-    } else if (isSubtypeOf(type, typeSystem.typeProvider.nullType)) {
+    } else if (isSubtypeOfInternal(
+        unwrapped, typeSystem.typeProvider.nullType)) {
       return TypeClassification.nullOrEquivalent;
     } else {
       return TypeClassification.potentiallyNullable;
@@ -427,30 +456,27 @@
   }
 
   @override
-  DartType extensionTypeErasure(DartType type) {
-    return type.extensionTypeErasure;
+  SharedTypeView<DartType> extensionTypeErasure(SharedTypeView<DartType> type) {
+    return SharedTypeView(type.unwrapTypeView().extensionTypeErasure);
   }
 
   @override
-  DartType factor(DartType from, DartType what) {
-    return typeSystem.factor(from, what);
+  SharedTypeView<DartType> factor(
+      SharedTypeView<DartType> from, SharedTypeView<DartType> what) {
+    return SharedTypeView(
+        typeSystem.factor(from.unwrapTypeView(), what.unwrapTypeView()));
   }
 
   @override
-  DartType futureType(DartType argumentType) {
+  DartType futureTypeInternal(DartType argumentType) {
     return typeSystem.typeProvider.futureType(argumentType);
   }
 
   @override
-  DartType futureTypeSchema(DartType argumentTypeSchema) {
-    return typeSystem.typeProvider.futureType(argumentTypeSchema);
-  }
-
-  @override
-  TypeDeclarationKind? getTypeDeclarationKind(DartType type) {
-    if (isInterfaceType(type)) {
+  TypeDeclarationKind? getTypeDeclarationKindInternal(DartType type) {
+    if (isInterfaceType(SharedTypeView(type))) {
       return TypeDeclarationKind.interfaceDeclaration;
-    } else if (isExtensionType(type)) {
+    } else if (isExtensionType(SharedTypeView(type))) {
       return TypeDeclarationKind.extensionTypeDeclaration;
     } else {
       return null;
@@ -466,72 +492,75 @@
   }
 
   @override
-  TypeDeclarationKind? getTypeSchemaDeclarationKind(DartType typeSchema) {
-    return getTypeDeclarationKind(typeSchema);
-  }
-
-  @override
-  DartType glb(DartType type1, DartType type2) {
+  DartType glbInternal(DartType type1, DartType type2) {
     return typeSystem.greatestLowerBound(type1, type2);
   }
 
   @override
-  DartType greatestClosure(DartType schema) =>
-      typeSystem.greatestClosureOfSchema(schema);
-
-  @override
-  bool isAlwaysExhaustiveType(DartType type) {
-    return typeSystem.isAlwaysExhaustive(type);
+  SharedTypeView<DartType> greatestClosure(
+      SharedTypeSchemaView<DartType> schema) {
+    return SharedTypeView(
+        typeSystem.greatestClosureOfSchema(schema.unwrapTypeSchemaView()));
   }
 
   @override
-  bool isAssignableTo(DartType fromType, DartType toType) {
-    return typeSystem.isAssignableTo(fromType, toType,
+  bool isAlwaysExhaustiveType(SharedTypeView<DartType> type) {
+    return typeSystem.isAlwaysExhaustive(type.unwrapTypeView());
+  }
+
+  @override
+  bool isAssignableTo(
+      SharedTypeView<DartType> fromType, SharedTypeView<DartType> toType) {
+    return typeSystem.isAssignableTo(
+        fromType.unwrapTypeView(), toType.unwrapTypeView(),
         strictCasts: strictCasts);
   }
 
   @override
-  bool isDartCoreFunction(DartType type) {
+  bool isDartCoreFunction(SharedTypeView<DartType> type) {
     return type.nullabilitySuffix == NullabilitySuffix.none &&
-        type.isDartCoreFunction;
+        type.unwrapTypeView().isDartCoreFunction;
   }
 
   @override
-  bool isExtensionType(DartType type) {
-    return type is InterfaceType && type.element is ExtensionTypeElement;
+  bool isExtensionType(SharedTypeView<DartType> type) {
+    DartType unwrappedType = type.unwrapTypeView();
+    return unwrappedType is InterfaceType &&
+        unwrappedType.element is ExtensionTypeElement;
   }
 
   @override
-  bool isFunctionType(DartType type) {
-    return type is FunctionType;
+  bool isFunctionType(SharedTypeView<DartType> type) {
+    return type.unwrapTypeView() is FunctionType;
   }
 
   @override
-  bool isInterfaceType(DartType type) {
-    return type is InterfaceType &&
-        !type.isDartCoreNull &&
-        !type.isDartAsyncFutureOr &&
-        type.element is! ExtensionTypeElement;
+  bool isInterfaceType(SharedTypeView<DartType> type) {
+    DartType unwrappedType = type.unwrapTypeView();
+    return unwrappedType is InterfaceType &&
+        !unwrappedType.isDartCoreNull &&
+        !unwrappedType.isDartAsyncFutureOr &&
+        unwrappedType.element is! ExtensionTypeElement;
   }
 
   @override
-  bool isNever(DartType type) {
-    return type.isBottom;
+  bool isNever(SharedTypeView<DartType> type) {
+    return type.unwrapTypeView().isBottom;
   }
 
   @override
-  bool isNonNullable(DartType typeSchema) {
-    return typeSystem.isNonNullable(typeSchema);
+  bool isNonNullable(SharedTypeSchemaView<DartType> typeSchema) {
+    return typeSystem.isNonNullable(typeSchema.unwrapTypeSchemaView());
   }
 
   @override
-  bool isNull(DartType type) {
-    return type.isDartCoreNull;
+  bool isNull(SharedTypeView<DartType> type) {
+    return type.unwrapTypeView().isDartCoreNull;
   }
 
   @override
-  bool isObject(DartType type) {
-    return type.isDartCoreObject &&
+  bool isObject(SharedTypeView<DartType> type) {
+    return type.unwrapTypeView().isDartCoreObject &&
         type.nullabilitySuffix == NullabilitySuffix.none;
   }
 
@@ -544,17 +573,22 @@
   }
 
   @override
-  bool isSubtypeOf(DartType leftType, DartType rightType) {
+  bool isSubtypeOfInternal(DartType leftType, DartType rightType) {
     return typeSystem.isSubtypeOf(leftType, rightType);
   }
 
   @override
-  bool isTypeParameterType(DartType type) => type is TypeParameterType;
+  bool isTypeParameterType(SharedTypeView<DartType> type) {
+    return type.unwrapTypeView() is TypeParameterType;
+  }
 
   @override
   bool isTypeSchemaSatisfied(
-          {required DartType typeSchema, required DartType type}) =>
-      isSubtypeOf(type, typeSchema);
+      {required SharedTypeSchemaView<DartType> typeSchema,
+      required SharedTypeView<DartType> type}) {
+    return typeSystem.isSubtypeOf(
+        type.unwrapTypeView(), typeSchema.unwrapTypeSchemaView());
+  }
 
   @override
   bool isVariableFinal(PromotableElement element) {
@@ -562,37 +596,29 @@
   }
 
   @override
-  DartType iterableTypeSchema(DartType elementTypeSchema) {
-    return typeSystem.typeProvider.iterableType(elementTypeSchema);
+  SharedTypeSchemaView<DartType> iterableTypeSchema(
+      SharedTypeSchemaView<DartType> elementTypeSchema) {
+    return SharedTypeSchemaView(typeSystem.typeProvider
+        .iterableType(elementTypeSchema.unwrapTypeSchemaView()));
   }
 
   @override
-  DartType listType(DartType elementType) {
+  DartType listTypeInternal(DartType elementType) {
     return typeSystem.typeProvider.listType(elementType);
   }
 
   @override
-  DartType listTypeSchema(DartType elementTypeSchema) {
-    return typeSystem.typeProvider.listType(elementTypeSchema);
-  }
-
-  @override
-  DartType lub(DartType type1, DartType type2) {
+  DartType lubInternal(DartType type1, DartType type2) {
     return typeSystem.leastUpperBound(type1, type2);
   }
 
   @override
-  DartType makeNullable(DartType type) {
+  DartType makeNullableInternal(DartType type) {
     return typeSystem.makeNullable(type);
   }
 
   @override
-  DartType makeTypeSchemaNullable(DartType typeSchema) {
-    return typeSystem.makeNullable(typeSchema);
-  }
-
-  @override
-  DartType mapType({
+  DartType mapTypeInternal({
     required DartType keyType,
     required DartType valueType,
   }) {
@@ -600,15 +626,7 @@
   }
 
   @override
-  DartType mapTypeSchema({
-    required DartType keyTypeSchema,
-    required DartType valueTypeSchema,
-  }) {
-    return typeSystem.typeProvider.mapType(keyTypeSchema, valueTypeSchema);
-  }
-
-  @override
-  DartType? matchFutureOr(DartType type) {
+  DartType? matchFutureOrInternal(DartType type) {
     if (type is InterfaceType && type.isDartAsyncFutureOr) {
       return type.typeArguments[0];
     } else {
@@ -617,66 +635,63 @@
   }
 
   @override
-  TypeParameterElement? matchInferableParameter(DartType type) {
-    if (type is TypeParameterType) {
-      return type.element;
+  TypeParameterElement? matchInferableParameter(SharedTypeView<DartType> type) {
+    DartType unwrappedType = type.unwrapTypeView();
+    if (unwrappedType is TypeParameterType) {
+      return unwrappedType.element;
     } else {
       return null;
     }
   }
 
   @override
-  DartType? matchIterableType(DartType type) {
+  DartType? matchIterableTypeInternal(DartType type) {
     var iterableElement = typeSystem.typeProvider.iterableElement;
     var listType = type.asInstanceOf(iterableElement);
     return listType?.typeArguments[0];
   }
 
   @override
-  DartType? matchIterableTypeSchema(DartType typeSchema) {
-    var iterableElement = typeSystem.typeProvider.iterableElement;
-    var listType = typeSchema.asInstanceOf(iterableElement);
-    return listType?.typeArguments[0];
-  }
-
-  @override
-  DartType? matchListType(DartType type) {
+  SharedTypeView<DartType>? matchListType(SharedTypeView<DartType> type) {
     var listElement = typeSystem.typeProvider.listElement;
-    var listType = type.asInstanceOf(listElement);
-    return listType?.typeArguments[0];
+    var listType = type.unwrapTypeView().asInstanceOf(listElement);
+    return listType == null ? null : SharedTypeView(listType.typeArguments[0]);
   }
 
   @override
-  ({DartType keyType, DartType valueType})? matchMapType(DartType type) {
+  ({SharedTypeView<DartType> keyType, SharedTypeView<DartType> valueType})?
+      matchMapType(SharedTypeView<DartType> type) {
     var mapElement = typeSystem.typeProvider.mapElement;
-    var mapType = type.asInstanceOf(mapElement);
+    var mapType = type.unwrapTypeView().asInstanceOf(mapElement);
     if (mapType != null) {
       return (
-        keyType: mapType.typeArguments[0],
-        valueType: mapType.typeArguments[1],
+        keyType: SharedTypeView(mapType.typeArguments[0]),
+        valueType: SharedTypeView(mapType.typeArguments[1]),
       );
     }
     return null;
   }
 
   @override
-  DartType? matchStreamType(DartType type) {
+  SharedTypeView<DartType>? matchStreamType(SharedTypeView<DartType> type) {
     var streamElement = typeSystem.typeProvider.streamElement;
-    var listType = type.asInstanceOf(streamElement);
-    return listType?.typeArguments[0];
+    var listType = type.unwrapTypeView().asInstanceOf(streamElement);
+    return listType == null ? null : SharedTypeView(listType.typeArguments[0]);
   }
 
   @override
-  TypeDeclarationMatchResult? matchTypeDeclarationType(DartType type) {
+  TypeDeclarationMatchResult? matchTypeDeclarationType(
+      SharedTypeView<DartType> type) {
+    DartType unwrappedType = type.unwrapTypeView();
     if (isInterfaceType(type)) {
-      InterfaceType interfaceType = type as InterfaceType;
+      InterfaceType interfaceType = unwrappedType as InterfaceType;
       return TypeDeclarationMatchResult(
           typeDeclarationKind: TypeDeclarationKind.interfaceDeclaration,
           typeDeclarationType: interfaceType,
           typeDeclaration: interfaceType.element,
           typeArguments: interfaceType.typeArguments);
     } else if (isExtensionType(type)) {
-      InterfaceType interfaceType = type as InterfaceType;
+      InterfaceType interfaceType = unwrappedType as InterfaceType;
       return TypeDeclarationMatchResult(
           typeDeclarationKind: TypeDeclarationKind.extensionTypeDeclaration,
           typeDeclarationType: interfaceType,
@@ -688,26 +703,17 @@
   }
 
   @override
-  DartType? matchTypeSchemaFutureOr(DartType typeSchema) {
-    if (typeSchema is InterfaceType && typeSchema.isDartAsyncFutureOr) {
-      return typeSchema.typeArguments[0];
-    } else {
-      return null;
-    }
+  SharedTypeView<DartType> normalize(SharedTypeView<DartType> type) {
+    return SharedTypeView(typeSystem.normalize(type.unwrapTypeView()));
   }
 
   @override
-  DartType normalize(DartType type) {
-    return typeSystem.normalize(type);
+  SharedTypeView<DartType> promoteToNonNull(SharedTypeView<DartType> type) {
+    return SharedTypeView(typeSystem.promoteToNonNull(type.unwrapTypeView()));
   }
 
   @override
-  DartType promoteToNonNull(DartType type) {
-    return typeSystem.promoteToNonNull(type);
-  }
-
-  @override
-  DartType recordType(
+  DartType recordTypeInternal(
       {required List<DartType> positional,
       required List<(String, DartType)> named}) {
     return RecordTypeImpl(
@@ -723,58 +729,28 @@
   }
 
   @override
-  DartType recordTypeSchema(
-          {required List<DartType> positional,
-          required List<(String, DartType)> named}) =>
-      recordType(positional: positional, named: named);
-
-  @override
-  DartType streamTypeSchema(DartType elementTypeSchema) {
-    return typeSystem.typeProvider.streamType(elementTypeSchema);
+  SharedTypeSchemaView<DartType> streamTypeSchema(
+      SharedTypeSchemaView<DartType> elementTypeSchema) {
+    return SharedTypeSchemaView(typeSystem.typeProvider
+        .streamType(elementTypeSchema.unwrapTypeSchemaView()));
   }
 
   @override
-  DartType? tryPromoteToType(DartType to, DartType from) {
-    return typeSystem.tryPromoteToType(to, from);
+  SharedTypeView<DartType>? tryPromoteToType(
+      SharedTypeView<DartType> to, SharedTypeView<DartType> from) {
+    DartType? result =
+        typeSystem.tryPromoteToType(to.unwrapTypeView(), from.unwrapTypeView());
+    return result == null ? null : SharedTypeView(result);
   }
 
   @override
-  bool typeIsSubtypeOfTypeSchema(DartType leftType, DartType rightSchema) {
-    return isSubtypeOf(leftType, rightSchema);
+  SharedTypeSchemaView<DartType> typeToSchema(SharedTypeView<DartType> type) {
+    return SharedTypeSchemaView(type.unwrapTypeView());
   }
 
   @override
-  DartType typeSchemaGlb(DartType typeSchema1, DartType typeSchema2) {
-    return typeSystem.greatestLowerBound(typeSchema1, typeSchema2);
-  }
-
-  @override
-  bool typeSchemaIsSubtypeOfType(DartType leftSchema, DartType rightType) {
-    return isSubtypeOf(leftSchema, rightType);
-  }
-
-  @override
-  bool typeSchemaIsSubtypeOfTypeSchema(
-      DartType leftSchema, DartType rightSchema) {
-    return isSubtypeOf(leftSchema, rightSchema);
-  }
-
-  @override
-  DartType typeSchemaLub(DartType typeSchema1, DartType typeSchema2) {
-    return typeSystem.leastUpperBound(typeSchema1, typeSchema2);
-  }
-
-  @override
-  NullabilitySuffix typeSchemaNullabilitySuffix(DartType typeSchema) {
-    return typeSchema.nullabilitySuffix;
-  }
-
-  @override
-  DartType typeToSchema(DartType type) => type;
-
-  @override
-  DartType variableType(PromotableElement variable) {
-    return variable.type;
+  SharedTypeView<DartType> variableType(PromotableElement variable) {
+    return SharedTypeView(variable.type);
   }
 
   @override
@@ -802,8 +778,10 @@
   }
 
   @override
-  DartType withNullabilitySuffix(DartType type, NullabilitySuffix suffix) {
-    return (type as TypeImpl).withNullability(suffix);
+  SharedTypeView<DartType> withNullabilitySuffix(
+      SharedTypeView<DartType> type, NullabilitySuffix suffix) {
+    return SharedTypeView(
+        (type.unwrapTypeView() as TypeImpl).withNullability(suffix));
   }
 }
 
@@ -1152,7 +1130,7 @@
       var promotedType = isRead
           ? _manager.flow?.variableRead(node, variable)
           : _manager.flow?.promotedType(variable);
-      if (promotedType != null) return promotedType;
+      if (promotedType != null) return promotedType.unwrapTypeView();
     }
     return variable.type;
   }
diff --git a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
index e8240fb..aef4207 100644
--- a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/for_resolver.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:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -158,8 +159,8 @@
           : _resolver.typeProvider.iterableType(valueType);
     }
 
-    _resolver.analyzeExpression(
-        iterable, targetType ?? UnknownInferredType.instance);
+    _resolver.analyzeExpression(iterable,
+        SharedTypeSchemaView(targetType ?? UnknownInferredType.instance));
     iterable = _resolver.popRewrite()!;
 
     _resolver.nullableDereferenceVerifier.expression(
@@ -177,15 +178,16 @@
 
     if (loopVariable != null) {
       var declaredElement = loopVariable.declaredElement!;
-      _resolver.flowAnalysis.flow
-          ?.declare(declaredElement, declaredElement.type, initialized: true);
+      _resolver.flowAnalysis.flow?.declare(
+          declaredElement, SharedTypeView(declaredElement.type),
+          initialized: true);
     }
 
     _resolver.flowAnalysis.flow?.forEach_bodyBegin(node);
     if (identifierElement is PromotableElement &&
         forEachParts is ForEachPartsWithIdentifier) {
-      _resolver.flowAnalysis.flow
-          ?.write(forEachParts, identifierElement, elementType, null);
+      _resolver.flowAnalysis.flow?.write(
+          forEachParts, identifierElement, SharedTypeView(elementType), null);
     }
 
     visitBody();
@@ -208,7 +210,8 @@
 
     var condition = forParts.condition;
     if (condition != null) {
-      _resolver.analyzeExpression(condition, _resolver.typeProvider.boolType);
+      _resolver.analyzeExpression(
+          condition, SharedTypeSchemaView(_resolver.typeProvider.boolType));
       condition = _resolver.popRewrite()!;
       var whyNotPromoted =
           _resolver.flowAnalysis.flow?.whyNotPromoted(condition);
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
index ef9e3d5..4ceebbe 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
@@ -5,6 +5,7 @@
 import 'package:_fe_analyzer_shared/src/base/errors.dart';
 import 'package:_fe_analyzer_shared/src/deferred_function_literal_heuristic.dart';
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -239,7 +240,8 @@
           rawType.typeFormals, inferrer.choosePreliminaryTypes());
     }
 
-    List<ExpressionInfo<DartType>?>? identicalInfo = _isIdentical ? [] : null;
+    List<ExpressionInfo<SharedTypeView<DartType>>?>? identicalInfo =
+        _isIdentical ? [] : null;
     var parameterMap = _computeParameterMap(rawType?.parameters ?? const []);
     var deferredFunctionLiterals = _visitArguments(
         parameterMap: parameterMap,
@@ -469,7 +471,8 @@
 
   /// If the invocation being processed is a call to `identical`, informs flow
   /// analysis about it, so that it can do appropriate promotions.
-  void _recordIdenticalInfo(List<ExpressionInfo<DartType>?>? identicalInfo) {
+  void _recordIdenticalInfo(
+      List<ExpressionInfo<SharedTypeView<DartType>>?>? identicalInfo) {
     var flow = resolver.flowAnalysis.flow;
     if (identicalInfo != null) {
       flow?.equalityOperation_end(argumentList.parent as Expression,
@@ -480,7 +483,7 @@
   /// Resolves any function literals that were deferred by [_visitArguments].
   void _resolveDeferredFunctionLiterals(
       {required List<_DeferredParamInfo> deferredFunctionLiterals,
-      List<ExpressionInfo<DartType>?>? identicalInfo,
+      List<ExpressionInfo<SharedTypeView<DartType>>?>? identicalInfo,
       Substitution? substitution,
       GenericInferrer? inferrer}) {
     var flow = resolver.flowAnalysis.flow;
@@ -498,11 +501,12 @@
         parameterContextType = UnknownInferredType.instance;
       }
       var argument = arguments[deferredArgument.index];
-      resolver.analyzeExpression(argument, parameterContextType);
+      resolver.analyzeExpression(
+          argument, SharedTypeSchemaView(parameterContextType));
       argument = resolver.popRewrite()!;
       if (flow != null) {
-        identicalInfo?[deferredArgument.index] =
-            flow.equalityOperand_end(argument, argument.typeOrThrow);
+        identicalInfo?[deferredArgument.index] = flow.equalityOperand_end(
+            argument, SharedTypeView(argument.typeOrThrow));
       }
       if (parameter != null) {
         inferrer?.constrainArgument(
@@ -517,7 +521,7 @@
   /// returned.
   List<_DeferredParamInfo>? _visitArguments(
       {required Map<Object, ParameterElement> parameterMap,
-      List<ExpressionInfo<DartType>?>? identicalInfo,
+      List<ExpressionInfo<SharedTypeView<DartType>>?>? identicalInfo,
       Substitution? substitution,
       GenericInferrer? inferrer}) {
     assert(whyNotPromotedList.isEmpty);
@@ -560,11 +564,12 @@
         } else {
           parameterContextType = UnknownInferredType.instance;
         }
-        resolver.analyzeExpression(argument, parameterContextType);
+        resolver.analyzeExpression(
+            argument, SharedTypeSchemaView(parameterContextType));
         argument = resolver.popRewrite()!;
         if (flow != null) {
-          identicalInfo
-              ?.add(flow.equalityOperand_end(argument, argument.typeOrThrow));
+          identicalInfo?.add(flow.equalityOperand_end(
+              argument, SharedTypeView(argument.typeOrThrow)));
           whyNotPromotedList.add(flow.whyNotPromoted(argument));
         }
         if (parameter != null) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/list_pattern_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/list_pattern_resolver.dart
index b08951c..5c35668 100644
--- a/pkg/analyzer/lib/src/dart/resolver/list_pattern_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/list_pattern_resolver.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/extensions.dart';
@@ -32,16 +33,17 @@
       }
     }
 
+    DartType? elementType = typeArguments?.arguments.first.typeOrThrow;
     var result = resolverVisitor.analyzeListPattern(context, node,
-        elementType: typeArguments?.arguments.first.typeOrThrow,
+        elementType: elementType?.wrapSharedTypeView(),
         elements: node.elements);
-    node.requiredType = result.requiredType;
+    node.requiredType = result.requiredType.unwrapTypeView();
 
     resolverVisitor.checkPatternNeverMatchesValueType(
       context: context,
       pattern: node,
-      requiredType: result.requiredType,
-      matchedValueType: result.matchedValueType,
+      requiredType: result.requiredType.unwrapTypeView(),
+      matchedValueType: result.matchedValueType.unwrapTypeView(),
     );
 
     return result;
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index 4853a6a..45af99b 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/listener.dart';
@@ -954,14 +955,16 @@
       if (element is ExecutableElement &&
           element.enclosingElement is InstanceElement &&
           !element.isStatic) {
-        targetType = _resolver.flowAnalysis.flow?.propertyGet(
-                functionExpression,
-                node.isCascaded
-                    ? CascadePropertyTarget.singleton
-                    : ThisPropertyTarget.singleton,
-                node.methodName.name,
-                element,
-                getterReturnType) ??
+        targetType = _resolver.flowAnalysis.flow
+                ?.propertyGet(
+                    functionExpression,
+                    node.isCascaded
+                        ? CascadePropertyTarget.singleton
+                        : ThisPropertyTarget.singleton,
+                    node.methodName.name,
+                    element,
+                    SharedTypeView(getterReturnType))
+                ?.unwrapTypeView() ??
             targetType;
       }
     } else {
@@ -980,20 +983,24 @@
         );
       }
       if (target is SuperExpressionImpl) {
-        targetType = _resolver.flowAnalysis.flow?.propertyGet(
-                functionExpression,
-                SuperPropertyTarget.singleton,
-                node.methodName.name,
-                node.methodName.staticElement,
-                getterReturnType) ??
+        targetType = _resolver.flowAnalysis.flow
+                ?.propertyGet(
+                    functionExpression,
+                    SuperPropertyTarget.singleton,
+                    node.methodName.name,
+                    node.methodName.staticElement,
+                    SharedTypeView(getterReturnType))
+                ?.unwrapTypeView() ??
             targetType;
       } else {
-        targetType = _resolver.flowAnalysis.flow?.propertyGet(
-                functionExpression,
-                ExpressionPropertyTarget(target),
-                node.methodName.name,
-                node.methodName.staticElement,
-                getterReturnType) ??
+        targetType = _resolver.flowAnalysis.flow
+                ?.propertyGet(
+                    functionExpression,
+                    ExpressionPropertyTarget(target),
+                    node.methodName.name,
+                    node.methodName.staticElement,
+                    SharedTypeView(getterReturnType))
+                ?.unwrapTypeView() ??
             targetType;
       }
       functionExpression.setPseudoExpressionStaticType(targetType);
diff --git a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
index 508ed9a..f55ceadd 100644
--- a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.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:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -176,7 +177,7 @@
         var element = operand.staticElement;
         if (element is PromotableElement) {
           _resolver.flowAnalysis.flow
-              ?.write(node, element, operatorReturnType, null);
+              ?.write(node, element, SharedTypeView(operatorReturnType), null);
         }
       }
       node.recordStaticType(receiverType, resolver: _resolver);
@@ -199,7 +200,8 @@
       return;
     }
 
-    _resolver.analyzeExpression(operand, _typeSystem.makeNullable(contextType));
+    _resolver.analyzeExpression(
+        operand, SharedTypeSchemaView(_typeSystem.makeNullable(contextType)));
     operand = _resolver.popRewrite()!;
 
     var operandType = operand.typeOrThrow;
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
index 7e9b0e7..ffaf6b4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.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:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -83,7 +84,8 @@
       } else {
         innerContextType = UnknownInferredType.instance;
       }
-      _resolver.analyzeExpression(operand, innerContextType);
+      _resolver.analyzeExpression(
+          operand, SharedTypeSchemaView(innerContextType));
       _resolver.popRewrite();
     }
 
@@ -234,7 +236,8 @@
         if (operand is SimpleIdentifier) {
           var element = operand.staticElement;
           if (element is PromotableElement) {
-            _resolver.flowAnalysis.flow?.write(node, element, staticType, null);
+            _resolver.flowAnalysis.flow
+                ?.write(node, element, SharedTypeView(staticType), null);
           }
         }
       }
@@ -297,7 +300,8 @@
   void _resolveNegation(PrefixExpressionImpl node) {
     var operand = node.operand;
 
-    _resolver.analyzeExpression(operand, _typeProvider.boolType);
+    _resolver.analyzeExpression(
+        operand, SharedTypeSchemaView(_typeProvider.boolType));
     operand = _resolver.popRewrite()!;
     var whyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(operand);
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index 4ed2f3b..c9c34c4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/error.dart';
@@ -261,12 +262,10 @@
       if (readElementRequested is PropertyAccessorElement &&
           !readElementRequested.isStatic) {
         var unpromotedType = readElementRequested.returnType;
-        getType = _resolver.flowAnalysis.flow?.propertyGet(
-                node,
-                ThisPropertyTarget.singleton,
-                node.name,
-                readElementRequested,
-                unpromotedType) ??
+        getType = _resolver.flowAnalysis.flow
+                ?.propertyGet(node, ThisPropertyTarget.singleton, node.name,
+                    readElementRequested, SharedTypeView(unpromotedType))
+                ?.unwrapTypeView() ??
             unpromotedType;
       }
       _resolver.checkReadOfNotAssignedLocalVariable(node, readElementRequested);
@@ -491,15 +490,17 @@
     if (hasRead) {
       var unpromotedType =
           result.getter?.returnType ?? _typeSystem.typeProvider.dynamicType;
-      getType = _resolver.flowAnalysis.flow?.propertyGet(
-              node,
-              isCascaded
-                  ? CascadePropertyTarget.singleton
-                      as PropertyTarget<Expression>
-                  : ExpressionPropertyTarget(target),
-              propertyName.name,
-              result.getter,
-              unpromotedType) ??
+      getType = _resolver.flowAnalysis.flow
+              ?.propertyGet(
+                  node,
+                  isCascaded
+                      ? CascadePropertyTarget.singleton
+                          as PropertyTarget<Expression>
+                      : ExpressionPropertyTarget(target),
+                  propertyName.name,
+                  result.getter,
+                  SharedTypeView(unpromotedType))
+              ?.unwrapTypeView() ??
           unpromotedType;
 
       _checkForStaticMember(target, propertyName, result.getter);
@@ -830,12 +831,14 @@
         }
         var unpromotedType =
             readElement?.returnType ?? _typeSystem.typeProvider.dynamicType;
-        getType = _resolver.flowAnalysis.flow?.propertyGet(
-                node,
-                SuperPropertyTarget.singleton,
-                propertyName.name,
-                readElement,
-                unpromotedType) ??
+        getType = _resolver.flowAnalysis.flow
+                ?.propertyGet(
+                    node,
+                    SuperPropertyTarget.singleton,
+                    propertyName.name,
+                    readElement,
+                    SharedTypeView(unpromotedType))
+                ?.unwrapTypeView() ??
             unpromotedType;
       }
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/record_literal_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/record_literal_resolver.dart
index d683bb1..c2aa391 100644
--- a/pkg/analyzer/lib/src/dart/resolver/record_literal_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/record_literal_resolver.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:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/listener.dart';
@@ -132,7 +133,9 @@
   }
 
   DartType _resolveField(ExpressionImpl field, DartType contextType) {
-    var staticType = _resolver.analyzeExpression(field, contextType);
+    var staticType = _resolver
+        .analyzeExpression(field, SharedTypeSchemaView(contextType))
+        .unwrapTypeView();
     field = _resolver.popRewrite()!;
 
     // Implicit cast from `dynamic`.
diff --git a/pkg/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart b/pkg/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart
index f66e62f..e6ddb81 100644
--- a/pkg/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart
@@ -5,6 +5,7 @@
 import 'package:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer.dart'
     as shared;
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/listener.dart';
@@ -20,7 +21,7 @@
 class SharedTypeAnalyzerErrors
     implements
         shared.TypeAnalyzerErrors<AstNode, Statement, Expression,
-            PromotableElement, DartType, DartPattern, void> {
+            PromotableElement, SharedTypeView<DartType>, DartPattern, void> {
   final ErrorReporter _errorReporter;
 
   SharedTypeAnalyzerErrors(this._errorReporter);
@@ -32,8 +33,8 @@
   void caseExpressionTypeMismatch(
       {required Expression scrutinee,
       required Expression caseExpression,
-      required DartType scrutineeType,
-      required DartType caseExpressionType,
+      required SharedTypeView<DartType> scrutineeType,
+      required SharedTypeView<DartType> caseExpressionType,
       required bool nullSafetyEnabled}) {
     _errorReporter.atNode(
       caseExpression,
@@ -119,7 +120,7 @@
   @override
   void matchedTypeIsStrictlyNonNullable({
     required DartPattern pattern,
-    required DartType matchedType,
+    required SharedTypeView<DartType> matchedType,
   }) {
     if (pattern is NullAssertPattern) {
       _errorReporter.atToken(
@@ -139,8 +140,8 @@
   @override
   void matchedTypeIsSubtypeOfRequired({
     required covariant CastPatternImpl pattern,
-    required DartType matchedType,
-    required DartType requiredType,
+    required SharedTypeView<DartType> matchedType,
+    required SharedTypeView<DartType> requiredType,
   }) {
     _errorReporter.atToken(
       pattern.asToken,
@@ -160,7 +161,7 @@
   void patternForInExpressionIsNotIterable({
     required AstNode node,
     required Expression expression,
-    required DartType expressionType,
+    required SharedTypeView<DartType> expressionType,
   }) {
     _errorReporter.atNode(
       expression,
@@ -173,8 +174,8 @@
   void patternTypeMismatchInIrrefutableContext({
     required covariant DartPatternImpl pattern,
     required AstNode context,
-    required DartType matchedType,
-    required DartType requiredType,
+    required SharedTypeView<DartType> matchedType,
+    required SharedTypeView<DartType> requiredType,
   }) {
     _errorReporter.atNode(
       pattern,
@@ -195,8 +196,8 @@
   @override
   void relationalPatternOperandTypeNotAssignable({
     required covariant RelationalPatternImpl pattern,
-    required DartType operandType,
-    required DartType parameterType,
+    required SharedTypeView<DartType> operandType,
+    required SharedTypeView<DartType> parameterType,
   }) {
     _errorReporter.atNode(
       pattern.operand,
@@ -208,7 +209,7 @@
   @override
   void relationalPatternOperatorReturnTypeNotAssignableToBool({
     required covariant RelationalPatternImpl pattern,
-    required DartType returnType,
+    required SharedTypeView<DartType> returnType,
   }) {
     _errorReporter.atToken(
       pattern.operator,
diff --git a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
index bd8340d..c985aca 100644
--- a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.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:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -156,8 +157,8 @@
         } else {
           var thisType = _resolver.thisType;
           if (thisType != null) {
-            messages = _resolver.computeWhyNotPromotedMessages(
-                nameErrorEntity, flow.whyNotPromotedImplicitThis(thisType)());
+            messages = _resolver.computeWhyNotPromotedMessages(nameErrorEntity,
+                flow.whyNotPromotedImplicitThis(SharedTypeView(thisType))());
           }
         }
       }
diff --git a/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
index 584be12..3389484 100644
--- a/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.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:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/extensions.dart';
@@ -51,14 +52,16 @@
             element.shouldUseTypeForInitializerInference
         ? element.type
         : UnknownInferredType.instance;
-    _resolver.analyzeExpression(initializer, contextType);
+    _resolver.analyzeExpression(initializer, SharedTypeSchemaView(contextType));
     initializer = _resolver.popRewrite()!;
     var whyNotPromoted =
         _resolver.flowAnalysis.flow?.whyNotPromoted(initializer);
 
     var initializerType = initializer.typeOrThrow;
     if (parent.type == null && element is LocalVariableElementImpl) {
-      element.type = _resolver.variableTypeFromInitializerType(initializerType);
+      element.type = _resolver
+          .variableTypeFromInitializerType(SharedTypeView(initializerType))
+          .unwrapTypeView();
     }
 
     if (isTopLevel) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart
index 2631892..4bc14b1 100644
--- a/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.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:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
@@ -163,8 +164,8 @@
     BodyInferenceContext bodyContext,
     YieldStatement node,
   ) {
-    _resolver.analyzeExpression(
-        node.expression, _computeContextType(bodyContext, node));
+    _resolver.analyzeExpression(node.expression,
+        SharedTypeSchemaView(_computeContextType(bodyContext, node)));
     _resolver.popRewrite();
 
     if (node.star != null) {
diff --git a/pkg/analyzer/lib/src/error/bool_expression_verifier.dart b/pkg/analyzer/lib/src/error/bool_expression_verifier.dart
index 198e929..dfa1410 100644
--- a/pkg/analyzer/lib/src/error/bool_expression_verifier.dart
+++ b/pkg/analyzer/lib/src/error/bool_expression_verifier.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/error.dart';
@@ -35,7 +36,8 @@
   ///
   /// See [CompileTimeErrorCode.NON_BOOL_CONDITION].
   void checkForNonBoolCondition(Expression condition,
-      {required Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
+      {required Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted}) {
     checkForNonBoolExpression(
       condition,
       errorCode: CompileTimeErrorCode.NON_BOOL_CONDITION,
@@ -48,7 +50,8 @@
   void checkForNonBoolExpression(Expression expression,
       {required ErrorCode errorCode,
       List<Object> arguments = const [],
-      required Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
+      required Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted}) {
     var type = expression.typeOrThrow;
     if (!_checkForUseOfVoidResult(expression) &&
         !_resolver.typeSystem.isAssignableTo(type, _boolType,
@@ -72,7 +75,8 @@
 
   /// Checks to ensure that the given [expression] is assignable to bool.
   void checkForNonBoolNegationExpression(Expression expression,
-      {required Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
+      {required Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted}) {
     checkForNonBoolExpression(
       expression,
       errorCode: CompileTimeErrorCode.NON_BOOL_NEGATION_EXPRESSION,
diff --git a/pkg/analyzer/lib/src/generated/error_detection_helpers.dart b/pkg/analyzer/lib/src/generated/error_detection_helpers.dart
index 8fe4050..fcf2428 100644
--- a/pkg/analyzer/lib/src/generated/error_detection_helpers.dart
+++ b/pkg/analyzer/lib/src/generated/error_detection_helpers.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -35,7 +36,8 @@
       DartType expectedStaticType,
       DartType actualStaticType,
       ErrorCode errorCode,
-      {Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
+      {Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted}) {
     if (expectedStaticType is! VoidType &&
         checkForUseOfVoidResult(expression)) {
       return;
@@ -55,7 +57,8 @@
   /// See [CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE].
   void checkForArgumentTypeNotAssignableForArgument(Expression argument,
       {bool promoteParameterToNullable = false,
-      Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
+      Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted}) {
     _checkForArgumentTypeNotAssignableForArgument(
       argument: argument is NamedExpression ? argument.expression : argument,
       parameter: argument.staticParameterElement,
@@ -69,7 +72,8 @@
       DartType actualStaticType,
       DartType expectedStaticType,
       ErrorCode errorCode,
-      {Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
+      {Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted}) {
     if (expectedStaticType is! VoidType &&
         checkForUseOfVoidResult(expression)) {
       return;
@@ -164,7 +168,8 @@
   void checkForFieldInitializerNotAssignable(
       ConstructorFieldInitializer initializer, FieldElement fieldElement,
       {required bool isConstConstructor,
-      required Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
+      required Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted}) {
     // prepare field type
     DartType fieldType = fieldElement.type;
     // prepare expression type
@@ -253,7 +258,8 @@
     Expression index, {
     required ExecutableElement? readElement,
     required ExecutableElement? writeElement,
-    required Map<DartType, NonPromotionReason> Function()? whyNotPromoted,
+    required Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+        whyNotPromoted,
   }) {
     if (readElement is MethodElement) {
       var parameters = readElement.parameters;
@@ -293,7 +299,7 @@
   /// analysis engine.
   List<DiagnosticMessage> computeWhyNotPromotedMessages(
       SyntacticEntity errorEntity,
-      Map<DartType, NonPromotionReason>? whyNotPromoted);
+      Map<SharedTypeView<DartType>, NonPromotionReason>? whyNotPromoted);
 
   /// If an assignment from [type] to [context] is a case of an implicit 'call'
   /// method, returns the element of the 'call' method.
@@ -343,7 +349,8 @@
     required Expression argument,
     required ParameterElement? parameter,
     required bool promoteParameterToNullable,
-    Map<DartType, NonPromotionReason> Function()? whyNotPromoted,
+    Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+        whyNotPromoted,
   }) {
     var staticParameterType = parameter?.type;
     if (staticParameterType != null) {
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index ee91d37..2ab3ed8 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -8,6 +8,7 @@
 import 'package:_fe_analyzer_shared/src/parser/util.dart' as shared;
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart'
     show Variance;
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/ast/token.dart';
@@ -327,7 +328,7 @@
   @override
   List<DiagnosticMessage> computeWhyNotPromotedMessages(
       SyntacticEntity errorEntity,
-      Map<DartType, NonPromotionReason>? whyNotPromoted) {
+      Map<SharedTypeView<DartType>, NonPromotionReason>? whyNotPromoted) {
     return [];
   }
 
diff --git a/pkg/analyzer/lib/src/generated/inference_log.dart b/pkg/analyzer/lib/src/generated/inference_log.dart
index d301abc..d0e5287 100644
--- a/pkg/analyzer/lib/src/generated/inference_log.dart
+++ b/pkg/analyzer/lib/src/generated/inference_log.dart
@@ -55,7 +55,8 @@
 /// The [SharedInferenceLogWriter] interface, augmented with analyzer-specific
 /// functionality.
 abstract interface class InferenceLogWriter
-    implements SharedInferenceLogWriter<DartType, TypeParameterElement> {
+    implements
+        SharedInferenceLogWriter<DartType, DartType, TypeParameterElement> {
   /// Checks that [enterExpression] was properly called for [expression].
   ///
   /// This is called from [ResolverVisitor.dispatchExpression], to verify that
@@ -65,9 +66,8 @@
 
 /// The [SharedInferenceLogWriterImpl] implementation, augmented with
 /// analyzer-specific functionality.
-final class _InferenceLogWriterImpl
-    extends SharedInferenceLogWriterImpl<DartType, TypeParameterElement>
-    implements InferenceLogWriter {
+final class _InferenceLogWriterImpl extends SharedInferenceLogWriterImpl<
+    DartType, DartType, TypeParameterElement> implements InferenceLogWriter {
   @override
   void assertExpressionWasRecorded(Object expression) {
     if (_recordedExpressions[expression] ?? false) return;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 3b17ec9..75248ca 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -15,6 +15,7 @@
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart'
     as shared;
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/ast/token.dart';
@@ -93,14 +94,15 @@
 bool Function(Source) inferenceLoggingPredicate = (_) => false;
 
 typedef SharedMatchContext = shared.MatchContext<AstNode, Expression,
-    DartPattern, DartType, PromotableElement>;
+    DartPattern, SharedTypeView<DartType>, PromotableElement>;
 
 typedef SharedPatternField
     = shared.RecordPatternField<PatternFieldImpl, DartPatternImpl>;
 
 /// A function which returns [NonPromotionReason]s that various types are not
 /// promoted.
-typedef WhyNotPromotedGetter = Map<DartType, NonPromotionReason> Function();
+typedef WhyNotPromotedGetter = Map<SharedTypeView<DartType>, NonPromotionReason>
+    Function();
 
 /// The context shared between different units of the same library.
 final class LibraryResolutionContext {
@@ -115,14 +117,13 @@
     with
         ErrorDetectionHelpers,
         TypeAnalyzer<
+            DartType,
             AstNode,
             Statement,
             Expression,
             PromotableElement,
-            DartType,
             DartPattern,
             void,
-            DartType,
             TypeParameterElement,
             InterfaceType,
             InterfaceElement> {
@@ -418,8 +419,8 @@
   ExecutableElement? get enclosingFunction => _enclosingFunction;
 
   @override
-  FlowAnalysis<AstNode, Statement, Expression, PromotableElement, DartType>
-      get flow => flowAnalysis.flow!;
+  FlowAnalysis<AstNode, Statement, Expression, PromotableElement,
+      SharedTypeView<DartType>> get flow => flowAnalysis.flow!;
 
   bool get isConstructorTearoffsEnabled =>
       _featureSet.isEnabled(Feature.constructor_tearoffs);
@@ -434,9 +435,8 @@
 
   @override
   shared.TypeAnalyzerOperations<
+      DartType,
       PromotableElement,
-      DartType,
-      DartType,
       TypeParameterElement,
       InterfaceType,
       InterfaceElement> get operations => flowAnalysis.typeOperations;
@@ -686,13 +686,15 @@
   @override
   List<DiagnosticMessage> computeWhyNotPromotedMessages(
       SyntacticEntity errorEntity,
-      Map<DartType, NonPromotionReason>? whyNotPromoted) {
+      Map<SharedTypeView<DartType>, NonPromotionReason>? whyNotPromoted) {
     List<DiagnosticMessage> messages = [];
     if (whyNotPromoted != null) {
       for (var entry in whyNotPromoted.entries) {
         var whyNotPromotedVisitor = _WhyNotPromotedVisitor(
             source, errorEntity, flowAnalysis.dataForTesting);
-        if (typeSystem.isPotentiallyNullable(entry.key)) continue;
+        if (typeSystem.isPotentiallyNullable(entry.key.unwrapTypeView())) {
+          continue;
+        }
         messages = entry.value.accept(whyNotPromotedVisitor);
         // `messages` will be passed to the ErrorReporter, which might add
         // additional entries. So make sure that it's not a `const []`.
@@ -735,7 +737,8 @@
 
   @override
   ExpressionTypeAnalysisResult<DartType> dispatchExpression(
-      covariant ExpressionImpl expression, DartType context) {
+      covariant ExpressionImpl expression,
+      SharedTypeSchemaView<DartType> context) {
     int? stackDepth;
     assert(() {
       stackDepth = rewriteStackDepth;
@@ -745,7 +748,7 @@
     // Stack: ()
     pushRewrite(expression);
     // Stack: (Expression)
-    expression.resolveExpression(this, context);
+    expression.resolveExpression(this, context.unwrapTypeSchemaView());
     inferenceLogWriter?.assertExpressionWasRecorded(expression);
     assert(rewriteStackDepth == stackDepth! + 1);
     var replacementExpression = peekRewrite()!;
@@ -769,9 +772,9 @@
           '(${replacementExpression.runtimeType}) $replacementExpression',
         );
       }
-      staticType = operations.unknownType;
+      staticType = operations.unknownType.unwrapTypeSchemaView();
     }
-    return SimpleTypeAnalysisResult<DartType>(type: staticType);
+    return SimpleTypeAnalysisResult<DartType>(type: SharedTypeView(staticType));
   }
 
   @override
@@ -780,7 +783,7 @@
     shared.PatternResult<DartType> analysisResult;
     if (node is DartPatternImpl) {
       analysisResult = node.resolvePattern(this, context);
-      node.matchedValueType = analysisResult.matchedValueType;
+      node.matchedValueType = analysisResult.matchedValueType.unwrapTypeView();
     } else {
       // This can occur inside conventional switch statements, since
       // [SwitchCase] points directly to an [Expression] rather than to a
@@ -796,8 +799,9 @@
   }
 
   @override
-  DartType dispatchPatternSchema(covariant DartPatternImpl node) {
-    return node.computePatternSchema(this);
+  SharedTypeSchemaView<DartType> dispatchPatternSchema(
+      covariant DartPatternImpl node) {
+    return SharedTypeSchemaView(node.computePatternSchema(this));
   }
 
   @override
@@ -806,8 +810,8 @@
   }
 
   @override
-  DartType downwardInferObjectPatternRequiredType({
-    required DartType matchedType,
+  SharedTypeView<DartType> downwardInferObjectPatternRequiredType({
+    required SharedTypeView<DartType> matchedType,
     required covariant ObjectPatternImpl pattern,
   }) {
     var typeNode = pattern.type;
@@ -820,13 +824,13 @@
             typeParameters: typeParameters,
             errorNode: typeNode,
             declaredType: typeNameElement.thisType,
-            contextType: matchedType,
+            contextType: matchedType.unwrapTypeView(),
             nodeForTesting: pattern,
           );
-          return typeNode.type = typeNameElement.instantiate(
+          return SharedTypeView(typeNode.type = typeNameElement.instantiate(
             typeArguments: typeArguments,
             nullabilitySuffix: NullabilitySuffix.none,
-          );
+          ));
         }
       } else if (typeNameElement is TypeAliasElement) {
         var typeParameters = typeNameElement.typeParameters;
@@ -835,17 +839,17 @@
             typeParameters: typeParameters,
             errorNode: typeNode,
             declaredType: typeNameElement.aliasedType,
-            contextType: matchedType,
+            contextType: matchedType.unwrapTypeView(),
             nodeForTesting: pattern,
           );
-          return typeNode.type = typeNameElement.instantiate(
+          return SharedTypeView(typeNode.type = typeNameElement.instantiate(
             typeArguments: typeArguments,
             nullabilitySuffix: NullabilitySuffix.none,
-          );
+          ));
         }
       }
     }
-    return typeNode.typeOrThrow;
+    return SharedTypeView(typeNode.typeOrThrow);
   }
 
   @override
@@ -864,11 +868,11 @@
     required JoinedPatternVariableLocation location,
     required shared.JoinedPatternVariableInconsistency inconsistency,
     required bool isFinal,
-    required DartType type,
+    required SharedTypeView<DartType> type,
   }) {
     variable.inconsistency = variable.inconsistency.maxWith(inconsistency);
     variable.isFinal = isFinal;
-    variable.type = type;
+    variable.type = type.unwrapTypeView();
 
     if (location == JoinedPatternVariableLocation.sharedCaseScope) {
       for (var reference in variable.references) {
@@ -1092,7 +1096,7 @@
   void handleMapPatternEntry(
     DartPattern container,
     covariant MapPatternEntryImpl entry,
-    DartType keyType,
+    SharedTypeView<DartType> keyType,
   ) {
     entry.key = popRewrite()!;
   }
@@ -1141,9 +1145,9 @@
   }
 
   @override
-  void handleSwitchScrutinee(DartType type) {
+  void handleSwitchScrutinee(SharedTypeView<DartType> type) {
     if (!options.patternsEnabled) {
-      legacySwitchExhaustiveness = SwitchExhaustiveness(type);
+      legacySwitchExhaustiveness = SwitchExhaustiveness(type.unwrapTypeView());
     }
   }
 
@@ -1206,7 +1210,8 @@
   }
 
   @override
-  bool isLegacySwitchExhaustive(AstNode node, DartType expressionType) =>
+  bool isLegacySwitchExhaustive(
+          AstNode node, SharedTypeView<DartType> expressionType) =>
       legacySwitchExhaustiveness!.isExhaustive;
 
   @override
@@ -1348,7 +1353,8 @@
   }) {
     var element = node.element;
     if (element is! PromotableElement) {
-      return PatternResult(matchedValueType: InvalidTypeImpl.instance);
+      return PatternResult(
+          matchedValueType: SharedTypeView(InvalidTypeImpl.instance));
     }
 
     if (element.isFinal) {
@@ -1403,7 +1409,8 @@
     } else if (node is IndexExpression) {
       var target = node.target;
       if (target != null) {
-        analyzeExpression(target, UnknownInferredType.instance);
+        analyzeExpression(
+            target, SharedTypeSchemaView(UnknownInferredType.instance));
         popRewrite();
       }
 
@@ -1415,7 +1422,8 @@
         hasWrite: true,
       );
 
-      analyzeExpression(node.index, result.indexContextType);
+      analyzeExpression(
+          node.index, SharedTypeSchemaView(result.indexContextType));
       popRewrite();
       var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(node.index);
       checkIndexExpressionIndex(
@@ -1481,7 +1489,8 @@
       return result;
     } else {
       inferenceLogWriter?.exitLValue(node, reanalyzeAsRValue: true);
-      analyzeExpression(node, UnknownInferredType.instance);
+      analyzeExpression(
+          node, SharedTypeSchemaView(UnknownInferredType.instance));
       popRewrite();
       return PropertyElementResolverResult();
     }
@@ -1492,7 +1501,10 @@
     required SharedMatchContext context,
   }) {
     inferenceLogWriter?.enterPattern(node);
-    ({DartType keyType, DartType valueType})? typeArguments;
+    ({
+      SharedTypeView<DartType> keyType,
+      SharedTypeView<DartType> valueType
+    })? typeArguments;
     var typeArgumentsList = node.typeArguments;
     if (typeArgumentsList != null) {
       typeArgumentsList.accept(this);
@@ -1500,8 +1512,8 @@
       var length = typeArgumentsList.arguments.length;
       if (length == 2) {
         typeArguments = (
-          keyType: typeArgumentsList.arguments[0].typeOrThrow,
-          valueType: typeArgumentsList.arguments[1].typeOrThrow,
+          keyType: SharedTypeView(typeArgumentsList.arguments[0].typeOrThrow),
+          valueType: SharedTypeView(typeArgumentsList.arguments[1].typeOrThrow),
         );
       } else {
         errorReporter.atNode(
@@ -1518,13 +1530,13 @@
       typeArguments: typeArguments,
       elements: node.elements,
     );
-    node.requiredType = result.requiredType;
+    node.requiredType = result.requiredType.unwrapTypeView();
 
     checkPatternNeverMatchesValueType(
       context: context,
       pattern: node,
-      requiredType: result.requiredType,
-      matchedValueType: result.matchedValueType,
+      requiredType: result.requiredType.unwrapTypeView(),
+      matchedValueType: result.matchedValueType.unwrapTypeView(),
     );
     inferenceLogWriter?.exitPattern(node);
 
@@ -1532,21 +1544,22 @@
   }
 
   @override
-  (ExecutableElement?, DartType) resolveObjectPatternPropertyGet({
+  (ExecutableElement?, SharedTypeView<DartType>)
+      resolveObjectPatternPropertyGet({
     required covariant ObjectPatternImpl objectPattern,
-    required DartType receiverType,
+    required SharedTypeView<DartType> receiverType,
     required covariant SharedPatternField field,
   }) {
     var fieldNode = field.node;
     var nameToken = fieldNode.name?.name;
     nameToken ??= field.pattern.variablePattern?.name;
     if (nameToken == null) {
-      return (null, typeProvider.dynamicType);
+      return (null, SharedTypeView(typeProvider.dynamicType));
     }
 
     var result = typePropertyResolver.resolve(
       receiver: null,
-      receiverType: receiverType,
+      receiverType: receiverType.unwrapTypeView(),
       name: nameToken.lexeme,
       propertyErrorEntity: objectPattern.type,
       nameErrorEntity: nameToken,
@@ -1564,24 +1577,24 @@
     if (getter != null) {
       fieldNode.element = getter;
       if (getter is PropertyAccessorElement) {
-        return (getter, getter.returnType);
+        return (getter, SharedTypeView(getter.returnType));
       } else {
-        return (getter, getter.type);
+        return (getter, SharedTypeView(getter.type));
       }
     }
 
     var recordField = result.recordField;
     if (recordField != null) {
-      return (null, recordField.type);
+      return (null, SharedTypeView(recordField.type));
     }
 
-    return (null, typeProvider.dynamicType);
+    return (null, SharedTypeView(typeProvider.dynamicType));
   }
 
   @override
   RelationalOperatorResolution<DartType>? resolveRelationalPatternOperator(
     covariant RelationalPatternImpl node,
-    DartType matchedType,
+    SharedTypeView<DartType> matchedType,
   ) {
     var operatorLexeme = node.operator.lexeme;
     RelationalOperatorKind kind;
@@ -1599,7 +1612,7 @@
 
     var result = typePropertyResolver.resolve(
       receiver: null,
-      receiverType: matchedType,
+      receiverType: matchedType.unwrapTypeView(),
       name: methodName,
       propertyErrorEntity: node.operator,
       nameErrorEntity: node,
@@ -1627,8 +1640,8 @@
 
     return RelationalOperatorResolution(
       kind: kind,
-      parameterType: parameterType,
-      returnType: element.returnType,
+      parameterType: SharedTypeView(parameterType),
+      returnType: SharedTypeView(element.returnType),
     );
   }
 
@@ -1670,9 +1683,10 @@
   }
 
   @override
-  void setVariableType(PromotableElement variable, DartType type) {
+  void setVariableType(
+      PromotableElement variable, SharedTypeView<DartType> type) {
     if (variable is LocalVariableElementImpl) {
-      variable.type = type;
+      variable.type = type.unwrapTypeView();
     } else {
       throw UnimplementedError('TODO(paulberry)');
     }
@@ -1737,8 +1751,10 @@
     if (node.isNullAware) {
       var flow = flowAnalysis.flow;
       if (flow != null) {
-        flow.nullAwareAccess_rightBegin(node.target,
-            node.realTarget.staticType ?? typeProvider.dynamicType);
+        flow.nullAwareAccess_rightBegin(
+            node.target,
+            SharedTypeView(
+                node.realTarget.staticType ?? typeProvider.dynamicType));
         _unfinishedNullShorts.add(node.nullShortingTermination);
       }
     }
@@ -1754,7 +1770,9 @@
           // `?.` to access static methods is equivalent to `.`, so do nothing.
         } else {
           flow.nullAwareAccess_rightBegin(
-              target, node.realTarget.staticType ?? typeProvider.dynamicType);
+              target,
+              SharedTypeView(
+                  node.realTarget.staticType ?? typeProvider.dynamicType));
           _unfinishedNullShorts.add(node.nullShortingTermination);
         }
       }
@@ -1774,11 +1792,13 @@
   }
 
   @override
-  DartType variableTypeFromInitializerType(DartType type) {
-    if (type.isDartCoreNull) {
-      return DynamicTypeImpl.instance;
+  SharedTypeView<DartType> variableTypeFromInitializerType(
+      SharedTypeView<DartType> type) {
+    DartType unwrapped = type.unwrapTypeView();
+    if (unwrapped.isDartCoreNull) {
+      return SharedTypeView(DynamicTypeImpl.instance);
     }
-    return typeSystem.demoteType(type);
+    return SharedTypeView(typeSystem.demoteType(unwrapped));
   }
 
   @override
@@ -1801,7 +1821,8 @@
       flowAnalysis.topLevelDeclaration_enter(node, null);
     }
     assert(flowAnalysis.flow != null);
-    var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
+    var whyNotPromotedList =
+        <Map<SharedTypeView<DartType>, NonPromotionReason> Function()>[];
     _annotationResolver.resolve(node, whyNotPromotedList);
     var arguments = node.arguments;
     if (arguments != null) {
@@ -1821,7 +1842,8 @@
     inferenceLogWriter?.enterExpression(node, contextType);
     checkUnreachableNode(node);
 
-    analyzeExpression(node.expression, UnknownInferredType.instance);
+    analyzeExpression(
+        node.expression, SharedTypeSchemaView(UnknownInferredType.instance));
     popRewrite();
 
     node.type.accept(this);
@@ -1855,7 +1877,8 @@
   @override
   void visitAssertInitializer(AssertInitializer node) {
     flowAnalysis.flow?.assert_begin();
-    analyzeExpression(node.condition, typeProvider.boolType);
+    analyzeExpression(
+        node.condition, SharedTypeSchemaView(typeProvider.boolType));
     popRewrite();
     boolExpressionVerifier.checkForNonBoolExpression(
       node.condition,
@@ -1872,7 +1895,8 @@
     inferenceLogWriter?.enterStatement(node);
     checkUnreachableNode(node);
     flowAnalysis.flow?.assert_begin();
-    analyzeExpression(node.condition, typeProvider.boolType);
+    analyzeExpression(
+        node.condition, SharedTypeSchemaView(typeProvider.boolType));
     popRewrite();
     boolExpressionVerifier.checkForNonBoolExpression(
       node.condition,
@@ -1948,14 +1972,16 @@
   }) {
     inferenceLogWriter?.enterExpression(node, contextType);
     checkUnreachableNode(node);
-    var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
+    var whyNotPromotedList =
+        <Map<SharedTypeView<DartType>, NonPromotionReason> Function()>[];
 
     var augmentation = enclosingAugmentation;
     var augmentationTarget = augmentation?.augmentationTarget;
 
     void resolveArgumentsOfInvalid() {
       for (var argument in node.arguments.arguments) {
-        analyzeExpression(argument, InvalidTypeImpl.instance);
+        analyzeExpression(
+            argument, SharedTypeSchemaView(InvalidTypeImpl.instance));
         popRewrite();
       }
     }
@@ -2042,7 +2068,8 @@
       {DartType contextType = UnknownInferredType.instance}) {
     inferenceLogWriter?.enterExpression(node, contextType);
     checkUnreachableNode(node);
-    analyzeExpression(node.expression, _createFutureOr(contextType));
+    analyzeExpression(
+        node.expression, SharedTypeSchemaView(_createFutureOr(contextType)));
     popRewrite();
     typeAnalyzer.visitAwaitExpression(node as AwaitExpressionImpl);
     _insertImplicitCallReference(
@@ -2113,15 +2140,17 @@
       {DartType contextType = UnknownInferredType.instance}) {
     inferenceLogWriter?.enterExpression(node, contextType);
     checkUnreachableNode(node);
-    analyzeExpression(node.target, contextType);
+    analyzeExpression(node.target, SharedTypeSchemaView(contextType));
     var targetType = node.target.staticType ?? typeProvider.dynamicType;
     popRewrite();
 
-    flowAnalysis.flow!.cascadeExpression_afterTarget(node.target, targetType,
+    flowAnalysis.flow!.cascadeExpression_afterTarget(
+        node.target, SharedTypeView(targetType),
         isNullAware: node.isNullAware);
 
     if (node.isNullAware) {
-      flowAnalysis.flow!.nullAwareAccess_rightBegin(node.target, targetType);
+      flowAnalysis.flow!
+          .nullAwareAccess_rightBegin(node.target, SharedTypeView(targetType));
       _unfinishedNullShorts.add(node.nullShortingTermination);
     }
 
@@ -2219,7 +2248,8 @@
     var flow = flowAnalysis.flow;
     flow?.conditional_conditionBegin();
 
-    analyzeExpression(node.condition, typeProvider.boolType);
+    analyzeExpression(
+        node.condition, SharedTypeSchemaView(typeProvider.boolType));
     condition = popRewrite()!;
     var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(condition);
     boolExpressionVerifier.checkForNonBoolCondition(condition,
@@ -2229,7 +2259,7 @@
       flow.conditional_thenBegin(condition, node);
       checkUnreachableNode(node.thenExpression);
     }
-    analyzeExpression(node.thenExpression, contextType);
+    analyzeExpression(node.thenExpression, SharedTypeSchemaView(contextType));
     popRewrite();
     nullSafetyDeadCodeVerifier.flowEnd(node.thenExpression);
 
@@ -2237,19 +2267,19 @@
 
     if (flow != null) {
       flow.conditional_elseBegin(
-          node.thenExpression, node.thenExpression.typeOrThrow);
+          node.thenExpression, SharedTypeView(node.thenExpression.typeOrThrow));
       checkUnreachableNode(elseExpression);
-      analyzeExpression(elseExpression, contextType);
+      analyzeExpression(elseExpression, SharedTypeSchemaView(contextType));
     } else {
-      analyzeExpression(elseExpression, contextType);
+      analyzeExpression(elseExpression, SharedTypeSchemaView(contextType));
     }
     elseExpression = popRewrite()!;
 
     typeAnalyzer.visitConditionalExpression(node as ConditionalExpressionImpl,
         contextType: contextType);
     if (flow != null) {
-      flow.conditional_end(
-          node, node.typeOrThrow, elseExpression, elseExpression.typeOrThrow);
+      flow.conditional_end(node, SharedTypeView(node.typeOrThrow),
+          elseExpression, SharedTypeView(elseExpression.typeOrThrow));
       nullSafetyDeadCodeVerifier.flowEnd(elseExpression);
     }
     _insertImplicitCallReference(node, contextType: contextType);
@@ -2320,7 +2350,7 @@
     fieldName.staticElement = fieldElement;
     var fieldType = fieldElement?.type ?? UnknownInferredType.instance;
     var expression = node.expression;
-    analyzeExpression(expression, fieldType);
+    analyzeExpression(expression, SharedTypeSchemaView(fieldType));
     expression = popRewrite()!;
     var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(expression);
     if (fieldElement != null) {
@@ -2377,8 +2407,10 @@
     node.parameter.accept(this);
     var defaultValue = node.defaultValue;
     if (defaultValue != null) {
-      analyzeExpression(defaultValue,
-          node.declaredElement?.type ?? UnknownInferredType.instance);
+      analyzeExpression(
+          defaultValue,
+          SharedTypeSchemaView(
+              node.declaredElement?.type ?? UnknownInferredType.instance));
       popRewrite();
     }
     ParameterElement element = node.declaredElement!;
@@ -2399,7 +2431,7 @@
     node.body.accept(this);
 
     flowAnalysis.flow?.doStatement_conditionBegin();
-    analyzeExpression(condition, typeProvider.boolType);
+    analyzeExpression(condition, SharedTypeSchemaView(typeProvider.boolType));
     condition = popRewrite()!;
     var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(condition);
     boolExpressionVerifier.checkForNonBoolCondition(condition,
@@ -2514,13 +2546,14 @@
       for (var argument in argumentList.arguments) {
         analyzeExpression(
             argument,
-            argument.staticParameterElement?.type ??
-                UnknownInferredType.instance);
+            SharedTypeSchemaView(argument.staticParameterElement?.type ??
+                UnknownInferredType.instance));
         popRewrite();
       }
       arguments.typeArguments?.accept(this);
 
-      var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
+      var whyNotPromotedList =
+          <Map<SharedTypeView<DartType>, NonPromotionReason> Function()>[];
       checkForArgumentTypesNotAssignableInList(
           argumentList, whyNotPromotedList);
     }
@@ -2567,7 +2600,8 @@
       checkUnreachableNode(node);
       analyzeExpression(
         node.expression,
-        bodyContext.contextType ?? UnknownInferredType.instance,
+        SharedTypeSchemaView(
+            bodyContext.contextType ?? UnknownInferredType.instance),
       );
       popRewrite();
 
@@ -2617,7 +2651,8 @@
   void visitExtensionOverride(covariant ExtensionOverrideImpl node,
       {DartType contextType = UnknownInferredType.instance}) {
     inferenceLogWriter?.enterExtensionOverride(node, contextType);
-    var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
+    var whyNotPromotedList =
+        <Map<SharedTypeView<DartType>, NonPromotionReason> Function()>[];
     node.typeArguments?.accept(this);
 
     var receiverContextType =
@@ -2746,7 +2781,8 @@
       node.documentationComment?.accept(this);
       node.metadata.accept(this);
       node.returnType?.accept(this);
-      analyzeExpression(node.functionExpression, functionType);
+      analyzeExpression(
+          node.functionExpression, SharedTypeSchemaView(functionType));
       popRewrite();
       elementResolver.visitFunctionDeclaration(node);
     } finally {
@@ -2800,10 +2836,12 @@
     DartType contextType = UnknownInferredType.instance,
   }) {
     inferenceLogWriter?.enterExpression(node, contextType);
-    analyzeExpression(node.function, UnknownInferredType.instance);
+    analyzeExpression(
+        node.function, SharedTypeSchemaView(UnknownInferredType.instance));
     node.function = popRewrite()!;
 
-    var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
+    var whyNotPromotedList =
+        <Map<SharedTypeView<DartType>, NonPromotionReason> Function()>[];
     _functionExpressionInvocationResolver.resolve(node, whyNotPromotedList,
         contextType: contextType);
     nullShortingTermination(node);
@@ -2927,7 +2965,8 @@
   @override
   void visitImplicitCallReference(ImplicitCallReference node) {
     checkUnreachableNode(node);
-    analyzeExpression(node.expression, UnknownInferredType.instance);
+    analyzeExpression(
+        node.expression, SharedTypeSchemaView(UnknownInferredType.instance));
     popRewrite();
     node.typeArguments?.accept(this);
   }
@@ -2947,7 +2986,8 @@
 
     var target = node.target;
     if (target != null) {
-      analyzeExpression(target, UnknownInferredType.instance);
+      analyzeExpression(
+          target, SharedTypeSchemaView(UnknownInferredType.instance));
       popRewrite();
     }
     var targetType = node.realTarget.staticType;
@@ -2963,7 +3003,8 @@
     var element = result.readElement;
     node.staticElement = element as MethodElement?;
 
-    analyzeExpression(node.index, result.indexContextType);
+    analyzeExpression(
+        node.index, SharedTypeSchemaView(result.indexContextType));
     popRewrite();
     var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(node.index);
     checkIndexExpressionIndex(
@@ -3033,7 +3074,8 @@
     inferenceLogWriter?.enterExpression(node, contextType);
     checkUnreachableNode(node);
 
-    analyzeExpression(node.expression, UnknownInferredType.instance);
+    analyzeExpression(
+        node.expression, SharedTypeSchemaView(UnknownInferredType.instance));
     popRewrite();
 
     node.type.accept(this);
@@ -3087,11 +3129,13 @@
       {CollectionLiteralContext? context}) {
     inferenceLogWriter?.enterElement(node);
     checkUnreachableNode(node);
-    analyzeExpression(
-        node.key, context?.keyType ?? UnknownInferredType.instance);
+    analyzeExpression(node.key,
+        SharedTypeSchemaView(context?.keyType ?? UnknownInferredType.instance));
     popRewrite();
     analyzeExpression(
-        node.value, context?.valueType ?? UnknownInferredType.instance);
+        node.value,
+        SharedTypeSchemaView(
+            context?.valueType ?? UnknownInferredType.instance));
     popRewrite();
     inferenceLogWriter?.exitElement(node);
   }
@@ -3145,7 +3189,8 @@
       {DartType contextType = UnknownInferredType.instance}) {
     inferenceLogWriter?.enterExpression(node, contextType);
     checkUnreachableNode(node);
-    var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
+    var whyNotPromotedList =
+        <Map<SharedTypeView<DartType>, NonPromotionReason> Function()>[];
     var target = node.target;
     target?.accept(this);
     target = node.target;
@@ -3158,7 +3203,9 @@
           // `?.` to access static methods is equivalent to `.`, so do nothing.
         } else {
           flow.nullAwareAccess_rightBegin(
-              target, node.realTarget!.staticType ?? typeProvider.dynamicType);
+              target,
+              SharedTypeView(
+                  node.realTarget!.staticType ?? typeProvider.dynamicType));
           _unfinishedNullShorts.add(node.nullShortingTermination);
         }
       }
@@ -3216,7 +3263,7 @@
     inferenceLogWriter?.enterExpression(node, contextType);
     checkUnreachableNode(node);
     node.name.accept(this);
-    analyzeExpression(node.expression, contextType);
+    analyzeExpression(node.expression, SharedTypeSchemaView(contextType));
     popRewrite();
     typeAnalyzer.visitNamedExpression(node as NamedExpressionImpl);
     // Any "why not promoted" information that flow analysis had associated with
@@ -3259,7 +3306,8 @@
       elementType = typeSystem.makeNullable(elementType);
     }
 
-    analyzeExpression(node.value, elementType ?? UnknownInferredType.instance);
+    analyzeExpression(node.value,
+        SharedTypeSchemaView(elementType ?? UnknownInferredType.instance));
 
     inferenceLogWriter?.exitElement(node);
   }
@@ -3270,7 +3318,7 @@
     inferenceLogWriter?.enterExpression(node, contextType);
     node.visitChildren(this);
     typeAnalyzer.visitNullLiteral(node as NullLiteralImpl);
-    flowAnalysis.flow?.nullLiteral(node, node.typeOrThrow);
+    flowAnalysis.flow?.nullLiteral(node, SharedTypeView(node.typeOrThrow));
     checkUnreachableNode(node);
     inferenceLogWriter?.exitExpression(node);
   }
@@ -3280,7 +3328,7 @@
       {DartType contextType = UnknownInferredType.instance}) {
     inferenceLogWriter?.enterExpression(node, contextType);
     checkUnreachableNode(node);
-    analyzeExpression(node.expression, contextType);
+    analyzeExpression(node.expression, SharedTypeSchemaView(contextType));
     popRewrite();
     typeAnalyzer
         .visitParenthesizedExpression(node as ParenthesizedExpressionImpl);
@@ -3309,8 +3357,10 @@
     checkUnreachableNode(node);
     var analysisResult =
         analyzePatternAssignment(node, node.pattern, node.expression);
-    node.patternTypeSchema = analysisResult.patternSchema;
-    node.recordStaticType(analysisResult.resolveShorting(), resolver: this);
+    node.patternTypeSchema =
+        analysisResult.patternSchema.unwrapTypeSchemaView();
+    node.recordStaticType(analysisResult.resolveShorting().unwrapTypeView(),
+        resolver: this);
     popRewrite(); // expression
     inferenceLogWriter?.exitExpression(node);
   }
@@ -3323,7 +3373,7 @@
             node, node.pattern, node.expression,
             isFinal: node.keyword.keyword == Keyword.FINAL)
         .patternSchema;
-    node.patternTypeSchema = patternSchema;
+    node.patternTypeSchema = patternSchema.unwrapTypeSchemaView();
     popRewrite(); // expression
   }
 
@@ -3398,7 +3448,8 @@
 
     var target = node.target;
     if (target != null) {
-      analyzeExpression(target, UnknownInferredType.instance);
+      analyzeExpression(
+          target, SharedTypeSchemaView(UnknownInferredType.instance));
       popRewrite();
     }
 
@@ -3503,7 +3554,8 @@
     // because it needs to be visited in the context of the constructor
     // invocation.
     //
-    var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
+    var whyNotPromotedList =
+        <Map<SharedTypeView<DartType>, NonPromotionReason> Function()>[];
     elementResolver.visitRedirectingConstructorInvocation(
         node as RedirectingConstructorInvocationImpl);
     InvocationInferrer<RedirectingConstructorInvocationImpl>(
@@ -3546,7 +3598,8 @@
     if (expression != null) {
       analyzeExpression(
         expression,
-        bodyContext?.contextType ?? UnknownInferredType.instance,
+        SharedTypeSchemaView(
+            bodyContext?.contextType ?? UnknownInferredType.instance),
       );
       // Pick up the expression again in case it was rewritten.
       expression = popRewrite();
@@ -3607,8 +3660,8 @@
       iterableType = typeSystem.makeNullable(iterableType);
     }
     checkUnreachableNode(node);
-    analyzeExpression(
-        node.expression, iterableType ?? UnknownInferredType.instance);
+    analyzeExpression(node.expression,
+        SharedTypeSchemaView(iterableType ?? UnknownInferredType.instance));
     popRewrite();
 
     if (!node.isNullAware) {
@@ -3638,7 +3691,8 @@
     // because it needs to be visited in the context of the constructor
     // invocation.
     //
-    var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
+    var whyNotPromotedList =
+        <Map<SharedTypeView<DartType>, NonPromotionReason> Function()>[];
     elementResolver.visitSuperConstructorInvocation(
         node as SuperConstructorInvocationImpl);
     InvocationInferrer<SuperConstructorInvocationImpl>(
@@ -3674,7 +3728,7 @@
     covariant SwitchExpressionImpl node, {
     DartType contextType = UnknownInferredType.instance,
   }) {
-    analyzeExpression(node, contextType);
+    analyzeExpression(node, SharedTypeSchemaView(contextType));
     popRewrite();
   }
 
@@ -3719,7 +3773,8 @@
       {DartType contextType = UnknownInferredType.instance}) {
     inferenceLogWriter?.enterExpression(node, contextType);
     checkUnreachableNode(node);
-    analyzeExpression(node.expression, typeProvider.objectType);
+    analyzeExpression(
+        node.expression, SharedTypeSchemaView(typeProvider.objectType));
     popRewrite();
     typeAnalyzer.visitThrowExpression(node as ThrowExpressionImpl);
     flowAnalysis.flow?.handleExit();
@@ -3831,8 +3886,8 @@
       var parent = node.parent as VariableDeclarationList;
       var declaredType = parent.type;
       var initializerStaticType = initializer.typeOrThrow;
-      flowAnalysis.flow?.initialize(
-          element as PromotableElement, initializerStaticType, initializer,
+      flowAnalysis.flow?.initialize(element as PromotableElement,
+          SharedTypeView(initializerStaticType), initializer,
           isFinal: parent.isFinal,
           isLate: parent.isLate,
           isImplicitlyTyped: declaredType == null);
@@ -3865,7 +3920,7 @@
     Expression condition = node.condition;
 
     flowAnalysis.flow?.whileStatement_conditionBegin(node);
-    analyzeExpression(condition, typeProvider.boolType);
+    analyzeExpression(condition, SharedTypeSchemaView(typeProvider.boolType));
     condition = popRewrite()!;
     var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(condition);
 
@@ -4088,8 +4143,10 @@
           target.staticElement is InterfaceElement) {
         // `?.` to access static methods is equivalent to `.`, so do nothing.
       } else {
-        flowAnalysis.flow!.nullAwareAccess_rightBegin(function,
-            function.realTarget.staticType ?? typeProvider.dynamicType);
+        flowAnalysis.flow!.nullAwareAccess_rightBegin(
+            function,
+            SharedTypeView(
+                function.realTarget.staticType ?? typeProvider.dynamicType));
         _unfinishedNullShorts.add(node.nullShortingTermination);
       }
     }
@@ -5455,7 +5512,7 @@
 class _WhyNotPromotedVisitor
     implements
         NonPromotionReasonVisitor<List<DiagnosticMessage>, AstNode,
-            PromotableElement, DartType> {
+            PromotableElement, SharedTypeView<DartType>> {
   final Source source;
 
   final SyntacticEntity _errorEntity;
@@ -5484,11 +5541,11 @@
 
   @override
   List<DiagnosticMessage> visitPropertyNotPromotedForInherentReason(
-      PropertyNotPromotedForInherentReason<DartType> reason) {
+      PropertyNotPromotedForInherentReason<SharedTypeView<DartType>> reason) {
     var receiverElement = reason.propertyMember;
     if (receiverElement is PropertyAccessorElement) {
       var property = propertyReference = receiverElement;
-      propertyType = reason.staticType;
+      propertyType = reason.staticType.unwrapTypeView();
       var propertyName = reason.propertyName;
       String message = switch (reason.whyNotPromotable) {
         shared.PropertyNonPromotabilityReason.isNotField =>
@@ -5522,11 +5579,12 @@
 
   @override
   List<DiagnosticMessage> visitPropertyNotPromotedForNonInherentReason(
-      PropertyNotPromotedForNonInherentReason<DartType> reason) {
+      PropertyNotPromotedForNonInherentReason<SharedTypeView<DartType>>
+          reason) {
     var receiverElement = reason.propertyMember;
     if (receiverElement is PropertyAccessorElement) {
       var property = propertyReference = receiverElement;
-      propertyType = reason.staticType;
+      propertyType = reason.staticType.unwrapTypeView();
       var propertyName = reason.propertyName;
       var library = receiverElement.library as LibraryElementImpl;
       var fieldNonPromotabilityInfo = library.fieldNameNonPromotabilityInfo;
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 376a948..b1f913c 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.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:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
@@ -238,8 +239,9 @@
 
   void visitSuperExpression(covariant SuperExpressionImpl node) {
     var thisType = _resolver.thisType;
-    _resolver.flowAnalysis.flow
-        ?.thisOrSuper(node, thisType ?? _dynamicType, isSuper: true);
+    _resolver.flowAnalysis.flow?.thisOrSuper(
+        node, SharedTypeView(thisType ?? _dynamicType),
+        isSuper: true);
     if (thisType == null ||
         node.thisOrAncestorOfType<ExtensionDeclaration>() != null) {
       // TODO(brianwilkerson): Report this error if it hasn't already been
@@ -258,8 +260,9 @@
   /// interface of the immediately enclosing class.</blockquote>
   void visitThisExpression(covariant ThisExpressionImpl node) {
     var thisType = _resolver.thisType;
-    _resolver.flowAnalysis.flow
-        ?.thisOrSuper(node, thisType ?? _dynamicType, isSuper: false);
+    _resolver.flowAnalysis.flow?.thisOrSuper(
+        node, SharedTypeView(thisType ?? _dynamicType),
+        isSuper: false);
     if (thisType == null) {
       // TODO(brianwilkerson): Report this error if it hasn't already been
       // reported.
diff --git a/pkg/analyzer/lib/src/summary2/ast_resolver.dart b/pkg/analyzer/lib/src/summary2/ast_resolver.dart
index 6e3d1eb..cc8dbbf 100644
--- a/pkg/analyzer/lib/src/summary2/ast_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_resolver.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:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/scope.dart';
@@ -110,7 +111,7 @@
     node.accept(_scopeResolverVisitor);
     _prepareEnclosingDeclarations();
     _flowAnalysis.topLevelDeclaration_enter(node.parent!, null);
-    _resolverVisitor.analyzeExpression(node, contextType);
+    _resolverVisitor.analyzeExpression(node, SharedTypeSchemaView(contextType));
     _resolverVisitor.popRewrite();
     _resolverVisitor.checkIdle();
     _flowAnalysis.topLevelDeclaration_exit();
diff --git a/pkg/analyzer/test/id_tests/type_constraint_generation_test.dart b/pkg/analyzer/test/id_tests/type_constraint_generation_test.dart
index 57e78bd..72e4e74 100644
--- a/pkg/analyzer/test/id_tests/type_constraint_generation_test.dart
+++ b/pkg/analyzer/test/id_tests/type_constraint_generation_test.dart
@@ -22,7 +22,7 @@
           'type_constraint_generation/data'));
   return runTests<
           List<
-              GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
+              GeneratedTypeConstraint<DartType, TypeParameterElement,
                   PromotableElement>>>(dataDir,
       args: args,
       createUriForFileName: createUriForFileName,
@@ -33,14 +33,14 @@
 
 class _TypeConstraintGenerationDataComputer extends DataComputer<
     List<
-        GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
+        GeneratedTypeConstraint<DartType, TypeParameterElement,
             PromotableElement>>> {
   const _TypeConstraintGenerationDataComputer();
 
   @override
   DataInterpreter<
       List<
-          GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
+          GeneratedTypeConstraint<DartType, TypeParameterElement,
               PromotableElement>>> get dataValidator =>
       const _TypeConstraintGenerationDataInterpreter();
 
@@ -55,8 +55,8 @@
               Id,
               ActualData<
                   List<
-                      GeneratedTypeConstraint<DartType, DartType,
-                          TypeParameterElement, PromotableElement>>>>
+                      GeneratedTypeConstraint<DartType, TypeParameterElement,
+                          PromotableElement>>>>
           actualMap) {
     _TypeConstraintGenerationDataExtractor(
             testingData.uriToTypeConstraintGenerationData[
@@ -69,7 +69,7 @@
 
 class _TypeConstraintGenerationDataExtractor extends AstDataExtractor<
     List<
-        GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
+        GeneratedTypeConstraint<DartType, TypeParameterElement,
             PromotableElement>>> {
   final TypeConstraintGenerationDataForTesting dataForTesting;
 
@@ -78,7 +78,7 @@
 
   @override
   List<
-      GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
+      GeneratedTypeConstraint<DartType, TypeParameterElement,
           PromotableElement>>? computeNodeValue(Id id, AstNode node) {
     return dataForTesting.generatedTypeConstraints[node];
   }
@@ -88,14 +88,14 @@
     implements
         DataInterpreter<
             List<
-                GeneratedTypeConstraint<DartType, DartType,
-                    TypeParameterElement, PromotableElement>>> {
+                GeneratedTypeConstraint<DartType, TypeParameterElement,
+                    PromotableElement>>> {
   const _TypeConstraintGenerationDataInterpreter();
 
   @override
   String getText(
       List<
-              GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
+              GeneratedTypeConstraint<DartType, TypeParameterElement,
                   PromotableElement>>
           actualData,
       [String? indentation]) {
@@ -120,7 +120,7 @@
   @override
   String? isAsExpected(
       List<
-              GeneratedTypeConstraint<DartType, DartType, TypeParameterElement,
+              GeneratedTypeConstraint<DartType, TypeParameterElement,
                   PromotableElement>>
           actualData,
       String? expectedData) {
@@ -135,8 +135,8 @@
   @override
   bool isEmpty(
           List<
-                  GeneratedTypeConstraint<DartType, DartType,
-                      TypeParameterElement, PromotableElement>>?
+                  GeneratedTypeConstraint<DartType, TypeParameterElement,
+                      PromotableElement>>?
               actualData) =>
       actualData == null || actualData.isEmpty;
 }
diff --git a/pkg/front_end/lib/src/kernel/body_builder.dart b/pkg/front_end/lib/src/kernel/body_builder.dart
index d18be49b..c1255ce 100644
--- a/pkg/front_end/lib/src/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/kernel/body_builder.dart
@@ -32,6 +32,7 @@
 import 'package:_fe_analyzer_shared/src/scanner/token_impl.dart'
     show isBinaryOperator, isMinusOperator, isUserDefinableOperator;
 import 'package:_fe_analyzer_shared/src/type_inference/assigned_variables.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:_fe_analyzer_shared/src/util/link.dart';
 import 'package:_fe_analyzer_shared/src/util/value_kind.dart';
 import 'package:kernel/ast.dart';
@@ -1192,15 +1193,17 @@
 
     FunctionNode function = _context.function;
     if (thisVariable != null) {
-      typeInferrer.flowAnalysis
-          .declare(thisVariable!, thisVariable!.type, initialized: true);
+      typeInferrer.flowAnalysis.declare(
+          thisVariable!, new SharedTypeView(thisVariable!.type),
+          initialized: true);
     }
     if (formals?.parameters != null) {
       for (int i = 0; i < formals!.parameters!.length; i++) {
         FormalParameterBuilder parameter = formals.parameters![i];
         VariableDeclaration variable = parameter.variable!;
-        typeInferrer.flowAnalysis
-            .declare(variable, variable.type, initialized: true);
+        typeInferrer.flowAnalysis.declare(
+            variable, new SharedTypeView(variable.type),
+            initialized: true);
       }
       for (int i = 0; i < formals.parameters!.length; i++) {
         FormalParameterBuilder parameter = formals.parameters![i];
@@ -1654,8 +1657,9 @@
     if (formals != null) {
       for (int i = 0; i < formals.length; i++) {
         VariableDeclaration variable = formals[i].variable!;
-        typeInferrer.flowAnalysis
-            .declare(variable, variable.type, initialized: true);
+        typeInferrer.flowAnalysis.declare(
+            variable, new SharedTypeView(variable.type),
+            initialized: true);
       }
     }
     InferredFunctionBody inferredFunctionBody = typeInferrer.inferFunctionBody(
@@ -1784,7 +1788,8 @@
         // around a failure in
         // co19/Language/Expressions/Postfix_Expressions/conditional_increment_t02;
         // fix this.
-        typeInferrer.flowAnalysis.declare(variable, variable.type,
+        typeInferrer.flowAnalysis.declare(
+            variable, new SharedTypeView(variable.type),
             initialized: true, skipDuplicateCheck: true);
       }
     }
diff --git a/pkg/front_end/lib/src/kernel/internal_ast.dart b/pkg/front_end/lib/src/kernel/internal_ast.dart
index b5b0bd4..5daaa79 100644
--- a/pkg/front_end/lib/src/kernel/internal_ast.dart
+++ b/pkg/front_end/lib/src/kernel/internal_ast.dart
@@ -21,6 +21,7 @@
 
 import 'package:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart'
     as shared;
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/names.dart';
 import 'package:kernel/src/printer.dart';
@@ -33,8 +34,8 @@
 import '../type_inference/inference_visitor.dart';
 import '../type_inference/type_schema.dart' show UnknownType;
 
-typedef SharedMatchContext = shared
-    .MatchContext<TreeNode, Expression, Pattern, DartType, VariableDeclaration>;
+typedef SharedMatchContext = shared.MatchContext<TreeNode, Expression, Pattern,
+    SharedTypeView<DartType>, VariableDeclaration>;
 
 int getExtensionTypeParameterCount(Arguments arguments) {
   if (arguments is ArgumentsImpl) {
diff --git a/pkg/front_end/lib/src/type_inference/for_in.dart b/pkg/front_end/lib/src/type_inference/for_in.dart
index 794d9ab..3165fcf 100644
--- a/pkg/front_end/lib/src/type_inference/for_in.dart
+++ b/pkg/front_end/lib/src/type_inference/for_in.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:kernel/ast.dart';
 
 import '../base/instrumentation.dart' show InstrumentationValueForMember;
@@ -44,7 +45,8 @@
   @override
   DartType computeElementType(InferenceVisitorBase visitor) {
     VariableDeclaration variable = variableSet.variable;
-    DartType? promotedType = visitor.flowAnalysis.promotedType(variable);
+    DartType? promotedType =
+        visitor.flowAnalysis.promotedType(variable)?.unwrapTypeView();
     return promotedType ?? variable.type;
   }
 
@@ -62,8 +64,8 @@
         isVoidAllowed: true);
 
     variableSet.value = rhs..parent = variableSet;
-    visitor.flowAnalysis
-        .write(variableSet, variableSet.variable, rhsType, null);
+    visitor.flowAnalysis.write(
+        variableSet, variableSet.variable, new SharedTypeView(rhsType), null);
     return variableSet;
   }
 }
diff --git a/pkg/front_end/lib/src/type_inference/inference_results.dart b/pkg/front_end/lib/src/type_inference/inference_results.dart
index e51ff0b..1ece2b4 100644
--- a/pkg/front_end/lib/src/type_inference/inference_results.dart
+++ b/pkg/front_end/lib/src/type_inference/inference_results.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:_fe_analyzer_shared/src/util/link.dart';
 import 'package:kernel/ast.dart';
 
@@ -397,14 +398,15 @@
     // Ensure the initializer of [_nullAwareVariable] is promoted to
     // non-nullable.
     _inferrer.flowAnalysis.nullAwareAccess_rightBegin(
-        _nullAwareVariable.initializer, _nullAwareVariable.type);
+        _nullAwareVariable.initializer,
+        new SharedTypeView(_nullAwareVariable.type));
     // Ensure [_nullAwareVariable] is promoted to non-nullable.
     // TODO(johnniwinther): Avoid creating a [VariableGet] to promote the
     // variable.
     VariableGet read = new VariableGet(_nullAwareVariable);
     _inferrer.flowAnalysis.variableRead(read, _nullAwareVariable);
-    _inferrer.flowAnalysis
-        .nullAwareAccess_rightBegin(read, _nullAwareVariable.type);
+    _inferrer.flowAnalysis.nullAwareAccess_rightBegin(
+        read, new SharedTypeView(_nullAwareVariable.type));
   }
 
   /// Creates the null-guarded application of [nullAwareAction] with the
diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/type_inference/inference_visitor.dart
index 3279666..0c43bb9 100644
--- a/pkg/front_end/lib/src/type_inference/inference_visitor.dart
+++ b/pkg/front_end/lib/src/type_inference/inference_visitor.dart
@@ -11,6 +11,7 @@
     as shared;
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer.dart'
     hide MapPatternEntry;
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:_fe_analyzer_shared/src/util/link.dart';
 import 'package:_fe_analyzer_shared/src/util/null_value.dart';
 import 'package:_fe_analyzer_shared/src/util/stack_checker.dart';
@@ -104,14 +105,13 @@
 class InferenceVisitorImpl extends InferenceVisitorBase
     with
         TypeAnalyzer<
+            DartType,
             TreeNode,
             Statement,
             Expression,
             VariableDeclaration,
-            DartType,
             Pattern,
             InvalidExpression,
-            DartType,
             StructuralParameter,
             TypeDeclarationType,
             TypeDeclaration>,
@@ -820,7 +820,7 @@
     ExpressionInferenceResult operandResult =
         inferExpression(node.operand, const UnknownType(), isVoidAllowed: true);
     node.operand = operandResult.expression..parent = node;
-    flowAnalysis.asExpression_end(node.operand, node.type);
+    flowAnalysis.asExpression_end(node.operand, new SharedTypeView(node.type));
     return new ExpressionInferenceResult(node.type, node);
   }
 
@@ -983,7 +983,7 @@
     node.variable.initializer = result.expression..parent = node.variable;
     node.variable.type = result.inferredType;
     flowAnalysis.cascadeExpression_afterTarget(
-        result.expression, result.inferredType,
+        result.expression, new SharedTypeView(result.inferredType),
         isNullAware: node.isNullAware);
     NullAwareGuard? nullAwareGuard;
     if (node.isNullAware) {
@@ -1072,7 +1072,8 @@
     DartType t1 = thenResult.inferredType;
 
     // - Let `T2` be the type of `e2` inferred with context type `K`
-    flowAnalysis.conditional_elseBegin(node.then, thenResult.inferredType);
+    flowAnalysis.conditional_elseBegin(
+        node.then, new SharedTypeView(thenResult.inferredType));
     bool isOtherwiseReachable = flowAnalysis.isReachable;
     ExpressionInferenceResult otherwiseResult =
         inferExpression(node.otherwise, typeContext, isVoidAllowed: true);
@@ -1109,8 +1110,8 @@
       inferredType = t;
     }
 
-    flowAnalysis.conditional_end(
-        node, inferredType, node.otherwise, otherwiseResult.inferredType);
+    flowAnalysis.conditional_end(node, new SharedTypeView(inferredType),
+        node.otherwise, new SharedTypeView(otherwiseResult.inferredType));
     node.staticType = inferredType;
     return new ExpressionInferenceResult(inferredType, node);
   }
@@ -1605,7 +1606,8 @@
 
     // This is matched by the call to [forEach_end] in
     // [inferElement], [inferMapEntry] or [inferForInStatement].
-    flowAnalysis.declare(variable, variable.type, initialized: true);
+    flowAnalysis.declare(variable, new SharedTypeView(variable.type),
+        initialized: true);
     flowAnalysis.forEach_bodyBegin(node);
 
     VariableDeclaration tempVariable = new VariableDeclaration(null,
@@ -1724,7 +1726,8 @@
     flowAnalysis.forEach_bodyBegin(node);
     syntheticAssignment = forInVariable.inferAssignment(this, inferredType);
     if (syntheticAssignment is VariableSet) {
-      flowAnalysis.write(node, variable, inferredType, null);
+      flowAnalysis.write(
+          node, variable, new SharedTypeView(inferredType), null);
     }
     if (expressionEffects != null) {
       StatementInferenceResult result = inferStatement(expressionEffects);
@@ -1757,7 +1760,8 @@
             pattern: patternVariableDeclaration.pattern,
             expression: iterable,
             dispatchBody: () {});
-    patternVariableDeclaration.matchedValueType = result.elementType;
+    patternVariableDeclaration.matchedValueType =
+        result.elementType.unwrapTypeView();
     if (result.patternForInExpressionIsNotIterableError != null) {
       assert(libraryBuilder.loader.assertProblemReportedElsewhere(
           "InferenceVisitorImpl._handlePatternForIn: "
@@ -1785,13 +1789,13 @@
     ForInVariable forInVariable =
         new PatternVariableDeclarationForInVariable(patternVariableDeclaration);
 
-    variable.type = result.elementType;
+    variable.type = result.elementType.unwrapTypeView();
     iterable = ensureAssignable(
         wrapType(
             const DynamicType(),
             isAsync ? coreTypes.streamClass : coreTypes.iterableClass,
             Nullability.nonNullable),
-        result.expressionType,
+        result.expressionType.unwrapTypeView(),
         iterable,
         errorTemplate: templateForInLoopTypeNotIterable,
         nullabilityErrorTemplate: templateForInLoopTypeNotIterableNullability,
@@ -1800,8 +1804,8 @@
     // This is matched by the call to [forEach_end] in
     // [inferElement], [inferMapEntry] or [inferForInStatement].
     flowAnalysis.forEach_bodyBegin(node);
-    syntheticAssignment =
-        forInVariable.inferAssignment(this, result.elementType);
+    syntheticAssignment = forInVariable.inferAssignment(
+        this, result.elementType.unwrapTypeView());
     if (syntheticAssignment is VariableSet) {
       // Coverage-ignore-block(suite): Not run.
       flowAnalysis.write(node, variable, result.elementType, null);
@@ -1989,7 +1993,8 @@
           inferredType.returnType;
     }
     variable.type = inferredType;
-    flowAnalysis.declare(variable, variable.type, initialized: true);
+    flowAnalysis.declare(variable, new SharedTypeView(variable.type),
+        initialized: true);
     flowAnalysis.functionExpression_end();
     _inTryOrLocalFunction = oldInTryOrLocalFunction;
     return const StatementInferenceResult();
@@ -2027,7 +2032,7 @@
     // This ends any shorting in `node.left`.
     Expression left = lhsResult.expression;
 
-    flowAnalysis.ifNullExpression_rightBegin(node.left, t1);
+    flowAnalysis.ifNullExpression_rightBegin(node.left, new SharedTypeView(t1));
 
     // - Let `T2` be the type of `e2` inferred with context type `J`, where:
     //   - If `K` is `_` or `dynamic`, `J = T1`.
@@ -2134,7 +2139,8 @@
         variable.name!: variable
     });
 
-    node.matchedValueType = analysisResult.matchedExpressionType;
+    node.matchedValueType =
+        analysisResult.matchedExpressionType.unwrapTypeView();
 
     assert(checkStack(node, stackBase, [
       /* ifFalse = */ ValueKinds.StatementOrNull,
@@ -2266,7 +2272,7 @@
         isVoidAllowed: false);
     node.operand = operandResult.expression..parent = node;
     flowAnalysis.isExpression_end(
-        node, node.operand, /*isNot:*/ false, node.type);
+        node, node.operand, /*isNot:*/ false, new SharedTypeView(node.type));
     return new ExpressionInferenceResult(
         coreTypes.boolRawType(Nullability.nonNullable), node);
   }
@@ -2482,7 +2488,8 @@
             ifFalse: element.otherwise,
             context: context);
 
-    element.matchedValueType = analysisResult.matchedExpressionType;
+    element.matchedValueType =
+        analysisResult.matchedExpressionType.unwrapTypeView();
 
     assert(checkStack(element, stackBase, [
       /* ifFalse = */ ValueKinds.ExpressionOrNull,
@@ -2555,14 +2562,14 @@
 
     PatternVariableDeclaration patternVariableDeclaration =
         element.patternVariableDeclaration;
-    PatternVariableDeclarationAnalysisResult<DartType, DartType>
-        analysisResult = analyzePatternVariableDeclaration(
+    PatternVariableDeclarationAnalysisResult<DartType> analysisResult =
+        analyzePatternVariableDeclaration(
             patternVariableDeclaration,
             patternVariableDeclaration.pattern,
             patternVariableDeclaration.initializer,
             isFinal: patternVariableDeclaration.isFinal);
     patternVariableDeclaration.matchedValueType =
-        analysisResult.initializerType;
+        analysisResult.initializerType.unwrapTypeView();
 
     assert(checkStack(element, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -4743,7 +4750,8 @@
               actualTypeForSet, actualTypesForSet[lengthForSet - 1]);
     }
 
-    entry.matchedValueType = analysisResult.matchedExpressionType;
+    entry.matchedValueType =
+        analysisResult.matchedExpressionType.unwrapTypeView();
 
     assert(checkStack(entry, stackBase, [
       /* ifFalse = */ unionOfKinds(
@@ -4816,14 +4824,14 @@
 
     PatternVariableDeclaration patternVariableDeclaration =
         entry.patternVariableDeclaration;
-    PatternVariableDeclarationAnalysisResult<DartType, DartType>
-        analysisResult = analyzePatternVariableDeclaration(
+    PatternVariableDeclarationAnalysisResult<DartType> analysisResult =
+        analyzePatternVariableDeclaration(
             patternVariableDeclaration,
             patternVariableDeclaration.pattern,
             patternVariableDeclaration.initializer,
             isFinal: patternVariableDeclaration.isFinal);
     patternVariableDeclaration.matchedValueType =
-        analysisResult.initializerType;
+        analysisResult.initializerType.unwrapTypeView();
 
     assert(checkStack(entry, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -5599,7 +5607,9 @@
 
     node.operand = operand..parent = node;
     flowAnalysis.nonNullAssert_end(node.operand);
-    DartType nonNullableResultType = operations.promoteToNonNull(operandType);
+    DartType nonNullableResultType = operations
+        .promoteToNonNull(new SharedTypeView(operandType))
+        .unwrapTypeView();
     return createNullAwareExpressionInferenceResult(
         nonNullableResultType, node, nullAwareGuards);
   }
@@ -5801,7 +5811,8 @@
         isSetter: true, instrumented: true, includeExtensionMethods: true);
     DartType writeContext = writeTarget.getSetterType(this);
 
-    flowAnalysis.ifNullExpression_rightBegin(read, readType);
+    flowAnalysis.ifNullExpression_rightBegin(
+        read, new SharedTypeView(readType));
     ExpressionInferenceResult rhsResult =
         inferExpression(node.rhs, writeContext, isVoidAllowed: true);
     flowAnalysis.ifNullExpression_end();
@@ -5913,7 +5924,8 @@
     Expression read = readResult.nullAwareAction;
     DartType readType = readResult.nullAwareActionType;
 
-    flowAnalysis.ifNullExpression_rightBegin(read, readType);
+    flowAnalysis.ifNullExpression_rightBegin(
+        read, new SharedTypeView(readType));
     ExpressionInferenceResult writeResult =
         inferExpression(node.write, typeContext, isVoidAllowed: true);
     flowAnalysis.ifNullExpression_end();
@@ -6257,8 +6269,8 @@
 
     VariableDeclaration? indexVariable;
     Expression readIndex = indexResult.expression;
-    Map<DartType, NonPromotionReason> Function() whyNotPromotedIndex =
-        flowAnalysis.whyNotPromoted(readIndex);
+    Map<SharedTypeView<DartType>, NonPromotionReason> Function()
+        whyNotPromotedIndex = flowAnalysis.whyNotPromoted(readIndex);
     Expression writeIndex;
     if (isPureExpression(readIndex)) {
       writeIndex = clonePureExpression(readIndex);
@@ -6282,7 +6294,8 @@
         checkKind);
     Expression read = readResult.expression;
     DartType readType = readResult.inferredType;
-    flowAnalysis.ifNullExpression_rightBegin(read, readType);
+    flowAnalysis.ifNullExpression_rightBegin(
+        read, new SharedTypeView(readType));
 
     writeIndex = ensureAssignable(
         writeIndexType, indexResult.inferredType, writeIndex,
@@ -6458,7 +6471,8 @@
         readTarget.classMember as Procedure)
       ..fileOffset = node.readOffset;
 
-    flowAnalysis.ifNullExpression_rightBegin(read, readType);
+    flowAnalysis.ifNullExpression_rightBegin(
+        read, new SharedTypeView(readType));
     ExpressionInferenceResult valueResult =
         inferExpression(node.value, valueType, isVoidAllowed: true);
     valueResult = ensureAssignableResult(valueType, valueResult);
@@ -6615,7 +6629,8 @@
         MethodContravarianceCheckKind.none);
     Expression read = readResult.expression;
     DartType readType = readResult.inferredType;
-    flowAnalysis.ifNullExpression_rightBegin(read, readType);
+    flowAnalysis.ifNullExpression_rightBegin(
+        read, new SharedTypeView(readType));
 
     writeIndex =
         ensureAssignable(writeIndexType, indexResult.inferredType, writeIndex);
@@ -6729,8 +6744,8 @@
   ExpressionInferenceResult _computeEqualsExpression(
       int fileOffset, Expression left, DartType leftType, Expression right,
       {required bool isNot}) {
-    ExpressionInfo<DartType>? equalityInfo =
-        flowAnalysis.equalityOperand_end(left, leftType);
+    ExpressionInfo<SharedTypeView<DartType>>? equalityInfo =
+        flowAnalysis.equalityOperand_end(left, new SharedTypeView(leftType));
 
     Expression? equals;
     ExpressionInferenceResult rightResult =
@@ -6748,8 +6763,8 @@
       flowAnalysis.equalityOperation_end(
           equals,
           equalityInfo,
-          flowAnalysis.equalityOperand_end(
-              rightResult.expression, rightResult.inferredType),
+          flowAnalysis.equalityOperand_end(rightResult.expression,
+              new SharedTypeView(rightResult.inferredType)),
           notEqual: isNot);
       return new ExpressionInferenceResult(
           coreTypes.boolRawType(Nullability.nonNullable), equals);
@@ -6795,8 +6810,11 @@
       equals = new Not(equals)..fileOffset = fileOffset;
     }
 
-    flowAnalysis.equalityOperation_end(equals, equalityInfo,
-        flowAnalysis.equalityOperand_end(right, rightResult.inferredType),
+    flowAnalysis.equalityOperation_end(
+        equals,
+        equalityInfo,
+        flowAnalysis.equalityOperand_end(
+            right, new SharedTypeView(rightResult.inferredType)),
         notEqual: isNot);
     return new ExpressionInferenceResult(
         equalsTarget.isNever
@@ -6818,7 +6836,8 @@
       DartType leftType,
       Name binaryName,
       Expression right,
-      Map<DartType, NonPromotionReason> Function()? whyNotPromoted) {
+      Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted) {
     assert(binaryName != equalsName);
 
     ObjectAccessTarget binaryTarget = findInterfaceMember(
@@ -6990,7 +7009,8 @@
       Expression expression,
       DartType expressionType,
       Name unaryName,
-      Map<DartType, NonPromotionReason> Function() whyNotPromoted) {
+      Map<SharedTypeView<DartType>, NonPromotionReason> Function()
+          whyNotPromoted) {
     ObjectAccessTarget unaryTarget = findInterfaceMember(
         expressionType, unaryName, fileOffset,
         includeExtensionMethods: true, isSetter: false);
@@ -7380,21 +7400,23 @@
       {required bool isThisReceiver,
       ObjectAccessTarget? readTarget,
       Expression? propertyGetNode}) {
-    Map<DartType, NonPromotionReason> Function() whyNotPromoted =
-        flowAnalysis.whyNotPromoted(receiver);
+    Map<SharedTypeView<DartType>, NonPromotionReason> Function()
+        whyNotPromoted = flowAnalysis.whyNotPromoted(receiver);
 
     readTarget ??= findInterfaceMember(receiverType, propertyName, fileOffset,
         includeExtensionMethods: true, isSetter: false);
 
     DartType readType = readTarget.getGetterType(this);
-    DartType? promotedReadType = flowAnalysis.propertyGet(
-        propertyGetNode,
-        computePropertyTarget(receiver),
-        propertyName.text,
-        readTarget is ExtensionTypeRepresentationAccessTarget
-            ? readTarget.representationField
-            : readTarget.member,
-        readType);
+    DartType? promotedReadType = flowAnalysis
+        .propertyGet(
+            propertyGetNode,
+            computePropertyTarget(receiver),
+            propertyName.text,
+            readTarget is ExtensionTypeRepresentationAccessTarget
+                ? readTarget.representationField
+                : readTarget.member,
+            new SharedTypeView(readType))
+        ?.unwrapTypeView();
     return createPropertyGet(
         fileOffset: fileOffset,
         receiver: receiver,
@@ -7577,8 +7599,8 @@
 
     VariableDeclaration? indexVariable;
     Expression readIndex = indexResult.expression;
-    Map<DartType, NonPromotionReason> Function() whyNotPromotedIndex =
-        flowAnalysis.whyNotPromoted(readIndex);
+    Map<SharedTypeView<DartType>, NonPromotionReason> Function()
+        whyNotPromotedIndex = flowAnalysis.whyNotPromoted(readIndex);
     Expression writeIndex;
     if (isPureExpression(readIndex)) {
       writeIndex = clonePureExpression(readIndex);
@@ -8173,7 +8195,7 @@
   ExpressionInferenceResult visitNullLiteral(
       NullLiteral node, DartType typeContext) {
     const NullType nullType = const NullType();
-    flowAnalysis.nullLiteral(node, nullType);
+    flowAnalysis.nullLiteral(node, new SharedTypeView(nullType));
     return new ExpressionInferenceResult(nullType, node);
   }
 
@@ -8303,7 +8325,8 @@
         .expressionInferenceResult;
     Expression read = readResult.expression;
     DartType readType = readResult.inferredType;
-    flowAnalysis.ifNullExpression_rightBegin(read, readType);
+    flowAnalysis.ifNullExpression_rightBegin(
+        read, new SharedTypeView(readType));
 
     VariableDeclaration? readVariable;
     if (!node.forEffect) {
@@ -8939,9 +8962,9 @@
     assert(checkStackBase(node, stackBase = stackHeight));
 
     SwitchExpressionResult<DartType, InvalidExpression> analysisResult =
-        analyzeSwitchExpression(
-            node, node.expression, node.cases.length, typeContext);
-    DartType valueType = analysisResult.type;
+        analyzeSwitchExpression(node, node.expression, node.cases.length,
+            new SharedTypeSchemaView(typeContext));
+    DartType valueType = analysisResult.type.unwrapTypeView();
     node.staticType = valueType;
 
     assert(checkStack(node, stackBase, [
@@ -8996,7 +9019,7 @@
         analysisResult =
         analyzeSwitchStatement(node, expression, node.cases.length);
 
-    node.expressionType = analysisResult.scrutineeType;
+    node.expressionType = analysisResult.scrutineeType.unwrapTypeView();
 
     assert(checkStack(node, stackBase, [
       /* cases = */ ...repeatedKind(ValueKinds.SwitchCase, node.cases.length),
@@ -9094,7 +9117,7 @@
       /* scrutinee = */ ValueKinds.Expression,
     ]));
 
-    node.expressionType = analysisResult.scrutineeType;
+    node.expressionType = analysisResult.scrutineeType.unwrapTypeView();
     for (int i = node.cases.length - 1; i >= 0; i--) {
       Object? rewrite = popRewrite();
       if (!identical(rewrite, node.cases[i])) {
@@ -9193,7 +9216,8 @@
   @override
   ExpressionInferenceResult visitThisExpression(
       ThisExpression node, DartType typeContext) {
-    flowAnalysis.thisOrSuper(node, thisType!, isSuper: false);
+    flowAnalysis.thisOrSuper(node, new SharedTypeView(thisType!),
+        isSuper: false);
     return new ExpressionInferenceResult(thisType!, node);
   }
 
@@ -9304,7 +9328,8 @@
     bool isDefinitelyAssigned = flowAnalysis.isAssigned(variable);
     bool isDefinitelyUnassigned = flowAnalysis.isUnassigned(variable);
     DartType declaredOrInferredType = variable.lateType ?? variable.type;
-    DartType? promotedType = flowAnalysis.promotedType(variable);
+    DartType? promotedType =
+        flowAnalysis.promotedType(variable)?.unwrapTypeView();
     ExpressionInferenceResult rhsResult = inferExpression(
         node.value, promotedType ?? declaredOrInferredType,
         isVoidAllowed: true);
@@ -9312,8 +9337,8 @@
         fileOffset: node.fileOffset,
         isVoidAllowed: declaredOrInferredType is VoidType);
     Expression rhs = rhsResult.expression;
-    flowAnalysis.write(
-        node, variable, rhsResult.inferredType, rhsResult.expression);
+    flowAnalysis.write(node, variable,
+        new SharedTypeView(rhsResult.inferredType), rhsResult.expression);
     DartType resultType = rhsResult.inferredType;
     Expression resultExpression;
     if (variable.lateSetter != null) {
@@ -9407,12 +9432,12 @@
       }
       node.type = inferredType;
     }
-    flowAnalysis.declare(node, node.type,
+    flowAnalysis.declare(node, new SharedTypeView(node.type),
         initialized: node.hasDeclaredInitializer);
     if (initializerResult != null) {
       DartType initializerType = initializerResult.inferredType;
-      flowAnalysis.initialize(
-          node, initializerType, initializerResult.expression,
+      flowAnalysis.initialize(node, new SharedTypeView(initializerType),
+          initializerResult.expression,
           isFinal: node.isFinal,
           isLate: node.isLate,
           isImplicitlyTyped: node.isImplicitlyTyped);
@@ -9568,11 +9593,10 @@
     int? stackBase;
     assert(checkStackBase(node, stackBase = stackHeight));
 
-    PatternVariableDeclarationAnalysisResult<DartType, DartType>
-        analysisResult = analyzePatternVariableDeclaration(
-            node, node.pattern, node.initializer,
+    PatternVariableDeclarationAnalysisResult<DartType> analysisResult =
+        analyzePatternVariableDeclaration(node, node.pattern, node.initializer,
             isFinal: node.isFinal);
-    node.matchedValueType = analysisResult.initializerType;
+    node.matchedValueType = analysisResult.initializerType.unwrapTypeView();
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -9609,7 +9633,8 @@
     DartType? promotedType;
     DartType declaredOrInferredType = variable.lateType ?? variable.type;
     if (isExtensionThis(variable)) {
-      flowAnalysis.thisOrSuper(node, variable.type, isSuper: true);
+      flowAnalysis.thisOrSuper(node, new SharedTypeView(variable.type),
+          isSuper: true);
     } else if (node.forNullGuardedAccess) {
       DartType nonNullableType = variable.type.toNonNull();
       if (nonNullableType != variable.type) {
@@ -9617,7 +9642,8 @@
       }
     } else if (!variable.isLocalFunction) {
       // Don't promote local functions.
-      promotedType = flowAnalysis.variableRead(node, variable);
+      promotedType =
+          flowAnalysis.variableRead(node, variable)?.unwrapTypeView();
     }
     if (promotedType != null) {
       instrumentation?.record(uriForInstrumentation, node.fileOffset,
@@ -9791,8 +9817,8 @@
       BinaryExpression node, DartType typeContext) {
     ExpressionInferenceResult leftResult =
         inferExpression(node.left, const UnknownType());
-    Map<DartType, NonPromotionReason> Function() whyNotPromoted =
-        flowAnalysis.whyNotPromoted(leftResult.expression);
+    Map<SharedTypeView<DartType>, NonPromotionReason> Function()
+        whyNotPromoted = flowAnalysis.whyNotPromoted(leftResult.expression);
     return _computeBinaryExpression(
         node.fileOffset,
         typeContext,
@@ -9873,7 +9899,8 @@
     if (expressionResult == null) {
       expressionResult = inferExpression(node.expression, const UnknownType());
     }
-    Map<DartType, NonPromotionReason> Function() whyNotPromoted =
+    Map<SharedTypeView<DartType>, NonPromotionReason> Function()
+        whyNotPromoted =
         flowAnalysis.whyNotPromoted(expressionResult.expression);
     return _computeUnaryExpression(node.fileOffset, expressionResult.expression,
         expressionResult.inferredType, node.unaryName, whyNotPromoted);
@@ -10132,7 +10159,7 @@
 
   @override
   ExpressionTypeAnalysisResult<DartType> dispatchExpression(
-      Expression node, DartType context) {
+      Expression node, SharedTypeSchemaView<DartType> context) {
     // Normally the CFE performs expression coercion in the process of type
     // inference of the nodes where an assignment is executed. The inference on
     // the pattern-related nodes is driven by the shared analysis, and some of
@@ -10159,11 +10186,13 @@
     ExpressionInferenceResult expressionResult =
         // TODO(johnniwinther): Handle [isVoidAllowed] through
         //  [dispatchExpression].
-        inferExpression(node, context, isVoidAllowed: true).stopShorting();
+        inferExpression(node, context.unwrapTypeSchemaView(),
+                isVoidAllowed: true)
+            .stopShorting();
 
     if (needsCoercion) {
       expressionResult = coerceExpressionForAssignment(
-              context, expressionResult,
+              context.unwrapTypeSchemaView(), expressionResult,
               treeNodeForTesting: node) ??
           expressionResult;
     }
@@ -10182,7 +10211,8 @@
     // TODO(paulberry): eliminate the need for this--see
     // https://github.com/dart-lang/sdk/issues/52189.
     flow.forwardExpression(node, expressionResult.expression);
-    return new SimpleTypeAnalysisResult(type: expressionResult.inferredType);
+    return new SimpleTypeAnalysisResult(
+        type: new SharedTypeView(expressionResult.inferredType));
   }
 
   @override
@@ -10196,7 +10226,7 @@
   }
 
   @override
-  DartType dispatchPatternSchema(Node node) {
+  SharedTypeSchemaView<DartType> dispatchPatternSchema(Node node) {
     if (node is AndPattern) {
       return analyzeLogicalAndPatternSchema(node.left, node.right);
     } else if (node is AssignedVariablePattern) {
@@ -10207,7 +10237,8 @@
       return analyzeConstantPatternSchema();
     } else if (node is ListPattern) {
       return analyzeListPatternSchema(
-          elementType: node.typeArgument, elements: node.patterns);
+          elementType: node.typeArgument?.wrapSharedTypeView(),
+          elements: node.patterns);
     } else if (node is MapPattern) {
       return analyzeMapPatternSchema(
           typeArguments: node.keyType != null &&
@@ -10215,7 +10246,10 @@
                   node.valueType != null
               ?
               // Coverage-ignore(suite): Not run.
-              (keyType: node.keyType!, valueType: node.valueType!)
+              (
+                  keyType: new SharedTypeView(node.keyType!),
+                  valueType: new SharedTypeView(node.valueType!)
+                )
               : null,
           elements: node.entries);
     } else if (node is NamedPattern) {
@@ -10228,7 +10262,7 @@
       return analyzeNullCheckOrAssertPatternSchema(node.pattern,
           isAssert: false);
     } else if (node is ObjectPattern) {
-      return analyzeObjectPatternSchema(node.requiredType);
+      return analyzeObjectPatternSchema(new SharedTypeView(node.requiredType));
     } else if (node is OrPattern) {
       // Coverage-ignore-block(suite): Not run.
       return analyzeLogicalOrPatternSchema(node.left, node.right);
@@ -10248,13 +10282,15 @@
       return analyzeRelationalPatternSchema();
     } else if (node is RestPattern) {
       // This pattern can't appear on it's own.
-      return const InvalidType();
+      return new SharedTypeSchemaView(const InvalidType());
     } else if (node is VariablePattern) {
-      return analyzeDeclaredVariablePatternSchema(node.type);
+      return analyzeDeclaredVariablePatternSchema(
+          node.type?.wrapSharedTypeView());
     } else if (node is WildcardPattern) {
-      return analyzeDeclaredVariablePatternSchema(node.type);
+      return analyzeDeclaredVariablePatternSchema(
+          node.type?.wrapSharedTypeView());
     } else if (node is InvalidPattern) {
-      return const InvalidType();
+      return new SharedTypeSchemaView(const InvalidType());
     } else {
       // Coverage-ignore-block(suite): Not run.
       return problems.unhandled("${node.runtimeType}", "dispatchPatternSchema",
@@ -10362,8 +10398,8 @@
   }
 
   @override
-  FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration, DartType>
-      get flow => flowAnalysis;
+  FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration,
+      SharedTypeView<DartType>> get flow => flowAnalysis;
 
   @override
   SwitchExpressionMemberInfo<TreeNode, Expression, VariableDeclaration>
@@ -10579,13 +10615,15 @@
   }) {}
 
   @override
-  void handleSwitchScrutinee(DartType type) {
+  void handleSwitchScrutinee(SharedTypeView<DartType> type) {
+    DartType unwrapped = type.unwrapTypeView();
     if ((!options.patternsEnabled) &&
-        type is InterfaceType &&
-        type.classNode.isEnum) {
+        unwrapped is InterfaceType &&
+        unwrapped.classNode.isEnum) {
       _enumFields = <Field?>{
-        ...type.classNode.fields.where((Field field) => field.isEnumElement),
-        if (type.isPotentiallyNullable) null
+        ...unwrapped.classNode.fields
+            .where((Field field) => field.isEnumElement),
+        if (type.unwrapTypeView().isPotentiallyNullable) null
       };
     } else {
       _enumFields = null;
@@ -10595,7 +10633,8 @@
   }
 
   @override
-  bool isLegacySwitchExhaustive(TreeNode node, DartType expressionType) {
+  bool isLegacySwitchExhaustive(
+      TreeNode node, SharedTypeView<DartType> expressionType) {
     Set<Field?>? enumFields = _enumFields;
     return enumFields != null && enumFields.isEmpty;
   }
@@ -10606,15 +10645,17 @@
   }
 
   @override
-  void setVariableType(VariableDeclaration variable, DartType type) {
-    variable.type = type;
+  void setVariableType(
+      VariableDeclaration variable, SharedTypeView<DartType> type) {
+    variable.type = type.unwrapTypeView();
   }
 
   @override
-  DartType variableTypeFromInitializerType(DartType type) {
+  SharedTypeView<DartType> variableTypeFromInitializerType(
+      SharedTypeView<DartType> type) {
     // TODO(paulberry): make a test verifying that we don't need to pass
     // `forSyntheticVariable: true` (and possibly a language issue)
-    return inferDeclarationType(type);
+    return new SharedTypeView(inferDeclarationType(type.unwrapTypeView()));
   }
 
   @override
@@ -10629,10 +10670,10 @@
     assert(checkStackBase(node, stackBase = stackHeight));
 
     DeclaredVariablePatternResult<DartType, InvalidExpression> analysisResult =
-        analyzeDeclaredVariablePattern(
-            context, node, node.variable, node.variable.name!, node.type);
+        analyzeDeclaredVariablePattern(context, node, node.variable,
+            node.variable.name!, node.type?.wrapSharedTypeView());
 
-    node.matchedValueType = analysisResult.matchedValueType;
+    node.matchedValueType = analysisResult.matchedValueType.unwrapTypeView();
 
     Pattern? replacement;
 
@@ -10645,7 +10686,7 @@
             ..fileOffset = error.fileOffset;
     }
 
-    DartType inferredType = analysisResult.staticType;
+    DartType inferredType = analysisResult.staticType.unwrapTypeView();
     instrumentation?.record(uriForInstrumentation, node.variable.fileOffset,
         'type', new InstrumentationValueForType(inferredType));
     if (node.type == null) {
@@ -10668,7 +10709,9 @@
 
     WildcardPatternResult<DartType, InvalidExpression> analysisResult =
         analyzeWildcardPattern(
-            context: context, node: node, declaredType: node.type);
+            context: context,
+            node: node,
+            declaredType: node.type?.wrapSharedTypeView());
 
     Pattern? replacement;
 
@@ -10709,7 +10752,7 @@
     }
 
     DartType expressionType =
-        node.expressionType = analysisResult.expressionType;
+        node.expressionType = analysisResult.expressionType.unwrapTypeView();
 
     ObjectAccessTarget equalsInvokeTarget = findInterfaceMember(
         expressionType, equalsName, node.fileOffset,
@@ -10857,7 +10900,7 @@
       context: context,
       pattern: node,
       innerPattern: node.pattern,
-      requiredType: node.type,
+      requiredType: new SharedTypeView(node.type),
     );
 
     assert(checkStack(node, stackBase, [
@@ -10953,10 +10996,11 @@
 
     ListPatternResult<DartType, InvalidExpression> analysisResult =
         analyzeListPattern(context, node,
-            elements: node.patterns, elementType: node.typeArgument);
+            elements: node.patterns,
+            elementType: node.typeArgument?.wrapSharedTypeView());
 
-    DartType matchedValueType =
-        node.matchedValueType = analysisResult.matchedValueType;
+    DartType matchedValueType = node.matchedValueType =
+        analysisResult.matchedValueType.unwrapTypeView();
 
     assert(checkStack(node, stackBase, [
       /* subpatterns = */ ...repeatedKind(
@@ -10989,7 +11033,8 @@
     // TODO(johnniwinther): The required type computed by the type analyzer
     // isn't trivially `List<dynamic>` in all cases. Does that matter for the
     // lowering?
-    DartType requiredType = node.requiredType = analysisResult.requiredType;
+    DartType requiredType =
+        node.requiredType = analysisResult.requiredType.unwrapTypeView();
 
     node.needsCheck =
         _needsCheck(matchedType: matchedValueType, requiredType: requiredType);
@@ -11119,15 +11164,15 @@
                 node: field, name: field.name, pattern: field.pattern)
         ]);
 
-    DartType matchedValueType =
-        node.matchedValueType = analysisResult.matchedValueType;
+    DartType matchedValueType = node.matchedValueType =
+        analysisResult.matchedValueType.unwrapTypeView();
 
     assert(checkStack(node, stackBase, [
       /* subpatterns = */ ...repeatedKind(
           ValueKinds.Pattern, node.fields.length)
     ]));
 
-    node.requiredType = analysisResult.requiredType;
+    node.requiredType = analysisResult.requiredType.unwrapTypeView();
 
     Pattern? replacement;
 
@@ -11290,7 +11335,8 @@
       /* pattern = */ ValueKinds.Pattern,
     ]));
 
-    return new PatternResult(matchedValueType: const InvalidType());
+    return new PatternResult(
+        matchedValueType: new SharedTypeView(const InvalidType()));
   }
 
   @override
@@ -11302,8 +11348,8 @@
     RelationalPatternResult<DartType, InvalidExpression> analysisResult =
         analyzeRelationalPattern(context, node, node.expression);
 
-    DartType matchedValueType =
-        node.matchedValueType = analysisResult.matchedValueType;
+    DartType matchedValueType = node.matchedValueType =
+        analysisResult.matchedValueType.unwrapTypeView();
 
     assert(checkStack(node, stackBase, [
       /* expression = */ ValueKinds.Expression,
@@ -11326,7 +11372,7 @@
       node.expression = (rewrite as Expression)..parent = node;
     }
 
-    DartType expressionType = analysisResult.operandType;
+    DartType expressionType = analysisResult.operandType.unwrapTypeView();
     node.expressionType = expressionType;
 
     Name name;
@@ -11434,19 +11480,21 @@
     int? stackBase;
     assert(checkStackBase(node, stackBase = stackHeight));
 
-    ({DartType keyType, DartType valueType})? typeArguments =
-        node.keyType == null && node.valueType == null
-            ? null
-            : (
-                keyType: node.keyType ?? const DynamicType(),
-                valueType: node.valueType ?? const DynamicType()
-              );
+    ({
+      SharedTypeView<DartType> keyType,
+      SharedTypeView<DartType> valueType
+    })? typeArguments = node.keyType == null && node.valueType == null
+        ? null
+        : (
+            keyType: new SharedTypeView(node.keyType ?? const DynamicType()),
+            valueType: new SharedTypeView(node.valueType ?? const DynamicType())
+          );
     MapPatternResult<DartType, InvalidExpression> analysisResult =
         analyzeMapPattern(context, node,
             typeArguments: typeArguments, elements: node.entries);
 
-    DartType matchedValueType =
-        node.matchedValueType = analysisResult.matchedValueType;
+    DartType matchedValueType = node.matchedValueType =
+        analysisResult.matchedValueType.unwrapTypeView();
 
     Pattern? replacement;
 
@@ -11469,7 +11517,8 @@
     // TODO(johnniwinther): The required type computed by the type analyzer
     // isn't trivially `Map<dynamic, dynamic>` in all cases. Does that matter
     // for the lowering?
-    DartType requiredType = node.requiredType = analysisResult.requiredType;
+    DartType requiredType =
+        node.requiredType = analysisResult.requiredType.unwrapTypeView();
 
     node.needsCheck =
         _needsCheck(matchedType: matchedValueType, requiredType: requiredType);
@@ -11566,8 +11615,8 @@
     RecordPatternResult<DartType, InvalidExpression> analysisResult =
         analyzeRecordPattern(context, node, fields: fields);
 
-    DartType matchedValueType =
-        node.matchedValueType = analysisResult.matchedValueType;
+    DartType matchedValueType = node.matchedValueType =
+        analysisResult.matchedValueType.unwrapTypeView();
 
     assert(checkStack(node, stackBase, [
       /* fields = */ ...repeatedKind(ValueKinds.Pattern, node.patterns.length)
@@ -11633,9 +11682,9 @@
     int? stackBase;
     assert(checkStackBase(node, stackBase = stackHeight));
 
-    PatternAssignmentAnalysisResult<DartType, DartType> analysisResult =
+    PatternAssignmentAnalysisResult<DartType> analysisResult =
         analyzePatternAssignment(node, node.pattern, node.expression);
-    node.matchedValueType = analysisResult.type;
+    node.matchedValueType = analysisResult.type.unwrapTypeView();
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -11659,7 +11708,7 @@
     assert(checkStack(node, stackBase, [/*empty*/]));
 
     return new ExpressionInferenceResult(
-        analysisResult.resolveShorting(), node);
+        analysisResult.resolveShorting().unwrapTypeView(), node);
   }
 
   @override
@@ -11710,8 +11759,8 @@
     AssignedVariablePatternResult<DartType, InvalidExpression> analysisResult =
         analyzeAssignedVariablePattern(context, node, node.variable);
 
-    DartType matchedValueType =
-        node.matchedValueType = analysisResult.matchedValueType;
+    DartType matchedValueType = node.matchedValueType =
+        analysisResult.matchedValueType.unwrapTypeView();
     node.needsCast = _needsCast(
         matchedType: matchedValueType, requiredType: node.variable.type);
     node.hasObservableEffect = _inTryOrLocalFunction;
@@ -11758,8 +11807,8 @@
   }
 
   @override
-  DartType downwardInferObjectPatternRequiredType({
-    required DartType matchedType,
+  SharedTypeView<DartType> downwardInferObjectPatternRequiredType({
+    required SharedTypeView<DartType> matchedType,
     required covariant ObjectPatternInternal pattern,
   }) {
     DartType requiredType = pattern.requiredType;
@@ -11776,7 +11825,7 @@
           List<DartType> inferredTypeArguments = _inferTypeArguments(
               typeParameters: typedefTypeParameters,
               declaredType: unaliasedTypedef,
-              contextType: matchedType,
+              contextType: matchedType.unwrapTypeView(),
               treeNodeForTesting: pattern);
           requiredType = new TypedefType(typedef,
                   libraryBuilder.library.nonNullable, inferredTypeArguments)
@@ -11800,7 +11849,7 @@
           List<DartType> inferredTypeArguments = _inferTypeArguments(
               typeParameters: typeParameters,
               declaredType: declaredType,
-              contextType: matchedType,
+              contextType: matchedType.unwrapTypeView(),
               treeNodeForTesting: pattern);
           requiredType = new InterfaceType(requiredType.classNode,
               requiredType.declaredNullability, inferredTypeArguments);
@@ -11825,7 +11874,7 @@
           List<DartType> inferredTypeArguments = _inferTypeArguments(
               typeParameters: typeParameters,
               declaredType: declaredType,
-              contextType: matchedType,
+              contextType: matchedType.unwrapTypeView(),
               treeNodeForTesting: pattern);
           requiredType = new ExtensionType(
               requiredType.extensionTypeDeclaration,
@@ -11834,7 +11883,7 @@
         }
       }
     }
-    return requiredType;
+    return new SharedTypeView(requiredType);
   }
 
   @override
@@ -11873,18 +11922,24 @@
   }
 
   @override
-  (Member?, DartType) resolveObjectPatternPropertyGet({
+  (Member?, SharedTypeView<DartType>) resolveObjectPatternPropertyGet({
     required Pattern objectPattern,
-    required DartType receiverType,
+    required SharedTypeView<DartType> receiverType,
     required shared.RecordPatternField<TreeNode, Pattern> field,
   }) {
     String fieldName = field.name!;
-    ObjectAccessTarget fieldAccessTarget = findInterfaceMember(receiverType,
-        new Name(fieldName, libraryBuilder.library), field.pattern.fileOffset,
-        isSetter: false, includeExtensionMethods: true);
+    ObjectAccessTarget fieldAccessTarget = findInterfaceMember(
+        receiverType.unwrapTypeView(),
+        new Name(fieldName, libraryBuilder.library),
+        field.pattern.fileOffset,
+        isSetter: false,
+        includeExtensionMethods: true);
     // TODO(johnniwinther): Should we use the `fieldAccessTarget.classMember`
     //  here?
-    return (fieldAccessTarget.member, fieldAccessTarget.getGetterType(this));
+    return (
+      fieldAccessTarget.member,
+      new SharedTypeView(fieldAccessTarget.getGetterType(this))
+    );
   }
 
   @override
@@ -11898,11 +11953,11 @@
     required JoinedPatternVariableLocation location,
     required JoinedPatternVariableInconsistency inconsistency,
     required bool isFinal,
-    required DartType type,
+    required SharedTypeView<DartType> type,
   }) {
     variable
       ..isFinal = isFinal
-      ..type = type;
+      ..type = type.unwrapTypeView();
   }
 
   @override
@@ -11964,8 +12019,10 @@
   }
 
   @override
-  void handleMapPatternEntry(Pattern container,
-      covariant MapPatternEntry entryElement, DartType keyType) {
+  void handleMapPatternEntry(
+      Pattern container,
+      covariant MapPatternEntry entryElement,
+      SharedTypeView<DartType> keyType) {
     Object? rewrite = popRewrite();
     if (!identical(rewrite, entryElement.value)) {
       // Coverage-ignore-block(suite): Not run.
@@ -11978,14 +12035,15 @@
       entryElement.key = (rewrite as Expression)..parent = entryElement;
     }
 
-    entryElement.keyType = keyType;
+    entryElement.keyType = keyType.unwrapTypeView();
 
     pushRewrite(entryElement);
   }
 
   @override
   RelationalOperatorResolution<DartType>? resolveRelationalPatternOperator(
-      covariant RelationalPattern node, DartType matchedValueType) {
+      covariant RelationalPattern node,
+      SharedTypeView<DartType> matchedValueType) {
     // TODO(johnniwinther): Reuse computed values between here and
     // visitRelationalPattern.
     Name operatorName;
@@ -12013,7 +12071,7 @@
         break;
     }
     ObjectAccessTarget binaryTarget = findInterfaceMember(
-        matchedValueType, operatorName, node.fileOffset,
+        matchedValueType.unwrapTypeView(), operatorName, node.fileOffset,
         isSetter: false);
 
     DartType returnType = binaryTarget.getReturnType(this);
@@ -12022,7 +12080,9 @@
     assert(!binaryTarget.isSpecialCasedBinaryOperator(this));
 
     return new RelationalOperatorResolution(
-        kind: kind, parameterType: parameterType, returnType: returnType);
+        kind: kind,
+        parameterType: new SharedTypeView(parameterType),
+        returnType: new SharedTypeView(returnType));
   }
 
   @override
diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
index de33a56..741afdb 100644
--- a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
+++ b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
@@ -8,6 +8,7 @@
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis_operations.dart';
 import 'package:_fe_analyzer_shared/src/testing/id.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/assigned_variables.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:_fe_analyzer_shared/src/util/link.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart'
@@ -154,8 +155,8 @@
 
   InferenceDataForTesting? get dataForTesting => _inferrer.dataForTesting;
 
-  FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration, DartType>
-      get flowAnalysis => _inferrer.flowAnalysis;
+  FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration,
+      SharedTypeView<DartType>> get flowAnalysis => _inferrer.flowAnalysis;
 
   /// Provides access to the [OperationsCfe] object.  This is needed by
   /// [isAssignable] and for caching types.
@@ -218,7 +219,7 @@
   /// promoted, to be used when reporting an error for a larger expression
   /// containing [receiver].  [node] is the containing tree node.
   List<LocatedMessage>? getWhyNotPromotedContext(
-      Map<DartType, NonPromotionReason>? whyNotPromoted,
+      Map<SharedTypeView<DartType>, NonPromotionReason>? whyNotPromoted,
       TreeNode node,
       bool Function(DartType) typeFilter) {
     List<LocatedMessage>? context;
@@ -226,9 +227,9 @@
       // Coverage-ignore-block(suite): Not run.
       _WhyNotPromotedVisitor whyNotPromotedVisitor =
           new _WhyNotPromotedVisitor(this);
-      for (MapEntry<DartType, NonPromotionReason> entry
+      for (MapEntry<SharedTypeView<DartType>, NonPromotionReason> entry
           in whyNotPromoted.entries) {
-        if (!typeFilter(entry.key)) continue;
+        if (!typeFilter(entry.key.unwrapTypeView())) continue;
         List<LocatedMessage> messages =
             entry.value.accept(whyNotPromotedVisitor);
         if (dataForTesting != null) {
@@ -349,8 +350,10 @@
         typeContext.classReference == coreTypes.doubleClass.reference;
   }
 
-  bool isAssignable(DartType contextType, DartType expressionType) =>
-      cfeOperations.isAssignableTo(expressionType, contextType);
+  bool isAssignable(DartType contextType, DartType expressionType) {
+    return cfeOperations.isAssignableTo(
+        new SharedTypeView(expressionType), new SharedTypeView(contextType));
+  }
 
   /// Ensures that [expressionType] is assignable to [contextType].
   ///
@@ -384,7 +387,8 @@
           nullabilityNullTypeErrorTemplate,
       Template<Message Function(DartType, DartType, DartType, DartType)>?
           nullabilityPartErrorTemplate,
-      Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
+      Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted}) {
     return ensureAssignableResult(expectedType,
             new ExpressionInferenceResult(expressionType, expression),
             fileOffset: fileOffset,
@@ -498,7 +502,8 @@
           nullabilityNullTypeErrorTemplate,
       Template<Message Function(DartType, DartType, DartType, DartType)>?
           nullabilityPartErrorTemplate,
-      Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
+      Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted}) {
     // [errorTemplate], [nullabilityErrorTemplate], and
     // [nullabilityPartErrorTemplate] should be provided together.
     assert((errorTemplate == null) == (nullabilityErrorTemplate == null) &&
@@ -658,7 +663,8 @@
           nullabilityNullTypeErrorTemplate,
       Template<Message Function(DartType, DartType, DartType, DartType)>?
           nullabilityPartErrorTemplate,
-      Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
+      Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted}) {
     if (coerceExpression) {
       ExpressionInferenceResult? coercionResult = coerceExpressionForAssignment(
           contextType, inferenceResult,
@@ -1721,7 +1727,7 @@
       return visitor.inferExpression(argumentExpression, inferredFormalType);
     }
 
-    List<ExpressionInfo<DartType>?>? identicalInfo =
+    List<ExpressionInfo<SharedTypeView<DartType>>?>? identicalInfo =
         isIdentical && arguments.positional.length == 2 ? [] : null;
     int positionalIndex = 0;
     int namedIndex = 0;
@@ -1789,8 +1795,8 @@
         }
         Expression expression =
             _hoist(result.expression, inferredType, hoistedExpressions);
-        identicalInfo
-            ?.add(flowAnalysis.equalityOperand_end(expression, inferredType));
+        identicalInfo?.add(flowAnalysis.equalityOperand_end(
+            expression, new SharedTypeView(inferredType)));
         if (isExpression) {
           arguments.positional[index] = expression..parent = arguments;
         } else {
@@ -1826,7 +1832,8 @@
           DartType inferredType = _computeInferredType(result);
           Expression expression = result.expression;
           identicalInfo?[deferredArgument.evaluationOrderIndex] =
-              flowAnalysis.equalityOperand_end(expression, inferredType);
+              flowAnalysis.equalityOperand_end(
+                  expression, new SharedTypeView(inferredType));
           if (deferredArgument.isNamed) {
             NamedExpression namedArgument =
                 arguments.named[deferredArgument.index];
@@ -2034,7 +2041,8 @@
         function.positionalParameters;
     for (int i = 0; i < positionalParameters.length; i++) {
       VariableDeclaration parameter = positionalParameters[i];
-      flowAnalysis.declare(parameter, parameter.type, initialized: true);
+      flowAnalysis.declare(parameter, new SharedTypeView(parameter.type),
+          initialized: true);
       inferMetadata(visitor, parameter, parameter.annotations);
       if (parameter.initializer != null) {
         ExpressionInferenceResult initializerResult =
@@ -2044,7 +2052,8 @@
       }
     }
     for (VariableDeclaration parameter in function.namedParameters) {
-      flowAnalysis.declare(parameter, parameter.type, initialized: true);
+      flowAnalysis.declare(parameter, new SharedTypeView(parameter.type),
+          initialized: true);
       inferMetadata(visitor, parameter, parameter.annotations);
       if (parameter.initializer != null) {
         ExpressionInferenceResult initializerResult =
@@ -2947,7 +2956,8 @@
       receiver = _hoist(receiver, receiverType, hoistedExpressions);
     }
 
-    Map<DartType, NonPromotionReason> Function()? whyNotPromoted;
+    Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+        whyNotPromoted;
     if (target.isNullable) {
       // We won't report the error until later (after we have an
       // invocationResult), but we need to gather "why not promoted" info now,
@@ -2977,12 +2987,14 @@
         kind, receiver, originalName,
         resultType: calleeType, interfaceTarget: originalTarget)
       ..fileOffset = fileOffset;
-    DartType? promotedCalleeType = flowAnalysis.propertyGet(
-        originalPropertyGet,
-        computePropertyTarget(originalReceiver),
-        originalName.text,
-        originalTarget,
-        calleeType);
+    DartType? promotedCalleeType = flowAnalysis
+        .propertyGet(
+            originalPropertyGet,
+            computePropertyTarget(originalReceiver),
+            originalName.text,
+            originalTarget,
+            new SharedTypeView(calleeType))
+        ?.unwrapTypeView();
     originalPropertyGet.resultType = calleeType;
     Expression propertyGet = originalPropertyGet;
     if (receiver is! ThisExpression &&
@@ -3311,13 +3323,15 @@
       // Coverage-ignore(suite): Not run.
       case ObjectAccessTargetKind.nullableExtensionTypeRepresentation:
         DartType type = target.getGetterType(this);
-        type = flowAnalysis.propertyGet(
-                null,
-                computePropertyTarget(receiver),
-                name.text,
-                (target as ExtensionTypeRepresentationAccessTarget)
-                    .representationField,
-                type) ??
+        type = flowAnalysis
+                .propertyGet(
+                    null,
+                    computePropertyTarget(receiver),
+                    name.text,
+                    (target as ExtensionTypeRepresentationAccessTarget)
+                        .representationField,
+                    new SharedTypeView(type))
+                ?.unwrapTypeView() ??
             type;
         Expression read = new AsExpression(receiver, type)
           ..isUnchecked = true
@@ -3481,8 +3495,10 @@
     if (member is Procedure && member.kind == ProcedureKind.Method) {
       return instantiateTearOff(inferredType, typeContext, expression);
     }
-    DartType? promotedType = flowAnalysis.propertyGet(expression,
-        SuperPropertyTarget.singleton, name.text, member, inferredType);
+    DartType? promotedType = flowAnalysis
+        .propertyGet(expression, SuperPropertyTarget.singleton, name.text,
+            member, new SharedTypeView(inferredType))
+        ?.unwrapTypeView();
     if (promotedType != null) {
       // Coverage-ignore-block(suite): Not run.
       expression = new AsExpression(expression, promotedType)
@@ -3941,7 +3957,8 @@
       DartType? readType,
       required DartType? promotedReadType,
       required bool isThisReceiver,
-      Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
+      Map<SharedTypeView<DartType>, NonPromotionReason> Function()?
+          whyNotPromoted}) {
     Expression read;
     ExpressionInferenceResult? readResult;
 
@@ -4346,7 +4363,7 @@
 class _WhyNotPromotedVisitor
     implements
         NonPromotionReasonVisitor<List<LocatedMessage>, Node,
-            VariableDeclaration, DartType> {
+            VariableDeclaration, SharedTypeView<DartType>> {
   final InferenceVisitorBase inferrer;
 
   Member? propertyReference;
@@ -4373,7 +4390,8 @@
 
   @override
   List<LocatedMessage> visitPropertyNotPromotedForNonInherentReason(
-      PropertyNotPromotedForNonInherentReason<DartType> reason) {
+      PropertyNotPromotedForNonInherentReason<SharedTypeView<DartType>>
+          reason) {
     FieldNonPromotabilityInfo? fieldNonPromotabilityInfo =
         this.inferrer.libraryBuilder.fieldNonPromotabilityInfo;
     if (fieldNonPromotabilityInfo == null) {
@@ -4429,7 +4447,7 @@
 
   @override
   List<LocatedMessage> visitPropertyNotPromotedForInherentReason(
-      PropertyNotPromotedForInherentReason<DartType> reason) {
+      PropertyNotPromotedForInherentReason<SharedTypeView<DartType>> reason) {
     Object? member = reason.propertyMember;
     if (member is Member) {
       if (member case Procedure(:var stubTarget?)) {
@@ -4438,7 +4456,7 @@
         member = stubTarget;
       }
       propertyReference = member;
-      propertyType = reason.staticType;
+      propertyType = reason.staticType.unwrapTypeView();
       Template<Message Function(String, String)> template =
           switch (reason.whyNotPromotable) {
         PropertyNonPromotabilityReason.isNotField =>
@@ -4476,7 +4494,8 @@
   }
 
   void _addFieldPromotionUnavailableMessage(
-      PropertyNotPromoted<DartType> reason, List<LocatedMessage> messages) {
+      PropertyNotPromoted<SharedTypeView<DartType>> reason,
+      List<LocatedMessage> messages) {
     Object? member = reason.propertyMember;
     if (member is Member) {
       messages.add(templateFieldNotPromotedBecauseNotEnabled
diff --git a/pkg/front_end/lib/src/type_inference/shared_type_analyzer.dart b/pkg/front_end/lib/src/type_inference/shared_type_analyzer.dart
index 49423b4..f860ff1 100644
--- a/pkg/front_end/lib/src/type_inference/shared_type_analyzer.dart
+++ b/pkg/front_end/lib/src/type_inference/shared_type_analyzer.dart
@@ -4,6 +4,7 @@
 
 import 'package:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/core_types.dart';
 
@@ -17,7 +18,7 @@
 class SharedTypeAnalyzerErrors
     implements
         TypeAnalyzerErrors<TreeNode, Statement, Expression, VariableDeclaration,
-            DartType, Pattern, InvalidExpression> {
+            SharedTypeView<DartType>, Pattern, InvalidExpression> {
   final InferenceVisitorImpl visitor;
   final InferenceHelper helper;
 
@@ -40,17 +41,19 @@
   InvalidExpression caseExpressionTypeMismatch(
       {required Expression scrutinee,
       required Expression caseExpression,
-      required DartType caseExpressionType,
-      required DartType scrutineeType,
+      required SharedTypeView<DartType> caseExpressionType,
+      required SharedTypeView<DartType> scrutineeType,
       required bool nullSafetyEnabled}) {
     return helper.buildProblem(
         nullSafetyEnabled
             ? templateSwitchExpressionNotSubtype.withArguments(
-                caseExpressionType, scrutineeType)
+                caseExpressionType.unwrapTypeView(),
+                scrutineeType.unwrapTypeView())
             :
             // Coverage-ignore(suite): Not run.
             templateSwitchExpressionNotAssignable.withArguments(
-                scrutineeType, caseExpressionType),
+                scrutineeType.unwrapTypeView(),
+                caseExpressionType.unwrapTypeView()),
         caseExpression.fileOffset,
         noLength,
         context: [
@@ -130,7 +133,7 @@
   @override
   InvalidExpression? matchedTypeIsStrictlyNonNullable({
     required Pattern pattern,
-    required DartType matchedType,
+    required SharedTypeView<DartType> matchedType,
   }) {
     // These are only warnings, so we don't report anything.
     return null;
@@ -139,8 +142,8 @@
   @override
   void matchedTypeIsSubtypeOfRequired({
     required Pattern pattern,
-    required DartType matchedType,
-    required DartType requiredType,
+    required SharedTypeView<DartType> matchedType,
+    required SharedTypeView<DartType> requiredType,
   }) {
     // TODO(scheglov) implement
   }
@@ -155,11 +158,12 @@
   InvalidExpression patternForInExpressionIsNotIterable({
     required TreeNode node,
     required Expression expression,
-    required DartType expressionType,
+    required SharedTypeView<DartType> expressionType,
   }) {
     return helper.buildProblem(
         templateForInLoopTypeNotIterable.withArguments(
-            expressionType, coreTypes.iterableNonNullableRawType),
+            expressionType.unwrapTypeView(),
+            coreTypes.iterableNonNullableRawType),
         expression.fileOffset,
         noLength);
   }
@@ -168,11 +172,11 @@
   InvalidExpression patternTypeMismatchInIrrefutableContext(
       {required Pattern pattern,
       required TreeNode context,
-      required DartType matchedType,
-      required DartType requiredType}) {
+      required SharedTypeView<DartType> matchedType,
+      required SharedTypeView<DartType> requiredType}) {
     return helper.buildProblem(
         templatePatternTypeMismatchInIrrefutableContext.withArguments(
-            matchedType, requiredType),
+            matchedType.unwrapTypeView(), requiredType.unwrapTypeView()),
         pattern.fileOffset,
         noLength);
   }
@@ -187,12 +191,12 @@
   @override
   InvalidExpression relationalPatternOperandTypeNotAssignable({
     required covariant RelationalPattern pattern,
-    required DartType operandType,
-    required DartType parameterType,
+    required SharedTypeView<DartType> operandType,
+    required SharedTypeView<DartType> parameterType,
   }) {
     return helper.buildProblem(
         templateArgumentTypeNotAssignable.withArguments(
-            operandType, parameterType),
+            operandType.unwrapTypeView(), parameterType.unwrapTypeView()),
         pattern.expression.fileOffset,
         noLength);
   }
@@ -200,11 +204,11 @@
   @override
   InvalidExpression relationalPatternOperatorReturnTypeNotAssignableToBool({
     required Pattern pattern,
-    required DartType returnType,
+    required SharedTypeView<DartType> returnType,
   }) {
     return helper.buildProblem(
         templateInvalidAssignmentError.withArguments(
-            returnType, coreTypes.boolNonNullableRawType),
+            returnType.unwrapTypeView(), coreTypes.boolNonNullableRawType),
         pattern.fileOffset,
         noLength);
   }
diff --git a/pkg/front_end/lib/src/type_inference/type_constraint_gatherer.dart b/pkg/front_end/lib/src/type_inference/type_constraint_gatherer.dart
index a6a53c0..6a5b2f1 100644
--- a/pkg/front_end/lib/src/type_inference/type_constraint_gatherer.dart
+++ b/pkg/front_end/lib/src/type_inference/type_constraint_gatherer.dart
@@ -12,8 +12,7 @@
         TypeDeclarationKind,
         TypeDeclarationMatchResult,
         Variance;
-import 'package:_fe_analyzer_shared/src/types/shared_type.dart'
-    show SharedDynamicType, SharedRecordType, SharedUnknownType, SharedVoidType;
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/names.dart' show callName;
 import 'package:kernel/type_algebra.dart';
@@ -26,9 +25,8 @@
 /// Creates a collection of [TypeConstraint]s corresponding to type parameters,
 /// based on an attempt to make one type schema a subtype of another.
 class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
+    DartType,
     VariableDeclaration,
-    DartType,
-    DartType,
     StructuralParameter,
     TypeDeclarationType,
     TypeDeclaration,
@@ -98,8 +96,8 @@
     Map<StructuralParameter, MergedTypeConstraint> result = {};
     for (StructuralParameter parameter in _parametersToConstrain) {
       result[parameter] = new MergedTypeConstraint(
-          lower: const UnknownType(),
-          upper: const UnknownType(),
+          lower: new SharedTypeSchemaView(const UnknownType()),
+          upper: new SharedTypeSchemaView(const UnknownType()),
           origin: const UnknownTypeConstraintOrigin());
     }
     for (GeneratedTypeConstraint protoConstraint in _protoConstraints) {
@@ -180,7 +178,8 @@
   void _constrainParameterLower(StructuralParameter parameter, DartType lower,
       {required TreeNode? treeNodeForTesting}) {
     GeneratedTypeConstraint generatedTypeConstraint =
-        new GeneratedTypeConstraint.lower(parameter, lower);
+        new GeneratedTypeConstraint.lower(
+            parameter, new SharedTypeSchemaView(lower));
     if (treeNodeForTesting != null && _inferenceResultForTesting != null) {
       // Coverage-ignore-block(suite): Not run.
       (_inferenceResultForTesting
@@ -194,7 +193,8 @@
   void _constrainParameterUpper(StructuralParameter parameter, DartType upper,
       {required TreeNode? treeNodeForTesting}) {
     GeneratedTypeConstraint generatedTypeConstraint =
-        new GeneratedTypeConstraint.upper(parameter, upper);
+        new GeneratedTypeConstraint.upper(
+            parameter, new SharedTypeSchemaView(upper));
     if (treeNodeForTesting != null && _inferenceResultForTesting != null) {
       // Coverage-ignore-block(suite): Not run.
       (_inferenceResultForTesting
@@ -349,16 +349,20 @@
   }
 
   @override
-  bool performSubtypeConstraintGenerationRightSchema(DartType p, DartType q,
+  bool performSubtypeConstraintGenerationRightSchema(
+      SharedTypeView<DartType> p, SharedTypeSchemaView<DartType> q,
       {required TreeNode? astNodeForTesting}) {
-    return _isNullabilityAwareSubtypeMatch(p, q,
+    return _isNullabilityAwareSubtypeMatch(
+        p.unwrapTypeView(), q.unwrapTypeSchemaView(),
         constrainSupertype: false, treeNodeForTesting: astNodeForTesting);
   }
 
   @override
-  bool performSubtypeConstraintGenerationLeftSchema(DartType p, DartType q,
+  bool performSubtypeConstraintGenerationLeftSchema(
+      SharedTypeSchemaView<DartType> p, SharedTypeView<DartType> q,
       {required TreeNode? astNodeForTesting}) {
-    return _isNullabilityAwareSubtypeMatch(p, q,
+    return _isNullabilityAwareSubtypeMatch(
+        p.unwrapTypeSchemaView(), q.unwrapTypeView(),
         constrainSupertype: true, treeNodeForTesting: astNodeForTesting);
   }
 
@@ -432,16 +436,16 @@
     if (p is InvalidType || q is InvalidType) return false;
 
     // If P is _ then the match holds with no constraints.
-    if (p is SharedUnknownType) return true;
+    if (p is SharedUnknownTypeStructure) return true;
 
     // If Q is _ then the match holds with no constraints.
-    if (q is SharedUnknownType) return true;
+    if (q is SharedUnknownTypeStructure) return true;
 
     // If P is a type variable X in L, then the match holds:
     //
     // Under constraint _ <: X <: Q.
     NullabilitySuffix pNullability = p.nullabilitySuffix;
-    if (typeOperations.matchInferableParameter(p)
+    if (typeOperations.matchInferableParameter(new SharedTypeView(p))
         case StructuralParameter pParameter?
         when pNullability == NullabilitySuffix.none &&
             _parametersToConstrain.contains(pParameter)) {
@@ -454,7 +458,7 @@
     //
     // Under constraint P <: X <: _.
     NullabilitySuffix qNullability = q.nullabilitySuffix;
-    if (typeOperations.matchInferableParameter(q)
+    if (typeOperations.matchInferableParameter(new SharedTypeView(q))
         case StructuralParameter qParameter?
         when qNullability == NullabilitySuffix.none &&
             _parametersToConstrain.contains(qParameter)) {
@@ -479,7 +483,11 @@
     if (pNullability == NullabilitySuffix.star) {
       // Coverage-ignore-block(suite): Not run.
       return _isNullabilityAwareSubtypeMatch(
-          typeOperations.withNullabilitySuffix(p, NullabilitySuffix.none), q,
+          typeOperations
+              .withNullabilitySuffix(
+                  new SharedTypeView(p), NullabilitySuffix.none)
+              .unwrapTypeView(),
+          q,
           constrainSupertype: constrainSupertype,
           treeNodeForTesting: treeNodeForTesting);
     }
@@ -494,21 +502,27 @@
       // Coverage-ignore-block(suite): Not run.
       final int baseConstraintCount = _protoConstraints.length;
 
-      if ((p is SharedDynamicType || p is SharedVoidType) &&
-          _isNullabilityAwareSubtypeMatch(p,
-              typeOperations.withNullabilitySuffix(q, NullabilitySuffix.none),
+      if ((p is SharedDynamicTypeStructure || p is SharedVoidTypeStructure) &&
+          _isNullabilityAwareSubtypeMatch(
+              p,
+              typeOperations
+                  .withNullabilitySuffix(
+                      new SharedTypeView(q), NullabilitySuffix.none)
+                  .unwrapTypeView(),
               constrainSupertype: constrainSupertype,
               treeNodeForTesting: treeNodeForTesting)) {
         return true;
       }
       _protoConstraints.length = baseConstraintCount;
 
-      if (p is! SharedDynamicType &&
-          p is! SharedVoidType &&
+      if (p is! SharedDynamicTypeStructure &&
+          p is! SharedVoidTypeStructure &&
           _isNullabilityAwareSubtypeMatch(
               p,
-              typeOperations.withNullabilitySuffix(
-                  q, NullabilitySuffix.question),
+              typeOperations
+                  .withNullabilitySuffix(
+                      new SharedTypeView(q), NullabilitySuffix.question)
+                  .unwrapTypeView(),
               constrainSupertype: constrainSupertype,
               treeNodeForTesting: treeNodeForTesting)) {
         return true;
@@ -517,9 +531,11 @@
     }
 
     if (constrainSupertype
-        ? performSubtypeConstraintGenerationForFutureOrLeftSchema(p, q,
+        ? performSubtypeConstraintGenerationForFutureOrLeftSchema(
+            new SharedTypeSchemaView(p), new SharedTypeView(q),
             astNodeForTesting: treeNodeForTesting)
-        : performSubtypeConstraintGenerationForFutureOrRightSchema(p, q,
+        : performSubtypeConstraintGenerationForFutureOrRightSchema(
+            new SharedTypeView(p), new SharedTypeSchemaView(q),
             astNodeForTesting: treeNodeForTesting)) {
       return true;
     }
@@ -534,10 +550,12 @@
     // Or if P is a subtype match for Q0 under empty constraint set C.
     if (qNullability == NullabilitySuffix.question) {
       final int baseConstraintCount = _protoConstraints.length;
-      final DartType rawP =
-          typeOperations.withNullabilitySuffix(p, NullabilitySuffix.none);
-      final DartType rawQ =
-          typeOperations.withNullabilitySuffix(q, NullabilitySuffix.none);
+      final DartType rawP = typeOperations
+          .withNullabilitySuffix(new SharedTypeView(p), NullabilitySuffix.none)
+          .unwrapTypeView();
+      final DartType rawQ = typeOperations
+          .withNullabilitySuffix(new SharedTypeView(q), NullabilitySuffix.none)
+          .unwrapTypeView();
 
       if (pNullability == NullabilitySuffix.question &&
           _isNullabilityAwareSubtypeMatch(rawP, rawQ,
@@ -547,8 +565,9 @@
       }
       _protoConstraints.length = baseConstraintCount;
 
-      if ((p is SharedDynamicType || p is SharedVoidType) &&
-          _isNullabilityAwareSubtypeMatch(typeOperations.objectType, rawQ,
+      if ((p is SharedDynamicTypeStructure || p is SharedVoidTypeStructure) &&
+          _isNullabilityAwareSubtypeMatch(
+              typeOperations.objectType.unwrapTypeView(), rawQ,
               constrainSupertype: constrainSupertype,
               treeNodeForTesting: treeNodeForTesting)) {
         return true;
@@ -565,7 +584,8 @@
       }
       _protoConstraints.length = baseConstraintCount;
 
-      if (_isNullabilityAwareSubtypeMatch(p, typeOperations.nullType,
+      if (_isNullabilityAwareSubtypeMatch(
+          p, typeOperations.nullType.unwrapTypeView(),
           constrainSupertype: constrainSupertype,
           treeNodeForTesting: treeNodeForTesting)) {
         return true;
@@ -582,9 +602,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) case DartType p0?) {
+    if (typeOperations.matchFutureOrInternal(p) case DartType p0?) {
       final int baseConstraintCount = _protoConstraints.length;
-      if (_isNullabilityAwareSubtypeMatch(typeOperations.futureType(p0), q,
+      if (_isNullabilityAwareSubtypeMatch(
+              typeOperations.futureTypeInternal(p0), q,
               constrainSupertype: constrainSupertype,
               treeNodeForTesting: treeNodeForTesting) &&
           // Coverage-ignore(suite): Not run.
@@ -603,11 +624,15 @@
     if (pNullability == NullabilitySuffix.question) {
       final int baseConstraintCount = _protoConstraints.length;
       if (_isNullabilityAwareSubtypeMatch(
-              typeOperations.withNullabilitySuffix(p, NullabilitySuffix.none),
+              typeOperations
+                  .withNullabilitySuffix(
+                      new SharedTypeView(p), NullabilitySuffix.none)
+                  .unwrapTypeView(),
               q,
               constrainSupertype: constrainSupertype,
               treeNodeForTesting: treeNodeForTesting) &&
-          _isNullabilityAwareSubtypeMatch(typeOperations.nullType, q,
+          _isNullabilityAwareSubtypeMatch(
+              typeOperations.nullType.unwrapTypeView(), q,
               constrainSupertype: constrainSupertype,
               treeNodeForTesting: treeNodeForTesting)) {
         return true;
@@ -617,28 +642,28 @@
 
     // If Q is dynamic, Object?, or void then the match holds under no
     // constraints.
-    if (q is SharedDynamicType ||
-        q is SharedVoidType ||
-        q == typeOperations.objectQuestionType) {
+    if (q is SharedDynamicTypeStructure ||
+        q is SharedVoidTypeStructure ||
+        q == typeOperations.objectQuestionType.unwrapTypeView()) {
       return true;
     }
 
     // If P is Never then the match holds under no constraints.
-    if (typeOperations.isNever(p)) {
+    if (typeOperations.isNever(new SharedTypeView(p))) {
       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.isNonNullable(p);
+    if (q == typeOperations.objectType.unwrapTypeView()) {
+      return typeOperations.isNonNullable(new SharedTypeSchemaView(p));
     }
 
     // If P is Null, then the match holds under no constraints:
     //
     // Only if Q is nullable.
-    if (typeOperations.isNull(p)) {
+    if (typeOperations.isNull(new SharedTypeView(p))) {
       return q.nullability == Nullability.nullable;
     }
 
@@ -668,8 +693,8 @@
     }
 
     switch ((
-      typeOperations.matchTypeDeclarationType(p),
-      typeOperations.matchTypeDeclarationType(q)
+      typeOperations.matchTypeDeclarationType(new SharedTypeView(p)),
+      typeOperations.matchTypeDeclarationType(new SharedTypeView(q))
     )) {
       // If P is C<M0, ..., Mk> and Q is C<N0, ..., Nk>, then the match holds
       // under constraints C0 + ... + Ck:
@@ -764,9 +789,9 @@
     // If Q is Function then the match holds under no constraints:
     //
     // If P is a function type.
-    if (typeOperations.isDartCoreFunction(q) &&
+    if (typeOperations.isDartCoreFunction(new SharedTypeView(q)) &&
         // Coverage-ignore(suite): Not run.
-        typeOperations.isFunctionType(p)) {
+        typeOperations.isFunctionType(new SharedTypeView(p))) {
       return true;
     }
 
@@ -777,8 +802,8 @@
     // 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) &&
+    if (typeOperations.isFunctionType(new SharedTypeView(p)) &&
+        typeOperations.isFunctionType(new SharedTypeView(q)) &&
         (p as FunctionType).typeParameters.isEmpty &&
         (q as FunctionType).typeParameters.isEmpty &&
         p.namedParameters.isEmpty &&
@@ -806,8 +831,8 @@
 
     // Function types with named parameters are treated analogously to the
     // positional parameter case above.
-    if (typeOperations.isFunctionType(p) &&
-        typeOperations.isFunctionType(q) &&
+    if (typeOperations.isFunctionType(new SharedTypeView(p)) &&
+        typeOperations.isFunctionType(new SharedTypeView(q)) &&
         (p as FunctionType).typeParameters.isEmpty &&
         (q as FunctionType).typeParameters.isEmpty &&
         p.positionalParameters.length == p.requiredParameterCount &&
@@ -869,8 +894,8 @@
     // 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) &&
+    if (typeOperations.isFunctionType(new SharedTypeView(p)) &&
+        typeOperations.isFunctionType(new SharedTypeView(q)) &&
         (p as FunctionType).typeParameters.isNotEmpty &&
         (q as FunctionType).typeParameters.isNotEmpty &&
         p.typeParameters.length == q.typeParameters.length) {
@@ -907,8 +932,8 @@
               new NullabilityAwareTypeVariableEliminator(
                   structuralEliminationTargets: p.typeParameters.toSet(),
                   nominalEliminationTargets: {},
-                  bottomType: typeOperations.neverType,
-                  topType: typeOperations.objectQuestionType,
+                  bottomType: typeOperations.neverType.unwrapTypeView(),
+                  topType: typeOperations.objectQuestionType.unwrapTypeView(),
                   topFunctionType:
                       _environment.coreTypes.functionNonNullableRawType,
                   unhandledTypeHandler:
@@ -921,12 +946,16 @@
                               "Unsupported type '${type.runtimeType}'."));
           for (GeneratedTypeConstraint constraint in constraints) {
             if (constraint.isUpper) {
-              _constrainParameterUpper(constraint.typeParameter,
-                  eliminator.eliminateToLeast(constraint.constraint),
+              _constrainParameterUpper(
+                  constraint.typeParameter,
+                  eliminator.eliminateToLeast(
+                      constraint.constraint.unwrapTypeSchemaView()),
                   treeNodeForTesting: treeNodeForTesting);
             } else {
-              _constrainParameterLower(constraint.typeParameter,
-                  eliminator.eliminateToGreatest(constraint.constraint),
+              _constrainParameterLower(
+                  constraint.typeParameter,
+                  eliminator.eliminateToGreatest(
+                      constraint.constraint.unwrapTypeSchemaView()),
                   treeNodeForTesting: treeNodeForTesting);
             }
           }
@@ -951,8 +980,8 @@
     // 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 (p is SharedRecordType<DartType> &&
-        q is SharedRecordType<DartType> &&
+    if (p is SharedRecordTypeStructure<DartType> &&
+        q is SharedRecordTypeStructure<DartType> &&
         (p as RecordType).positional.length ==
             (q as RecordType).positional.length &&
         p.named.length == q.named.length) {
@@ -997,10 +1026,10 @@
       {required TreeNode? treeNodeForTesting}) {
     // The unknown type `?` is a subtype match for any type `Q` with no
     // constraints.
-    if (subtype is SharedUnknownType) return true;
+    if (subtype is SharedUnknownTypeStructure) return true;
     // Any type `P` is a subtype match for the unknown type `?` with no
     // constraints.
-    if (supertype is SharedUnknownType) return true;
+    if (supertype is SharedUnknownTypeStructure) return true;
     // A type variable `T` in `L` is a subtype match for any type schema `Q`:
     // - Under constraint `T <: Q`.
 
@@ -1044,7 +1073,7 @@
     if (identical(subtype, supertype)) return true;
 
     // Handle FutureOr<T> union type.
-    if (typeOperations.matchFutureOr(subtype) != null) {
+    if (typeOperations.matchFutureOrInternal(subtype) != null) {
       DartType subtypeArg = (subtype as FutureOrType).typeArgument;
       if (supertype is FutureOrType) {
         // `FutureOr<P>` is a subtype match for `FutureOr<Q>` with respect to
@@ -1062,7 +1091,8 @@
       //   constraints `C0`.
       // - And `P` is a subtype match for `Q` with respect to `L` under
       //   constraints `C1`.
-      InterfaceType subtypeFuture = typeOperations.futureType(subtypeArg);
+      InterfaceType subtypeFuture =
+          typeOperations.futureTypeInternal(subtypeArg);
       return _isNullabilityObliviousSubtypeMatch(subtypeFuture, supertype,
               treeNodeForTesting: treeNodeForTesting) &&
           _isNullabilityObliviousSubtypeMatch(subtypeArg, supertype,
@@ -1071,7 +1101,7 @@
               .isSubtypeWhenUsingNullabilities();
     }
 
-    if (typeOperations.matchFutureOr(supertype) != null) {
+    if (typeOperations.matchFutureOrInternal(supertype) != null) {
       // `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
@@ -1098,7 +1128,7 @@
       DartType supertypeArg =
           supertype.typeArgument.withDeclaredNullability(unitedNullability);
       DartType supertypeFuture = typeOperations
-          .futureType(supertypeArg)
+          .futureTypeInternal(supertypeArg)
           .withDeclaredNullability(unitedNullability);
 
       // The match against FutureOr<X> succeeds if the match against either
@@ -1121,7 +1151,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 (typeOperations.isNull(new SharedTypeView(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
@@ -1163,14 +1193,14 @@
           subtype.parameter.bound, supertype,
           treeNodeForTesting: treeNodeForTesting);
     }
-    if (typeOperations.isInterfaceType(subtype) &&
-        typeOperations.isInterfaceType(supertype)) {
+    if (typeOperations.isInterfaceType(new SharedTypeView(subtype)) &&
+        typeOperations.isInterfaceType(new SharedTypeView(supertype))) {
       return _isNullabilityObliviousInterfaceSubtypeMatch(
           subtype as InterfaceType, supertype as InterfaceType,
           treeNodeForTesting: treeNodeForTesting);
     }
-    if (typeOperations.isFunctionType(subtype)) {
-      if (typeOperations.isInterfaceType(supertype)) {
+    if (typeOperations.isFunctionType(new SharedTypeView(subtype))) {
+      if (typeOperations.isInterfaceType(new SharedTypeView(supertype))) {
         return supertype == _environment.coreTypes.functionLegacyRawType ||
             supertype == _environment.coreTypes.objectLegacyRawType;
       } else if (supertype is FunctionType) {
@@ -1183,7 +1213,7 @@
     // - 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)) {
+    if (typeOperations.isInterfaceType(new SharedTypeView(subtype))) {
       Member? callMember =
           getInterfaceMember((subtype as InterfaceType).classNode, callName);
       if (callMember is Procedure && !callMember.isGetter) {
diff --git a/pkg/front_end/lib/src/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/type_inference/type_inference_engine.dart
index b2f0942..2210e8c 100644
--- a/pkg/front_end/lib/src/type_inference/type_inference_engine.dart
+++ b/pkg/front_end/lib/src/type_inference/type_inference_engine.dart
@@ -7,6 +7,7 @@
 import 'package:_fe_analyzer_shared/src/type_inference/nullability_suffix.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart'
     hide Variance;
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart'
     show ClassHierarchy, ClassHierarchyBase;
@@ -432,8 +433,11 @@
 
 /// CFE-specific implementation of [FlowAnalysisOperations].
 class OperationsCfe
+    with
+        TypeAnalyzerOperationsMixin<DartType, VariableDeclaration,
+            StructuralParameter, TypeDeclarationType, TypeDeclaration>
     implements
-        TypeAnalyzerOperations<VariableDeclaration, DartType, DartType,
+        TypeAnalyzerOperations<DartType, VariableDeclaration,
             StructuralParameter, TypeDeclarationType, TypeDeclaration> {
   final TypeEnvironment typeEnvironment;
 
@@ -459,48 +463,69 @@
       required this.typeCacheLegacy});
 
   @override
-  DartType get boolType =>
-      typeEnvironment.coreTypes.boolRawType(Nullability.nonNullable);
+  SharedTypeView<DartType> get boolType {
+    return new SharedTypeView(
+        typeEnvironment.coreTypes.boolRawType(Nullability.nonNullable));
+  }
 
   @override
   // Coverage-ignore(suite): Not run.
-  DartType get doubleType => throw new UnimplementedError('TODO(paulberry)');
+  SharedTypeView<DartType> get doubleType {
+    throw new UnimplementedError('TODO(paulberry)');
+  }
 
   @override
-  DartType get dynamicType => const DynamicType();
+  SharedTypeView<DartType> get dynamicType {
+    return new SharedTypeView(const DynamicType());
+  }
 
   @override
-  DartType get errorType => const InvalidType();
+  SharedTypeView<DartType> get errorType {
+    return new SharedTypeView(const InvalidType());
+  }
 
   @override
   // Coverage-ignore(suite): Not run.
-  DartType get intType => throw new UnimplementedError('TODO(paulberry)');
+  SharedTypeView<DartType> get intType {
+    throw new UnimplementedError('TODO(paulberry)');
+  }
 
   @override
-  DartType get neverType => const NeverType.nonNullable();
+  SharedTypeView<DartType> get neverType {
+    return new SharedTypeView(const NeverType.nonNullable());
+  }
 
   @override
-  DartType get nullType => const NullType();
+  SharedTypeView<DartType> get nullType {
+    return new SharedTypeView(const NullType());
+  }
 
   @override
-  DartType get objectQuestionType =>
-      typeEnvironment.coreTypes.objectNullableRawType;
+  SharedTypeView<DartType> get objectQuestionType {
+    return new SharedTypeView(typeEnvironment.coreTypes.objectNullableRawType);
+  }
 
   @override
-  DartType get objectType => typeEnvironment.coreTypes.objectNonNullableRawType;
+  SharedTypeView<DartType> get objectType {
+    return new SharedTypeView(
+        typeEnvironment.coreTypes.objectNonNullableRawType);
+  }
 
   @override
-  DartType get unknownType => const UnknownType();
+  SharedTypeSchemaView<DartType> get unknownType {
+    return new SharedTypeSchemaView(const UnknownType());
+  }
 
   @override
-  TypeClassification classifyType(DartType? type) {
-    if (type == null) {
+  TypeClassification classifyType(SharedTypeView<DartType>? type) {
+    DartType? unwrapped = type?.unwrapTypeView();
+    if (unwrapped == null) {
       // Note: this can happen during top-level inference.
       return TypeClassification.potentiallyNullable;
-    } else if (isSubtypeOf(
-        type, typeEnvironment.coreTypes.objectNonNullableRawType)) {
+    } else if (isSubtypeOfInternal(
+        unwrapped, typeEnvironment.coreTypes.objectNonNullableRawType)) {
       return TypeClassification.nonNullable;
-    } else if (isSubtypeOf(type, const NullType())) {
+    } else if (isSubtypeOfInternal(unwrapped, const NullType())) {
       return TypeClassification.nullOrEquivalent;
     } else {
       return TypeClassification.potentiallyNullable;
@@ -508,48 +533,56 @@
   }
 
   @override
-  DartType factor(DartType from, DartType what) {
-    return factorType(typeEnvironment, from, what);
+  SharedTypeView<DartType> factor(
+      SharedTypeView<DartType> from, SharedTypeView<DartType> what) {
+    return new SharedTypeView(factorType(
+        typeEnvironment, from.unwrapTypeView(), what.unwrapTypeView()));
   }
 
   @override
-  DartType greatestClosure(DartType schema) =>
-      type_schema_elimination.greatestClosure(
-          schema, const DynamicType(), const NeverType.nonNullable());
+  SharedTypeView<DartType> greatestClosure(
+      SharedTypeSchemaView<DartType> schema) {
+    return new SharedTypeView(type_schema_elimination.greatestClosure(
+        schema.unwrapTypeSchemaView(),
+        const DynamicType(),
+        const NeverType.nonNullable()));
+  }
 
   @override
-  bool isAlwaysExhaustiveType(DartType type) {
-    return computeIsAlwaysExhaustiveType(type, typeEnvironment.coreTypes);
+  bool isAlwaysExhaustiveType(SharedTypeView<DartType> type) {
+    return computeIsAlwaysExhaustiveType(
+        type.unwrapTypeView(), typeEnvironment.coreTypes);
   }
 
   @override
   // Coverage-ignore(suite): Not run.
-  bool isExtensionType(DartType type) {
-    return type is ExtensionType;
+  bool isExtensionType(SharedTypeView<DartType> type) {
+    return type.unwrapTypeView() is ExtensionType;
   }
 
   @override
   // Coverage-ignore(suite): Not run.
-  bool isInterfaceType(DartType type) {
-    return type is InterfaceType;
+  bool isInterfaceType(SharedTypeView<DartType> type) {
+    return type.unwrapTypeView() is InterfaceType;
   }
 
   @override
-  bool isNever(DartType type) {
-    return typeEnvironment.coreTypes.isBottom(type);
+  bool isNever(SharedTypeView<DartType> type) {
+    return typeEnvironment.coreTypes.isBottom(type.unwrapTypeView());
   }
 
   @override
-  bool isNull(DartType type) {
-    return type is NullType;
+  bool isNull(SharedTypeView<DartType> type) {
+    return type.unwrapTypeView() is NullType;
   }
 
   @override
   // Coverage-ignore(suite): Not run.
-  bool isObject(DartType type) {
-    return type is InterfaceType &&
-        type.classNode == typeEnvironment.objectClass &&
-        type.nullability == Nullability.nonNullable;
+  bool isObject(SharedTypeView<DartType> type) {
+    DartType unwrappedType = type.unwrapTypeView();
+    return unwrappedType is InterfaceType &&
+        unwrappedType.classNode == typeEnvironment.objectClass &&
+        unwrappedType.nullability == Nullability.nonNullable;
   }
 
   @override
@@ -590,23 +623,24 @@
   }
 
   @override
-  bool isSubtypeOf(DartType leftType, DartType rightType) {
+  bool isSubtypeOfInternal(DartType leftType, DartType rightType) {
     return typeEnvironment.isSubtypeOf(
         leftType, rightType, SubtypeCheckMode.withNullabilities);
   }
 
   @override
-  DartType promoteToNonNull(DartType type) {
-    if (type.nullability == Nullability.nonNullable) {
+  SharedTypeView<DartType> promoteToNonNull(SharedTypeView<DartType> type) {
+    DartType unwrappedType = type.unwrapTypeView();
+    if (unwrappedType.nullability == Nullability.nonNullable) {
       return type;
     }
-    DartType? cached = typeCacheNonNullable[type];
+    DartType? cached = typeCacheNonNullable[unwrappedType];
     if (cached != null) {
-      return cached;
+      return new SharedTypeView(cached);
     }
-    DartType result = type.toNonNull();
-    typeCacheNonNullable[type] = result;
-    return result;
+    DartType result = unwrappedType.toNonNull();
+    typeCacheNonNullable[unwrappedType] = result;
+    return new SharedTypeView(result);
   }
 
   DartType getNullableType(DartType type) {
@@ -626,68 +660,78 @@
   }
 
   @override
-  DartType variableType(VariableDeclaration variable) {
+  SharedTypeView<DartType> variableType(VariableDeclaration variable) {
     if (variable is VariableDeclarationImpl) {
       // When late variables get lowered, their type is changed, but the
       // original type is stored in `VariableDeclarationImpl.lateType`, so we
       // use that if it exists.
-      return variable.lateType ?? variable.type;
+      return new SharedTypeView(variable.lateType ?? variable.type);
     }
-    return variable.type;
+    return new SharedTypeView(variable.type);
   }
 
   @override
-  bool isTypeParameterType(DartType type) {
-    return type is TypeParameterType || type is IntersectionType;
+  bool isTypeParameterType(SharedTypeView<DartType> type) {
+    return type.unwrapTypeView() is TypeParameterType ||
+        type.unwrapTypeView() is IntersectionType;
   }
 
   @override
-  DartType tryPromoteToType(DartType to, DartType from) {
-    if (isSubtypeOf(to, from)) {
+  SharedTypeView<DartType> tryPromoteToType(
+      SharedTypeView<DartType> to, SharedTypeView<DartType> from) {
+    DartType unwrappedTo = to.unwrapTypeView();
+    DartType unwrappedFrom = from.unwrapTypeView();
+    if (isSubtypeOfInternal(unwrappedTo, unwrappedFrom)) {
       return to;
     }
-    if (from is TypeParameterType) {
-      if (isSubtypeOf(to, from.bound)) {
-        if (to.nullability != Nullability.nullable) {
+    if (unwrappedFrom is TypeParameterType) {
+      if (isSubtypeOfInternal(unwrappedTo, unwrappedFrom.bound)) {
+        if (to.unwrapTypeView().nullability != Nullability.nullable) {
           // We treat promotions of the form `x is T`, where `T` is not
           // nullable, as a two-step promotions equivalent to
           // `x != null && x is T`.
-          return new IntersectionType(
-              from.withDeclaredNullability(
+          return new SharedTypeView(new IntersectionType(
+              unwrappedFrom.withDeclaredNullability(
                   TypeParameterType.computeNullabilityFromBound(
-                      from.parameter)),
-              to);
+                      unwrappedFrom.parameter)),
+              unwrappedTo));
         } else {
-          return new IntersectionType(from, to);
+          return new SharedTypeView(
+              new IntersectionType(unwrappedFrom, unwrappedTo));
         }
       }
     }
-    if (from is IntersectionType) {
-      if (isSubtypeOf(to, from.right)) {
-        return new IntersectionType(from.left, to);
+    if (unwrappedFrom is IntersectionType) {
+      if (isSubtypeOfInternal(unwrappedTo, unwrappedFrom.right)) {
+        return new SharedTypeView(
+            new IntersectionType(unwrappedFrom.left, unwrappedTo));
       }
     }
-    return from;
+    return new SharedTypeView(unwrappedFrom);
   }
 
   @override
-  DartType glb(DartType type1, DartType type2) {
+  DartType glbInternal(DartType type1, DartType type2) {
     return typeEnvironment.getStandardLowerBound(type1, type2);
   }
 
   @override
-  bool isAssignableTo(DartType fromType, DartType toType) {
+  bool isAssignableTo(
+      SharedTypeView<DartType> fromType, SharedTypeView<DartType> toType) {
     if (fromType is DynamicType) return true;
     return typeEnvironment
-        .performNullabilityAwareSubtypeCheck(fromType, toType)
+        .performNullabilityAwareSubtypeCheck(
+            fromType.unwrapTypeView(), toType.unwrapTypeView())
         .isSubtypeWhenUsingNullabilities();
   }
 
   @override
-  bool isFunctionType(DartType type) => type is FunctionType;
+  bool isFunctionType(SharedTypeView<DartType> type) {
+    return type.unwrapTypeView() is FunctionType;
+  }
 
   @override
-  DartType? matchFutureOr(DartType type) {
+  DartType? matchFutureOrInternal(DartType type) {
     if (type is! FutureOrType) {
       return null;
     } else {
@@ -698,8 +742,11 @@
   @override
   // Coverage-ignore(suite): Not run.
   bool isTypeSchemaSatisfied(
-          {required DartType typeSchema, required DartType type}) =>
-      isSubtypeOf(type, typeSchema);
+      {required SharedTypeSchemaView<DartType> typeSchema,
+      required SharedTypeView<DartType> type}) {
+    return isSubtypeOfInternal(
+        type.unwrapTypeView(), typeSchema.unwrapTypeSchemaView());
+  }
 
   @override
   bool isVariableFinal(VariableDeclaration node) {
@@ -707,64 +754,48 @@
   }
 
   @override
-  DartType iterableTypeSchema(DartType elementTypeSchema) {
-    return new InterfaceType(typeEnvironment.coreTypes.iterableClass,
-        Nullability.nonNullable, <DartType>[elementTypeSchema]);
+  SharedTypeSchemaView<DartType> iterableTypeSchema(
+      SharedTypeSchemaView<DartType> elementTypeSchema) {
+    return new SharedTypeSchemaView(new InterfaceType(
+        typeEnvironment.coreTypes.iterableClass,
+        Nullability.nonNullable,
+        <DartType>[elementTypeSchema.unwrapTypeSchemaView()]));
   }
 
   @override
-  DartType listType(DartType elementType) {
+  DartType listTypeInternal(DartType elementType) {
     return new InterfaceType(typeEnvironment.coreTypes.listClass,
         Nullability.nonNullable, <DartType>[elementType]);
   }
 
   @override
-  DartType listTypeSchema(DartType elementTypeSchema) {
-    return new InterfaceType(typeEnvironment.coreTypes.listClass,
-        Nullability.nonNullable, <DartType>[elementTypeSchema]);
-  }
-
-  @override
-  DartType lub(DartType type1, DartType type2) {
+  DartType lubInternal(DartType type1, DartType type2) {
     return typeEnvironment.getStandardUpperBound(type1, type2);
   }
 
   @override
-  DartType makeNullable(DartType type) {
+  DartType makeNullableInternal(DartType type) {
     return type.withDeclaredNullability(Nullability.nullable);
   }
 
   @override
-  DartType makeTypeSchemaNullable(DartType typeSchema) =>
-      typeSchema.withDeclaredNullability(Nullability.nullable);
-
-  @override
-  DartType mapType({required DartType keyType, required DartType valueType}) {
+  DartType mapTypeInternal(
+      {required DartType keyType, required DartType valueType}) {
     return new InterfaceType(typeEnvironment.coreTypes.mapClass,
         Nullability.nonNullable, <DartType>[keyType, valueType]);
   }
 
   @override
-  DartType mapTypeSchema(
-      {required DartType keyTypeSchema, required DartType valueTypeSchema}) {
-    return new InterfaceType(typeEnvironment.coreTypes.mapClass,
-        Nullability.nonNullable, <DartType>[keyTypeSchema, valueTypeSchema]);
-  }
-
-  @override
-  DartType? matchIterableTypeSchema(DartType typeSchema) =>
-      matchIterableType(typeSchema);
-
-  @override
-  DartType? matchListType(DartType type) {
-    if (type is TypeDeclarationType) {
+  SharedTypeView<DartType>? matchListType(SharedTypeView<DartType> type) {
+    DartType unwrappedType = type.unwrapTypeView();
+    if (unwrappedType is TypeDeclarationType) {
       List<DartType>? typeArguments =
           typeEnvironment.getTypeArgumentsAsInstanceOf(
-              type, typeEnvironment.coreTypes.listClass);
+              unwrappedType, typeEnvironment.coreTypes.listClass);
       if (typeArguments == null || typeArguments.length != 1) {
         return null;
       } else {
-        return typeArguments.single;
+        return new SharedTypeView(typeArguments.single);
       }
     } else {
       return null;
@@ -772,33 +803,38 @@
   }
 
   @override
-  ({DartType keyType, DartType valueType})? matchMapType(DartType type) {
-    if (type is! TypeDeclarationType) {
+  ({SharedTypeView<DartType> keyType, SharedTypeView<DartType> valueType})?
+      matchMapType(SharedTypeView<DartType> type) {
+    DartType unwrappedType = type.unwrapTypeView();
+    if (unwrappedType is! TypeDeclarationType) {
       return null;
     } else {
       TypeDeclarationType? mapType = typeEnvironment.getTypeAsInstanceOf(
-          type, typeEnvironment.coreTypes.mapClass, typeEnvironment.coreTypes);
+          unwrappedType,
+          typeEnvironment.coreTypes.mapClass,
+          typeEnvironment.coreTypes);
       if (mapType == null) {
         return null;
       } else {
         return (
-          keyType: mapType.typeArguments[0],
-          valueType: mapType.typeArguments[1]
+          keyType: new SharedTypeView(mapType.typeArguments[0]),
+          valueType: new SharedTypeView(mapType.typeArguments[1])
         );
       }
     }
   }
 
   @override
-  DartType? matchStreamType(DartType type) {
-    if (type is TypeDeclarationType) {
+  SharedTypeView<DartType>? matchStreamType(SharedTypeView<DartType> type) {
+    DartType unwrappedType = type.unwrapTypeView();
+    if (unwrappedType is TypeDeclarationType) {
       List<DartType>? typeArguments =
           typeEnvironment.getTypeArgumentsAsInstanceOf(
-              type, typeEnvironment.coreTypes.streamClass);
+              unwrappedType, typeEnvironment.coreTypes.streamClass);
       if (typeArguments == null || typeArguments.length != 1) {
         return null;
       } else {
-        return typeArguments.single;
+        return new SharedTypeView(typeArguments.single);
       }
     } else {
       return null;
@@ -806,12 +842,13 @@
   }
 
   @override
-  DartType normalize(DartType type) {
-    return norm(typeEnvironment.coreTypes, type);
+  SharedTypeView<DartType> normalize(SharedTypeView<DartType> type) {
+    return new SharedTypeView(
+        norm(typeEnvironment.coreTypes, type.unwrapTypeView()));
   }
 
   @override
-  DartType? matchIterableType(DartType type) {
+  DartType? matchIterableTypeInternal(DartType type) {
     if (type is! TypeDeclarationType) {
       return null;
     } else {
@@ -828,7 +865,7 @@
   }
 
   @override
-  DartType recordType(
+  DartType recordTypeInternal(
       {required List<DartType> positional,
       required List<(String, DartType)> named}) {
     List<NamedType> namedFields = [];
@@ -840,70 +877,46 @@
   }
 
   @override
-  DartType recordTypeSchema(
-          {required List<DartType> positional,
-          required List<(String, DartType)> named}) =>
-      recordType(positional: positional, named: named);
-
-  @override
-  DartType streamTypeSchema(DartType elementTypeSchema) {
-    return new InterfaceType(typeEnvironment.coreTypes.streamClass,
-        Nullability.nonNullable, <DartType>[elementTypeSchema]);
+  SharedTypeSchemaView<DartType> streamTypeSchema(
+      SharedTypeSchemaView<DartType> elementTypeSchema) {
+    return new SharedTypeSchemaView(new InterfaceType(
+        typeEnvironment.coreTypes.streamClass,
+        Nullability.nonNullable,
+        <DartType>[elementTypeSchema.unwrapTypeSchemaView()]));
   }
 
   @override
-  DartType extensionTypeErasure(DartType type) {
-    return type.extensionTypeErasure;
+  SharedTypeView<DartType> extensionTypeErasure(SharedTypeView<DartType> type) {
+    return new SharedTypeView(type.unwrapTypeView().extensionTypeErasure);
   }
 
   @override
-  DartType typeSchemaGlb(DartType typeSchema1, DartType typeSchema2) =>
-      glb(typeSchema1, typeSchema2);
-
-  @override
-  DartType typeToSchema(DartType type) => type;
-
-  @override
-  DartType typeSchemaLub(DartType typeSchema1, DartType typeSchema2) {
-    return lub(typeSchema1, typeSchema2);
+  SharedTypeSchemaView<DartType> typeToSchema(SharedTypeView<DartType> type) {
+    return new SharedTypeSchemaView(type.unwrapTypeView());
   }
 
   @override
-  // Coverage-ignore(suite): Not run.
-  bool typeSchemaIsSubtypeOfTypeSchema(
-      DartType leftSchema, DartType rightSchema) {
-    return isSubtypeOf(leftSchema, rightSchema);
-  }
-
-  @override
-  // Coverage-ignore(suite): Not run.
-  bool typeIsSubtypeOfTypeSchema(DartType leftType, DartType rightSchema) {
-    return isSubtypeOf(leftType, rightSchema);
-  }
-
-  @override
-  // Coverage-ignore(suite): Not run.
-  bool typeSchemaIsSubtypeOfType(DartType leftSchema, DartType rightType) {
-    return isSubtypeOf(leftSchema, rightType);
-  }
-
-  @override
-  DartType withNullabilitySuffix(DartType type, NullabilitySuffix modifier) {
+  SharedTypeView<DartType> withNullabilitySuffix(
+      SharedTypeView<DartType> type, NullabilitySuffix modifier) {
     switch (modifier) {
       case NullabilitySuffix.none:
-        return computeTypeWithoutNullabilityMarker(type);
+        return new SharedTypeView(
+            computeTypeWithoutNullabilityMarker(type.unwrapTypeView()));
       // Coverage-ignore(suite): Not run.
       case NullabilitySuffix.question:
-        return type.withDeclaredNullability(Nullability.nullable);
+        return new SharedTypeView(type
+            .unwrapTypeView()
+            .withDeclaredNullability(Nullability.nullable));
       // Coverage-ignore(suite): Not run.
       case NullabilitySuffix.star:
-        return type.withDeclaredNullability(Nullability.legacy);
+        return new SharedTypeView(
+            type.unwrapTypeView().withDeclaredNullability(Nullability.legacy));
     }
   }
 
   @override
   // Coverage-ignore(suite): Not run.
-  TypeDeclarationKind? getTypeDeclarationKind(DartType type) {
+  TypeDeclarationKind? getTypeDeclarationKindInternal(DartType type) {
     if (type is TypeDeclarationType) {
       switch (type) {
         case InterfaceType():
@@ -917,40 +930,38 @@
   }
 
   @override
-  // Coverage-ignore(suite): Not run.
-  TypeDeclarationKind? getTypeSchemaDeclarationKind(DartType typeSchema) {
-    return getTypeDeclarationKind(typeSchema);
+  bool isNonNullable(SharedTypeSchemaView<DartType> typeSchema) {
+    return typeSchema.unwrapTypeSchemaView().nullability ==
+        Nullability.nonNullable;
   }
 
   @override
-  bool isNonNullable(DartType typeSchema) {
-    return typeSchema.nullability == Nullability.nonNullable;
-  }
-
-  @override
-  StructuralParameter? matchInferableParameter(DartType type) {
-    if (type is StructuralParameterType) {
-      return type.parameter;
+  StructuralParameter? matchInferableParameter(SharedTypeView<DartType> type) {
+    DartType unwrappedType = type.unwrapTypeView();
+    if (unwrappedType is StructuralParameterType) {
+      return unwrappedType.parameter;
     } else {
       return null;
     }
   }
 
   @override
-  InterfaceType futureType(DartType argumentType) {
+  InterfaceType futureTypeInternal(DartType argumentType) {
     return new InterfaceType(typeEnvironment.coreTypes.futureClass,
         Nullability.nonNullable, <DartType>[argumentType]);
   }
 
   @override
-  TypeDeclarationMatchResult? matchTypeDeclarationType(DartType type) {
-    if (type is TypeDeclarationType) {
-      switch (type) {
+  TypeDeclarationMatchResult? matchTypeDeclarationType(
+      SharedTypeView<DartType> type) {
+    DartType unwrappedType = type.unwrapTypeView();
+    if (unwrappedType is TypeDeclarationType) {
+      switch (unwrappedType) {
         case InterfaceType(:List<DartType> typeArguments, :Class classNode):
           return new TypeDeclarationMatchResult(
               typeDeclarationKind: TypeDeclarationKind.interfaceDeclaration,
               typeDeclaration: classNode,
-              typeDeclarationType: type,
+              typeDeclarationType: unwrappedType,
               typeArguments: typeArguments);
         case ExtensionType(
             :List<DartType> typeArguments,
@@ -959,7 +970,7 @@
           return new TypeDeclarationMatchResult(
               typeDeclarationKind: TypeDeclarationKind.extensionTypeDeclaration,
               typeDeclaration: extensionTypeDeclaration,
-              typeDeclarationType: type,
+              typeDeclarationType: unwrappedType,
               typeArguments: typeArguments);
       }
     } else {
@@ -974,29 +985,9 @@
   }
 
   @override
-  bool isDartCoreFunction(DartType type) {
-    return type == typeEnvironment.coreTypes.functionNonNullableRawType;
-  }
-
-  @override
-  // Coverage-ignore(suite): Not run.
-  NullabilitySuffix typeSchemaNullabilitySuffix(DartType typeSchema) {
-    return typeSchema.nullabilitySuffix;
-  }
-
-  @override
-  DartType futureTypeSchema(DartType argumentTypeSchema) {
-    return new InterfaceType(typeEnvironment.coreTypes.futureClass,
-        Nullability.nonNullable, <DartType>[argumentTypeSchema]);
-  }
-
-  @override
-  DartType? matchTypeSchemaFutureOr(DartType typeSchema) {
-    if (typeSchema is! FutureOrType) {
-      return null;
-    } else {
-      return typeSchema.typeArgument;
-    }
+  bool isDartCoreFunction(SharedTypeView<DartType> type) {
+    return type.unwrapTypeView() ==
+        typeEnvironment.coreTypes.functionNonNullableRawType;
   }
 }
 
diff --git a/pkg/front_end/lib/src/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/type_inference/type_inferrer.dart
index 207282b..256971b 100644
--- a/pkg/front_end/lib/src/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/type_inference/type_inferrer.dart
@@ -4,6 +4,7 @@
 
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/assigned_variables.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/type_environment.dart';
 
@@ -32,8 +33,8 @@
   TypeSchemaEnvironment get typeSchemaEnvironment;
 
   /// Returns the [FlowAnalysis] used during inference.
-  FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration, DartType>
-      get flowAnalysis;
+  FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration,
+      SharedTypeView<DartType>> get flowAnalysis;
 
   AssignedVariables<TreeNode, VariableDeclaration> get assignedVariables;
 
@@ -89,7 +90,7 @@
 
   @override
   late final FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration,
-          DartType> flowAnalysis =
+          SharedTypeView<DartType>> flowAnalysis =
       new FlowAnalysis(operations, assignedVariables,
           respectImplicitlyTypedVarInitializers:
               libraryBuilder.libraryFeatures.constructorTearoffs.isEnabled,
@@ -211,14 +212,16 @@
     List<Expression> positionalArguments = <Expression>[];
     for (VariableDeclaration parameter
         in redirectingFactoryFunction.positionalParameters) {
-      flowAnalysis.declare(parameter, parameter.type, initialized: true);
+      flowAnalysis.declare(parameter, new SharedTypeView(parameter.type),
+          initialized: true);
       positionalArguments
           .add(new VariableGetImpl(parameter, forNullGuardedAccess: false));
     }
     List<NamedExpression> namedArguments = <NamedExpression>[];
     for (VariableDeclaration parameter
         in redirectingFactoryFunction.namedParameters) {
-      flowAnalysis.declare(parameter, parameter.type, initialized: true);
+      flowAnalysis.declare(parameter, new SharedTypeView(parameter.type),
+          initialized: true);
       namedArguments.add(new NamedExpression(parameter.name!,
           new VariableGetImpl(parameter, forNullGuardedAccess: false)));
     }
@@ -321,8 +324,8 @@
       impl.assignedVariables;
 
   @override
-  FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration, DartType>
-      get flowAnalysis => impl.flowAnalysis;
+  FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration,
+      SharedTypeView<DartType>> get flowAnalysis => impl.flowAnalysis;
 
   @override
   TypeSchemaEnvironment get typeSchemaEnvironment => impl.typeSchemaEnvironment;
diff --git a/pkg/front_end/lib/src/type_inference/type_schema.dart b/pkg/front_end/lib/src/type_inference/type_schema.dart
index 312efc1..013ee58 100644
--- a/pkg/front_end/lib/src/type_inference/type_schema.dart
+++ b/pkg/front_end/lib/src/type_inference/type_schema.dart
@@ -49,7 +49,8 @@
 ///
 /// The unknown type cannot appear in programs or in final inferred types: it is
 /// purely part of the local inference process.
-class UnknownType extends AuxiliaryType implements SharedUnknownType<DartType> {
+class UnknownType extends AuxiliaryType
+    implements SharedUnknownTypeStructure<DartType> {
   const UnknownType();
 
   @override
diff --git a/pkg/front_end/lib/src/type_inference/type_schema_environment.dart b/pkg/front_end/lib/src/type_inference/type_schema_environment.dart
index b0c065b..9b484ab 100644
--- a/pkg/front_end/lib/src/type_inference/type_schema_environment.dart
+++ b/pkg/front_end/lib/src/type_inference/type_schema_environment.dart
@@ -6,6 +6,7 @@
     as shared;
 import 'package:_fe_analyzer_shared/src/type_inference/type_constraint.dart'
     as shared;
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 import 'package:kernel/core_types.dart' show CoreTypes;
@@ -23,11 +24,10 @@
 import 'type_schema_elimination.dart' show greatestClosure, leastClosure;
 
 typedef GeneratedTypeConstraint = shared.GeneratedTypeConstraint<DartType,
-    DartType, StructuralParameter, VariableDeclaration>;
+    StructuralParameter, VariableDeclaration>;
 
 typedef MergedTypeConstraint = shared.MergedTypeConstraint<
     DartType,
-    DartType,
     StructuralParameter,
     VariableDeclaration,
     TypeDeclarationType,
@@ -35,7 +35,6 @@
 
 typedef UnknownTypeConstraintOrigin = shared.UnknownTypeConstraintOrigin<
     DartType,
-    DartType,
     VariableDeclaration,
     StructuralParameter,
     TypeDeclarationType,
@@ -341,43 +340,53 @@
         bottomType == const NullType());
     if (!isContravariant) {
       // Prefer the known bound, if any.
-      if (isKnown(constraint.lower)) return constraint.lower;
-      if (isKnown(constraint.upper)) return constraint.upper;
+      if (isKnown(constraint.lower.unwrapTypeSchemaView())) {
+        return constraint.lower.unwrapTypeSchemaView();
+      }
+      if (isKnown(constraint.upper.unwrapTypeSchemaView())) {
+        return constraint.upper.unwrapTypeSchemaView();
+      }
 
       // Otherwise take whatever bound has partial information,
       // e.g. `Iterable<?>`
-      if (constraint.lower is! UnknownType) {
+      if (constraint.lower is! SharedUnknownTypeSchemaView<DartType>) {
         return grounded
-            ? leastClosure(constraint.lower, topType, bottomType)
-            : constraint.lower;
+            ? leastClosure(
+                constraint.lower.unwrapTypeSchemaView(), topType, bottomType)
+            : constraint.lower.unwrapTypeSchemaView();
       } else if (constraint.upper is! UnknownType) {
         return grounded
-            ? greatestClosure(constraint.upper, topType, bottomType)
-            : constraint.upper;
+            ? greatestClosure(
+                constraint.upper.unwrapTypeSchemaView(), topType, bottomType)
+            : constraint.upper.unwrapTypeSchemaView();
       } else {
         return const UnknownType();
       }
     } else {
       // Prefer the known bound, if any.
-      if (isKnown(constraint.upper)) {
+      if (isKnown(constraint.upper.unwrapTypeSchemaView())) {
         // Coverage-ignore-block(suite): Not run.
-        return constraint.upper;
+        return constraint.upper.unwrapTypeSchemaView();
       }
-      if (isKnown(constraint.lower)) return constraint.lower;
+      if (isKnown(constraint.lower.unwrapTypeSchemaView())) {
+        return constraint.lower.unwrapTypeSchemaView();
+      }
 
       // Otherwise take whatever bound has partial information,
       // e.g. `Iterable<?>`
       if (constraint.upper is! UnknownType) {
         // Coverage-ignore-block(suite): Not run.
         return grounded
-            ? greatestClosure(constraint.upper, topType, bottomType)
-            : constraint.upper;
+            ? greatestClosure(
+                constraint.upper.unwrapTypeSchemaView(), topType, bottomType)
+            : constraint.upper.unwrapTypeSchemaView();
       } else if (constraint.lower is! UnknownType) {
         return grounded
-            ? leastClosure(constraint.lower, topType, bottomType)
+            ? leastClosure(
+                constraint.lower.unwrapTypeSchemaView(), topType, bottomType)
             :
             // Coverage-ignore(suite): Not run.
-            constraint.lower;
+            constraint.lower.unwrapTypeSchemaView();
       } else {
         return const UnknownType();
       }
@@ -387,9 +396,10 @@
   // Coverage-ignore(suite): Not run.
   /// Determine if the given [type] satisfies the given type [constraint].
   bool typeSatisfiesConstraint(DartType type, MergedTypeConstraint constraint) {
-    return isSubtypeOf(
-            constraint.lower, type, SubtypeCheckMode.withNullabilities) &&
-        isSubtypeOf(type, constraint.upper, SubtypeCheckMode.withNullabilities);
+    return isSubtypeOf(constraint.lower.unwrapTypeSchemaView(), type,
+            SubtypeCheckMode.withNullabilities) &&
+        isSubtypeOf(type, constraint.upper.unwrapTypeSchemaView(),
+            SubtypeCheckMode.withNullabilities);
   }
 
   /// Performs upwards inference, producing a final set of inferred types that
@@ -437,7 +447,8 @@
 
     if (extendsConstraint != null) {
       constraint = constraint.clone();
-      constraint.mergeInTypeSchemaUpper(extendsConstraint, operations);
+      constraint.mergeInTypeSchemaUpper(
+          new SharedTypeSchemaView(extendsConstraint), operations);
     }
 
     return solveTypeConstraint(constraint, coreTypes.objectNullableRawType,
@@ -472,7 +483,8 @@
     // If we consider the `T extends num` we conclude `<num>`, which works.
     if (extendsConstraint != null) {
       constraint = constraint.clone();
-      constraint.mergeInTypeSchemaUpper(extendsConstraint, operations);
+      constraint.mergeInTypeSchemaUpper(
+          new SharedTypeSchemaView(extendsConstraint), operations);
       return solveTypeConstraint(constraint, coreTypes.objectNullableRawType,
           const NeverType.nonNullable());
     }
diff --git a/pkg/front_end/test/coverage_suite_expected.dart b/pkg/front_end/test/coverage_suite_expected.dart
index 9877a43..ad33b53 100644
--- a/pkg/front_end/test/coverage_suite_expected.dart
+++ b/pkg/front_end/test/coverage_suite_expected.dart
@@ -485,7 +485,7 @@
   ),
   // 100.0%.
   "package:front_end/src/kernel/body_builder.dart": (
-    hitCount: 7157,
+    hitCount: 7160,
     missCount: 0,
   ),
   // 100.0%.
@@ -904,25 +904,25 @@
     hitCount: 16,
     missCount: 0,
   ),
-  // 100.0%.
+  // 99.18032786885246%.
   "package:front_end/src/type_inference/for_in.dart": (
-    hitCount: 120,
-    missCount: 0,
+    hitCount: 121,
+    missCount: 1,
   ),
   // 100.0%.
   "package:front_end/src/type_inference/inference_results.dart": (
-    hitCount: 166,
+    hitCount: 168,
     missCount: 0,
   ),
-  // 100.0%.
+  // 99.98780636507743%.
   "package:front_end/src/type_inference/inference_visitor.dart": (
-    hitCount: 8109,
-    missCount: 0,
+    hitCount: 8200,
+    missCount: 1,
   ),
-  // 100.0%.
+  // 99.91697799916977%.
   "package:front_end/src/type_inference/inference_visitor_base.dart": (
-    hitCount: 2397,
-    missCount: 0,
+    hitCount: 2407,
+    missCount: 2,
   ),
   // 100.0%.
   "package:front_end/src/type_inference/matching_cache.dart": (
@@ -941,7 +941,7 @@
   ),
   // 100.0%.
   "package:front_end/src/type_inference/shared_type_analyzer.dart": (
-    hitCount: 102,
+    hitCount: 110,
     missCount: 0,
   ),
   // 100.0%.
@@ -951,7 +951,7 @@
   ),
   // 100.0%.
   "package:front_end/src/type_inference/type_constraint_gatherer.dart": (
-    hitCount: 457,
+    hitCount: 498,
     missCount: 0,
   ),
   // 100.0%.
@@ -961,12 +961,12 @@
   ),
   // 100.0%.
   "package:front_end/src/type_inference/type_inference_engine.dart": (
-    hitCount: 489,
+    hitCount: 515,
     missCount: 0,
   ),
   // 100.0%.
   "package:front_end/src/type_inference/type_inferrer.dart": (
-    hitCount: 96,
+    hitCount: 98,
     missCount: 0,
   ),
   // 100.0%.
@@ -981,7 +981,7 @@
   ),
   // 100.0%.
   "package:front_end/src/type_inference/type_schema_environment.dart": (
-    hitCount: 233,
+    hitCount: 247,
     missCount: 0,
   ),
   // 100.0%.
diff --git a/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_nnbd_test.dart b/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_nnbd_test.dart
index b39a1db..70fb640 100644
--- a/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_nnbd_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_nnbd_test.dart
@@ -417,10 +417,12 @@
           constraint.upper is! UnknownType) {
         var s = t.name;
         if (constraint.lower is! UnknownType) {
-          s = '${typeSchemaToString(constraint.lower)} <: $s';
+          s = '${typeSchemaToString(constraint.lower.unwrapTypeSchemaView())}'
+              ' <: $s';
         }
         if (constraint.upper is! UnknownType) {
-          s = '$s <: ${typeSchemaToString(constraint.upper)}';
+          s = '$s <: '
+              '${typeSchemaToString(constraint.upper.unwrapTypeSchemaView())}';
         }
         constraintStrings.add(s as String);
       }
diff --git a/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_test.dart b/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_test.dart
index 7d0d619..d472787 100644
--- a/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_test.dart
@@ -325,10 +325,12 @@
           constraint.upper is! UnknownType) {
         var s = t.name;
         if (constraint.lower is! UnknownType) {
-          s = '${typeSchemaToString(constraint.lower)} <: $s';
+          s = '${typeSchemaToString(constraint.lower.unwrapTypeSchemaView())}'
+              ' <: $s';
         }
         if (constraint.upper is! UnknownType) {
-          s = '$s <: ${typeSchemaToString(constraint.upper)}';
+          s = '$s <: '
+              '${typeSchemaToString(constraint.upper.unwrapTypeSchemaView())}';
         }
         constraintStrings.add(s as String);
       }
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_environment_test_base.dart b/pkg/front_end/test/fasta/type_inference/type_schema_environment_test_base.dart
index 5f17ffc..f79f989 100644
--- a/pkg/front_end/test/fasta/type_inference/type_schema_environment_test_base.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_environment_test_base.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:front_end/src/source/source_library_builder.dart';
 import 'package:front_end/src/type_inference/type_constraint_gatherer.dart';
 import 'package:front_end/src/type_inference/type_inference_engine.dart';
@@ -245,8 +246,8 @@
   /// the [constraint] string, from left to right.
   MergedTypeConstraint parseConstraint(String constraint) {
     MergedTypeConstraint result = new MergedTypeConstraint(
-        lower: const UnknownType(),
-        upper: const UnknownType(),
+        lower: SharedTypeSchemaView(const UnknownType()),
+        upper: SharedTypeSchemaView(const UnknownType()),
         origin: const UnknownTypeConstraintOrigin());
     List<String> upperBoundSegments = constraint.split("<:");
     bool firstUpperBoundSegment = true;
@@ -263,10 +264,12 @@
         if (firstLowerBoundSegment) {
           firstLowerBoundSegment = false;
           if (segment.isNotEmpty) {
-            result.mergeInTypeSchemaUpper(parseType(segment), _operations);
+            result.mergeInTypeSchemaUpper(
+                SharedTypeSchemaView(parseType(segment)), _operations);
           }
         } else {
-          result.mergeInTypeSchemaLower(parseType(segment), _operations);
+          result.mergeInTypeSchemaLower(
+              SharedTypeSchemaView(parseType(segment)), _operations);
         }
       }
     }
diff --git a/pkg/front_end/test/id_tests/type_constraint_generation_test.dart b/pkg/front_end/test/id_tests/type_constraint_generation_test.dart
index 5c8eb58..843af31 100644
--- a/pkg/front_end/test/id_tests/type_constraint_generation_test.dart
+++ b/pkg/front_end/test/id_tests/type_constraint_generation_test.dart
@@ -91,11 +91,11 @@
         }
         if (actualData[i].isUpper) {
           sb.write("${actualData[i].typeParameter.name} <: ");
-          sb.write(typeToText(actualData[i].constraint,
+          sb.write(typeToText(actualData[i].constraint.unwrapTypeSchemaView(),
               TypeRepresentation.analyzerNonNullableByDefault));
         } else {
           sb.write("${actualData[i].typeParameter.name} :> ");
-          sb.write(typeToText(actualData[i].constraint,
+          sb.write(typeToText(actualData[i].constraint.unwrapTypeSchemaView(),
               TypeRepresentation.analyzerNonNullableByDefault));
         }
       }
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index a000ecf..c09a6c3 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -25,6 +25,7 @@
 absolute
 abstract
 abstracted
+abstracting
 abstraction
 abstractly
 abstracts
@@ -345,6 +346,7 @@
 breaks
 briefly
 bring
+bringing
 brittle
 broken
 browser
@@ -585,6 +587,7 @@
 concatenating
 concatenation
 concepts
+concise
 conclude
 conclusion
 concrete
@@ -3299,6 +3302,7 @@
 unhelpful
 unicode
 unified
+uniformity
 unifying
 unimplemented
 uninitialized
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index afd6e4f..69b1ff6 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -72,12 +72,12 @@
     show Variance;
 import 'package:_fe_analyzer_shared/src/types/shared_type.dart'
     show
-        SharedDynamicType,
-        SharedInvalidType,
-        SharedNamedType,
-        SharedRecordType,
-        SharedType,
-        SharedVoidType;
+        SharedDynamicTypeStructure,
+        SharedInvalidTypeStructure,
+        SharedNamedTypeStructure,
+        SharedRecordTypeStructure,
+        SharedTypeStructure,
+        SharedVoidTypeStructure;
 
 import 'src/extension_type_erasure.dart';
 import 'visitor.dart';
@@ -11054,7 +11054,7 @@
 ///
 /// The `==` operator on [DartType]s compare based on type equality, not
 /// object identity.
-sealed class DartType extends Node implements SharedType<DartType> {
+sealed class DartType extends Node implements SharedTypeStructure<DartType> {
   const DartType();
 
   @override
@@ -11173,7 +11173,7 @@
   String getDisplayString() => toText(const AstTextStrategy());
 
   @override
-  bool isStructurallyEqualTo(SharedType other) {
+  bool isStructurallyEqualTo(SharedTypeStructure other) {
     // TODO(cstefantsova): Use the actual algorithm for structural equality.
     return this == other;
   }
@@ -11221,7 +11221,8 @@
 ///
 /// 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 implements SharedInvalidType<DartType> {
+class InvalidType extends DartType
+    implements SharedInvalidTypeStructure<DartType> {
   @override
   final int hashCode = 12345;
 
@@ -11274,7 +11275,8 @@
   }
 }
 
-class DynamicType extends DartType implements SharedDynamicType<DartType> {
+class DynamicType extends DartType
+    implements SharedDynamicTypeStructure<DartType> {
   @override
   final int hashCode = 54321;
 
@@ -11319,7 +11321,7 @@
   }
 }
 
-class VoidType extends DartType implements SharedVoidType<DartType> {
+class VoidType extends DartType implements SharedVoidTypeStructure<DartType> {
   @override
   final int hashCode = 123121;
 
@@ -12172,7 +12174,7 @@
 
 /// A named parameter in [FunctionType].
 class NamedType extends Node
-    implements Comparable<NamedType>, SharedNamedType<DartType> {
+    implements Comparable<NamedType>, SharedNamedTypeStructure<DartType> {
   // Flag used for serialization if [isRequired].
   static const int FlagRequiredNamedType = 1 << 0;
 
@@ -12899,7 +12901,8 @@
   }
 }
 
-class RecordType extends DartType implements SharedRecordType<DartType> {
+class RecordType extends DartType
+    implements SharedRecordTypeStructure<DartType> {
   final List<DartType> positional;
   final List<NamedType> named;
 
@@ -12924,7 +12927,7 @@
             "in a RecordType: ${named}");
 
   @override
-  List<SharedNamedType<DartType>> get namedTypes => named;
+  List<SharedNamedTypeStructure<DartType>> get namedTypes => named;
 
   @override
   Nullability get nullability => declaredNullability;