[cfe] Add TypeDeclarationType and asInstanceOf

This add a common sealed superclass TypeDeclarationType for
ExtensionType and InterfaceType and uses it to add a common
asInstanceOf method to ClassHierarchy.

Change-Id: I7294e41069b063305c3bd4e384ff90614a3936a6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/331981
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
This commit is contained in:
Johnni Winther 2023-10-26 08:46:48 +00:00 committed by Commit Queue
parent 3a41ee6d8d
commit 4b2cf0744d
21 changed files with 309 additions and 245 deletions

View file

@ -165,7 +165,7 @@ class Types {
for (InterfaceType subtype in subtypes) {
interfaceTypeEnvironment._add(subtype);
List<DartType>? typeArguments = translator.hierarchy
.getTypeArgumentsAsInstanceOf(subtype, superclass)
.getInterfaceTypeArgumentsAsInstanceOfClass(subtype, superclass)
?.map(normalize)
.toList();
ClassInfo subclassInfo = translator.classInfo[subtype.classNode]!;
@ -668,7 +668,7 @@ class Types {
// arguments.
Class cls = translator.classForType(operandType);
InterfaceType? base = translator.hierarchy
.getTypeAsInstanceOf(type, cls,
.getInterfaceTypeAsInstanceOfClass(type, cls,
isNonNullableByDefault:
codeGen.member.enclosingLibrary.isNonNullableByDefault)
?.withDeclaredNullability(operandType.declaredNullability);

View file

@ -4205,7 +4205,7 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
.returnType;
if (type is InterfaceType) {
var matchArguments =
_hierarchy.getTypeArgumentsAsInstanceOf(type, expected);
_hierarchy.getInterfaceTypeArgumentsAsInstanceOfClass(type, expected);
if (matchArguments != null) return matchArguments[0];
}
return const DynamicType();

View file

@ -270,8 +270,8 @@ abstract class CombinedMemberSignatureBase {
return _containsNnbdTypes;
}
/// Returns the [declarationBuilder] as an instance of [cls].
InterfaceType _asInstanceOfClass(Class cls);
/// Returns the this type of the [declarationBuilder].
TypeDeclarationType get thisType;
/// Returns `true` if the canonical member is declared in
/// [declarationBuilder].
@ -726,11 +726,14 @@ abstract class CombinedMemberSignatureBase {
unhandled("${member.runtimeType}", "$member",
declarationBuilder.charOffset, declarationBuilder.fileUri);
}
if (member.enclosingClass!.typeParameters.isEmpty) {
if (member.enclosingTypeDeclaration!.typeParameters.isEmpty) {
return type;
}
InterfaceType instance = _asInstanceOfClass(member.enclosingClass!);
return Substitution.fromInterfaceType(instance).substituteType(type);
TypeDeclarationType instance = hierarchy.getTypeAsInstanceOf(
thisType, member.enclosingTypeDeclaration!,
isNonNullableByDefault:
declarationBuilder.libraryBuilder.isNonNullableByDefault)!;
return Substitution.fromTypeDeclarationType(instance).substituteType(type);
}
bool _isMoreSpecific(DartType a, DartType b, bool forSetter) {
@ -771,18 +774,12 @@ class CombinedClassMemberSignature extends CombinedMemberSignatureBase {
DeclarationBuilder get declarationBuilder => classBuilder;
/// The this type of [classBuilder].
@override
InterfaceType get thisType {
return _thisType ??= _coreTypes.thisInterfaceType(
classBuilder.cls, declarationBuilder.libraryBuilder.nonNullable);
}
@override
InterfaceType _asInstanceOfClass(Class cls) {
return hierarchy.getTypeAsInstanceOf(thisType, cls,
isNonNullableByDefault:
declarationBuilder.libraryBuilder.isNonNullableByDefault);
}
/// Returns `true` if the canonical member is declared in
/// [declarationBuilder].
@override
@ -824,19 +821,13 @@ class CombinedExtensionTypeMemberSignature extends CombinedMemberSignatureBase {
DeclarationBuilder get declarationBuilder => extensionTypeDeclarationBuilder;
/// The this type of [extensionTypeDeclarationBuilder].
@override
ExtensionType get thisType {
return _thisType ??= _coreTypes.thisExtensionType(
extensionTypeDeclarationBuilder.extensionTypeDeclaration,
declarationBuilder.libraryBuilder.nonNullable);
}
@override
InterfaceType _asInstanceOfClass(Class cls) {
return hierarchy.getExtensionTypeAsInstanceOfClass(thisType, cls,
isNonNullableByDefault:
declarationBuilder.libraryBuilder.isNonNullableByDefault)!;
}
@override
bool get isCanonicalMemberDeclared => false;
}

View file

@ -136,8 +136,8 @@ class CfeTypeOperations implements TypeOperations<DartType> {
Class declaringClass = member.enclosingClass!;
if (declaringClass.typeParameters.isNotEmpty) {
Substitution substitution = substitutions[declaringClass] ??=
Substitution.fromInterfaceType(
_classHierarchy.getTypeAsInstanceOf(type, declaringClass,
Substitution.fromInterfaceType(_classHierarchy
.getInterfaceTypeAsInstanceOfClass(type, declaringClass,
isNonNullableByDefault: true)!);
fieldType = substitution.substituteType(fieldType);
}
@ -188,9 +188,10 @@ class CfeTypeOperations implements TypeOperations<DartType> {
DartType? getListElementType(DartType type) {
type = type.resolveTypeParameterType;
if (type is InterfaceType) {
InterfaceType? listType = _classHierarchy.getTypeAsInstanceOf(
type, _typeEnvironment.coreTypes.listClass,
isNonNullableByDefault: true);
InterfaceType? listType =
_classHierarchy.getInterfaceTypeAsInstanceOfClass(
type, _typeEnvironment.coreTypes.listClass,
isNonNullableByDefault: true);
if (listType != null) {
return listType.typeArguments[0];
}
@ -202,7 +203,7 @@ class CfeTypeOperations implements TypeOperations<DartType> {
DartType? getListType(DartType type) {
type = type.resolveTypeParameterType;
if (type is InterfaceType) {
return _classHierarchy.getTypeAsInstanceOf(
return _classHierarchy.getInterfaceTypeAsInstanceOfClass(
type, _typeEnvironment.coreTypes.listClass,
isNonNullableByDefault: true);
}
@ -213,9 +214,10 @@ class CfeTypeOperations implements TypeOperations<DartType> {
DartType? getMapValueType(DartType type) {
type = type.resolveTypeParameterType;
if (type is InterfaceType) {
InterfaceType? mapType = _classHierarchy.getTypeAsInstanceOf(
type, _typeEnvironment.coreTypes.mapClass,
isNonNullableByDefault: true);
InterfaceType? mapType =
_classHierarchy.getInterfaceTypeAsInstanceOfClass(
type, _typeEnvironment.coreTypes.mapClass,
isNonNullableByDefault: true);
if (mapType != null) {
return mapType.typeArguments[1];
}
@ -394,9 +396,9 @@ class CfeSealedClassOperations
Class subClass, covariant InterfaceType sealedClassType) {
InterfaceType thisType = subClass.getThisType(
_typeEnvironment.coreTypes, Nullability.nonNullable);
InterfaceType asSealedType = _typeEnvironment.hierarchy.getTypeAsInstanceOf(
thisType, sealedClassType.classNode,
isNonNullableByDefault: true)!;
InterfaceType asSealedType = _typeEnvironment.hierarchy
.getInterfaceTypeAsInstanceOfClass(thisType, sealedClassType.classNode,
isNonNullableByDefault: true)!;
if (thisType.typeArguments.isEmpty) {
return thisType;
}

View file

@ -112,7 +112,8 @@ class ClassHierarchyBuilder
}
@override
InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass,
InterfaceType getInterfaceTypeAsInstanceOfClass(
InterfaceType type, Class superclass,
{required bool isNonNullableByDefault}) {
if (type.classNode == superclass) return type;
return asSupertypeOf(type, superclass)!
@ -121,7 +122,7 @@ class ClassHierarchyBuilder
}
@override
List<DartType>? getTypeArgumentsAsInstanceOf(
List<DartType>? getInterfaceTypeArgumentsAsInstanceOfClass(
InterfaceType type, Class superclass) {
if (type.classReference == superclass.reference) return type.typeArguments;
return asSupertypeOf(type, superclass)?.typeArguments;
@ -133,14 +134,11 @@ class ClassHierarchyBuilder
}
InterfaceType _getLegacyLeastUpperBoundInternal(
/* InterfaceType | ExtensionType */ DartType type1,
/* InterfaceType | ExtensionType */ DartType type2,
TypeDeclarationType type1,
TypeDeclarationType type2,
List<ClassHierarchyNode> supertypeNodes1,
List<ClassHierarchyNode> supertypeNodes2,
{required bool isNonNullableByDefault}) {
assert(type1 is InterfaceType || type1 is ExtensionType);
assert(type2 is InterfaceType || type2 is ExtensionType);
Set<ClassHierarchyNode> supertypeNodesSet1 = supertypeNodes1.toSet();
List<ClassHierarchyNode> common = <ClassHierarchyNode>[];
@ -151,27 +149,10 @@ class ClassHierarchyBuilder
continue;
}
if (supertypeNodesSet1.contains(node)) {
DartType candidate1;
if (type1 is InterfaceType) {
candidate1 = getTypeAsInstanceOf(type1, node.classBuilder.cls,
isNonNullableByDefault: isNonNullableByDefault);
} else {
type1 as ExtensionType;
candidate1 = getExtensionTypeAsInstanceOfClass(
type1, node.classBuilder.cls,
isNonNullableByDefault: isNonNullableByDefault)!;
}
DartType candidate2;
if (type2 is InterfaceType) {
candidate2 = getTypeAsInstanceOf(type2, node.classBuilder.cls,
isNonNullableByDefault: isNonNullableByDefault);
} else {
type2 as ExtensionType;
candidate2 = getExtensionTypeAsInstanceOfClass(
type2, node.classBuilder.cls,
isNonNullableByDefault: isNonNullableByDefault)!;
}
DartType candidate1 = getTypeAsInstanceOf(type1, node.classBuilder.cls,
isNonNullableByDefault: isNonNullableByDefault)!;
DartType candidate2 = getTypeAsInstanceOf(type2, node.classBuilder.cls,
isNonNullableByDefault: isNonNullableByDefault)!;
if (candidate1 == candidate2) {
common.add(node);
}
@ -194,7 +175,7 @@ class ClassHierarchyBuilder
ClassHierarchyNode node = common[i];
if (node.maxInheritancePath != common[i + 1].maxInheritancePath) {
if (type1 is InterfaceType) {
return getTypeAsInstanceOf(type1, node.classBuilder.cls,
return getInterfaceTypeAsInstanceOfClass(type1, node.classBuilder.cls,
isNonNullableByDefault: isNonNullableByDefault)
.withDeclaredNullability(
uniteNullabilities(type1.nullability, type2.nullability));
@ -246,8 +227,8 @@ class ClassHierarchyBuilder
@override
InterfaceType getLegacyLeastUpperBoundFromSupertypeLists(
/* InterfaceType | ExtensionType */ DartType type1,
/* InterfaceType | ExtensionType */ DartType type2,
TypeDeclarationType type1,
TypeDeclarationType type2,
List<InterfaceType> supertypes1,
List<InterfaceType> supertypes2,
{required bool isNonNullableByDefault}) {

View file

@ -82,14 +82,15 @@ class TypeBuilderConstraintGatherer extends TypeConstraintGatherer
InterfaceType getTypeAsInstanceOf(
InterfaceType type, Class superclass, CoreTypes coreTypes,
{required bool isNonNullableByDefault}) {
return hierarchy.getTypeAsInstanceOf(type, superclass,
return hierarchy.getInterfaceTypeAsInstanceOfClass(type, superclass,
isNonNullableByDefault: isNonNullableByDefault);
}
@override
List<DartType>? getTypeArgumentsAsInstanceOf(
InterfaceType type, Class superclass) {
return hierarchy.getTypeArgumentsAsInstanceOf(type, superclass);
return hierarchy.getInterfaceTypeArgumentsAsInstanceOfClass(
type, superclass);
}
@override

View file

@ -903,9 +903,10 @@ class SourceClassBuilder extends ClassBuilderImpl
for (Supertype constraint in cls.mixedInClass!.onClause) {
InterfaceType requiredInterface =
substitution.substituteSupertype(constraint).asInterfaceType;
InterfaceType? implementedInterface = hierarchy.getTypeAsInstanceOf(
supertype, requiredInterface.classNode,
isNonNullableByDefault: libraryBuilder.isNonNullableByDefault);
InterfaceType? implementedInterface =
hierarchy.getInterfaceTypeAsInstanceOfClass(
supertype, requiredInterface.classNode,
isNonNullableByDefault: libraryBuilder.isNonNullableByDefault);
if (implementedInterface == null ||
!typeEnvironment.areMutualSubtypes(
implementedInterface,
@ -1374,7 +1375,7 @@ class SourceClassBuilder extends ClassBuilderImpl
if (getter.enclosingClass!.typeParameters.isNotEmpty) {
getterType = Substitution.fromPairs(
getter.enclosingClass!.typeParameters,
types.hierarchy.getTypeArgumentsAsInstanceOf(
types.hierarchy.getInterfaceTypeArgumentsAsInstanceOfClass(
thisType, getter.enclosingClass!)!)
.substituteType(getterType);
}
@ -1383,7 +1384,7 @@ class SourceClassBuilder extends ClassBuilderImpl
if (setter.enclosingClass!.typeParameters.isNotEmpty) {
setterType = Substitution.fromPairs(
setter.enclosingClass!.typeParameters,
types.hierarchy.getTypeArgumentsAsInstanceOf(
types.hierarchy.getInterfaceTypeArgumentsAsInstanceOfClass(
thisType, setter.enclosingClass!)!)
.substituteType(setterType);
}
@ -1531,8 +1532,8 @@ class SourceClassBuilder extends ClassBuilderImpl
Class enclosingClass = interfaceMember.enclosingClass!;
interfaceSubstitution = Substitution.fromPairs(
enclosingClass.typeParameters,
types.hierarchy
.getTypeArgumentsAsInstanceOf(thisType, enclosingClass)!);
types.hierarchy.getInterfaceTypeArgumentsAsInstanceOfClass(
thisType, enclosingClass)!);
}
if (declaredFunction?.typeParameters.length !=
@ -1643,8 +1644,8 @@ class SourceClassBuilder extends ClassBuilderImpl
Class enclosingClass = declaredMember.enclosingClass!;
declaredSubstitution = Substitution.fromPairs(
enclosingClass.typeParameters,
types.hierarchy
.getTypeArgumentsAsInstanceOf(thisType, enclosingClass)!);
types.hierarchy.getInterfaceTypeArgumentsAsInstanceOfClass(
thisType, enclosingClass)!);
}
return declaredSubstitution;
}

View file

@ -1518,8 +1518,9 @@ class InferenceVisitorImpl extends InferenceVisitorBase
if (inferredExpressionType is InterfaceType) {
// TODO(johnniwinther): Should we use the type of
// `iterable.iterator.current` instead?
List<DartType>? supertypeArguments = hierarchyBuilder
.getTypeArgumentsAsInstanceOf(inferredExpressionType, iterableClass);
List<DartType>? supertypeArguments =
hierarchyBuilder.getInterfaceTypeArgumentsAsInstanceOfClass(
inferredExpressionType, iterableClass);
if (supertypeArguments != null) {
inferredType = supertypeArguments[0];
}

View file

@ -1450,8 +1450,9 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
if (enclosingClass.typeParameters.isNotEmpty) {
receiverType = resolveTypeParameter(receiverType);
if (receiverType is InterfaceType) {
List<DartType> castedTypeArguments = hierarchyBuilder
.getTypeArgumentsAsInstanceOf(receiverType, enclosingClass)!;
List<DartType> castedTypeArguments =
hierarchyBuilder.getInterfaceTypeArgumentsAsInstanceOfClass(
receiverType, enclosingClass)!;
calleeType = Substitution.fromPairs(
enclosingClass.typeParameters, castedTypeArguments)
.substituteType(calleeType);
@ -1492,8 +1493,8 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
DartType? getDerivedTypeArgumentOf(DartType type, Class class_) {
if (type is InterfaceType) {
List<DartType>? typeArgumentsAsInstanceOfClass =
hierarchyBuilder.getTypeArgumentsAsInstanceOf(type, class_);
List<DartType>? typeArgumentsAsInstanceOfClass = hierarchyBuilder
.getInterfaceTypeArgumentsAsInstanceOfClass(type, class_);
if (typeArgumentsAsInstanceOfClass != null) {
return typeArgumentsAsInstanceOfClass[0];
}

View file

@ -123,7 +123,7 @@ class InheritanceDataExtractor extends CfeDataExtractor<String> {
if (member.enclosingClass == _coreTypes.objectClass) {
return;
}
InterfaceType supertype = _hierarchy.getTypeAsInstanceOf(
InterfaceType supertype = _hierarchy.getInterfaceTypeAsInstanceOfClass(
_coreTypes.thisInterfaceType(node, node.enclosingLibrary.nonNullable),
member.enclosingClass!,
isNonNullableByDefault:

View file

@ -11097,6 +11097,20 @@ sealed class DartType extends Node {
void toTextInternal(AstPrinter printer);
}
/// A type which is an instantiation of a [TypeDeclaration].
sealed class TypeDeclarationType extends DartType {
/// The [Reference] to the [TypeDeclaration] on which this
/// [TypeDeclarationType] is built.
Reference get typeDeclarationReference;
/// The type arguments used to instantiate this [TypeDeclarationType].
List<DartType> get typeArguments;
/// The [TypeDeclaration] on which this [TypeDeclarationType] is built.
TypeDeclaration get typeDeclaration =>
typeDeclarationReference.asTypeDeclaration;
}
abstract class AuxiliaryType extends DartType {
const AuxiliaryType();
@ -11360,12 +11374,13 @@ class NullType extends DartType {
}
}
class InterfaceType extends DartType {
class InterfaceType extends TypeDeclarationType {
final Reference classReference;
@override
final Nullability declaredNullability;
@override
final List<DartType> typeArguments;
/// The [typeArguments] list must not be modified after this call. If the
@ -11378,6 +11393,9 @@ class InterfaceType extends DartType {
InterfaceType.byReference(
this.classReference, this.declaredNullability, this.typeArguments);
@override
Reference get typeDeclarationReference => classReference;
Class get classNode => classReference.asClass;
@override
@ -11841,12 +11859,13 @@ class FutureOrType extends DartType {
}
}
class ExtensionType extends DartType {
class ExtensionType extends TypeDeclarationType {
final Reference extensionTypeDeclarationReference;
@override
final Nullability declaredNullability;
@override
final List<DartType> typeArguments;
ExtensionType(ExtensionTypeDeclaration extensionTypeDeclaration,
@ -11862,6 +11881,9 @@ class ExtensionType extends DartType {
ExtensionTypeDeclaration get extensionTypeDeclaration =>
extensionTypeDeclarationReference.asExtensionTypeDeclaration;
@override
Reference get typeDeclarationReference => extensionTypeDeclarationReference;
/// Returns the type erasure of this extension type.
///
/// This is the type used at runtime for this type, for instance in is-tests

View file

@ -508,6 +508,15 @@ class Reference implements Comparable<Reference> {
return node as Library;
}
TypeDeclaration get asTypeDeclaration {
NamedNode? node = this.node;
if (node == null) {
throw '$this is not bound to an AST node. '
'A type declaration was expected';
}
return node as TypeDeclaration;
}
Class get asClass {
NamedNode? node = this.node;
if (node == null) {

View file

@ -31,15 +31,28 @@ abstract class ClassHierarchyBase {
/// or `null` if [class_] does not implement [superclass] at all.
Supertype? getClassAsInstanceOf(Class class_, Class superclass);
/// Returns the instantiation of [typeDeclaration] that is implemented by
/// [type], or `null` if [type] does not implement [typeDeclaration] at all.
TypeDeclarationType? getTypeAsInstanceOf(
TypeDeclarationType type, TypeDeclaration typeDeclaration,
{required bool isNonNullableByDefault});
/// Returns the type arguments of the instantiation of [typeDeclaration] that
/// is implemented by [type], or `null` if [type] does not implement
/// [typeDeclaration] at all.
List<DartType>? getTypeArgumentsAsInstanceOf(
TypeDeclarationType type, TypeDeclaration typeDeclaration);
/// Returns the instantiation of [superclass] that is implemented by [type],
/// or `null` if [type] does not implement [superclass] at all.
InterfaceType? getTypeAsInstanceOf(InterfaceType type, Class superclass,
InterfaceType? getInterfaceTypeAsInstanceOfClass(
InterfaceType type, Class superclass,
{required bool isNonNullableByDefault});
/// Returns the type arguments of the instantiation of [superclass] that is
/// implemented by [type], or `null` if [type] does not implement [superclass]
/// at all.
List<DartType>? getTypeArgumentsAsInstanceOf(
List<DartType>? getInterfaceTypeArgumentsAsInstanceOfClass(
InterfaceType type, Class superclass);
/// Returns the instantiation of [superDeclaration] that is implemented by
@ -101,14 +114,65 @@ abstract class ClassHierarchyBase {
/// its non-extension supertypes. It is used as a part of the algorithm for
/// finding the upper bound of extension types.
InterfaceType getLegacyLeastUpperBoundFromSupertypeLists(
/* InterfaceType | ExtensionType */ DartType type1,
/* InterfaceType | ExtensionType */ DartType type2,
TypeDeclarationType type1,
TypeDeclarationType type2,
List<InterfaceType> supertypes1,
List<InterfaceType> supertypes2,
{required bool isNonNullableByDefault});
}
mixin ClassHierarchyExtensionTypeMixin implements ClassHierarchyBase {
@override
TypeDeclarationType? getTypeAsInstanceOf(
TypeDeclarationType type, TypeDeclaration typeDeclaration,
{required bool isNonNullableByDefault}) {
switch (type) {
case InterfaceType():
switch (typeDeclaration) {
case Class():
return getInterfaceTypeAsInstanceOfClass(type, typeDeclaration,
isNonNullableByDefault: isNonNullableByDefault);
case ExtensionTypeDeclaration():
return null;
}
case ExtensionType():
switch (typeDeclaration) {
case Class():
return getExtensionTypeAsInstanceOfClass(type, typeDeclaration,
isNonNullableByDefault: isNonNullableByDefault);
case ExtensionTypeDeclaration():
return getExtensionTypeAsInstanceOfExtensionTypeDeclaration(
type, typeDeclaration,
isNonNullableByDefault: isNonNullableByDefault);
}
}
}
@override
List<DartType>? getTypeArgumentsAsInstanceOf(
TypeDeclarationType type, TypeDeclaration typeDeclaration) {
switch (type) {
case InterfaceType():
switch (typeDeclaration) {
case Class():
return getInterfaceTypeArgumentsAsInstanceOfClass(
type, typeDeclaration);
case ExtensionTypeDeclaration():
return null;
}
case ExtensionType():
switch (typeDeclaration) {
case Class():
return getExtensionTypeArgumentsAsInstanceOfClass(
type, typeDeclaration);
case ExtensionTypeDeclaration():
// ignore: lines_longer_than_80_chars
return getExtensionTypeArgumentsAsInstanceOfExtensionTypeDeclaration(
type, typeDeclaration);
}
}
}
ExtensionType?
getExtensionTypeDeclarationAsInstanceOfExtensionTypeDeclaration(
ExtensionTypeDeclaration subDeclaration,
@ -878,15 +942,13 @@ class ClosedWorldClassHierarchy
}
InterfaceType _getLegacyLeastUpperBoundInternal(
/* InterfaceType | ExtensionType */ DartType type1,
/* InterfaceType | ExtensionType */ DartType type2,
TypeDeclarationType type1,
TypeDeclarationType type2,
_ClassInfo? info1,
_ClassInfo? info2,
List<_ClassInfo> classInfos1,
List<_ClassInfo> classInfos2,
{required bool isNonNullableByDefault}) {
assert(type1 is InterfaceType || type1 is ExtensionType);
assert(type2 is InterfaceType || type2 is ExtensionType);
assert(type1 is! InterfaceType || info1 != null);
assert(type2 is! InterfaceType || info2 != null);
@ -983,13 +1045,11 @@ class ClosedWorldClassHierarchy
@override
InterfaceType getLegacyLeastUpperBoundFromSupertypeLists(
/* InterfaceType | ExtensionType */ DartType type1,
/* InterfaceType | ExtensionType */ DartType type2,
TypeDeclarationType type1,
TypeDeclarationType type2,
List<InterfaceType> supertypes1,
List<InterfaceType> supertypes2,
{required bool isNonNullableByDefault}) {
assert(type1 is InterfaceType || type1 is ExtensionType);
assert(type2 is InterfaceType || type2 is ExtensionType);
assert(supertypes1.isNotEmpty || type1 is ExtensionType);
assert(supertypes2.isNotEmpty || type2 is ExtensionType);
@ -1035,10 +1095,11 @@ class ClosedWorldClassHierarchy
}
@override
InterfaceType? getTypeAsInstanceOf(InterfaceType type, Class superclass,
InterfaceType? getInterfaceTypeAsInstanceOfClass(
InterfaceType type, Class superclass,
{required bool isNonNullableByDefault}) {
List<DartType>? typeArguments =
getTypeArgumentsAsInstanceOf(type, superclass);
getInterfaceTypeArgumentsAsInstanceOfClass(type, superclass);
if (typeArguments == null) return null;
// The return value should be a legacy type if it's computed for an
// opted-out library, unless the return value is Null? which is always
@ -1049,7 +1110,7 @@ class ClosedWorldClassHierarchy
}
@override
List<DartType>? getTypeArgumentsAsInstanceOf(
List<DartType>? getInterfaceTypeArgumentsAsInstanceOfClass(
InterfaceType type, Class superclass) {
if (type.classReference == superclass.reference) {
// TODO(johnniwinther): This is necessary because [getClassAsInstanceOf]

View file

@ -865,6 +865,18 @@ class CoverageVisitor implements Visitor<void> {
node.visitChildren(this);
}
@override
void visitInterfaceType(InterfaceType node) {
visited.add(DartTypeKind.InterfaceType);
node.visitChildren(this);
}
@override
void visitExtensionType(ExtensionType node) {
visited.add(DartTypeKind.ExtensionType);
node.visitChildren(this);
}
@override
void visitAuxiliaryType(AuxiliaryType node) {
throw new UnsupportedError(
@ -901,12 +913,6 @@ class CoverageVisitor implements Visitor<void> {
node.visitChildren(this);
}
@override
void visitInterfaceType(InterfaceType node) {
visited.add(DartTypeKind.InterfaceType);
node.visitChildren(this);
}
@override
void visitFunctionType(FunctionType node) {
visited.add(DartTypeKind.FunctionType);
@ -925,12 +931,6 @@ class CoverageVisitor implements Visitor<void> {
node.visitChildren(this);
}
@override
void visitExtensionType(ExtensionType node) {
visited.add(DartTypeKind.ExtensionType);
node.visitChildren(this);
}
@override
void visitIntersectionType(IntersectionType node) {
visited.add(DartTypeKind.IntersectionType);

View file

@ -742,6 +742,16 @@ class EquivalenceVisitor implements Visitor1<bool, Node> {
return strategy.checkName(this, node, other);
}
@override
bool visitInterfaceType(InterfaceType node, Node other) {
return strategy.checkInterfaceType(this, node, other);
}
@override
bool visitExtensionType(ExtensionType node, Node other) {
return strategy.checkExtensionType(this, node, other);
}
@override
bool visitAuxiliaryType(AuxiliaryType node, Node other) {
return strategy.checkAuxiliaryType(this, node, other);
@ -772,11 +782,6 @@ class EquivalenceVisitor implements Visitor1<bool, Node> {
return strategy.checkNullType(this, node, other);
}
@override
bool visitInterfaceType(InterfaceType node, Node other) {
return strategy.checkInterfaceType(this, node, other);
}
@override
bool visitFunctionType(FunctionType node, Node other) {
return strategy.checkFunctionType(this, node, other);
@ -792,11 +797,6 @@ class EquivalenceVisitor implements Visitor1<bool, Node> {
return strategy.checkFutureOrType(this, node, other);
}
@override
bool visitExtensionType(ExtensionType node, Node other) {
return strategy.checkExtensionType(this, node, other);
}
@override
bool visitIntersectionType(IntersectionType node, Node other) {
return strategy.checkIntersectionType(this, node, other);
@ -5119,6 +5119,47 @@ class EquivalenceStrategy {
return result;
}
bool checkInterfaceType(
EquivalenceVisitor visitor, InterfaceType? node, Object? other) {
if (identical(node, other)) return true;
if (node is! InterfaceType) return false;
if (other is! InterfaceType) return false;
visitor.pushNodeState(node, other);
bool result = true;
if (!checkInterfaceType_classReference(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkInterfaceType_declaredNullability(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkInterfaceType_typeArguments(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
visitor.popState();
return result;
}
bool checkExtensionType(
EquivalenceVisitor visitor, ExtensionType? node, Object? other) {
if (identical(node, other)) return true;
if (node is! ExtensionType) return false;
if (other is! ExtensionType) return false;
visitor.pushNodeState(node, other);
bool result = true;
if (!checkExtensionType_extensionTypeDeclarationReference(
visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkExtensionType_declaredNullability(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkExtensionType_typeArguments(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
visitor.popState();
return result;
}
bool checkAuxiliaryType(
EquivalenceVisitor visitor, AuxiliaryType? node, Object? other) {
if (identical(node, other)) return true;
@ -5188,26 +5229,6 @@ class EquivalenceStrategy {
return result;
}
bool checkInterfaceType(
EquivalenceVisitor visitor, InterfaceType? node, Object? other) {
if (identical(node, other)) return true;
if (node is! InterfaceType) return false;
if (other is! InterfaceType) return false;
visitor.pushNodeState(node, other);
bool result = true;
if (!checkInterfaceType_classReference(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkInterfaceType_declaredNullability(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkInterfaceType_typeArguments(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
visitor.popState();
return result;
}
bool checkFunctionType(
EquivalenceVisitor visitor, FunctionType? node, Object? other) {
if (identical(node, other)) return true;
@ -5274,27 +5295,6 @@ class EquivalenceStrategy {
return result;
}
bool checkExtensionType(
EquivalenceVisitor visitor, ExtensionType? node, Object? other) {
if (identical(node, other)) return true;
if (node is! ExtensionType) return false;
if (other is! ExtensionType) return false;
visitor.pushNodeState(node, other);
bool result = true;
if (!checkExtensionType_extensionTypeDeclarationReference(
visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkExtensionType_declaredNullability(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkExtensionType_typeArguments(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
visitor.popState();
return result;
}
bool checkIntersectionType(
EquivalenceVisitor visitor, IntersectionType? node, Object? other) {
if (identical(node, other)) return true;
@ -9344,12 +9344,6 @@ class EquivalenceStrategy {
return visitor.checkValues(node.text, other.text, 'text');
}
bool checkNeverType_declaredNullability(
EquivalenceVisitor visitor, NeverType node, NeverType other) {
return visitor.checkValues(node.declaredNullability,
other.declaredNullability, 'declaredNullability');
}
bool checkInterfaceType_classReference(
EquivalenceVisitor visitor, InterfaceType node, InterfaceType other) {
return visitor.checkReferences(
@ -9368,6 +9362,32 @@ class EquivalenceStrategy {
visitor.checkNodes, 'typeArguments');
}
bool checkExtensionType_extensionTypeDeclarationReference(
EquivalenceVisitor visitor, ExtensionType node, ExtensionType other) {
return visitor.checkReferences(
node.extensionTypeDeclarationReference,
other.extensionTypeDeclarationReference,
'extensionTypeDeclarationReference');
}
bool checkExtensionType_declaredNullability(
EquivalenceVisitor visitor, ExtensionType node, ExtensionType other) {
return visitor.checkValues(node.declaredNullability,
other.declaredNullability, 'declaredNullability');
}
bool checkExtensionType_typeArguments(
EquivalenceVisitor visitor, ExtensionType node, ExtensionType other) {
return visitor.checkLists(node.typeArguments, other.typeArguments,
visitor.checkNodes, 'typeArguments');
}
bool checkNeverType_declaredNullability(
EquivalenceVisitor visitor, NeverType node, NeverType other) {
return visitor.checkValues(node.declaredNullability,
other.declaredNullability, 'declaredNullability');
}
bool checkFunctionType_typeParameters(
EquivalenceVisitor visitor, FunctionType node, FunctionType other) {
return visitor.checkLists(node.typeParameters, other.typeParameters,
@ -9433,26 +9453,6 @@ class EquivalenceStrategy {
other.declaredNullability, 'declaredNullability');
}
bool checkExtensionType_extensionTypeDeclarationReference(
EquivalenceVisitor visitor, ExtensionType node, ExtensionType other) {
return visitor.checkReferences(
node.extensionTypeDeclarationReference,
other.extensionTypeDeclarationReference,
'extensionTypeDeclarationReference');
}
bool checkExtensionType_declaredNullability(
EquivalenceVisitor visitor, ExtensionType node, ExtensionType other) {
return visitor.checkValues(node.declaredNullability,
other.declaredNullability, 'declaredNullability');
}
bool checkExtensionType_typeArguments(
EquivalenceVisitor visitor, ExtensionType node, ExtensionType other) {
return visitor.checkLists(node.typeArguments, other.typeArguments,
visitor.checkNodes, 'typeArguments');
}
bool checkIntersectionType_left(EquivalenceVisitor visitor,
IntersectionType node, IntersectionType other) {
return visitor.checkNodes(node.left, other.left, 'left');

View file

@ -23,7 +23,7 @@ class HierarchyBasedTypeEnvironment extends TypeEnvironment {
InterfaceType? getTypeAsInstanceOf(
InterfaceType type, Class superclass, CoreTypes coreTypes,
{required bool isNonNullableByDefault}) {
return hierarchy.getTypeAsInstanceOf(type, superclass,
return hierarchy.getInterfaceTypeAsInstanceOfClass(type, superclass,
isNonNullableByDefault: isNonNullableByDefault);
}
@ -31,7 +31,8 @@ class HierarchyBasedTypeEnvironment extends TypeEnvironment {
List<DartType>? getTypeArgumentsAsInstanceOf(
InterfaceType type, Class superclass) {
if (type.classNode == superclass) return type.typeArguments;
return hierarchy.getTypeArgumentsAsInstanceOf(type, superclass);
return hierarchy.getInterfaceTypeArgumentsAsInstanceOfClass(
type, superclass);
}
@override

View file

@ -925,31 +925,13 @@ mixin StandardBounds {
}
// UP(C<T0, ..., Tn>, C<S0, ..., Sn>) = C<R0,..., Rn> where Ri is UP(Ti, Si)
Class? cls;
ExtensionTypeDeclaration? extensionTypeDeclaration;
List<TypeParameter>? typeParameters;
List<DartType>? leftArguments;
List<DartType>? rightArguments;
if (type1 is InterfaceType && type2 is InterfaceType) {
if (type1.classNode == type2.classNode) {
cls = type1.classNode;
typeParameters = cls.typeParameters;
leftArguments = type1.typeArguments;
rightArguments = type2.typeArguments;
}
}
if (type1 is ExtensionType && type2 is ExtensionType) {
if (type1.extensionTypeDeclaration == type2.extensionTypeDeclaration) {
extensionTypeDeclaration = type1.extensionTypeDeclaration;
typeParameters = extensionTypeDeclaration.typeParameters;
leftArguments = type1.typeArguments;
rightArguments = type2.typeArguments;
}
}
if (typeParameters != null &&
leftArguments != null &&
rightArguments != null) {
if (type1 is TypeDeclarationType &&
type2 is TypeDeclarationType &&
type1.typeDeclarationReference == type2.typeDeclarationReference) {
TypeDeclaration typeDeclaration = type1.typeDeclaration;
List<TypeParameter> typeParameters = typeDeclaration.typeParameters;
List<DartType> leftArguments = type1.typeArguments;
List<DartType> rightArguments = type2.typeArguments;
int n = typeParameters.length;
List<DartType> typeArguments = new List<DartType>.of(leftArguments);
for (int i = 0; i < n; ++i) {
@ -970,32 +952,32 @@ mixin StandardBounds {
isNonNullableByDefault: isNonNullableByDefault);
}
}
if (cls != null) {
return new InterfaceType(
cls,
uniteNullabilities(
type1.declaredNullability, type2.declaredNullability),
typeArguments);
} else {
return new ExtensionType(
extensionTypeDeclaration!,
uniteNullabilities(
type1.declaredNullability, type2.declaredNullability),
typeArguments);
switch (typeDeclaration) {
case Class():
return new InterfaceType(
typeDeclaration,
uniteNullabilities(
type1.declaredNullability, type2.declaredNullability),
typeArguments);
case ExtensionTypeDeclaration():
return new ExtensionType(
typeDeclaration,
uniteNullabilities(
type1.declaredNullability, type2.declaredNullability),
typeArguments);
}
}
// UP(C0<T0, ..., Tn>, C1<S0, ..., Sk>)
// = least upper bound of two interfaces as in Dart 1.
return _getLegacyLeastUpperBound(type1, type2,
return _getLegacyLeastUpperBound(
type1 as TypeDeclarationType, type2 as TypeDeclarationType,
isNonNullableByDefault: isNonNullableByDefault);
}
DartType _getLegacyLeastUpperBound(DartType type1, DartType type2,
DartType _getLegacyLeastUpperBound(
TypeDeclarationType type1, TypeDeclarationType type2,
{required bool isNonNullableByDefault}) {
assert((type1 is InterfaceType || type1 is ExtensionType) &&
(type2 is InterfaceType || type2 is ExtensionType));
if (type1 is InterfaceType && type2 is InterfaceType) {
return hierarchy.getLegacyLeastUpperBound(type1, type2,
isNonNullableByDefault: isNonNullableByDefault);

View file

@ -423,13 +423,14 @@ class Types with StandardBounds {
InterfaceType? getTypeAsInstanceOf(
InterfaceType type, Class superclass, CoreTypes coreTypes,
{required bool isNonNullableByDefault}) {
return hierarchy.getTypeAsInstanceOf(type, superclass,
return hierarchy.getInterfaceTypeAsInstanceOfClass(type, superclass,
isNonNullableByDefault: isNonNullableByDefault);
}
List<DartType>? getTypeArgumentsAsInstanceOf(
InterfaceType type, Class superclass) {
return hierarchy.getTypeArgumentsAsInstanceOf(type, superclass);
return hierarchy.getInterfaceTypeArgumentsAsInstanceOfClass(
type, superclass);
}
List<DartType>? getExtensionTypeArgumentsAsInstanceOfExtensionTypeDeclaration(
@ -497,8 +498,8 @@ class IsInterfaceSubtypeOf extends TypeRelation<InterfaceType> {
if (s.classReference == t.classReference) {
asSupertypeArguments = s.typeArguments;
} else {
asSupertypeArguments =
types.hierarchy.getTypeArgumentsAsInstanceOf(s, t.classNode);
asSupertypeArguments = types.hierarchy
.getInterfaceTypeArgumentsAsInstanceOfClass(s, t.classNode);
}
if (asSupertypeArguments == null) {
return const IsSubtypeOf.never();

View file

@ -479,6 +479,14 @@ abstract class Substitution {
supertype.classNode.typeParameters, supertype.typeArguments));
}
/// Returns the [Substitution] for the type parameters on the type declaration
/// of [type] with the type arguments provided in [type].
static Substitution fromTypeDeclarationType(TypeDeclarationType type) {
if (type.typeArguments.isEmpty) return _NullSubstitution.instance;
return fromMap(new Map<TypeParameter, DartType>.fromIterables(
type.typeDeclaration.typeParameters, type.typeArguments));
}
/// Substitutes the type parameters on the class of [type] with the
/// type arguments provided in [type].
static Substitution fromInterfaceType(InterfaceType type) {

View file

@ -256,8 +256,8 @@ class TypeCheckingVisitor
}
if (type is InterfaceType && typeDeclaration is Class) {
// The receiver type should implement the interface declaring the member.
List<DartType>? upcastTypeArguments =
hierarchy.getTypeArgumentsAsInstanceOf(type, typeDeclaration);
List<DartType>? upcastTypeArguments = hierarchy
.getInterfaceTypeArgumentsAsInstanceOfClass(type, typeDeclaration);
if (upcastTypeArguments != null) {
return Substitution.fromPairs(
typeDeclaration.typeParameters, upcastTypeArguments);
@ -940,7 +940,7 @@ class TypeCheckingVisitor
hierarchy.getInterfaceMember(iterable.classNode, iteratorName);
if (iteratorGetter == null) return const DynamicType();
List<DartType> castedIterableArguments =
hierarchy.getTypeArgumentsAsInstanceOf(
hierarchy.getInterfaceTypeArgumentsAsInstanceOfClass(
iterable, iteratorGetter.enclosingClass!)!;
DartType iteratorType = Substitution.fromPairs(
iteratorGetter.enclosingClass!.typeParameters,
@ -951,7 +951,7 @@ class TypeCheckingVisitor
hierarchy.getInterfaceMember(iteratorType.classNode, currentName);
if (currentGetter == null) return const DynamicType();
List<DartType> castedIteratorTypeArguments =
hierarchy.getTypeArgumentsAsInstanceOf(
hierarchy.getInterfaceTypeArgumentsAsInstanceOfClass(
iteratorType, currentGetter.enclosingClass!)!;
return Substitution.fromPairs(
currentGetter.enclosingClass!.typeParameters,
@ -965,7 +965,8 @@ class TypeCheckingVisitor
DartType getStreamElementType(DartType stream) {
if (stream is InterfaceType) {
List<DartType>? asStreamArguments =
hierarchy.getTypeArgumentsAsInstanceOf(stream, coreTypes.streamClass);
hierarchy.getInterfaceTypeArgumentsAsInstanceOfClass(
stream, coreTypes.streamClass);
if (asStreamArguments == null) return const DynamicType();
return asStreamArguments.single;
}
@ -1065,7 +1066,8 @@ class TypeCheckingVisitor
: coreTypes.iterableClass;
DartType type = visitExpression(node.expression);
List<DartType>? asContainerArguments = type is InterfaceType
? hierarchy.getTypeArgumentsAsInstanceOf(type, container)
? hierarchy.getInterfaceTypeArgumentsAsInstanceOfClass(
type, container)
: null;
if (asContainerArguments != null) {
checkAssignable(

View file

@ -1346,11 +1346,11 @@ class B<T*> extends self::A<self::B::T*, core::bool*> {}
var b_int = new InterfaceType(b, Nullability.legacy, [int]);
expect(
hierarchy.getTypeAsInstanceOf(b_int, a,
hierarchy.getInterfaceTypeAsInstanceOfClass(b_int, a,
isNonNullableByDefault: library.isNonNullableByDefault),
new InterfaceType(a, Nullability.legacy, [int, bool]));
expect(
hierarchy.getTypeAsInstanceOf(b_int, objectClass,
hierarchy.getInterfaceTypeAsInstanceOfClass(b_int, objectClass,
isNonNullableByDefault: library.isNonNullableByDefault),
new InterfaceType(objectClass, Nullability.legacy));
}