Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(423)

Unified Diff: tool/input_sdk/private/ddc_runtime/types.dart

Issue 1945113003: Better is/as check handling. With this CL, the subtype function in (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Update new tests after rebase Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tool/input_sdk/private/ddc_runtime/operations.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tool/input_sdk/private/ddc_runtime/types.dart
diff --git a/tool/input_sdk/private/ddc_runtime/types.dart b/tool/input_sdk/private/ddc_runtime/types.dart
index 0b0098731c29271cb36134dc049a9e57e183bb27..c3dabfd1ec02bd7edad5de3173e65dd62756ab8c 100644
--- a/tool/input_sdk/private/ddc_runtime/types.dart
+++ b/tool/input_sdk/private/ddc_runtime/types.dart
@@ -313,7 +313,13 @@ bool isDartType(type) => JS('bool', '#(#) === #', _getRuntimeType, type, Type);
typeName(type) => JS('', '''(() => {
// Non-instance types
- if ($type instanceof $TypeRep) return $type.toString();
+ if ($type instanceof $TypeRep) {
+ if ($type instanceof $Typedef) {
+ return $type.name + "(" + $type.functionType.toString() + ")";
+ }
+ return $type.toString();
+ }
+
// Instance types
let tag = $_getRuntimeType($type);
if (tag === $Type) {
@@ -355,36 +361,35 @@ isFunctionType(type) =>
JS('bool', '# instanceof # || # === #',
type, AbstractFunctionType, type, Function);
-isFunctionSubType(ft1, ft2) => JS('', '''(() => {
- if ($ft2 == $Function) {
+/// Returns true if [ft1] <: [ft2].
+/// Returns false if [ft1] </: [ft2] in both spec and strong mode
+/// Returns null if [ft1] </: [ft2] in strong mode, but spec mode
+/// may differ
+/// If [covariant] is true, then we are checking subtyping in a covariant
+/// position, and hence the direction of the check for function types
+/// corresponds to the direction of the check according to the Dart spec.
+isFunctionSubtype(ft1, ft2, covariant) => JS('', '''(() => {
+ if ($ft2 === $Function) {
return true;
}
let ret1 = $ft1.returnType;
let ret2 = $ft2.returnType;
- if (!$isSubtype_(ret1, ret2)) {
- // Covariant return types
- // Note, void (which can only appear as a return type) is effectively
- // treated as dynamic. If the base return type is void, we allow any
- // subtype return type.
- // E.g., we allow:
- // () -> int <: () -> void
- if (ret2 != $voidR) {
- return false;
- }
- }
-
let args1 = $ft1.args;
let args2 = $ft2.args;
if (args1.length > args2.length) {
- return false;
+ // If we're in a covariant position, then Dart's arity rules
+ // agree with strong mode, otherwise we can't be sure.
+ return ($covariant) ? false : null;
}
for (let i = 0; i < args1.length; ++i) {
- if (!$isSubtype_(args2[i], args1[i])) {
- return false;
+ if (!$isSubtype_(args2[i], args1[i], !$covariant)) {
+ // Even if isSubtype returns false, assignability
+ // means that we can't be definitive
+ return null;
}
}
@@ -392,19 +397,19 @@ isFunctionSubType(ft1, ft2) => JS('', '''(() => {
let optionals2 = $ft2.optionals;
if (args1.length + optionals1.length < args2.length + optionals2.length) {
- return false;
+ return ($covariant) ? false : null;
}
let j = 0;
for (let i = args1.length; i < args2.length; ++i, ++j) {
- if (!$isSubtype_(args2[i], optionals1[j])) {
- return false;
+ if (!$isSubtype_(args2[i], optionals1[j], !$covariant)) {
+ return null;
}
}
for (let i = 0; i < optionals2.length; ++i, ++j) {
- if (!$isSubtype_(optionals2[i], optionals1[j])) {
- return false;
+ if (!$isSubtype_(optionals2[i], optionals1[j], !$covariant)) {
+ return null;
}
}
@@ -417,10 +422,28 @@ isFunctionSubType(ft1, ft2) => JS('', '''(() => {
let n1 = named1[name];
let n2 = named2[name];
if (n1 === void 0) {
- return false;
+ return ($covariant) ? false : null;
}
- if (!$isSubtype_(n2, n1)) {
- return false;
+ if (!$isSubtype_(n2, n1, !$covariant)) {
+ return null;
+ }
+ }
+
+ // Check return type last, so that arity mismatched functions can be
+ // definitively rejected.
+ {
+ let result = $isSubtype_(ret1, ret2, $covariant);
+ if (result === null) return result;
+ if (!result) {
+ // Covariant return types
+ // Note, void (which can only appear as a return type) is effectively
+ // treated as dynamic. If the base return type is void, we allow any
+ // subtype return type.
+ // E.g., we allow:
+ // () -> int <: () -> void
+ if (ret2 !== $voidR) {
+ return null;
+ }
}
}
@@ -446,6 +469,10 @@ canonicalType(t) => JS('', '''(() => {
})()''');
final subtypeMap = JS('', 'new Map()');
+/// Returns true if [t1] <: [t2].
+/// Returns false if [t1] </: [t2] in both spec and strong mode
+/// Returns undefined if [t1] </: [t2] in strong mode, but spec
+/// mode may differ
isSubtype(t1, t2) => JS('', '''(() => {
// See if we already know the answer
// TODO(jmesserly): general purpose memoize function?
@@ -457,7 +484,7 @@ isSubtype(t1, t2) => JS('', '''(() => {
} else {
$subtypeMap.set($t1, map = new Map());
}
- result = $isSubtype_($t1, $t2);
+ result = $isSubtype_($t1, $t2, true);
map.set($t2, result);
return result;
})()''');
@@ -466,10 +493,10 @@ _isBottom(type) => JS('bool', '# == #', type, bottom);
_isTop(type) => JS('bool', '# == # || # == #', type, Object, type, dynamicR);
-isSubtype_(t1, t2) => JS('', '''(() => {
+isSubtype_(t1, t2, covariant) => JS('', '''(() => {
$t1 = $canonicalType($t1);
$t2 = $canonicalType($t2);
- if ($t1 == $t2) return true;
+ if ($t1 === $t2) return true;
// Trivially true.
if ($_isTop($t2) || $_isBottom($t1)) {
@@ -477,13 +504,16 @@ isSubtype_(t1, t2) => JS('', '''(() => {
}
// Trivially false.
- if ($_isTop($t1) || $_isBottom($t2)) {
+ if ($_isBottom($t2)) return null;
+ if ($_isTop($t1)) {
+ if ($t1 === $dynamicR) return null;
return false;
}
// "Traditional" name-based subtype check.
- if ($isClassSubType($t1, $t2)) {
- return true;
+ {
+ let result = $isClassSubType($t1, $t2, $covariant);
+ if (result === true || result === null) return result;
}
// Function subtyping.
@@ -495,12 +525,12 @@ isSubtype_(t1, t2) => JS('', '''(() => {
if ($isFunctionType($t1) &&
$isFunctionType($t2)) {
- return $isFunctionSubType($t1, $t2);
+ return $isFunctionSubtype($t1, $t2, $covariant);
}
return false;
})()''');
-isClassSubType(t1, t2) => JS('', '''(() => {
+isClassSubType(t1, t2, covariant) => JS('', '''(() => {
// We support Dart's covariant generics with the caveat that we do not
// substitute bottom for dynamic in subtyping rules.
// I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow:
@@ -528,26 +558,38 @@ isClassSubType(t1, t2) => JS('', '''(() => {
return true;
} else if (length == 0) {
// t1 is raw, but t2 is not
- return false;
+ if (typeArguments2.every($_isTop)) return true;
+ return null;
}
$assert_(length == typeArguments2.length);
for (let i = 0; i < length; ++i) {
- if (!$isSubtype(typeArguments1[i], typeArguments2[i])) {
- return false;
+ let result =
+ $isSubtype_(typeArguments1[i], typeArguments2[i], $covariant);
+ if (!result) {
+ return result;
}
}
return true;
}
- // Check superclass.
- if ($isClassSubType($t1.__proto__, $t2)) return true;
+ let indefinite = false;
+ function definitive(t1, t2) {
+ let result = $isClassSubType(t1, t2, $covariant);
+ if (result == null) {
+ indefinite = true;
+ return false;
+ }
+ return result;
+ }
+
+ if (definitive($t1.__proto__, $t2)) return true;
// Check mixins.
let mixins = $getMixins($t1);
if (mixins) {
for (let m1 of mixins) {
// TODO(jmesserly): remove the != null check once we can load core libs.
- if (m1 != null && $isClassSubType(m1, $t2)) return true;
+ if (m1 != null && definitive(m1, $t2)) return true;
}
}
@@ -556,10 +598,15 @@ isClassSubType(t1, t2) => JS('', '''(() => {
if (getInterfaces) {
for (let i1 of getInterfaces()) {
// TODO(jmesserly): remove the != null check once we can load core libs.
- if (i1 != null && $isClassSubType(i1, $t2)) return true;
+ if (i1 != null && definitive(i1, $t2)) return true;
}
}
+ // We found no definite supertypes, and at least one indefinite supertype
+ // so the answer is indefinite.
+ if (indefinite) return null;
+ // We found no definite supertypes and no indefinite supertypes, so we
+ // can return false.
return false;
})()''');
« no previous file with comments | « tool/input_sdk/private/ddc_runtime/operations.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698