[cfe] Implement least upper bound for inline types

Closes #51556

Change-Id: I44f2ae947b5316d21d23b39b88f1515702525955
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/294983
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
Johnni Winther 2023-04-24 09:14:07 +00:00 committed by Commit Queue
parent 92239e6b27
commit fe01a2068d
11 changed files with 668 additions and 32 deletions

View file

@ -41,6 +41,7 @@ approximation
arbitrarily
area
arglebargle
arr
asdf
asserter
assure

View file

@ -0,0 +1,44 @@
// Copyright (c) 2023, 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.
inline class JSAny {
final Object value;
JSAny(this.value);
}
inline class JSObject implements JSAny {
final Object value;
JSObject(this.value);
}
inline class JSArray implements JSObject {
final List<JSAny?> value;
JSArray(this.value);
}
inline class JSExportedDartObject implements JSObject {
final Object value;
JSExportedDartObject(this.value);
}
inline class JSNumber implements JSAny {
final double value;
JSNumber(this.value);
}
extension ObjectToJSExportedDartObject on Object {
JSExportedDartObject get toJS => JSExportedDartObject(this);
}
extension ListToJSArray on List<JSAny?> {
JSArray get toJS => JSArray(this);
}
extension DoubleToJSNumber on double {
JSNumber get toJS => JSNumber(this);
}
void main() {
JSArray arr = [1.0.toJS, 'foo'.toJS].toJS;
}

View file

@ -0,0 +1,72 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
extension ObjectToJSExportedDartObject on core::Object {
get toJS = self::ObjectToJSExportedDartObject|get#toJS;
}
extension ListToJSArray on core::List<self::JSAny?> {
get toJS = self::ListToJSArray|get#toJS;
}
extension DoubleToJSNumber on core::double {
get toJS = self::DoubleToJSNumber|get#toJS;
}
inline class JSAny /* declaredRepresentationType = core::Object */ {
constructor • = self::JSAny|;
tearoff • = self::JSAny|get#;
}
inline class JSObject /* declaredRepresentationType = core::Object */ implements self::JSAny {
constructor • = self::JSObject|;
tearoff • = self::JSObject|get#;
}
inline class JSArray /* declaredRepresentationType = core::List<self::JSAny?> */ implements self::JSObject {
constructor • = self::JSArray|;
tearoff • = self::JSArray|get#;
}
inline class JSExportedDartObject /* declaredRepresentationType = core::Object */ implements self::JSObject {
constructor • = self::JSExportedDartObject|;
tearoff • = self::JSExportedDartObject|get#;
}
inline class JSNumber /* declaredRepresentationType = core::double */ implements self::JSAny {
constructor • = self::JSNumber|;
tearoff • = self::JSNumber|get#;
}
static method JSAny|(core::Object value) → self::JSAny {
final self::JSAny #this = value;
return #this;
}
static method JSAny|get#(core::Object value) → self::JSAny
return self::JSAny|(value);
static method JSObject|(core::Object value) → self::JSObject {
final self::JSObject #this = value;
return #this;
}
static method JSObject|get#(core::Object value) → self::JSObject
return self::JSObject|(value);
static method JSArray|(core::List<self::JSAny?> value) → self::JSArray {
final self::JSArray #this = value;
return #this;
}
static method JSArray|get#(core::List<self::JSAny?> value) → self::JSArray
return self::JSArray|(value);
static method JSExportedDartObject|(core::Object value) → self::JSExportedDartObject {
final self::JSExportedDartObject #this = value;
return #this;
}
static method JSExportedDartObject|get#(core::Object value) → self::JSExportedDartObject
return self::JSExportedDartObject|(value);
static method JSNumber|(core::double value) → self::JSNumber {
final self::JSNumber #this = value;
return #this;
}
static method JSNumber|get#(core::double value) → self::JSNumber
return self::JSNumber|(value);
static method ObjectToJSExportedDartObject|get#toJS(lowered final core::Object #this) → self::JSExportedDartObject
return self::JSExportedDartObject|(#this);
static method ListToJSArray|get#toJS(lowered final core::List<self::JSAny?> #this) → self::JSArray
return self::JSArray|(#this);
static method DoubleToJSNumber|get#toJS(lowered final core::double #this) → self::JSNumber
return self::JSNumber|(#this);
static method main() → void {
self::JSArray arr = self::ListToJSArray|get#toJS(<self::JSAny>[self::DoubleToJSNumber|get#toJS(1.0), self::ObjectToJSExportedDartObject|get#toJS("foo")]);
}

View file

@ -0,0 +1,72 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
extension ObjectToJSExportedDartObject on core::Object {
get toJS = self::ObjectToJSExportedDartObject|get#toJS;
}
extension ListToJSArray on core::List<self::JSAny?> {
get toJS = self::ListToJSArray|get#toJS;
}
extension DoubleToJSNumber on core::double {
get toJS = self::DoubleToJSNumber|get#toJS;
}
inline class JSAny /* declaredRepresentationType = core::Object */ {
constructor • = self::JSAny|;
tearoff • = self::JSAny|get#;
}
inline class JSObject /* declaredRepresentationType = core::Object */ implements self::JSAny {
constructor • = self::JSObject|;
tearoff • = self::JSObject|get#;
}
inline class JSArray /* declaredRepresentationType = core::List<self::JSAny?> */ implements self::JSObject {
constructor • = self::JSArray|;
tearoff • = self::JSArray|get#;
}
inline class JSExportedDartObject /* declaredRepresentationType = core::Object */ implements self::JSObject {
constructor • = self::JSExportedDartObject|;
tearoff • = self::JSExportedDartObject|get#;
}
inline class JSNumber /* declaredRepresentationType = core::double */ implements self::JSAny {
constructor • = self::JSNumber|;
tearoff • = self::JSNumber|get#;
}
static method JSAny|(core::Object value) → self::JSAny {
final self::JSAny #this = value;
return #this;
}
static method JSAny|get#(core::Object value) → self::JSAny
return self::JSAny|(value);
static method JSObject|(core::Object value) → self::JSObject {
final self::JSObject #this = value;
return #this;
}
static method JSObject|get#(core::Object value) → self::JSObject
return self::JSObject|(value);
static method JSArray|(core::List<self::JSAny?> value) → self::JSArray {
final self::JSArray #this = value;
return #this;
}
static method JSArray|get#(core::List<self::JSAny?> value) → self::JSArray
return self::JSArray|(value);
static method JSExportedDartObject|(core::Object value) → self::JSExportedDartObject {
final self::JSExportedDartObject #this = value;
return #this;
}
static method JSExportedDartObject|get#(core::Object value) → self::JSExportedDartObject
return self::JSExportedDartObject|(value);
static method JSNumber|(core::double value) → self::JSNumber {
final self::JSNumber #this = value;
return #this;
}
static method JSNumber|get#(core::double value) → self::JSNumber
return self::JSNumber|(value);
static method ObjectToJSExportedDartObject|get#toJS(lowered final core::Object #this) → self::JSExportedDartObject
return self::JSExportedDartObject|(#this);
static method ListToJSArray|get#toJS(lowered final core::List<self::JSAny?> #this) → self::JSArray
return self::JSArray|(#this);
static method DoubleToJSNumber|get#toJS(lowered final core::double #this) → self::JSNumber
return self::JSNumber|(#this);
static method main() → void {
self::JSArray arr = self::ListToJSArray|get#toJS(core::_GrowableList::_literal2<self::JSAny>(self::DoubleToJSNumber|get#toJS(1.0), self::ObjectToJSExportedDartObject|get#toJS("foo")));
}

View file

@ -0,0 +1,38 @@
inline class JSAny {
final Object value;
JSAny(this.value);
}
inline class JSObject implements JSAny {
final Object value;
JSObject(this.value);
}
inline class JSArray implements JSObject {
final List<JSAny?> value;
JSArray(this.value);
}
inline class JSExportedDartObject implements JSObject {
final Object value;
JSExportedDartObject(this.value);
}
inline class JSNumber implements JSAny {
final double value;
JSNumber(this.value);
}
extension ObjectToJSExportedDartObject on Object {
JSExportedDartObject get toJS => JSExportedDartObject(this);
}
extension ListToJSArray on List<JSAny?> {
JSArray get toJS => JSArray(this);
}
extension DoubleToJSNumber on double {
JSNumber get toJS => JSNumber(this);
}
void main() {}

View file

@ -0,0 +1,38 @@
extension DoubleToJSNumber on double {
JSNumber get toJS => JSNumber(this);
}
extension ListToJSArray on List<JSAny?> {
JSArray get toJS => JSArray(this);
}
extension ObjectToJSExportedDartObject on Object {
JSExportedDartObject get toJS => JSExportedDartObject(this);
}
inline class JSAny {
JSAny(this.value);
final Object value;
}
inline class JSArray implements JSObject {
JSArray(this.value);
final List<JSAny?> value;
}
inline class JSExportedDartObject implements JSObject {
JSExportedDartObject(this.value);
final Object value;
}
inline class JSNumber implements JSAny {
JSNumber(this.value);
final double value;
}
inline class JSObject implements JSAny {
JSObject(this.value);
final Object value;
}
void main() {}

View file

@ -0,0 +1,72 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
extension ObjectToJSExportedDartObject on core::Object {
get toJS = self::ObjectToJSExportedDartObject|get#toJS;
}
extension ListToJSArray on core::List<self::JSAny?> {
get toJS = self::ListToJSArray|get#toJS;
}
extension DoubleToJSNumber on core::double {
get toJS = self::DoubleToJSNumber|get#toJS;
}
inline class JSAny /* declaredRepresentationType = core::Object */ {
constructor • = self::JSAny|;
tearoff • = self::JSAny|get#;
}
inline class JSObject /* declaredRepresentationType = core::Object */ implements self::JSAny {
constructor • = self::JSObject|;
tearoff • = self::JSObject|get#;
}
inline class JSArray /* declaredRepresentationType = core::List<self::JSAny?> */ implements self::JSObject {
constructor • = self::JSArray|;
tearoff • = self::JSArray|get#;
}
inline class JSExportedDartObject /* declaredRepresentationType = core::Object */ implements self::JSObject {
constructor • = self::JSExportedDartObject|;
tearoff • = self::JSExportedDartObject|get#;
}
inline class JSNumber /* declaredRepresentationType = core::double */ implements self::JSAny {
constructor • = self::JSNumber|;
tearoff • = self::JSNumber|get#;
}
static method JSAny|(core::Object value) → self::JSAny {
final self::JSAny #this = value;
return #this;
}
static method JSAny|get#(core::Object value) → self::JSAny
return self::JSAny|(value);
static method JSObject|(core::Object value) → self::JSObject {
final self::JSObject #this = value;
return #this;
}
static method JSObject|get#(core::Object value) → self::JSObject
return self::JSObject|(value);
static method JSArray|(core::List<self::JSAny?> value) → self::JSArray {
final self::JSArray #this = value;
return #this;
}
static method JSArray|get#(core::List<self::JSAny?> value) → self::JSArray
return self::JSArray|(value);
static method JSExportedDartObject|(core::Object value) → self::JSExportedDartObject {
final self::JSExportedDartObject #this = value;
return #this;
}
static method JSExportedDartObject|get#(core::Object value) → self::JSExportedDartObject
return self::JSExportedDartObject|(value);
static method JSNumber|(core::double value) → self::JSNumber {
final self::JSNumber #this = value;
return #this;
}
static method JSNumber|get#(core::double value) → self::JSNumber
return self::JSNumber|(value);
static method ObjectToJSExportedDartObject|get#toJS(lowered final core::Object #this) → self::JSExportedDartObject
return self::JSExportedDartObject|(#this);
static method ListToJSArray|get#toJS(lowered final core::List<self::JSAny?> #this) → self::JSArray
return self::JSArray|(#this);
static method DoubleToJSNumber|get#toJS(lowered final core::double #this) → self::JSNumber
return self::JSNumber|(#this);
static method main() → void {
self::JSArray arr = self::ListToJSArray|get#toJS(<self::JSAny>[self::DoubleToJSNumber|get#toJS(1.0), self::ObjectToJSExportedDartObject|get#toJS("foo")]);
}

View file

@ -0,0 +1,72 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
extension ObjectToJSExportedDartObject on core::Object {
get toJS = self::ObjectToJSExportedDartObject|get#toJS;
}
extension ListToJSArray on core::List<self::JSAny?> {
get toJS = self::ListToJSArray|get#toJS;
}
extension DoubleToJSNumber on core::double {
get toJS = self::DoubleToJSNumber|get#toJS;
}
inline class JSAny /* declaredRepresentationType = core::Object */ {
constructor • = self::JSAny|;
tearoff • = self::JSAny|get#;
}
inline class JSObject /* declaredRepresentationType = core::Object */ implements self::JSAny {
constructor • = self::JSObject|;
tearoff • = self::JSObject|get#;
}
inline class JSArray /* declaredRepresentationType = core::List<self::JSAny?> */ implements self::JSObject {
constructor • = self::JSArray|;
tearoff • = self::JSArray|get#;
}
inline class JSExportedDartObject /* declaredRepresentationType = core::Object */ implements self::JSObject {
constructor • = self::JSExportedDartObject|;
tearoff • = self::JSExportedDartObject|get#;
}
inline class JSNumber /* declaredRepresentationType = core::double */ implements self::JSAny {
constructor • = self::JSNumber|;
tearoff • = self::JSNumber|get#;
}
static method JSAny|(core::Object value) → self::JSAny {
final self::JSAny #this = value;
return #this;
}
static method JSAny|get#(core::Object value) → self::JSAny
return self::JSAny|(value);
static method JSObject|(core::Object value) → self::JSObject {
final self::JSObject #this = value;
return #this;
}
static method JSObject|get#(core::Object value) → self::JSObject
return self::JSObject|(value);
static method JSArray|(core::List<self::JSAny?> value) → self::JSArray {
final self::JSArray #this = value;
return #this;
}
static method JSArray|get#(core::List<self::JSAny?> value) → self::JSArray
return self::JSArray|(value);
static method JSExportedDartObject|(core::Object value) → self::JSExportedDartObject {
final self::JSExportedDartObject #this = value;
return #this;
}
static method JSExportedDartObject|get#(core::Object value) → self::JSExportedDartObject
return self::JSExportedDartObject|(value);
static method JSNumber|(core::double value) → self::JSNumber {
final self::JSNumber #this = value;
return #this;
}
static method JSNumber|get#(core::double value) → self::JSNumber
return self::JSNumber|(value);
static method ObjectToJSExportedDartObject|get#toJS(lowered final core::Object #this) → self::JSExportedDartObject
return self::JSExportedDartObject|(#this);
static method ListToJSArray|get#toJS(lowered final core::List<self::JSAny?> #this) → self::JSArray
return self::JSArray|(#this);
static method DoubleToJSNumber|get#toJS(lowered final core::double #this) → self::JSNumber
return self::JSNumber|(#this);
static method main() → void {
self::JSArray arr = self::ListToJSArray|get#toJS(<self::JSAny>[self::DoubleToJSNumber|get#toJS(1.0), self::ObjectToJSExportedDartObject|get#toJS("foo")]);
}

View file

@ -0,0 +1,61 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
extension ObjectToJSExportedDartObject on core::Object {
get toJS = self::ObjectToJSExportedDartObject|get#toJS;
}
extension ListToJSArray on core::List<self::JSAny?> {
get toJS = self::ListToJSArray|get#toJS;
}
extension DoubleToJSNumber on core::double {
get toJS = self::DoubleToJSNumber|get#toJS;
}
inline class JSAny /* declaredRepresentationType = core::Object */ {
constructor • = self::JSAny|;
tearoff • = self::JSAny|get#;
}
inline class JSObject /* declaredRepresentationType = core::Object */ implements self::JSAny {
constructor • = self::JSObject|;
tearoff • = self::JSObject|get#;
}
inline class JSArray /* declaredRepresentationType = core::List<self::JSAny?> */ implements self::JSObject {
constructor • = self::JSArray|;
tearoff • = self::JSArray|get#;
}
inline class JSExportedDartObject /* declaredRepresentationType = core::Object */ implements self::JSObject {
constructor • = self::JSExportedDartObject|;
tearoff • = self::JSExportedDartObject|get#;
}
inline class JSNumber /* declaredRepresentationType = core::double */ implements self::JSAny {
constructor • = self::JSNumber|;
tearoff • = self::JSNumber|get#;
}
static method JSAny|(core::Object value) → self::JSAny
;
static method JSAny|get#(core::Object value) → self::JSAny
return self::JSAny|(value);
static method JSObject|(core::Object value) → self::JSObject
;
static method JSObject|get#(core::Object value) → self::JSObject
return self::JSObject|(value);
static method JSArray|(core::List<self::JSAny?> value) → self::JSArray
;
static method JSArray|get#(core::List<self::JSAny?> value) → self::JSArray
return self::JSArray|(value);
static method JSExportedDartObject|(core::Object value) → self::JSExportedDartObject
;
static method JSExportedDartObject|get#(core::Object value) → self::JSExportedDartObject
return self::JSExportedDartObject|(value);
static method JSNumber|(core::double value) → self::JSNumber
;
static method JSNumber|get#(core::double value) → self::JSNumber
return self::JSNumber|(value);
static method ObjectToJSExportedDartObject|get#toJS(lowered final core::Object #this) → self::JSExportedDartObject
;
static method ListToJSArray|get#toJS(lowered final core::List<self::JSAny?> #this) → self::JSArray
;
static method DoubleToJSNumber|get#toJS(lowered final core::double #this) → self::JSNumber
;
static method main() → void
;

View file

@ -0,0 +1,72 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
extension ObjectToJSExportedDartObject on core::Object {
get toJS = self::ObjectToJSExportedDartObject|get#toJS;
}
extension ListToJSArray on core::List<self::JSAny?> {
get toJS = self::ListToJSArray|get#toJS;
}
extension DoubleToJSNumber on core::double {
get toJS = self::DoubleToJSNumber|get#toJS;
}
inline class JSAny /* declaredRepresentationType = core::Object */ {
constructor • = self::JSAny|;
tearoff • = self::JSAny|get#;
}
inline class JSObject /* declaredRepresentationType = core::Object */ implements self::JSAny {
constructor • = self::JSObject|;
tearoff • = self::JSObject|get#;
}
inline class JSArray /* declaredRepresentationType = core::List<self::JSAny?> */ implements self::JSObject {
constructor • = self::JSArray|;
tearoff • = self::JSArray|get#;
}
inline class JSExportedDartObject /* declaredRepresentationType = core::Object */ implements self::JSObject {
constructor • = self::JSExportedDartObject|;
tearoff • = self::JSExportedDartObject|get#;
}
inline class JSNumber /* declaredRepresentationType = core::double */ implements self::JSAny {
constructor • = self::JSNumber|;
tearoff • = self::JSNumber|get#;
}
static method JSAny|(core::Object value) → self::JSAny {
final self::JSAny #this = value;
return #this;
}
static method JSAny|get#(core::Object value) → self::JSAny
return self::JSAny|(value);
static method JSObject|(core::Object value) → self::JSObject {
final self::JSObject #this = value;
return #this;
}
static method JSObject|get#(core::Object value) → self::JSObject
return self::JSObject|(value);
static method JSArray|(core::List<self::JSAny?> value) → self::JSArray {
final self::JSArray #this = value;
return #this;
}
static method JSArray|get#(core::List<self::JSAny?> value) → self::JSArray
return self::JSArray|(value);
static method JSExportedDartObject|(core::Object value) → self::JSExportedDartObject {
final self::JSExportedDartObject #this = value;
return #this;
}
static method JSExportedDartObject|get#(core::Object value) → self::JSExportedDartObject
return self::JSExportedDartObject|(value);
static method JSNumber|(core::double value) → self::JSNumber {
final self::JSNumber #this = value;
return #this;
}
static method JSNumber|get#(core::double value) → self::JSNumber
return self::JSNumber|(value);
static method ObjectToJSExportedDartObject|get#toJS(lowered final core::Object #this) → self::JSExportedDartObject
return self::JSExportedDartObject|(#this);
static method ListToJSArray|get#toJS(lowered final core::List<self::JSAny?> #this) → self::JSArray
return self::JSArray|(#this);
static method DoubleToJSNumber|get#toJS(lowered final core::double #this) → self::JSNumber
return self::JSNumber|(#this);
static method main() → void {
self::JSArray arr = self::ListToJSArray|get#toJS(core::_GrowableList::_literal2<self::JSAny>(self::DoubleToJSNumber|get#toJS(1.0), self::ObjectToJSExportedDartObject|get#toJS("foo")));
}

View file

@ -865,22 +865,22 @@ mixin StandardBounds {
}
// UP(T1, T2) = T2 if T1 <: T2
// Note that both types must be class types at this point.
assert(type1 is InterfaceType,
// Note that both types must be interface or inline types at this point.
assert(type1 is InterfaceType || type1 is InlineType,
"Expected type1 to be an interface type, got '${type1.runtimeType}'.");
assert(type2 is InterfaceType,
assert(type2 is InterfaceType || type2 is InlineType,
"Expected type2 to be an interface type, got '${type2.runtimeType}'.");
// We use the non-nullable variants of the two interfaces types to determine
// T1 <: T2 without using the nullability of the outermost type. The result
// uses [uniteNullabilities] to compute the resulting type if the subtype
// relation is established.
InterfaceType typeWithoutNullabilityMarker1 =
DartType typeWithoutNullabilityMarker1 =
computeTypeWithoutNullabilityMarker(type1,
isNonNullableByDefault: isNonNullableByDefault) as InterfaceType;
InterfaceType typeWithoutNullabilityMarker2 =
isNonNullableByDefault: isNonNullableByDefault);
DartType typeWithoutNullabilityMarker2 =
computeTypeWithoutNullabilityMarker(type2,
isNonNullableByDefault: isNonNullableByDefault) as InterfaceType;
isNonNullableByDefault: isNonNullableByDefault);
if (isSubtypeOf(typeWithoutNullabilityMarker1,
typeWithoutNullabilityMarker2, SubtypeCheckMode.withNullabilities)) {
@ -889,7 +889,7 @@ mixin StandardBounds {
}
// UP(T1, T2) = T1 if T2 <: T1
// Note that both types must be class types at this point.
// Note that both types must be interface or inline types at this point.
if (isSubtypeOf(typeWithoutNullabilityMarker2,
typeWithoutNullabilityMarker1, SubtypeCheckMode.withNullabilities)) {
return type1.withDeclaredNullability(uniteNullabilities(
@ -897,33 +897,59 @@ mixin StandardBounds {
}
// UP(C<T0, ..., Tn>, C<S0, ..., Sn>) = C<R0,..., Rn> where Ri is UP(Ti, Si)
Class? cls;
InlineClass? inlineClass;
List<TypeParameter>? typeParameters;
List<DartType>? leftArguments;
List<DartType>? rightArguments;
if (type1 is InterfaceType && type2 is InterfaceType) {
Class klass = type1.classNode;
if (type2.classNode == klass) {
int n = klass.typeParameters.length;
List<DartType> leftArguments = type1.typeArguments;
List<DartType> rightArguments = type2.typeArguments;
List<DartType> typeArguments = new List<DartType>.of(leftArguments);
for (int i = 0; i < n; ++i) {
int variance = klass.typeParameters[i].variance;
if (variance == Variance.contravariant) {
typeArguments[i] = _getNullabilityAwareStandardLowerBound(
leftArguments[i], rightArguments[i],
isNonNullableByDefault: isNonNullableByDefault);
} else if (variance == Variance.invariant) {
if (!areMutualSubtypes(leftArguments[i], rightArguments[i],
SubtypeCheckMode.withNullabilities)) {
return hierarchy.getLegacyLeastUpperBound(type1, type2,
isNonNullableByDefault: isNonNullableByDefault);
}
} else {
typeArguments[i] = _getNullabilityAwareStandardUpperBound(
leftArguments[i], rightArguments[i],
if (type1.classNode == type2.classNode) {
cls = type1.classNode;
typeParameters = cls.typeParameters;
leftArguments = type1.typeArguments;
rightArguments = type2.typeArguments;
}
}
if (type1 is InlineType && type2 is InlineType) {
if (type1.inlineClass == type2.inlineClass) {
inlineClass = type1.inlineClass;
leftArguments = type1.typeArguments;
rightArguments = type2.typeArguments;
}
}
if (typeParameters != null &&
leftArguments != null &&
rightArguments != null) {
int n = typeParameters.length;
List<DartType> typeArguments = new List<DartType>.of(leftArguments);
for (int i = 0; i < n; ++i) {
int variance = typeParameters[i].variance;
if (variance == Variance.contravariant) {
typeArguments[i] = _getNullabilityAwareStandardLowerBound(
leftArguments[i], rightArguments[i],
isNonNullableByDefault: isNonNullableByDefault);
} else if (variance == Variance.invariant) {
if (!areMutualSubtypes(leftArguments[i], rightArguments[i],
SubtypeCheckMode.withNullabilities)) {
return _getLegacyLeastUpperBound(type1, type2,
isNonNullableByDefault: isNonNullableByDefault);
}
} else {
typeArguments[i] = _getNullabilityAwareStandardUpperBound(
leftArguments[i], rightArguments[i],
isNonNullableByDefault: isNonNullableByDefault);
}
}
if (cls != null) {
return new InterfaceType(
klass,
cls,
uniteNullabilities(
type1.declaredNullability, type2.declaredNullability),
typeArguments);
} else {
return new InlineType(
inlineClass!,
uniteNullabilities(
type1.declaredNullability, type2.declaredNullability),
typeArguments);
@ -932,11 +958,79 @@ mixin StandardBounds {
// UP(C0<T0, ..., Tn>, C1<S0, ..., Sk>)
// = least upper bound of two interfaces as in Dart 1.
return hierarchy.getLegacyLeastUpperBound(
type1 as InterfaceType, type2 as InterfaceType,
return _getLegacyLeastUpperBound(type1, type2,
isNonNullableByDefault: isNonNullableByDefault);
}
DartType _getLegacyLeastUpperBound(DartType type1, DartType type2,
{required bool isNonNullableByDefault}) {
if (type1 is InterfaceType && type2 is InterfaceType) {
return hierarchy.getLegacyLeastUpperBound(type1, type2,
isNonNullableByDefault: isNonNullableByDefault);
} else if (type1 is InlineType && type2 is InlineType) {
// This mimics the legacy least upper bound implementation for regular
// classes, where the least upper bound is found as the single common
// supertype with the highest class hierarchy depth.
// TODO(johnniwinther): Move this computation to [ClassHierarchyBase] and
// cache it there.
Map<InlineClass, int> inlineClassDepth = {};
int computeInlineClassDepth(InlineClass inlineClass) {
int? depth = inlineClassDepth[inlineClass];
if (depth == null) {
int maxDepth = 0;
for (InlineType implemented in inlineClass.implements) {
int supertypeDepth =
computeInlineClassDepth(implemented.inlineClass);
if (supertypeDepth >= maxDepth) {
maxDepth = supertypeDepth + 1;
}
}
depth = inlineClassDepth[inlineClass] = maxDepth;
}
return depth;
}
void computeSuperTypes(InlineType type, List<InlineType> supertypes) {
computeInlineClassDepth(type.inlineClass);
supertypes.add(type);
for (InlineType implemented in type.inlineClass.implements) {
InlineType supertype = hierarchy.getInlineTypeAsInstanceOf(
type, implemented.inlineClass,
isNonNullableByDefault: isNonNullableByDefault)!;
computeSuperTypes(supertype, supertypes);
}
}
List<InlineType> supertypes1 = [];
computeSuperTypes(type1, supertypes1);
List<InlineType> supertypes2 = [];
computeSuperTypes(type2, supertypes2);
Set<InlineType> set = supertypes1.toSet()..retainAll(supertypes2);
Map<int, List<InlineType>> commonSupertypesByDepth = {};
for (InlineType type in set) {
(commonSupertypesByDepth[inlineClassDepth[type.inlineClass]!] ??= [])
.add(type);
}
int maxDepth = -1;
InlineType? candidate;
for (MapEntry<int, List<InlineType>> entry
in commonSupertypesByDepth.entries) {
if (entry.key > maxDepth && entry.value.length == 1) {
maxDepth = entry.key;
candidate = entry.value.single;
}
}
if (candidate != null) {
return candidate;
}
}
return coreTypes.objectRawType(
uniteNullabilities(type1.nullability, type2.nullability));
}
/// Computes the nullability-aware lower bound of two function types.
///
/// The algorithm is defined as follows: