[cfe] Add calls to isExtensionRelated to subtype implementation

Closes #45775.

Bug: https://github.com/dart-lang/sdk/issues/45775

Change-Id: Ibffdd24b1a691b2149323dbc984c0d3ae7134c25
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/196120
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/testcases/extension_types/extension_on_nullable.dart b/pkg/front_end/testcases/extension_types/extension_on_nullable.dart
new file mode 100644
index 0000000..ea57240
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/extension_on_nullable.dart
@@ -0,0 +1,13 @@
+// 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.
+
+class A {}
+
+extension E on A? {
+  void foo() {}
+}
+
+bar(E e) => e.foo();
+
+main() {}
diff --git a/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.strong.expect b/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.strong.expect
new file mode 100644
index 0000000..3074033
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.strong.expect
@@ -0,0 +1,19 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+}
+extension E on self::A? {
+  method foo = self::E|foo;
+  tearoff foo = self::E|get#foo;
+}
+static method E|foo(lowered final self::A? #this) → void {}
+static method E|get#foo(lowered final self::A? #this) → () → void
+  return () → void => self::E|foo(#this);
+static method bar(self::E e) → dynamic
+  return self::E|foo(e);
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.textual_outline.expect b/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.textual_outline.expect
new file mode 100644
index 0000000..37161fe
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+class A {}
+
+extension E on A? {
+  void foo() {}
+}
+
+bar(E e) => e.foo();
+main() {}
diff --git a/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..a6cd4d8
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.textual_outline_modelled.expect
@@ -0,0 +1,9 @@
+bar(E e) => e.foo();
+
+class A {}
+
+extension E on A? {
+  void foo() {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.weak.expect b/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.weak.expect
new file mode 100644
index 0000000..3074033
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.weak.expect
@@ -0,0 +1,19 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+}
+extension E on self::A? {
+  method foo = self::E|foo;
+  tearoff foo = self::E|get#foo;
+}
+static method E|foo(lowered final self::A? #this) → void {}
+static method E|get#foo(lowered final self::A? #this) → () → void
+  return () → void => self::E|foo(#this);
+static method bar(self::E e) → dynamic
+  return self::E|foo(e);
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.weak.outline.expect b/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.weak.outline.expect
new file mode 100644
index 0000000..c897d7f
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/extension_on_nullable.dart.weak.outline.expect
@@ -0,0 +1,20 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    ;
+}
+extension E on self::A? {
+  method foo = self::E|foo;
+  tearoff foo = self::E|get#foo;
+}
+static method E|foo(lowered final self::A? #this) → void
+  ;
+static method E|get#foo(lowered final self::A? #this) → () → void
+  return () → void => self::E|foo(#this);
+static method bar(self::E e) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extension_types/issue45775.dart b/pkg/front_end/testcases/extension_types/issue45775.dart
new file mode 100644
index 0000000..012fff6
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/issue45775.dart
@@ -0,0 +1,11 @@
+// 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.
+
+class Foo {}
+
+extension Bar on Foo {}
+
+void main() {
+  Bar bar = Foo();
+}
diff --git a/pkg/front_end/testcases/extension_types/issue45775.dart.strong.expect b/pkg/front_end/testcases/extension_types/issue45775.dart.strong.expect
new file mode 100644
index 0000000..f5b3d09
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/issue45775.dart.strong.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extension_types/issue45775.dart:10:13: Error: A value of type 'Foo' can't be assigned to a variable of type 'Bar'.
+//  - 'Foo' is from 'pkg/front_end/testcases/extension_types/issue45775.dart'.
+//   Bar bar = Foo();
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → self::Foo
+    : super core::Object::•()
+    ;
+}
+extension Bar on self::Foo {
+}
+static method main() → void {
+  self::Bar bar = let final Never #t1 = invalid-expression "pkg/front_end/testcases/extension_types/issue45775.dart:10:13: Error: A value of type 'Foo' can't be assigned to a variable of type 'Bar'.
+ - 'Foo' is from 'pkg/front_end/testcases/extension_types/issue45775.dart'.
+  Bar bar = Foo();
+            ^" in new self::Foo::•() as{TypeError,ForNonNullableByDefault} self::Bar;
+}
diff --git a/pkg/front_end/testcases/extension_types/issue45775.dart.textual_outline.expect b/pkg/front_end/testcases/extension_types/issue45775.dart.textual_outline.expect
new file mode 100644
index 0000000..a30a73d
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/issue45775.dart.textual_outline.expect
@@ -0,0 +1,5 @@
+class Foo {}
+
+extension Bar on Foo {}
+
+void main() {}
diff --git a/pkg/front_end/testcases/extension_types/issue45775.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/extension_types/issue45775.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..a30a73d
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/issue45775.dart.textual_outline_modelled.expect
@@ -0,0 +1,5 @@
+class Foo {}
+
+extension Bar on Foo {}
+
+void main() {}
diff --git a/pkg/front_end/testcases/extension_types/issue45775.dart.weak.expect b/pkg/front_end/testcases/extension_types/issue45775.dart.weak.expect
new file mode 100644
index 0000000..f5b3d09
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/issue45775.dart.weak.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extension_types/issue45775.dart:10:13: Error: A value of type 'Foo' can't be assigned to a variable of type 'Bar'.
+//  - 'Foo' is from 'pkg/front_end/testcases/extension_types/issue45775.dart'.
+//   Bar bar = Foo();
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → self::Foo
+    : super core::Object::•()
+    ;
+}
+extension Bar on self::Foo {
+}
+static method main() → void {
+  self::Bar bar = let final Never #t1 = invalid-expression "pkg/front_end/testcases/extension_types/issue45775.dart:10:13: Error: A value of type 'Foo' can't be assigned to a variable of type 'Bar'.
+ - 'Foo' is from 'pkg/front_end/testcases/extension_types/issue45775.dart'.
+  Bar bar = Foo();
+            ^" in new self::Foo::•() as{TypeError,ForNonNullableByDefault} self::Bar;
+}
diff --git a/pkg/front_end/testcases/extension_types/issue45775.dart.weak.outline.expect b/pkg/front_end/testcases/extension_types/issue45775.dart.weak.outline.expect
new file mode 100644
index 0000000..621635e
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/issue45775.dart.weak.outline.expect
@@ -0,0 +1,12 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → self::Foo
+    ;
+}
+extension Bar on self::Foo {
+}
+static method main() → void
+  ;
diff --git a/pkg/front_end/testcases/outline.status b/pkg/front_end/testcases/outline.status
index dc7cac2..b9f3dfa 100644
--- a/pkg/front_end/testcases/outline.status
+++ b/pkg/front_end/testcases/outline.status
@@ -3,6 +3,7 @@
 # BSD-style license that can be found in the LICENSE.md file.
 
 const_functions/const_functions_const_factory: VerificationError
+extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized
 extension_types/simple_getter_resolution: ExpectationFileMismatchSerialized
 extension_types/simple_method_resolution: ExpectationFileMismatchSerialized
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index c0d86e6..6403bd3 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -6,6 +6,8 @@
 # Kernel ASTs directly, that is, code in pkg/fasta/lib/src/kernel/ with
 # strong-mode enabled.
 
+extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
+extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple_getter_resolution: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple_method_resolution: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 6b0b79c..c8b4bc7 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -6,6 +6,8 @@
 # the round trip for Kernel textual serialization where the initial binary
 # Kernel files are produced by compiling Dart code via Fasta.
 
+extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
+extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple_getter_resolution: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple_method_resolution: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/weak.status b/pkg/front_end/testcases/weak.status
index 9af0078..865813b 100644
--- a/pkg/front_end/testcases/weak.status
+++ b/pkg/front_end/testcases/weak.status
@@ -10,6 +10,8 @@
 general/error_recovery/issue_39058.crash: SemiFuzzFailure
 regress/utf_16_le_content.crash: SemiFuzzCrash
 
+extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
+extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple_getter_resolution: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple_method_resolution: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/kernel/lib/src/types.dart b/pkg/kernel/lib/src/types.dart
index 550417c..47c4b89 100644
--- a/pkg/kernel/lib/src/types.dart
+++ b/pkg/kernel/lib/src/types.dart
@@ -112,6 +112,8 @@
         return relation.isTypedefRelated(s, t, this);
       } else if (s is FutureOrType) {
         return relation.isFutureOrRelated(s, t, this);
+      } else if (s is ExtensionType) {
+        return relation.isExtensionRelated(s, t, this);
       }
     } else if (t is FunctionType) {
       const IsFunctionSubtypeOf relation = const IsFunctionSubtypeOf();
@@ -131,6 +133,8 @@
         return relation.isTypedefRelated(s, t, this);
       } else if (s is FutureOrType) {
         return relation.isFutureOrRelated(s, t, this);
+      } else if (s is ExtensionType) {
+        return relation.isExtensionRelated(s, t, this);
       }
     } else if (t is TypeParameterType) {
       if (t.promotedBound == null) {
@@ -152,6 +156,8 @@
           return relation.isTypedefRelated(s, t, this);
         } else if (s is FutureOrType) {
           return relation.isFutureOrRelated(s, t, this);
+        } else if (s is ExtensionType) {
+          return relation.isExtensionRelated(s, t, this);
         }
       } else {
         const IsIntersectionSubtypeOf relation =
@@ -172,6 +178,8 @@
           return relation.isTypedefRelated(s, t, this);
         } else if (s is FutureOrType) {
           return relation.isFutureOrRelated(s, t, this);
+        } else if (s is ExtensionType) {
+          return relation.isExtensionRelated(s, t, this);
         }
       }
     } else if (t is TypedefType) {
@@ -192,6 +200,8 @@
         return relation.isTypedefRelated(s, t, this);
       } else if (s is FutureOrType) {
         return relation.isFutureOrRelated(s, t, this);
+      } else if (s is ExtensionType) {
+        return relation.isExtensionRelated(s, t, this);
       }
     } else if (t is FutureOrType) {
       const IsFutureOrSubtypeOf relation = const IsFutureOrSubtypeOf();
@@ -211,6 +221,8 @@
         return relation.isTypedefRelated(s, t, this);
       } else if (s is FutureOrType) {
         return relation.isFutureOrRelated(s, t, this);
+      } else if (s is ExtensionType) {
+        return relation.isExtensionRelated(s, t, this);
       }
     } else if (t is NullType) {
       const IsNullTypeSubtypeOf relation = const IsNullTypeSubtypeOf();
@@ -230,6 +242,8 @@
         return relation.isTypedefRelated(s, t, this);
       } else if (s is FutureOrType) {
         return relation.isFutureOrRelated(s, t, this);
+      } else if (s is ExtensionType) {
+        return relation.isExtensionRelated(s, t, this);
       }
     } else if (t is NeverType) {
       const IsNeverTypeSubtypeOf relation = const IsNeverTypeSubtypeOf();
@@ -249,6 +263,30 @@
         return relation.isTypedefRelated(s, t, this);
       } else if (s is FutureOrType) {
         return relation.isFutureOrRelated(s, t, this);
+      } else if (s is ExtensionType) {
+        return relation.isExtensionRelated(s, t, this);
+      }
+    } else if (t is ExtensionType) {
+      const IsExtensionTypeSubtypeOf relation =
+          const IsExtensionTypeSubtypeOf();
+      if (s is DynamicType) {
+        return relation.isDynamicRelated(s, t, this);
+      } else if (s is VoidType) {
+        return relation.isVoidRelated(s, t, this);
+      } else if (s is InterfaceType) {
+        return relation.isInterfaceRelated(s, t, this);
+      } else if (s is FunctionType) {
+        return relation.isFunctionRelated(s, t, this);
+      } else if (s is TypeParameterType) {
+        return s.promotedBound == null
+            ? relation.isTypeParameterRelated(s, t, this)
+            : relation.isIntersectionRelated(s, t, this);
+      } else if (s is TypedefType) {
+        return relation.isTypedefRelated(s, t, this);
+      } else if (s is FutureOrType) {
+        return relation.isFutureOrRelated(s, t, this);
+      } else if (s is ExtensionType) {
+        return relation.isExtensionRelated(s, t, this);
       }
     } else {
       throw "Unhandled type: ${t.runtimeType}";