Version 2.13.0-135.0.dev

Merge commit 'a7e5965495dd60bfe0c6717c416cc133526ca5a3' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 36ef5eb..6fffc20 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
     "constraint, update this by running tools/generate_package_config.dart."
   ],
   "configVersion": 2,
-  "generated": "2021-03-09T13:31:13.443396",
+  "generated": "2021-03-12T09:00:31.497265",
   "generator": "tools/generate_package_config.dart",
   "packages": [
     {
diff --git a/DEPS b/DEPS
index e47320e..318184f 100644
--- a/DEPS
+++ b/DEPS
@@ -159,7 +159,7 @@
   "test_process_tag": "1.0.3",
   "term_glyph_rev": "6a0f9b6fb645ba75e7a00a4e20072678327a0347",
   "test_reflective_loader_rev": "54e930a11c372683792e22bddad79197728c91ce",
-  "test_rev": "2cd8a4e774439447b01f9d381da020319a9808d8",
+  "test_rev": "e673623f45d75ccec750d35271b0b4d1423e9fac",
   "typed_data_tag": "f94fc57b8e8c0e4fe4ff6cfd8290b94af52d3719",
   "usage_rev": "6c64d9e7b6b3758d06d030efcb5afe20bfc04dde",
   "vector_math_rev": "0c9f5d68c047813a6dcdeb88ba7a42daddf25025",
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 5413fb9..b2a37c1 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -7152,6 +7152,13 @@
         aliasElement: this,
         aliasArguments: typeArguments,
       );
+    } else if (type is TypeParameterType) {
+      return TypeParameterTypeImpl(
+        element: type.element,
+        nullabilitySuffix: resultNullability,
+        aliasElement: this,
+        aliasArguments: typeArguments,
+      );
     } else {
       return (type as TypeImpl).withNullability(resultNullability);
     }
diff --git a/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart b/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart
index 8f1d3e5..e4f5c28 100644
--- a/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart
@@ -135,6 +135,8 @@
       element: type.element,
       nullabilitySuffix: newNullability ?? type.nullabilitySuffix,
       promotedBound: newPromotedBound ?? promotedBound,
+      aliasElement: type.aliasElement,
+      aliasArguments: type.aliasArguments,
     );
   }
 
@@ -149,6 +151,8 @@
     return TypeParameterTypeImpl(
       element: type.element,
       nullabilitySuffix: newNullability,
+      aliasElement: type.aliasElement,
+      aliasArguments: type.aliasArguments,
     );
   }
 
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 312a064..a1b36a1 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -1801,7 +1801,13 @@
     required TypeParameterElement element,
     required this.nullabilitySuffix,
     this.promotedBound,
-  }) : super(element);
+    TypeAliasElement? aliasElement,
+    List<DartType>? aliasArguments,
+  }) : super(
+          element,
+          aliasElement: aliasElement,
+          aliasArguments: aliasArguments,
+        );
 
   @override
   DartType get bound =>
diff --git a/pkg/analyzer/lib/src/dart/element/type_demotion.dart b/pkg/analyzer/lib/src/dart/element/type_demotion.dart
index 92390a4..4b1cc1a 100644
--- a/pkg/analyzer/lib/src/dart/element/type_demotion.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_demotion.dart
@@ -38,6 +38,8 @@
         return TypeParameterTypeImpl(
           element: type.element,
           nullabilitySuffix: newNullability ?? type.nullabilitySuffix,
+          aliasElement: type.aliasElement,
+          aliasArguments: type.aliasArguments,
         );
       }
     }
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index 383977d..9f484b6 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -744,6 +744,13 @@
           aliasElement: aliasElement,
           aliasArguments: aliasArguments,
         );
+      } else if (type is TypeParameterType) {
+        return TypeParameterTypeImpl(
+          element: type.element,
+          nullabilitySuffix: type.nullabilitySuffix,
+          aliasElement: aliasElement,
+          aliasArguments: aliasArguments,
+        );
       } else if (type is VoidType) {
         // TODO(scheglov) add support for `void` aliasing
         return type;
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 0598c70..ece3d72 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -12509,10 +12509,6 @@
         withAliasElementArguments: true);
   }
 
-  @FailingTest(
-    issue: 'https://github.com/dart-lang/sdk/issues/45291',
-    reason: 'Must be implemented',
-  )
   test_typedef_nonFunction_aliasElement_typeParameterType() async {
     featureSet = FeatureSets.nonFunctionTypeAliases;
     var library = await checkLibrary(r'''
diff --git a/pkg/compiler/lib/src/ir/util.dart b/pkg/compiler/lib/src/ir/util.dart
index 44de884..b8c1318 100644
--- a/pkg/compiler/lib/src/ir/util.dart
+++ b/pkg/compiler/lib/src/ir/util.dart
@@ -208,6 +208,11 @@
   }
 
   @override
+  bool visitExtensionType(ir.ExtensionType node) {
+    return visitList(node.typeArguments);
+  }
+
+  @override
   bool visitFutureOrType(ir.FutureOrType node) {
     return visit(node.typeArgument);
   }
diff --git a/pkg/compiler/test/helpers/ir_types.dart b/pkg/compiler/test/helpers/ir_types.dart
index 2be57b7..b9745e5 100644
--- a/pkg/compiler/test/helpers/ir_types.dart
+++ b/pkg/compiler/test/helpers/ir_types.dart
@@ -98,6 +98,12 @@
   }
 
   @override
+  void visitExtensionType(ir.ExtensionType node, StringBuffer sb) {
+    sb.write(node.extension.name);
+    _writeTypeArguments(node.typeArguments, sb);
+  }
+
+  @override
   void visitFutureOrType(ir.FutureOrType node, StringBuffer sb) {
     sb.write('FutureOr<');
     writeType(node.typeArgument, sb);
diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart
index 45bfd1e..db32bfe 100644
--- a/pkg/dartdev/lib/src/commands/run.dart
+++ b/pkg/dartdev/lib/src/commands/run.dart
@@ -243,13 +243,18 @@
 class _DebuggingSession {
   Future<bool> start(
       String host, String port, bool disableServiceAuthCodes) async {
-    final serviceInfo = await Service.getInfo();
     final ddsSnapshot = (dirname(sdk.dart).endsWith('bin'))
         ? sdk.ddsSnapshot
         : absolute(dirname(sdk.dart), 'gen', 'dds.dart.snapshot');
     if (!Sdk.checkArtifactExists(ddsSnapshot)) {
       return false;
     }
+    ServiceProtocolInfo serviceInfo = await Service.getInfo();
+    // Wait for VM service to publish its connection info.
+    while (serviceInfo.serverUri == null) {
+      await Future.delayed(Duration(milliseconds: 10));
+      serviceInfo = await Service.getInfo();
+    }
     final process = await Process.start(
         sdk.dart,
         [
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index a1437e9..8bcc7bf 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -2746,6 +2746,10 @@
       _emitInterfaceType(type);
 
   @override
+  js_ast.Expression visitExtensionType(ExtensionType type) =>
+      type.onType.accept(this);
+
+  @override
   js_ast.Expression visitFutureOrType(FutureOrType type) =>
       _normalizeFutureOr(type);
 
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
index 16a64f3..ab5c83e 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
@@ -684,7 +684,7 @@
   ..addOption('sdk-root')
   ..addOption('asset-server-address')
   ..addOption('asset-server-port')
-  ..addOption('module-format')
+  ..addOption('module-format', defaultsTo: 'amd')
   ..addFlag('track-widget-creation', defaultsTo: false)
   ..addFlag('sound-null-safety', defaultsTo: false)
   ..addFlag('verbose', defaultsTo: false);
diff --git a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
index b953844..8617f88 100644
--- a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
@@ -9,7 +9,6 @@
 
 import '../fasta_codes.dart'
     show templateInternalProblemNotFoundIn, templateTypeArgumentMismatch;
-import '../kernel/internal_ast.dart';
 import '../scope.dart';
 import '../source/source_library_builder.dart';
 import '../problems.dart';
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 1089515..ec0a9bb 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -3340,6 +3340,29 @@
   }
 
   @override
+  ExecutionStatus visitIfStatement(IfStatement node) {
+    Constant condition = evaluate(node.condition);
+    if (condition is AbortConstant) return new ReturnStatus(condition);
+    if (condition is BoolConstant) {
+      if (condition.value) {
+        return node.then.accept(this);
+      } else if (node.otherwise != null) {
+        return node.otherwise.accept(this);
+      } else {
+        return const ProceedStatus();
+      }
+    } else {
+      return new ReturnStatus(exprEvaluator.createErrorConstant(
+          node.condition,
+          templateConstEvalInvalidType.withArguments(
+              condition,
+              exprEvaluator.typeEnvironment.coreTypes.boolLegacyRawType,
+              condition.getType(exprEvaluator._staticTypeContext),
+              exprEvaluator.isNonNullableByDefault)));
+    }
+  }
+
+  @override
   ExecutionStatus visitExpressionStatement(ExpressionStatement node) {
     Constant value = evaluate(node.expression);
     if (value is AbortConstant) return new ReturnStatus(value);
@@ -3436,7 +3459,12 @@
   EvaluationEnvironment.withParent(this._parent);
 
   /// Whether the current environment is empty.
-  bool get isEmpty => _typeVariables.isEmpty && _variables.isEmpty;
+  bool get isEmpty {
+    // Since we look up variables in enclosing environment, the environment
+    // is not empty if its parent is not empty.
+    if (_parent != null && !_parent.isEmpty) return false;
+    return _typeVariables.isEmpty && _variables.isEmpty;
+  }
 
   void addTypeParameterValue(TypeParameter parameter, DartType value) {
     assert(!_typeVariables.containsKey(parameter));
diff --git a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
index 06bdd72..35da3d2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
@@ -21,13 +21,9 @@
 /// with the same kind of root node.
 
 import 'package:kernel/ast.dart';
-import 'package:kernel/binary/ast_to_binary.dart';
 import 'package:kernel/core_types.dart';
-import 'package:kernel/src/assumptions.dart';
 import 'package:kernel/src/printer.dart';
-import 'package:kernel/src/text_util.dart';
 import 'package:kernel/text/ast_to_text.dart' show Precedence, Printer;
-import 'package:kernel/type_algebra.dart';
 import 'package:kernel/type_environment.dart';
 
 import '../builder/type_alias_builder.dart';
@@ -54,8 +50,6 @@
 
 import 'inference_visitor.dart';
 
-import 'type_labeler.dart';
-
 /// Computes the return type of a (possibly factory) constructor.
 InterfaceType computeConstructorReturnType(
     Member constructor, CoreTypes coreTypes) {
@@ -4232,170 +4226,3 @@
   }
   throw new UnsupportedError("Clone not supported for ${node.runtimeType}.");
 }
-
-class ExtensionType extends DartType {
-  final Reference extensionName;
-
-  @override
-  final Nullability declaredNullability;
-
-  final List<DartType> typeArguments;
-
-  final DartType onType;
-
-  ExtensionType(Extension extensionNode, Nullability declaredNullability,
-      [List<DartType> typeArguments])
-      : this.byReference(extensionNode.reference, declaredNullability,
-            typeArguments ?? _defaultTypeArguments(extensionNode));
-
-  ExtensionType.byReference(
-      this.extensionName, this.declaredNullability, this.typeArguments)
-      : assert(declaredNullability != null),
-        onType = _computeOnType(extensionName, typeArguments);
-
-  Extension get extensionNode => extensionName.asExtension;
-
-  @override
-  Nullability get nullability {
-    return uniteNullabilities(
-        declaredNullability, extensionNode.onType.nullability);
-  }
-
-  static List<DartType> _defaultTypeArguments(Extension extensionNode) {
-    if (extensionNode.typeParameters.length == 0) {
-      // Avoid allocating a list in this very common case.
-      return const <DartType>[];
-    } else {
-      return new List<DartType>.filled(
-          extensionNode.typeParameters.length, const DynamicType());
-    }
-  }
-
-  static DartType _computeOnType(
-      Reference extensionName, List<DartType> typeArguments) {
-    Extension extensionNode = extensionName.asExtension;
-    if (extensionNode.typeParameters.isEmpty) {
-      return extensionNode.onType;
-    } else {
-      assert(extensionNode.typeParameters.length == typeArguments.length);
-      return Substitution.fromPairs(extensionNode.typeParameters, typeArguments)
-          .substituteType(extensionNode.onType);
-    }
-  }
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) {
-    if (v is Printer) {
-      // TODO(dmitryas): Move this guarded code into Printer.visitExtensionType
-      // when it's available.
-      Printer printer = v as Printer;
-      printer.writeExtensionReferenceFromReference(extensionName);
-      if (typeArguments.isNotEmpty) {
-        printer.writeSymbol('<');
-        printer.writeList(typeArguments, printer.writeType);
-        printer.writeSymbol('>');
-        printer.state = Printer.WORD;
-      }
-      printer.writeNullability(declaredNullability);
-      // The following line is needed to supply the return value and make the
-      // compiler happy. It should go away once ExtensionType is moved to
-      // ast.dart.
-      return null;
-    } else if (v is BinaryPrinter) {
-      // TODO(dmitryas): Remove the following line and implement
-      // BinaryPrinter.visitExtensionType when it's available.
-      return onType.accept(v);
-    } else if (v is TypeLabeler) {
-      // TODO(dmitryas): Move this guarded code into
-      // TypeLabeler.visitExtensionType when it's available.
-      TypeLabeler typeLabeler = v as TypeLabeler;
-      typeLabeler.result.add(typeLabeler.nameForEntity(
-          extensionNode,
-          extensionNode.name,
-          extensionNode.enclosingLibrary.importUri,
-          extensionNode.enclosingLibrary.fileUri));
-      if (typeArguments.isNotEmpty) {
-        typeLabeler.result.add("<");
-        bool first = true;
-        for (DartType typeArg in typeArguments) {
-          if (!first) typeLabeler.result.add(", ");
-          typeArg.accept(typeLabeler);
-          first = false;
-        }
-        typeLabeler.result.add(">");
-      }
-      typeLabeler.addNullability(declaredNullability);
-      // The following line is needed to supply the return value and make the
-      // compiler happy. It should go away once ExtensionType is moved to
-      // ast.dart.
-      return null;
-    }
-    // TODO(dmitryas): Change this to `v.visitExtensionType(this)` when
-    // ExtensionType is moved to ast.dart.
-    return v.defaultDartType(this);
-  }
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) {
-    // TODO(dmitryas): Change this to `v.visitExtensionType(this, arg)` when
-    // ExtensionType is moved to ast.dart.
-    return v.defaultDartType(this, arg);
-  }
-
-  @override
-  void visitChildren(Visitor v) {
-    // TODO(dmitryas): Uncomment the following line when ExtensionType is moved
-    // to ast.dart.
-    //extensionNode.acceptReference(v);
-    visitList(typeArguments, v);
-  }
-
-  @override
-  bool equals(Object other, Assumptions assumptions) {
-    if (identical(this, other)) return true;
-    if (other is ExtensionType) {
-      if (nullability != other.nullability) return false;
-      if (extensionName != other.extensionName) return false;
-      if (typeArguments.length != other.typeArguments.length) return false;
-      for (int i = 0; i < typeArguments.length; ++i) {
-        if (!typeArguments[i].equals(other.typeArguments[i], assumptions)) {
-          return false;
-        }
-      }
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  @override
-  int get hashCode {
-    int hash = 0x3fffffff & extensionName.hashCode;
-    for (int i = 0; i < typeArguments.length; ++i) {
-      hash = 0x3fffffff & (hash * 31 + (hash ^ typeArguments[i].hashCode));
-    }
-    int nullabilityHash = (0x33333333 >> nullability.index) ^ 0x33333333;
-    hash = 0x3fffffff & (hash * 31 + (hash ^ nullabilityHash));
-    return hash;
-  }
-
-  @override
-  ExtensionType withDeclaredNullability(Nullability declaredNullability) {
-    return declaredNullability == this.declaredNullability
-        ? this
-        : new ExtensionType.byReference(
-            extensionName, declaredNullability, typeArguments);
-  }
-
-  @override
-  String toString() {
-    return "ExtensionType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExtensionName(extensionName);
-    printer.writeTypeArguments(typeArguments);
-    printer.write(nullabilityToString(declaredNullability));
-  }
-}
diff --git a/pkg/front_end/lib/src/fasta/kernel/invalid_type.dart b/pkg/front_end/lib/src/fasta/kernel/invalid_type.dart
index b66b0ab..bfaef2c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/invalid_type.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/invalid_type.dart
@@ -9,8 +9,6 @@
 
 import '../type_inference/type_schema.dart';
 
-import 'internal_ast.dart';
-
 /// Check if [type] contains [InvalidType] as its part.
 ///
 /// The helper function is intended for stopping cascading errors because of
@@ -60,6 +58,15 @@
   }
 
   @override
+  bool visitExtensionType(
+      ExtensionType node, Set<TypedefType> visitedTypedefs) {
+    for (DartType typeArgument in node.typeArguments) {
+      if (typeArgument.accept1(this, visitedTypedefs)) return true;
+    }
+    return false;
+  }
+
+  @override
   bool visitFutureOrType(FutureOrType node, Set<TypedefType> visitedTypedefs) {
     return node.typeArgument.accept1(this, visitedTypedefs);
   }
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
index ac56037..80f2dcb 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
@@ -4,23 +4,7 @@
 
 // @dart = 2.9
 
-import 'package:kernel/ast.dart'
-    show
-        DartType,
-        DartTypeVisitor,
-        DynamicType,
-        FunctionType,
-        FutureOrType,
-        InterfaceType,
-        InvalidType,
-        NamedType,
-        NeverType,
-        NullType,
-        TypeParameter,
-        TypeParameterType,
-        TypedefType,
-        Variance,
-        VoidType;
+import 'package:kernel/ast.dart';
 
 import 'package:kernel/type_algebra.dart' show containsTypeVariable;
 
@@ -1029,24 +1013,37 @@
     return false;
   }
 
+  @override
   bool visitInvalidType(InvalidType node) => false;
 
+  @override
   bool visitDynamicType(DynamicType node) => false;
 
+  @override
   bool visitVoidType(VoidType node) => false;
 
+  @override
   bool visitNeverType(NeverType node) => false;
 
+  @override
   bool visitNullType(NullType node) => false;
 
+  @override
   bool visitInterfaceType(InterfaceType node) {
     return anyTypeVariables(node.typeArguments);
   }
 
+  @override
+  bool visitExtensionType(ExtensionType node) {
+    return anyTypeVariables(node.typeArguments);
+  }
+
+  @override
   bool visitFutureOrType(FutureOrType node) {
     return node.typeArgument.accept(this);
   }
 
+  @override
   bool visitFunctionType(FunctionType node) {
     if (anyTypeVariables(node.positionalParameters)) return true;
     for (TypeParameter variable in node.typeParameters) {
@@ -1058,8 +1055,10 @@
     return false;
   }
 
+  @override
   bool visitTypeParameterType(TypeParameterType node) => true;
 
+  @override
   bool visitTypedefType(TypedefType node) {
     return anyTypeVariables(node.typeArguments);
   }
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
index 8735d07..f0e5030 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
@@ -9,26 +9,7 @@
 import 'package:_fe_analyzer_shared/src/parser/parser.dart'
     show FormalParameterKind;
 
-import 'package:kernel/ast.dart'
-    show
-        Class,
-        DartType,
-        DartTypeVisitor,
-        DynamicType,
-        FunctionType,
-        FutureOrType,
-        InterfaceType,
-        InvalidType,
-        Library,
-        NamedType,
-        NeverType,
-        NullType,
-        TreeNode,
-        TypeParameter,
-        TypeParameterType,
-        Typedef,
-        TypedefType,
-        VoidType;
+import 'package:kernel/ast.dart';
 
 import '../builder/class_builder.dart';
 import '../builder/dynamic_type_declaration_builder.dart';
@@ -131,6 +112,11 @@
   }
 
   @override
+  TypeBuilder visitExtensionType(ExtensionType node) {
+    throw "Not implemented";
+  }
+
+  @override
   TypeBuilder visitFutureOrType(FutureOrType node) {
     TypeBuilder argument = node.typeArgument.accept(this);
     return new NamedTypeBuilder(
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart b/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
index 0b66c6e..bf845a4 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
@@ -6,43 +6,7 @@
 
 import 'dart:convert' show json;
 
-import 'package:kernel/ast.dart'
-    show
-        BoolConstant,
-        Class,
-        Constant,
-        ConstantMapEntry,
-        DartType,
-        DoubleConstant,
-        DynamicType,
-        Field,
-        FunctionType,
-        FutureOrType,
-        InvalidType,
-        InstanceConstant,
-        IntConstant,
-        InterfaceType,
-        Library,
-        ListConstant,
-        MapConstant,
-        NeverType,
-        NullConstant,
-        NullType,
-        Nullability,
-        PartialInstantiationConstant,
-        Procedure,
-        SetConstant,
-        StringConstant,
-        SymbolConstant,
-        TearOffConstant,
-        TreeNode,
-        Typedef,
-        TypedefType,
-        TypeLiteralConstant,
-        TypeParameter,
-        TypeParameterType,
-        UnevaluatedConstant,
-        VoidType;
+import 'package:kernel/ast.dart';
 
 import 'package:kernel/visitor.dart' show ConstantVisitor, DartTypeVisitor;
 
@@ -286,6 +250,25 @@
     addNullability(node.declaredNullability);
   }
 
+  void visitExtensionType(ExtensionType node) {
+    result.add(nameForEntity(
+        node.extension,
+        node.extension.name,
+        node.extension.enclosingLibrary.importUri,
+        node.extension.enclosingLibrary.fileUri));
+    if (node.typeArguments.isNotEmpty) {
+      result.add("<");
+      bool first = true;
+      for (DartType typeArg in node.typeArguments) {
+        if (!first) result.add(", ");
+        typeArg.accept(this);
+        first = false;
+      }
+      result.add(">");
+    }
+    addNullability(node.declaredNullability);
+  }
+
   void defaultConstant(Constant node) {}
 
   void visitNullConstant(NullConstant node) {
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 72483c4..0c4eca9 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -896,7 +896,7 @@
     Member targetTearoff;
     ProcedureKind targetKind;
     for (ExtensionMemberDescriptor descriptor
-        in receiverType.extensionNode.members) {
+        in receiverType.extension.members) {
       if (descriptor.name == name) {
         switch (descriptor.kind) {
           case ExtensionMemberKind.Method:
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
index 172476b..bc3f745 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
@@ -17,8 +17,6 @@
 import 'package:kernel/src/hierarchy_based_type_environment.dart'
     show HierarchyBasedTypeEnvironment;
 
-import '../kernel/internal_ast.dart' show ExtensionType;
-
 import 'standard_bounds.dart' show TypeSchemaStandardBounds;
 
 import 'type_constraint_gatherer.dart' show TypeConstraintGatherer;
@@ -373,7 +371,7 @@
       if (coreTypes.isTop(supertype)) {
         return const IsSubtypeOf.always();
       } else if (supertype is ExtensionType &&
-          subtype.extensionNode == supertype.extensionNode) {
+          subtype.extension == supertype.extension) {
         assert(subtype.typeArguments.length == supertype.typeArguments.length);
         IsSubtypeOf result = const IsSubtypeOf.always();
         for (int i = 0; i < subtype.typeArguments.length; ++i) {
@@ -399,7 +397,7 @@
       if (coreTypes.isBottom(subtype)) {
         return const IsSubtypeOf.always();
       } else if (subtype is ExtensionType &&
-          subtype.extensionNode == unwrappedSupertype.extensionNode) {
+          subtype.extension == unwrappedSupertype.extension) {
         assert(subtype.typeArguments.length ==
             unwrappedSupertype.typeArguments.length);
         IsSubtypeOf result = const IsSubtypeOf.always();
diff --git a/pkg/front_end/lib/src/testing/id_testing_utils.dart b/pkg/front_end/lib/src/testing/id_testing_utils.dart
index 94c3bfd..68cbf92 100644
--- a/pkg/front_end/lib/src/testing/id_testing_utils.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_utils.dart
@@ -570,6 +570,16 @@
     }
     sb.write(nullabilityToText(node.nullability, typeRepresentation));
   }
+
+  void visitExtensionType(ExtensionType node) {
+    sb.write(node.extension.name);
+    if (node.typeArguments.isNotEmpty) {
+      sb.write('<');
+      visitList(node.typeArguments);
+      sb.write('>');
+    }
+    sb.write(nullabilityToText(node.declaredNullability, typeRepresentation));
+  }
 }
 
 /// Returns `true` if [type] is `Object` from `dart:core`.
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart
new file mode 100644
index 0000000..a4118a3
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart
@@ -0,0 +1,75 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests if statements for const functions.
+
+import "package:expect/expect.dart";
+
+const var1 = ifTest(1);
+const var2 = ifTest(2);
+const var3 = ifTest(3);
+int ifTest(int a) {
+  if (a == 1) {
+    return 100;
+  } else if (a == 2) {
+    return 200;
+  } else {
+    return 300;
+  }
+}
+
+const one = 1;
+const var4 = ifTest2(1);
+const var5 = ifTest2(2);
+int ifTest2(int a) {
+  if (a == one) {
+    return 100;
+  } else {
+    return 200;
+  }
+}
+
+const var6 = ifTest3(1);
+const var6_1 = ifTest3(2);
+const var6_2 = ifTest3(0);
+int ifTest3(int a) {
+  if (a > 0) {
+    if (a == 1) return 100;
+    return 200;
+  }
+  return 300;
+}
+
+const var7 = ifTest4(1);
+int ifTest4(int a) {
+  int b = a;
+  if (a == 1) {
+    b += a;
+    if (a % 2 == 1) {
+      b += a;
+    }
+  } else if (a == 2) {
+    b -= a;
+  }
+
+  return b;
+}
+
+const var8 = ifTest5();
+int ifTest5() {
+  var x = 10;
+  if (true) var x = 20;
+  return x;
+}
+
+void main() {
+  Expect.equals(var1, 100);
+  Expect.equals(var2, 200);
+  Expect.equals(var3, 300);
+  Expect.equals(var4, 100);
+  Expect.equals(var5, 200);
+  Expect.equals(var6, 100);
+  Expect.equals(var7, 3);
+  Expect.equals(var8, 10);
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.strong.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.strong.expect
new file mode 100644
index 0000000..8d0f813
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.strong.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+static const field core::int var1 = #C1;
+static const field core::int var2 = #C2;
+static const field core::int var3 = #C3;
+static const field core::int one = #C4;
+static const field core::int var4 = #C1;
+static const field core::int var5 = #C2;
+static const field core::int var6 = #C1;
+static const field core::int var6_1 = #C2;
+static const field core::int var6_2 = #C3;
+static const field core::int var7 = #C5;
+static const field core::int var8 = #C6;
+static method ifTest(core::int a) → core::int {
+  if(a.{core::num::==}(1)) {
+    return 100;
+  }
+  else
+    if(a.{core::num::==}(2)) {
+      return 200;
+    }
+    else {
+      return 300;
+    }
+}
+static method ifTest2(core::int a) → core::int {
+  if(a.{core::num::==}(#C4)) {
+    return 100;
+  }
+  else {
+    return 200;
+  }
+}
+static method ifTest3(core::int a) → core::int {
+  if(a.{core::num::>}(0)) {
+    if(a.{core::num::==}(1))
+      return 100;
+    return 200;
+  }
+  return 300;
+}
+static method ifTest4(core::int a) → core::int {
+  core::int b = a;
+  if(a.{core::num::==}(1)) {
+    b = b.{core::num::+}(a);
+    if(a.{core::num::%}(2).{core::num::==}(1)) {
+      b = b.{core::num::+}(a);
+    }
+  }
+  else
+    if(a.{core::num::==}(2)) {
+      b = b.{core::num::-}(a);
+    }
+  return b;
+}
+static method ifTest5() → core::int {
+  core::int x = 10;
+  if(true) {
+    core::int x = 20;
+  }
+  return x;
+}
+static method main() → void {
+  exp::Expect::equals(#C1, 100);
+  exp::Expect::equals(#C2, 200);
+  exp::Expect::equals(#C3, 300);
+  exp::Expect::equals(#C1, 100);
+  exp::Expect::equals(#C2, 200);
+  exp::Expect::equals(#C1, 100);
+  exp::Expect::equals(#C5, 3);
+  exp::Expect::equals(#C6, 10);
+}
+
+constants  {
+  #C1 = 100
+  #C2 = 200
+  #C3 = 300
+  #C4 = 1
+  #C5 = 3
+  #C6 = 10
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.strong.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.strong.transformed.expect
new file mode 100644
index 0000000..8d0f813
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.strong.transformed.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+static const field core::int var1 = #C1;
+static const field core::int var2 = #C2;
+static const field core::int var3 = #C3;
+static const field core::int one = #C4;
+static const field core::int var4 = #C1;
+static const field core::int var5 = #C2;
+static const field core::int var6 = #C1;
+static const field core::int var6_1 = #C2;
+static const field core::int var6_2 = #C3;
+static const field core::int var7 = #C5;
+static const field core::int var8 = #C6;
+static method ifTest(core::int a) → core::int {
+  if(a.{core::num::==}(1)) {
+    return 100;
+  }
+  else
+    if(a.{core::num::==}(2)) {
+      return 200;
+    }
+    else {
+      return 300;
+    }
+}
+static method ifTest2(core::int a) → core::int {
+  if(a.{core::num::==}(#C4)) {
+    return 100;
+  }
+  else {
+    return 200;
+  }
+}
+static method ifTest3(core::int a) → core::int {
+  if(a.{core::num::>}(0)) {
+    if(a.{core::num::==}(1))
+      return 100;
+    return 200;
+  }
+  return 300;
+}
+static method ifTest4(core::int a) → core::int {
+  core::int b = a;
+  if(a.{core::num::==}(1)) {
+    b = b.{core::num::+}(a);
+    if(a.{core::num::%}(2).{core::num::==}(1)) {
+      b = b.{core::num::+}(a);
+    }
+  }
+  else
+    if(a.{core::num::==}(2)) {
+      b = b.{core::num::-}(a);
+    }
+  return b;
+}
+static method ifTest5() → core::int {
+  core::int x = 10;
+  if(true) {
+    core::int x = 20;
+  }
+  return x;
+}
+static method main() → void {
+  exp::Expect::equals(#C1, 100);
+  exp::Expect::equals(#C2, 200);
+  exp::Expect::equals(#C3, 300);
+  exp::Expect::equals(#C1, 100);
+  exp::Expect::equals(#C2, 200);
+  exp::Expect::equals(#C1, 100);
+  exp::Expect::equals(#C5, 3);
+  exp::Expect::equals(#C6, 10);
+}
+
+constants  {
+  #C1 = 100
+  #C2 = 200
+  #C3 = 300
+  #C4 = 1
+  #C5 = 3
+  #C6 = 10
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.textual_outline.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.textual_outline.expect
new file mode 100644
index 0000000..0af1a72
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.textual_outline.expect
@@ -0,0 +1,19 @@
+import "package:expect/expect.dart";
+
+const var1 = ifTest(1);
+const var2 = ifTest(2);
+const var3 = ifTest(3);
+int ifTest(int a) {}
+const one = 1;
+const var4 = ifTest2(1);
+const var5 = ifTest2(2);
+int ifTest2(int a) {}
+const var6 = ifTest3(1);
+const var6_1 = ifTest3(2);
+const var6_2 = ifTest3(0);
+int ifTest3(int a) {}
+const var7 = ifTest4(1);
+int ifTest4(int a) {}
+const var8 = ifTest5();
+int ifTest5() {}
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..5f5b560
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.textual_outline_modelled.expect
@@ -0,0 +1,19 @@
+import "package:expect/expect.dart";
+
+const one = 1;
+const var1 = ifTest(1);
+const var2 = ifTest(2);
+const var3 = ifTest(3);
+const var4 = ifTest2(1);
+const var5 = ifTest2(2);
+const var6 = ifTest3(1);
+const var6_1 = ifTest3(2);
+const var6_2 = ifTest3(0);
+const var7 = ifTest4(1);
+const var8 = ifTest5();
+int ifTest(int a) {}
+int ifTest2(int a) {}
+int ifTest3(int a) {}
+int ifTest4(int a) {}
+int ifTest5() {}
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.expect
new file mode 100644
index 0000000..8d0f813
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+static const field core::int var1 = #C1;
+static const field core::int var2 = #C2;
+static const field core::int var3 = #C3;
+static const field core::int one = #C4;
+static const field core::int var4 = #C1;
+static const field core::int var5 = #C2;
+static const field core::int var6 = #C1;
+static const field core::int var6_1 = #C2;
+static const field core::int var6_2 = #C3;
+static const field core::int var7 = #C5;
+static const field core::int var8 = #C6;
+static method ifTest(core::int a) → core::int {
+  if(a.{core::num::==}(1)) {
+    return 100;
+  }
+  else
+    if(a.{core::num::==}(2)) {
+      return 200;
+    }
+    else {
+      return 300;
+    }
+}
+static method ifTest2(core::int a) → core::int {
+  if(a.{core::num::==}(#C4)) {
+    return 100;
+  }
+  else {
+    return 200;
+  }
+}
+static method ifTest3(core::int a) → core::int {
+  if(a.{core::num::>}(0)) {
+    if(a.{core::num::==}(1))
+      return 100;
+    return 200;
+  }
+  return 300;
+}
+static method ifTest4(core::int a) → core::int {
+  core::int b = a;
+  if(a.{core::num::==}(1)) {
+    b = b.{core::num::+}(a);
+    if(a.{core::num::%}(2).{core::num::==}(1)) {
+      b = b.{core::num::+}(a);
+    }
+  }
+  else
+    if(a.{core::num::==}(2)) {
+      b = b.{core::num::-}(a);
+    }
+  return b;
+}
+static method ifTest5() → core::int {
+  core::int x = 10;
+  if(true) {
+    core::int x = 20;
+  }
+  return x;
+}
+static method main() → void {
+  exp::Expect::equals(#C1, 100);
+  exp::Expect::equals(#C2, 200);
+  exp::Expect::equals(#C3, 300);
+  exp::Expect::equals(#C1, 100);
+  exp::Expect::equals(#C2, 200);
+  exp::Expect::equals(#C1, 100);
+  exp::Expect::equals(#C5, 3);
+  exp::Expect::equals(#C6, 10);
+}
+
+constants  {
+  #C1 = 100
+  #C2 = 200
+  #C3 = 300
+  #C4 = 1
+  #C5 = 3
+  #C6 = 10
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.outline.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.outline.expect
new file mode 100644
index 0000000..ee08b4b
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.outline.expect
@@ -0,0 +1,29 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "package:expect/expect.dart";
+
+static const field core::int var1 = self::ifTest(1);
+static const field core::int var2 = self::ifTest(2);
+static const field core::int var3 = self::ifTest(3);
+static const field core::int one = 1;
+static const field core::int var4 = self::ifTest2(1);
+static const field core::int var5 = self::ifTest2(2);
+static const field core::int var6 = self::ifTest3(1);
+static const field core::int var6_1 = self::ifTest3(2);
+static const field core::int var6_2 = self::ifTest3(0);
+static const field core::int var7 = self::ifTest4(1);
+static const field core::int var8 = self::ifTest5();
+static method ifTest(core::int a) → core::int
+  ;
+static method ifTest2(core::int a) → core::int
+  ;
+static method ifTest3(core::int a) → core::int
+  ;
+static method ifTest4(core::int a) → core::int
+  ;
+static method ifTest5() → core::int
+  ;
+static method main() → void
+  ;
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.transformed.expect
new file mode 100644
index 0000000..8d0f813
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.transformed.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+static const field core::int var1 = #C1;
+static const field core::int var2 = #C2;
+static const field core::int var3 = #C3;
+static const field core::int one = #C4;
+static const field core::int var4 = #C1;
+static const field core::int var5 = #C2;
+static const field core::int var6 = #C1;
+static const field core::int var6_1 = #C2;
+static const field core::int var6_2 = #C3;
+static const field core::int var7 = #C5;
+static const field core::int var8 = #C6;
+static method ifTest(core::int a) → core::int {
+  if(a.{core::num::==}(1)) {
+    return 100;
+  }
+  else
+    if(a.{core::num::==}(2)) {
+      return 200;
+    }
+    else {
+      return 300;
+    }
+}
+static method ifTest2(core::int a) → core::int {
+  if(a.{core::num::==}(#C4)) {
+    return 100;
+  }
+  else {
+    return 200;
+  }
+}
+static method ifTest3(core::int a) → core::int {
+  if(a.{core::num::>}(0)) {
+    if(a.{core::num::==}(1))
+      return 100;
+    return 200;
+  }
+  return 300;
+}
+static method ifTest4(core::int a) → core::int {
+  core::int b = a;
+  if(a.{core::num::==}(1)) {
+    b = b.{core::num::+}(a);
+    if(a.{core::num::%}(2).{core::num::==}(1)) {
+      b = b.{core::num::+}(a);
+    }
+  }
+  else
+    if(a.{core::num::==}(2)) {
+      b = b.{core::num::-}(a);
+    }
+  return b;
+}
+static method ifTest5() → core::int {
+  core::int x = 10;
+  if(true) {
+    core::int x = 20;
+  }
+  return x;
+}
+static method main() → void {
+  exp::Expect::equals(#C1, 100);
+  exp::Expect::equals(#C2, 200);
+  exp::Expect::equals(#C3, 300);
+  exp::Expect::equals(#C1, 100);
+  exp::Expect::equals(#C2, 200);
+  exp::Expect::equals(#C1, 100);
+  exp::Expect::equals(#C5, 3);
+  exp::Expect::equals(#C6, 10);
+}
+
+constants  {
+  #C1 = 100
+  #C2 = 200
+  #C3 = 300
+  #C4 = 1
+  #C5 = 3
+  #C6 = 10
+}
diff --git a/pkg/front_end/tool/_fasta/bench_maker.dart b/pkg/front_end/tool/_fasta/bench_maker.dart
index 0cc8476..22732a7 100644
--- a/pkg/front_end/tool/_fasta/bench_maker.dart
+++ b/pkg/front_end/tool/_fasta/bench_maker.dart
@@ -345,6 +345,11 @@
     throw "not implemented";
   }
 
+  @override
+  void visitExtensionType(ExtensionType node, StringBuffer sb) {
+    throw "not implemented";
+  }
+
   Map<String, dynamic> toJson() {
     return <String, dynamic>{
       "classes": classes,
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index fe1c348..4ed539a 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -1466,6 +1466,8 @@
   @override
   R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitExtension(this, arg);
 
+  R acceptReference<R>(Visitor<R> v) => v.visitExtensionReference(this);
+
   @override
   void visitChildren(Visitor v) {
     visitList(typeParameters, v);
@@ -11150,6 +11152,123 @@
   }
 }
 
+class ExtensionType extends DartType {
+  final Reference extensionReference;
+
+  @override
+  final Nullability declaredNullability;
+
+  final List<DartType> typeArguments;
+
+  final DartType onType;
+
+  ExtensionType(Extension extensionNode, Nullability declaredNullability,
+      [List<DartType>? typeArguments])
+      : this.byReference(extensionNode.reference, declaredNullability,
+            typeArguments ?? _defaultTypeArguments(extensionNode));
+
+  ExtensionType.byReference(
+      this.extensionReference, this.declaredNullability, this.typeArguments)
+      // ignore: unnecessary_null_comparison
+      : assert(declaredNullability != null),
+        onType = _computeOnType(extensionReference, typeArguments);
+
+  Extension get extension => extensionReference.asExtension;
+
+  @override
+  Nullability get nullability {
+    return uniteNullabilities(
+        declaredNullability, extension.onType.nullability);
+  }
+
+  static List<DartType> _defaultTypeArguments(Extension extensionNode) {
+    if (extensionNode.typeParameters.length == 0) {
+      // Avoid allocating a list in this very common case.
+      return const <DartType>[];
+    } else {
+      return new List<DartType>.filled(
+          extensionNode.typeParameters.length, const DynamicType());
+    }
+  }
+
+  static DartType _computeOnType(
+      Reference extensionName, List<DartType> typeArguments) {
+    Extension extensionNode = extensionName.asExtension;
+    if (extensionNode.typeParameters.isEmpty) {
+      return extensionNode.onType;
+    } else {
+      assert(extensionNode.typeParameters.length == typeArguments.length);
+      return Substitution.fromPairs(extensionNode.typeParameters, typeArguments)
+          .substituteType(extensionNode.onType);
+    }
+  }
+
+  @override
+  R accept<R>(DartTypeVisitor<R> v) {
+    return v.visitExtensionType(this);
+  }
+
+  @override
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) {
+    return v.visitExtensionType(this, arg);
+  }
+
+  @override
+  void visitChildren(Visitor v) {
+    extension.acceptReference(v);
+    visitList(typeArguments, v);
+  }
+
+  @override
+  bool equals(Object other, Assumptions? assumptions) {
+    if (identical(this, other)) return true;
+    if (other is ExtensionType) {
+      if (nullability != other.nullability) return false;
+      if (extensionReference != other.extensionReference) return false;
+      if (typeArguments.length != other.typeArguments.length) return false;
+      for (int i = 0; i < typeArguments.length; ++i) {
+        if (!typeArguments[i].equals(other.typeArguments[i], assumptions)) {
+          return false;
+        }
+      }
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0x3fffffff & extensionReference.hashCode;
+    for (int i = 0; i < typeArguments.length; ++i) {
+      hash = 0x3fffffff & (hash * 31 + (hash ^ typeArguments[i].hashCode));
+    }
+    int nullabilityHash = (0x33333333 >> nullability.index) ^ 0x33333333;
+    hash = 0x3fffffff & (hash * 31 + (hash ^ nullabilityHash));
+    return hash;
+  }
+
+  @override
+  ExtensionType withDeclaredNullability(Nullability declaredNullability) {
+    return declaredNullability == this.declaredNullability
+        ? this
+        : new ExtensionType.byReference(
+            extensionReference, declaredNullability, typeArguments);
+  }
+
+  @override
+  String toString() {
+    return "ExtensionType(${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeExtensionName(extensionReference);
+    printer.writeTypeArguments(typeArguments);
+    printer.write(nullabilityToString(declaredNullability));
+  }
+}
+
 /// A named parameter in [FunctionType].
 class NamedType extends Node implements Comparable<NamedType> {
   // Flag used for serialization if [isRequired].
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index bd8343c..0d63926 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -2288,6 +2288,12 @@
   }
 
   @override
+  void visitExtensionType(ExtensionType node) {
+    // TODO(dmitryas): Serialize ExtensionType.
+    node.onType.accept(this);
+  }
+
+  @override
   void visitFutureOrType(FutureOrType node) {
     // TODO(dmitryas): Remove special treatment of FutureOr when the VM supports
     // the new encoding: just write the tag.
@@ -2525,6 +2531,11 @@
   }
 
   @override
+  void visitExtensionReference(Extension node) {
+    throw new UnsupportedError('serialization of Class references');
+  }
+
+  @override
   void visitConstructorReference(Constructor node) {
     throw new UnsupportedError('serialization of Constructor references');
   }
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index 6505325..13b791c 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -739,6 +739,21 @@
   }
 
   @override
+  int visitExtensionType(ExtensionType node,
+      Map<TypeParameter, Map<DartType, int>> computedVariances) {
+    int result = Variance.unrelated;
+    for (int i = 0; i < node.typeArguments.length; ++i) {
+      result = Variance.meet(
+          result,
+          Variance.combine(
+              node.extension.typeParameters[i].variance,
+              computeVariance(typeParameter, node.typeArguments[i],
+                  computedVariances: computedVariances)));
+    }
+    return result;
+  }
+
+  @override
   int visitFutureOrType(FutureOrType node,
       Map<TypeParameter, Map<DartType, int>> computedVariances) {
     return computeVariance(typeParameter, node.typeArgument,
diff --git a/pkg/kernel/lib/src/dart_type_equivalence.dart b/pkg/kernel/lib/src/dart_type_equivalence.dart
index d051caa..08c2009 100644
--- a/pkg/kernel/lib/src/dart_type_equivalence.dart
+++ b/pkg/kernel/lib/src/dart_type_equivalence.dart
@@ -171,6 +171,32 @@
   }
 
   @override
+  bool visitExtensionType(ExtensionType node, DartType other) {
+    // First, check Object*, Object?.
+    if (equateTopTypes && coreTypes.isTop(node)) {
+      return coreTypes.isTop(other);
+    }
+
+    if (other is ExtensionType) {
+      if (!_checkAndRegisterNullabilities(
+          node.declaredNullability, other.declaredNullability)) {
+        return false;
+      }
+      if (node.extension != other.extension) {
+        return false;
+      }
+      assert(node.typeArguments.length == other.typeArguments.length);
+      for (int i = 0; i < node.typeArguments.length; ++i) {
+        if (!node.typeArguments[i].accept1(this, other.typeArguments[i])) {
+          return false;
+        }
+      }
+      return true;
+    }
+    return false;
+  }
+
+  @override
   bool visitFutureOrType(FutureOrType node, DartType other) {
     // First, check FutureOr<dynamic>, FutureOr<Object?>, etc.
     if (equateTopTypes && coreTypes.isTop(node)) {
diff --git a/pkg/kernel/lib/src/future_value_type.dart b/pkg/kernel/lib/src/future_value_type.dart
index ab5067b..773c8e7 100644
--- a/pkg/kernel/lib/src/future_value_type.dart
+++ b/pkg/kernel/lib/src/future_value_type.dart
@@ -94,6 +94,12 @@
   }
 
   @override
+  DartType visitExtensionType(DartType node, CoreTypes coreTypes) {
+    // Otherwise, for all S, futureValueType(S) = Object?.
+    return coreTypes.objectNullableRawType;
+  }
+
+  @override
   DartType visitVoidType(DartType node, CoreTypes coreTypes) {
     // futureValueType(void) = void.
     return node;
diff --git a/pkg/kernel/lib/src/merge_visitor.dart b/pkg/kernel/lib/src/merge_visitor.dart
index bbc745e..b626fa1 100644
--- a/pkg/kernel/lib/src/merge_visitor.dart
+++ b/pkg/kernel/lib/src/merge_visitor.dart
@@ -175,6 +175,41 @@
   }
 
   @override
+  DartType? visitExtensionType(ExtensionType a, DartType b) {
+    if (b is ExtensionType &&
+        a.extension == b.extension &&
+        a.typeArguments.length == b.typeArguments.length) {
+      Nullability? nullability = mergeNullability(a.nullability, b.nullability);
+      if (nullability != null) {
+        return mergeExtensionTypes(a, b, nullability);
+      }
+    }
+    if (b is InvalidType) {
+      return b;
+    }
+    return null;
+  }
+
+  DartType? mergeExtensionTypes(
+      ExtensionType a, ExtensionType b, Nullability nullability) {
+    assert(a.extension == b.extension);
+    assert(a.typeArguments.length == b.typeArguments.length);
+    if (a.typeArguments.isEmpty) {
+      return new ExtensionType(a.extension, nullability);
+    }
+    List<DartType> newTypeArguments =
+        new List<DartType>.filled(a.typeArguments.length, dummyDartType);
+    for (int i = 0; i < a.typeArguments.length; i++) {
+      DartType? newType = a.typeArguments[i].accept1(this, b.typeArguments[i]);
+      if (newType == null) {
+        return null;
+      }
+      newTypeArguments[i] = newType;
+    }
+    return new ExtensionType(a.extension, nullability, newTypeArguments);
+  }
+
+  @override
   DartType? visitFutureOrType(FutureOrType a, DartType b) {
     if (b is FutureOrType) {
       Nullability? nullability = mergeNullability(a.nullability, b.nullability);
diff --git a/pkg/kernel/lib/src/non_null.dart b/pkg/kernel/lib/src/non_null.dart
index 2d908f0..d8b3c73 100644
--- a/pkg/kernel/lib/src/non_null.dart
+++ b/pkg/kernel/lib/src/non_null.dart
@@ -53,6 +53,14 @@
   }
 
   @override
+  DartType? visitExtensionType(ExtensionType node) {
+    if (node.declaredNullability == Nullability.nonNullable) {
+      return null;
+    }
+    return node.withDeclaredNullability(Nullability.nonNullable);
+  }
+
+  @override
   DartType? visitInvalidType(InvalidType node) => null;
 
   @override
diff --git a/pkg/kernel/lib/src/replacement_visitor.dart b/pkg/kernel/lib/src/replacement_visitor.dart
index b3defb8..a3db97a2 100644
--- a/pkg/kernel/lib/src/replacement_visitor.dart
+++ b/pkg/kernel/lib/src/replacement_visitor.dart
@@ -268,5 +268,35 @@
   }
 
   @override
+  DartType? visitExtensionType(ExtensionType node, int variance) {
+    Nullability? newNullability = visitNullability(node);
+    List<DartType>? newTypeArguments = null;
+    for (int i = 0; i < node.typeArguments.length; i++) {
+      DartType? substitution = node.typeArguments[i].accept1(
+          this,
+          Variance.combine(
+              variance, node.extension.typeParameters[i].variance));
+      if (substitution != null) {
+        newTypeArguments ??= node.typeArguments.toList(growable: false);
+        newTypeArguments[i] = substitution;
+      }
+    }
+    return createExtensionType(node, newNullability, newTypeArguments);
+  }
+
+  DartType? createExtensionType(ExtensionType node, Nullability? newNullability,
+      List<DartType>? newTypeArguments) {
+    if (newNullability == null && newTypeArguments == null) {
+      // No nullability or type arguments needed to be substituted.
+      return null;
+    } else {
+      return new ExtensionType(
+          node.extension,
+          newNullability ?? node.nullability,
+          newTypeArguments ?? node.typeArguments);
+    }
+  }
+
+  @override
   DartType? defaultDartType(DartType node, int variance) => null;
 }
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index 6aa0dc8..fe66446 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -2436,6 +2436,17 @@
     writeNullability(node.nullability);
   }
 
+  visitExtensionType(ExtensionType node) {
+    writeExtensionReferenceFromReference(node.extensionReference);
+    if (node.typeArguments.isNotEmpty) {
+      writeSymbol('<');
+      writeList(node.typeArguments, writeType);
+      writeSymbol('>');
+      state = Printer.WORD;
+    }
+    writeNullability(node.declaredNullability);
+  }
+
   visitFutureOrType(FutureOrType node) {
     writeWord('FutureOr');
     writeSymbol('<');
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index 0976e98..ebf18f2 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -675,6 +675,10 @@
     return node.typeArguments.any(visit);
   }
 
+  bool visitExtensionType(ExtensionType node) {
+    return node.typeArguments.any(visit);
+  }
+
   bool visitFutureOrType(FutureOrType node) {
     return visit(node.typeArgument);
   }
@@ -727,6 +731,10 @@
     return node.typeArguments.any(visit);
   }
 
+  bool visitExtensionType(ExtensionType node) {
+    return node.typeArguments.any(visit);
+  }
+
   bool visitFutureOrType(FutureOrType node) {
     return visit(node.typeArgument);
   }
@@ -782,6 +790,10 @@
     return node.typeArguments.any(visit);
   }
 
+  bool visitExtensionType(ExtensionType node) {
+    return node.typeArguments.any(visit);
+  }
+
   bool visitFutureOrType(FutureOrType node) {
     return visit(node.typeArgument);
   }
@@ -881,6 +893,11 @@
   }
 
   @override
+  bool visitExtensionType(ExtensionType node) {
+    return node.typeArguments.isEmpty;
+  }
+
+  @override
   bool visitInvalidType(InvalidType node) {
     throw new UnsupportedError(
         "Unsupported operation: _PrimitiveTypeVerifier(InvalidType).");
@@ -950,6 +967,11 @@
   }
 
   @override
+  DartType visitExtensionType(ExtensionType node, CoreTypes coreTypes) {
+    return node.withDeclaredNullability(Nullability.nonNullable);
+  }
+
+  @override
   DartType visitInvalidType(InvalidType node, CoreTypes coreTypes) => node;
 
   @override
@@ -1163,6 +1185,13 @@
   }
 
   @override
+  bool visitExtensionType(ExtensionType node) {
+    assert(node.declaredNullability != Nullability.undetermined);
+    return node.declaredNullability == Nullability.nullable ||
+        node.declaredNullability == Nullability.legacy;
+  }
+
+  @override
   bool visitInvalidType(InvalidType node) => false;
 
   @override
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index f4afa00..11032aa 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -529,6 +529,7 @@
   R visitTypedefType(TypedefType node) => defaultDartType(node);
   R visitNeverType(NeverType node) => defaultDartType(node);
   R visitNullType(NullType node) => defaultDartType(node);
+  R visitExtensionType(ExtensionType node) => defaultDartType(node);
 }
 
 abstract class DartTypeVisitor1<R, T> {
@@ -545,6 +546,7 @@
   R visitTypedefType(TypedefType node, T arg) => defaultDartType(node, arg);
   R visitNeverType(NeverType node, T arg) => defaultDartType(node, arg);
   R visitNullType(NullType node, T arg) => defaultDartType(node, arg);
+  R visitExtensionType(ExtensionType node, T arg) => defaultDartType(node, arg);
 }
 
 /// Visitor for [Constant] nodes.
@@ -783,6 +785,7 @@
   R visitTypedefType(TypedefType node) => defaultDartType(node);
   R visitNeverType(NeverType node) => defaultDartType(node);
   R visitNullType(NullType node) => defaultDartType(node);
+  R visitExtensionType(ExtensionType node) => defaultDartType(node);
 
   // Constants
   R defaultConstant(Constant node) => defaultNode(node);
@@ -807,6 +810,8 @@
 
   R visitTypedefReference(Typedef node);
 
+  R visitExtensionReference(Extension node);
+
   // Constant references
   R defaultConstantReference(Constant node);
 
@@ -906,6 +911,9 @@
   R? visitTypedefReference(Typedef node) => null;
 
   @override
+  R? visitExtensionReference(Extension node) => null;
+
+  @override
   R? defaultConstantReference(Constant node) => null;
 
   @override
@@ -924,6 +932,9 @@
   void visitTypedefReference(Typedef node) {}
 
   @override
+  void visitExtensionReference(Extension node) {}
+
+  @override
   void defaultConstantReference(Constant node) {}
 
   @override
@@ -944,6 +955,9 @@
   R visitTypedefReference(Typedef node) => defaultValue;
 
   @override
+  R visitExtensionReference(Extension node) => defaultValue;
+
+  @override
   R defaultConstantReference(Constant node) => defaultValue;
 
   @override
diff --git a/tests/language/const_functions/const_functions_if_statements_test.dart b/tests/language/const_functions/const_functions_if_statements_test.dart
new file mode 100644
index 0000000..e4998ee
--- /dev/null
+++ b/tests/language/const_functions/const_functions_if_statements_test.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests if statements for const functions.
+
+// SharedOptions=--enable-experiment=const-functions
+
+import "package:expect/expect.dart";
+
+const var1 = ifTest(1);
+//           ^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+const var2 = ifTest(2);
+//           ^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+const var3 = ifTest(3);
+//           ^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int ifTest(int a) {
+  if (a == 1) {
+    return 100;
+  } else if (a == 2) {
+    return 200;
+  } else {
+    return 300;
+  }
+}
+
+const one = 1;
+const var4 = ifTest2(1);
+//           ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+const var5 = ifTest2(2);
+//           ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int ifTest2(int a) {
+  if (a == one) {
+    return 100;
+  } else {
+    return 200;
+  }
+}
+
+const var6 = ifTest3(1);
+//           ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+const var6_1 = ifTest3(2);
+//             ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+const var6_2 = ifTest3(0);
+//             ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int ifTest3(int a) {
+  if (a > 0) {
+    if (a == 1) return 100;
+    return 200;
+  }
+  return 300;
+}
+
+const var7 = ifTest4(1);
+//           ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int ifTest4(int a) {
+  int b = a;
+  if (a == 1) {
+    b += a;
+    if (a % 2 == 1) {
+      b += a;
+    }
+  } else if (a == 2) {
+    b -= a;
+  }
+
+  return b;
+}
+
+const var8 = ifTest5();
+//           ^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int ifTest5() {
+  var x = 10;
+  if (true) var x = 20;
+  return x;
+}
+
+void main() {
+  Expect.equals(var1, 100);
+  Expect.equals(var2, 200);
+  Expect.equals(var3, 300);
+  Expect.equals(var4, 100);
+  Expect.equals(var5, 200);
+  Expect.equals(var6, 100);
+  Expect.equals(var7, 3);
+  Expect.equals(var8, 10);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 529971b..ea5a9d5 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 134
+PRERELEASE 135
 PRERELEASE_PATCH 0
\ No newline at end of file