Skip to content

Commit

Permalink
[cfe] Implement full subtyping rules for extension types vs FutureOr
Browse files Browse the repository at this point in the history
Closes #55578

Change-Id: Id344e9057f42b3fc19a6ff83ce000775aec5789a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/364720
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
  • Loading branch information
chloestefantsova authored and Commit Queue committed Apr 29, 2024
1 parent 5b2ea0c commit 54c9b37
Show file tree
Hide file tree
Showing 10 changed files with 178 additions and 3 deletions.
13 changes: 13 additions & 0 deletions pkg/front_end/testcases/extension_types/issue55578.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';

extension type E(Future<String> it) implements Future<String> {}

foo(FutureOr<String> x) {}

E bar() => throw 0;

test() => foo(bar()); // Ok.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
library;
import self as self;
import "dart:async" as asy;
import "dart:core" as core;

import "dart:async";

extension type E(asy::Future<core::String> it) implements asy::Future<core::String> {
abstract extension-type-member representation-field get it() → asy::Future<core::String>;
constructor • = self::E|constructor#;
constructor tearoff • = self::E|constructor#_#new#tearOff;
}
static extension-type-member method E|constructor#(asy::Future<core::String> it) → self::E /* erasure=asy::Future<core::String> */ {
lowered final self::E /* erasure=asy::Future<core::String> */ #this = it;
return #this;
}
static extension-type-member method E|constructor#_#new#tearOff(asy::Future<core::String> it) → self::E /* erasure=asy::Future<core::String> */
return self::E|constructor#(it);
static method foo(FutureOr<core::String>x) → dynamic {}
static method bar() → self::E /* erasure=asy::Future<core::String> */
return throw 0;
static method test() → dynamic
return self::foo(self::bar());
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
library;
import self as self;
import "dart:async" as asy;
import "dart:core" as core;

import "dart:async";

extension type E(asy::Future<core::String> it) implements asy::Future<core::String> {
abstract extension-type-member representation-field get it() → asy::Future<core::String>;
constructor • = self::E|constructor#;
constructor tearoff • = self::E|constructor#_#new#tearOff;
}
static extension-type-member method E|constructor#(asy::Future<core::String> it) → self::E /* erasure=asy::Future<core::String> */ {
lowered final self::E /* erasure=asy::Future<core::String> */ #this = it;
return #this;
}
static extension-type-member method E|constructor#_#new#tearOff(asy::Future<core::String> it) → self::E /* erasure=asy::Future<core::String> */
return self::E|constructor#(it);
static method foo(FutureOr<core::String>x) → dynamic {}
static method bar() → self::E /* erasure=asy::Future<core::String> */
return throw 0;
static method test() → dynamic
return self::foo(self::bar());
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'dart:async';

extension type E(Future<String> it) implements Future<String> {}

foo(FutureOr<String> x) {}

E bar() => throw 0;

test() => foo(bar());
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'dart:async';

E bar() => throw 0;

extension type E(Future<String> it) implements Future<String> {}

foo(FutureOr<String> x) {}

test() => foo(bar());
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
library;
import self as self;
import "dart:async" as asy;
import "dart:core" as core;

import "dart:async";

extension type E(asy::Future<core::String> it) implements asy::Future<core::String> {
abstract extension-type-member representation-field get it() → asy::Future<core::String>;
constructor • = self::E|constructor#;
constructor tearoff • = self::E|constructor#_#new#tearOff;
}
static extension-type-member method E|constructor#(asy::Future<core::String> it) → self::E /* erasure=asy::Future<core::String> */ {
lowered final self::E /* erasure=asy::Future<core::String> */ #this = it;
return #this;
}
static extension-type-member method E|constructor#_#new#tearOff(asy::Future<core::String> it) → self::E /* erasure=asy::Future<core::String> */
return self::E|constructor#(it);
static method foo(FutureOr<core::String>x) → dynamic {}
static method bar() → self::E /* erasure=asy::Future<core::String> */
return throw 0;
static method test() → dynamic
return self::foo(self::bar());
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
library;
import self as self;
import "dart:async" as asy;
import "dart:core" as core;

import "dart:async";

extension type E(asy::Future<core::String> it) implements asy::Future<core::String> {
abstract extension-type-member representation-field get it() → asy::Future<core::String>;
constructor • = self::E|constructor#;
constructor tearoff • = self::E|constructor#_#new#tearOff;
}
static extension-type-member method E|constructor#(asy::Future<core::String> it) → self::E /* erasure=asy::Future<core::String> */ {
lowered final self::E /* erasure=asy::Future<core::String> */ #this = it;
return #this;
}
static extension-type-member method E|constructor#_#new#tearOff(asy::Future<core::String> it) → self::E /* erasure=asy::Future<core::String> */
return self::E|constructor#(it);
static method foo(FutureOr<core::String>x) → dynamic {}
static method bar() → self::E /* erasure=asy::Future<core::String> */
return throw 0;
static method test() → dynamic
return self::foo(self::bar());
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
library;
import self as self;
import "dart:async" as asy;
import "dart:core" as core;

import "dart:async";

extension type E(asy::Future<core::String> it) implements asy::Future<core::String> {
abstract extension-type-member representation-field get it() → asy::Future<core::String>;
constructor • = self::E|constructor#;
constructor tearoff • = self::E|constructor#_#new#tearOff;
}
static extension-type-member method E|constructor#(asy::Future<core::String> it) → self::E /* erasure=asy::Future<core::String> */
;
static extension-type-member method E|constructor#_#new#tearOff(asy::Future<core::String> it) → self::E /* erasure=asy::Future<core::String> */
return self::E|constructor#(it);
static method foo(FutureOr<core::String>x) → dynamic
;
static method bar() → self::E /* erasure=asy::Future<core::String> */
;
static method test() → dynamic
;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
library;
import self as self;
import "dart:async" as asy;
import "dart:core" as core;

import "dart:async";

extension type E(asy::Future<core::String> it) implements asy::Future<core::String> {
abstract extension-type-member representation-field get it() → asy::Future<core::String>;
constructor • = self::E|constructor#;
constructor tearoff • = self::E|constructor#_#new#tearOff;
}
static extension-type-member method E|constructor#(asy::Future<core::String> it) → self::E /* erasure=asy::Future<core::String> */ {
lowered final self::E /* erasure=asy::Future<core::String> */ #this = it;
return #this;
}
static extension-type-member method E|constructor#_#new#tearOff(asy::Future<core::String> it) → self::E /* erasure=asy::Future<core::String> */
return self::E|constructor#(it);
static method foo(FutureOr<core::String>x) → dynamic {}
static method bar() → self::E /* erasure=asy::Future<core::String> */
return throw 0;
static method test() → dynamic
return self::foo(self::bar());
13 changes: 10 additions & 3 deletions pkg/kernel/lib/src/types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1283,9 +1283,16 @@ class IsFutureOrSubtypeOf extends TypeRelation<FutureOrType> {
@override
IsSubtypeOf isExtensionTypeRelated(
ExtensionType s, FutureOrType t, Types types) {
// Rule 11.
return types.performNullabilityAwareSubtypeCheck(
s, t.typeArgument.withDeclaredNullability(t.nullability));
return types
// Rule 11.
.performNullabilityAwareSubtypeCheck(
s, t.typeArgument.withDeclaredNullability(t.nullability))
// Rule 10.
.orSubtypeCheckFor(
s,
new InterfaceType(types.hierarchy.coreTypes.futureClass,
t.nullability, [t.typeArgument]),
types);
}
}

Expand Down

0 comments on commit 54c9b37

Please sign in to comment.