Extension type. Update nullability, remove implied interfaces.

2edfa84697

Change-Id: I108d57aa2b601ccc3de0e7097507f6115b430d94
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/337000
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2023-11-17 20:59:48 +00:00 committed by Commit Queue
parent 1941a8f463
commit e6b02b5895
11 changed files with 80 additions and 253 deletions

View file

@ -1470,17 +1470,6 @@ extension type E2(A it) implements E1 {}
'location': anything,
'flags': 0
},
'interfaces': [2],
'mixins': [],
'subclasses': []
},
{
'classElement': {
'kind': 'CLASS',
'name': 'Object',
'location': anything,
'flags': 0
},
'interfaces': [],
'mixins': [],
'subclasses': []

View file

@ -130,21 +130,8 @@ class InterfaceLeastUpperBoundHelper {
return;
}
final representationType = type.representationType;
if (representationType != null) {
// TODO(scheglov): See https://github.com/dart-lang/language/pull/3402
// When it lands, we might need to remove `Object` from the element
// interfaces, and return from the type interfaces.
final first = type.interfaces.singleOrNull;
if (first != null && first.isDartCoreObject) {
final replacement = typeSystem.isNonNullable(representationType)
? typeSystem.objectNone
: typeSystem.objectQuestion;
if (set.add(replacement)) {
_addSuperinterfaces(set, replacement);
}
return;
}
if (type.element is ExtensionTypeElement) {
set.add(typeSystem.objectQuestion);
}
for (var interface in type.interfaces) {

View file

@ -120,15 +120,14 @@ class SubtypeHelper {
T0_nullability == NullabilitySuffix.question) {
return false;
}
// Extension types:
// If `R` is a non-nullable type then `V0` is a proper subtype
// of `Object`, and a non-nullable type.
// Extension types require explicit `Object` implementation.
if (T0 is InterfaceTypeImpl && T0.element is ExtensionTypeElement) {
if (T0.representationType case final representationType?) {
if (_typeSystem.isNullable(representationType)) {
return false;
for (final interface in T0.interfaces) {
if (isSubtypeOf(interface, T1_)) {
return true;
}
}
return false;
}
// Otherwise `T0 <: T1` is true.
return true;

View file

@ -1312,8 +1312,8 @@ class TypeSystemImpl implements TypeSystem {
if (type.isDartAsyncFutureOr) {
return isNonNullable(type.typeArguments[0]);
}
if (type.representationType case final representationType?) {
return isNonNullable(representationType);
if (type.element is ExtensionTypeElement) {
return type.interfaces.isNotEmpty;
}
} else if (type is TypeParameterType) {
var bound = type.element.bound;
@ -1408,8 +1408,8 @@ class TypeSystemImpl implements TypeSystem {
if (type.isDartAsyncFutureOr) {
return isStrictlyNonNullable(type.typeArguments[0]);
}
if (type.representationType case final representationType?) {
return isStrictlyNonNullable(representationType);
if (type.element is ExtensionTypeElement) {
return type.interfaces.isNotEmpty;
}
} else if (type is TypeParameterType) {
return isStrictlyNonNullable(type.bound);

View file

@ -153,18 +153,14 @@ class _Node extends graph.Node<_Node> {
element.representation.type = type;
element.typeErasure = ExtensionTypeErasure().perform(type);
var interfaces = node.implementsClause?.interfaces
final interfaces = node.implementsClause?.interfaces
.map((e) => e.type)
.whereType<InterfaceType>()
.where(typeSystem.isValidExtensionTypeSuperinterface)
.toFixedList();
if (interfaces == null || interfaces.isEmpty) {
final superInterface = typeSystem.isNonNullable(type)
? typeSystem.objectNone
: typeSystem.objectQuestion;
interfaces = [superInterface];
if (interfaces != null) {
element.interfaces = interfaces;
}
element.interfaces = interfaces;
final primaryConstructor = element.constructors.first;
final primaryFormalParameter = primaryConstructor.parameters.first;

View file

@ -1132,31 +1132,9 @@ extension type A(int it) {}
printerConfiguration.withObjectMembers = true;
assertInterfaceText(element, r'''
map
==: dart:core::@class::Object::@method::==
hashCode: dart:core::@class::Object::@getter::hashCode
it: self::@extensionType::A::@getter::it
noSuchMethod: dart:core::@class::Object::@method::noSuchMethod
runtimeType: dart:core::@class::Object::@getter::runtimeType
toString: dart:core::@class::Object::@method::toString
declared
it: self::@extensionType::A::@getter::it
redeclared
==
dart:core::@class::Object::@method::==
hashCode
dart:core::@class::Object::@getter::hashCode
noSuchMethod
dart:core::@class::Object::@method::noSuchMethod
runtimeType
dart:core::@class::Object::@getter::runtimeType
toString
dart:core::@class::Object::@method::toString
inheritedMap
==: dart:core::@class::Object::@method::==
hashCode: dart:core::@class::Object::@getter::hashCode
noSuchMethod: dart:core::@class::Object::@method::noSuchMethod
runtimeType: dart:core::@class::Object::@getter::runtimeType
toString: dart:core::@class::Object::@method::toString
''');
}

View file

@ -105,15 +105,15 @@ class IsNonNullableTest extends AbstractTypeSystemTest {
}
test_interface_extensionType() {
isNonNullable(
isNotNonNullable(
interfaceTypeNone(
extensionType('A', representationType: intNone),
),
);
isNotNonNullable(
isNonNullable(
interfaceTypeNone(
extensionType('A', representationType: intQuestion),
extensionType('A', representationType: intNone, interfaces: [intNone]),
),
);
}
@ -294,21 +294,15 @@ class IsNullableTest extends AbstractTypeSystemTest {
),
);
isNullable(
interfaceTypeQuestion(
extensionType('A', representationType: intNone),
),
);
isNotNullable(
interfaceTypeNone(
extensionType('A', representationType: intQuestion),
extensionType('A', representationType: intNone, interfaces: [intNone]),
),
);
isNullable(
interfaceTypeQuestion(
extensionType('A', representationType: intQuestion),
extensionType('A', representationType: intNone, interfaces: [intNone]),
),
);
}
@ -443,7 +437,7 @@ class IsPotentiallyNonNullableTest extends AbstractTypeSystemTest {
isPotentiallyNonNullable(
interfaceTypeNone(
extensionType('A', representationType: intQuestion),
extensionType('A', representationType: intNone, interfaces: [intNone]),
),
);
}
@ -500,27 +494,21 @@ class IsPotentiallyNullableTest extends AbstractTypeSystemTest {
}
test_interface_extensionType() {
isPotentiallyNullable(
interfaceTypeQuestion(
extensionType('A', representationType: intNone),
),
);
isPotentiallyNullable(
interfaceTypeNone(
extensionType('A', representationType: intNone),
),
);
isNotPotentiallyNullable(
interfaceTypeNone(
extensionType('A', representationType: intNone),
),
);
isPotentiallyNullable(
interfaceTypeQuestion(
extensionType('A', representationType: intNone),
),
);
isPotentiallyNullable(
interfaceTypeNone(
extensionType('A', representationType: intQuestion),
),
);
isPotentiallyNullable(
interfaceTypeQuestion(
extensionType('A', representationType: intQuestion),
extensionType('A', representationType: intNone, interfaces: [intNone]),
),
);
}
@ -625,15 +613,15 @@ class IsStrictlyNonNullableTest extends AbstractTypeSystemTest {
}
test_interface_extensionType() {
isStrictlyNonNullable(
isNotStrictlyNonNullable(
interfaceTypeNone(
extensionType('A', representationType: intNone),
),
);
isNotStrictlyNonNullable(
isStrictlyNonNullable(
interfaceTypeNone(
extensionType('A', representationType: intQuestion),
extensionType('A', representationType: intNone, interfaces: [intNone]),
),
);
}

View file

@ -75,21 +75,28 @@ class SubtypeTest extends _SubtypingTestBase with StringTypes {
defineStringTypes();
}
test_extensionType_nonNullableRepresentation() {
final element = extensionType('A', representationType: intNone);
test_extensionType_implementsNotNullable() {
final element = extensionType(
'A',
representationType: intNone,
interfaces: [intNone],
);
final type = interfaceTypeNone(element);
isSubtype(type, objectQuestion);
isSubtype(type, objectNone);
isSubtype(type, intNone);
isSubtype(type, numNone);
isSubtype(neverNone, type);
}
test_extensionType_nullableRepresentation() {
final element = extensionType('A', representationType: intQuestion);
test_extensionType_noImplementedInterfaces() {
final element = extensionType('A', representationType: intNone);
final type = interfaceTypeNone(element);
isSubtype(type, objectQuestion);
isNotSubtype(type, objectNone);
isNotSubtype(type, intNone);
}
test_extensionType_superinterfaces() {

View file

@ -2885,81 +2885,24 @@ class UpperBoundTest extends _BoundsTestBase {
}
void test_extensionType_noTypeParameters_noInterfaces() {
// A(Object?) and B(Object?)
// extension type A(int) {}
// extension type B(double) {}
_checkLeastUpperBound(
interfaceTypeNone(
extensionType(
'A',
representationType: objectQuestion,
interfaces: [objectQuestion],
representationType: intNone,
),
),
interfaceTypeNone(
extensionType(
'B',
representationType: objectQuestion,
interfaces: [objectQuestion],
representationType: doubleNone,
),
),
objectQuestion,
);
// A(Object) and B(Object?)
_checkLeastUpperBound(
interfaceTypeNone(
extensionType(
'A',
representationType: objectNone,
interfaces: [objectNone],
),
),
interfaceTypeNone(
extensionType(
'B',
representationType: objectQuestion,
interfaces: [objectQuestion],
),
),
objectQuestion,
);
// A(Object) and B(Object)
_checkLeastUpperBound(
interfaceTypeNone(
extensionType(
'A',
representationType: objectNone,
interfaces: [objectNone],
),
),
interfaceTypeNone(
extensionType(
'B',
representationType: objectNone,
interfaces: [objectNone],
),
),
objectNone,
);
// A(String) and B(num)
_checkLeastUpperBound(
interfaceTypeNone(
extensionType(
'A',
representationType: stringNone,
interfaces: [objectNone],
),
),
interfaceTypeNone(
extensionType(
'B',
representationType: numNone,
interfaces: [objectNone],
),
),
objectNone,
);
}
void test_extensionType_withTypeParameters_objectNone() {

View file

@ -398,6 +398,34 @@ void f(bool b) {
''');
}
test_extensionType_hasImplements() async {
// Extension types are always potentially non-nullable.
await assertErrorsInCode(r'''
extension type E(int it) implements int {}
void f() {
E v;
v;
}
''', [
_notAssignedError(64, 1),
]);
}
test_extensionType_noImplements() async {
// Extension types are always potentially non-nullable.
await assertErrorsInCode(r'''
extension type E(int it) {}
void f() {
E v;
v;
}
''', [
_notAssignedError(49, 1),
]);
}
test_for_body() async {
await assertErrorsInCode(r'''
void f(bool b) {

View file

@ -10180,8 +10180,6 @@ library
representation: self::@extensionType::B::@field::it
primaryConstructor: self::@extensionType::B::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @32
type: int
@ -10709,8 +10707,6 @@ library
representation: self::@extensionType::B::@field::it
primaryConstructor: self::@extensionType::B::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @32
type: int
@ -12142,8 +12138,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @21
type: int
@ -24285,8 +24279,6 @@ library
representation: self::@extensionType::E::@def::0::@field::it
primaryConstructor: self::@extensionType::E::@def::0::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @21
reference: self::@extensionType::E::@def::0::@field::it
@ -24307,8 +24299,6 @@ library
representation: self::@extensionType::E::@def::1::@field::it
primaryConstructor: self::@extensionType::E::@def::1::@constructor::new
typeErasure: double
interfaces
Object
fields
final it @52
reference: self::@extensionType::E::@def::1::@field::it
@ -25957,8 +25947,6 @@ library
representation: self::@extensionType::B::@field::it
primaryConstructor: self::@extensionType::B::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @32
type: int
@ -26311,8 +26299,6 @@ library
representation: self::@extensionType::B::@field::it
primaryConstructor: self::@extensionType::B::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @32
type: int
@ -39943,8 +39929,6 @@ library
representation: self::@extensionType::B::@field::it
primaryConstructor: self::@extensionType::B::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @32
type: int
@ -40079,8 +40063,6 @@ library
representation: self::@extensionType::B::@field::it
primaryConstructor: self::@extensionType::B::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @32
type: int
@ -48856,8 +48838,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @27
type: int
@ -48889,8 +48869,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::named
typeErasure: int
interfaces
Object
fields
final it @27
codeOffset: 23
@ -48929,8 +48907,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: num
interfaces
Object
fields
final it @21
type: num
@ -48968,8 +48944,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: num
interfaces
Object
fields
final it @21
type: num
@ -49007,8 +48981,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: num
interfaces
Object
fields
final it @21
type: num
@ -49057,8 +49029,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @21
codeOffset: 17
@ -49096,8 +49066,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @30
type: int
@ -49129,8 +49097,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @21
type: int
@ -49165,8 +49131,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @21
type: int
@ -49201,8 +49165,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @21
type: int
@ -49237,8 +49199,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @43
metadata
@ -49278,8 +49238,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @21
type: int
@ -49407,8 +49365,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: num
interfaces
Object
fields
final it @21
type: num
@ -49469,8 +49425,6 @@ library
representation: self::@extensionType::X::@field::it
primaryConstructor: self::@extensionType::X::@constructor::new
typeErasure: int?
interfaces
Object?
fields
final it @22
type: int?
@ -49497,8 +49451,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: T
interfaces
Object?
fields
final it @22
type: T
@ -49561,8 +49513,6 @@ library
representation: self::@extensionType::A::@field::_it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int?
interfaces
Object?
fields
final promotable _it @22
type: int?
@ -49604,8 +49554,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @43
type: int
@ -49637,8 +49585,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @21
type: int
@ -49670,8 +49616,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @21
type: int
@ -49707,8 +49651,6 @@ library
representation: self::@extensionType::A::@field::<empty>
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: InvalidType
interfaces
Object?
fields
final <empty> @17
codeOffset: 17
@ -49748,8 +49690,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @34
type: int
@ -49775,8 +49715,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @21
type: int
@ -49809,8 +49747,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: InvalidType
interfaces
Object?
fields
final it @19
type: InvalidType
@ -49821,8 +49757,6 @@ library
representation: self::@extensionType::B::@field::it
primaryConstructor: self::@extensionType::B::@constructor::new
typeErasure: InvalidType
interfaces
Object?
fields
final it @46
type: InvalidType
@ -49848,8 +49782,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: InvalidType
interfaces
Object?
fields
final it @19
type: B
@ -49860,8 +49792,6 @@ library
representation: self::@extensionType::B::@field::it
primaryConstructor: self::@extensionType::B::@constructor::new
typeErasure: InvalidType
interfaces
Object?
fields
final it @52
type: InvalidType
@ -49885,8 +49815,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: InvalidType
interfaces
Object?
fields
final it @19
type: InvalidType
@ -49912,8 +49840,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @21
type: int
@ -49924,8 +49850,6 @@ library
representation: self::@extensionType::B::@field::it
primaryConstructor: self::@extensionType::B::@constructor::new
typeErasure: int Function(int)
interfaces
Object
fields
final it @62
type: A Function(A)
@ -49954,8 +49878,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: T
interfaces
Object?
fields
final it @22
type: T
@ -49966,8 +49888,6 @@ library
representation: self::@extensionType::B::@field::it
primaryConstructor: self::@extensionType::B::@constructor::new
typeErasure: double
interfaces
Object
fields
final it @57
type: A<double>
@ -49993,8 +49913,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @21
type: int
@ -50005,8 +49923,6 @@ library
representation: self::@extensionType::B::@field::it
primaryConstructor: self::@extensionType::B::@constructor::new
typeErasure: List<int>
interfaces
Object
fields
final it @54
type: List<A>
@ -50030,8 +49946,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: int
interfaces
Object
fields
final it @21
type: int
@ -50060,8 +49974,6 @@ library
representation: self::@extensionType::A::@field::it
primaryConstructor: self::@extensionType::A::@constructor::new
typeErasure: Map<T, U>
interfaces
Object
fields
final it @45
type: Map<T, U>