Skip to content

Commit

Permalink
[cfe] Ensure reporting all supertype conflicts in extension types
Browse files Browse the repository at this point in the history
Closes #53799
Part of #49731

Change-Id: Ic273541973de6377bb376f51850ec3d7d114c764
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/334180
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
  • Loading branch information
chloestefantsova authored and Commit Queue committed Nov 6, 2023
1 parent de7e3b7 commit 2ea55d4
Show file tree
Hide file tree
Showing 16 changed files with 1,234 additions and 16 deletions.
33 changes: 17 additions & 16 deletions pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_node.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ abstract class HierarchyNodeBuilder {
}

List<Supertype> _substSupertypes(
Supertype supertype, List<Supertype> supertypes) {
List<TypeParameter> typeVariables = supertype.classNode.typeParameters;
TypeDeclarationType supertype, List<Supertype> supertypes) {
List<TypeParameter> typeVariables =
supertype.typeDeclaration.typeParameters;
if (typeVariables.isEmpty) {
return supertypes;
}
Expand Down Expand Up @@ -166,7 +167,7 @@ class ClassHierarchyNodeBuilder extends HierarchyNodeBuilder {
new Supertype(_hierarchy.coreTypes.objectClass, const <DartType>[]);
}
superclasses.setRange(0, superclasses.length - 1,
_substSupertypes(supertype, supernode.superclasses));
_substSupertypes(supertype.asInterfaceType, supernode.superclasses));
superclasses[superclasses.length - 1] = supertype;
if (!_classBuilder.libraryBuilder.isNonNullableByDefault &&
supernode.classBuilder.libraryBuilder.isNonNullableByDefault) {
Expand All @@ -192,7 +193,7 @@ class ClassHierarchyNodeBuilder extends HierarchyNodeBuilder {
List<Supertype> superclassInterfaces = supernode.interfaces;
if (superclassInterfaces.isNotEmpty) {
superclassInterfaces =
_substSupertypes(supertype, superclassInterfaces);
_substSupertypes(supertype.asInterfaceType, superclassInterfaces);
}

if (directInterfaceBuilders != null) {
Expand All @@ -216,14 +217,14 @@ class ClassHierarchyNodeBuilder extends HierarchyNodeBuilder {
maxInheritancePath = interfaceNode.maxInheritancePath + 1;
}

List<Supertype> types =
_substSupertypes(directInterface, interfaceNode.superclasses);
List<Supertype> types = _substSupertypes(
directInterface.asInterfaceType, interfaceNode.superclasses);
for (int i = 0; i < types.length; i++) {
_addInterface(interfaces, superclasses, types[i]);
}
if (interfaceNode.interfaces.isNotEmpty) {
List<Supertype> types =
_substSupertypes(directInterface, interfaceNode.interfaces);
List<Supertype> types = _substSupertypes(
directInterface.asInterfaceType, interfaceNode.interfaces);
for (int i = 0; i < types.length; i++) {
_addInterface(interfaces, superclasses, types[i]);
}
Expand Down Expand Up @@ -448,14 +449,14 @@ class ExtensionTypeHierarchyNodeBuilder extends HierarchyNodeBuilder {
maxInheritancePath = interfaceNode.maxInheritancePath + 1;
}

List<Supertype> types =
_substSupertypes(supertype, interfaceNode.superclasses);
List<Supertype> types = _substSupertypes(
supertype.asInterfaceType, interfaceNode.superclasses);
for (int i = 0; i < types.length; i++) {
_addSuperClass(superclasses, types[i]);
}
if (interfaceNode.interfaces.isNotEmpty) {
List<Supertype> types =
_substSupertypes(supertype, interfaceNode.interfaces);
List<Supertype> types = _substSupertypes(
supertype.asInterfaceType, interfaceNode.interfaces);
for (int i = 0; i < types.length; i++) {
_addSuperClass(superclasses, types[i]);
}
Expand All @@ -476,11 +477,11 @@ class ExtensionTypeHierarchyNodeBuilder extends HierarchyNodeBuilder {
for (int i = 0; i < types.length; i++) {
_addSuperExtensionType(superExtensionTypes, types[i]);
}
if (interfaceNode.superExtensionTypes.isNotEmpty) {
List<ExtensionType> types = _substSuperExtensionTypes(
directInterface, interfaceNode.superExtensionTypes);
if (interfaceNode.superclasses.isNotEmpty) {
List<Supertype> types =
_substSupertypes(directInterface, interfaceNode.superclasses);
for (int i = 0; i < types.length; i++) {
_addSuperExtensionType(superExtensionTypes, types[i]);
_addSuperClass(superclasses, types[i]);
}
}
}
Expand Down
26 changes: 26 additions & 0 deletions pkg/front_end/testcases/extension_types/issue53799.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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.

class A<X> {}
class B<X> extends A<X> {}
class C extends A<String> {}
extension type E<X>(X it) {}

extension type E1(A<Never> it) implements A<String>, A<int> {} // Error.

extension type E2(B<Never> it) implements B<String>, A<double> {} // Error.

extension type E3(C it) implements C, A<num> {} // Error.

extension type E41(A<Never> it) implements A<String> {}
extension type E42(A<Never> it) implements E41, A<int> {} // Error.

extension type E5(E<Never> it) implements E<String>, E<bool> {} // Error.

extension type E61(E<Never> it) implements E<num> {}
extension type E62(E<Never> it) implements E61, E<String> {} // Error.

extension type E71(E<Never> it) implements E<double> {}
extension type E72(E<Never> it) implements E<bool> {}
extension type E73(E<Never> it) implements E71, E72 {} // Error.
193 changes: 193 additions & 0 deletions pkg/front_end/testcases/extension_types/issue53799.dart.strong.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
library;
//
// Problems in library:
//
// pkg/front_end/testcases/extension_types/issue53799.dart:10:16: Error: 'E1' can't implement both 'A<String>' and 'A<int>'
// - 'A' is from 'pkg/front_end/testcases/extension_types/issue53799.dart'.
// extension type E1(A<Never> it) implements A<String>, A<int> {} // Error.
// ^
//
// pkg/front_end/testcases/extension_types/issue53799.dart:12:16: Error: 'E2' can't implement both 'A<String>' and 'A<double>'
// - 'A' is from 'pkg/front_end/testcases/extension_types/issue53799.dart'.
// extension type E2(B<Never> it) implements B<String>, A<double> {} // Error.
// ^
//
// pkg/front_end/testcases/extension_types/issue53799.dart:14:16: Error: 'E3' can't implement both 'A<String>' and 'A<num>'
// - 'A' is from 'pkg/front_end/testcases/extension_types/issue53799.dart'.
// extension type E3(C it) implements C, A<num> {} // Error.
// ^
//
// pkg/front_end/testcases/extension_types/issue53799.dart:17:16: Error: 'E42' can't implement both 'A<String>' and 'A<int>'
// - 'A' is from 'pkg/front_end/testcases/extension_types/issue53799.dart'.
// extension type E42(A<Never> it) implements E41, A<int> {} // Error.
// ^
//
// pkg/front_end/testcases/extension_types/issue53799.dart:19:16: Error: 'E5' can't implement both 'E<String>' and 'E<bool>'
// extension type E5(E<Never> it) implements E<String>, E<bool> {} // Error.
// ^
//
// pkg/front_end/testcases/extension_types/issue53799.dart:22:16: Error: 'E62' can't implement both 'E<num>' and 'E<String>'
// extension type E62(E<Never> it) implements E61, E<String> {} // Error.
// ^
//
// pkg/front_end/testcases/extension_types/issue53799.dart:26:16: Error: 'E73' can't implement both 'E<double>' and 'E<bool>'
// extension type E73(E<Never> it) implements E71, E72 {} // Error.
// ^
//
// pkg/front_end/testcases/extension_types/issue53799.dart:14:39: Error: The implemented interface 'A<num>' must be a supertype of the representation type 'C' of extension type 'E3'.
// - 'A' is from 'pkg/front_end/testcases/extension_types/issue53799.dart'.
// - 'C' is from 'pkg/front_end/testcases/extension_types/issue53799.dart'.
// Try changing the interface type to a supertype of 'C' or the representation type to a subtype of 'A<num>'.
// extension type E3(C it) implements C, A<num> {} // Error.
// ^
//
import self as self;
import "dart:core" as core;

class A<X extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::A<self::A::X%>
: super core::Object::•()
;
}
class B<X extends core::Object? = dynamic> extends self::A<self::B::X%> {
synthetic constructor •() → self::B<self::B::X%>
: super self::A::•()
;
}
class C extends self::A<core::String> {
synthetic constructor •() → self::C
: super self::A::•()
;
}
extension type E<X extends core::Object? = dynamic>(X% it) {
abstract inline-class-member representation-field get it() → X%;
constructor • = self::E|constructor#;
constructor tearoff • = self::E|constructor#_#new#tearOff;
}
extension type E1(self::A<Never> it) implements self::A<core::String>, self::A<core::int> {
abstract inline-class-member representation-field get it() → self::A<Never>;
constructor • = self::E1|constructor#;
constructor tearoff • = self::E1|constructor#_#new#tearOff;
}
extension type E2(self::B<Never> it) implements self::B<core::String>, self::A<core::double> {
abstract inline-class-member representation-field get it() → self::B<Never>;
constructor • = self::E2|constructor#;
constructor tearoff • = self::E2|constructor#_#new#tearOff;
}
extension type E3(self::C it) implements self::C, self::A<core::num> {
abstract inline-class-member representation-field get it() → self::C;
constructor • = self::E3|constructor#;
constructor tearoff • = self::E3|constructor#_#new#tearOff;
}
extension type E41(self::A<Never> it) implements self::A<core::String> {
abstract inline-class-member representation-field get it() → self::A<Never>;
constructor • = self::E41|constructor#;
constructor tearoff • = self::E41|constructor#_#new#tearOff;
}
extension type E42(self::A<Never> it) implements self::E41 /* = self::A<Never> */, self::A<core::int> {
abstract inline-class-member representation-field get it() → self::A<Never>;
constructor • = self::E42|constructor#;
constructor tearoff • = self::E42|constructor#_#new#tearOff;
}
extension type E5(self::E<Never> /* = Never */ it) implements self::E<core::String> /* = core::String */, self::E<core::bool> /* = core::bool */ {
abstract inline-class-member representation-field get it() → self::E<Never> /* = Never */;
constructor • = self::E5|constructor#;
constructor tearoff • = self::E5|constructor#_#new#tearOff;
}
extension type E61(self::E<Never> /* = Never */ it) implements self::E<core::num> /* = core::num */ {
abstract inline-class-member representation-field get it() → self::E<Never> /* = Never */;
constructor • = self::E61|constructor#;
constructor tearoff • = self::E61|constructor#_#new#tearOff;
}
extension type E62(self::E<Never> /* = Never */ it) implements self::E61 /* = Never */, self::E<core::String> /* = core::String */ {
abstract inline-class-member representation-field get it() → self::E<Never> /* = Never */;
constructor • = self::E62|constructor#;
constructor tearoff • = self::E62|constructor#_#new#tearOff;
}
extension type E71(self::E<Never> /* = Never */ it) implements self::E<core::double> /* = core::double */ {
abstract inline-class-member representation-field get it() → self::E<Never> /* = Never */;
constructor • = self::E71|constructor#;
constructor tearoff • = self::E71|constructor#_#new#tearOff;
}
extension type E72(self::E<Never> /* = Never */ it) implements self::E<core::bool> /* = core::bool */ {
abstract inline-class-member representation-field get it() → self::E<Never> /* = Never */;
constructor • = self::E72|constructor#;
constructor tearoff • = self::E72|constructor#_#new#tearOff;
}
extension type E73(self::E<Never> /* = Never */ it) implements self::E71 /* = Never */, self::E72 /* = Never */ {
abstract inline-class-member representation-field get it() → self::E<Never> /* = Never */;
constructor • = self::E73|constructor#;
constructor tearoff • = self::E73|constructor#_#new#tearOff;
}
static inline-class-member method E|constructor#<X extends core::Object? = dynamic>(self::E|constructor#::X% it) → self::E<self::E|constructor#::X%> /* = self::E|constructor#::X% */ {
lowered final self::E<self::E|constructor#::X%> /* = self::E|constructor#::X% */ #this = it;
return #this;
}
static inline-class-member method E|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E|constructor#_#new#tearOff::X% it) → self::E<self::E|constructor#_#new#tearOff::X%>% /* = self::E|constructor#_#new#tearOff::X% */
return self::E|constructor#<self::E|constructor#_#new#tearOff::X%>(it);
static inline-class-member method E1|constructor#(self::A<Never> it) → self::E1 /* = self::A<Never> */ {
lowered final self::E1 /* = self::A<Never> */ #this = it;
return #this;
}
static inline-class-member method E1|constructor#_#new#tearOff(self::A<Never> it) → self::E1 /* = self::A<Never> */
return self::E1|constructor#(it);
static inline-class-member method E2|constructor#(self::B<Never> it) → self::E2 /* = self::B<Never> */ {
lowered final self::E2 /* = self::B<Never> */ #this = it;
return #this;
}
static inline-class-member method E2|constructor#_#new#tearOff(self::B<Never> it) → self::E2 /* = self::B<Never> */
return self::E2|constructor#(it);
static inline-class-member method E3|constructor#(self::C it) → self::E3 /* = self::C */ {
lowered final self::E3 /* = self::C */ #this = it;
return #this;
}
static inline-class-member method E3|constructor#_#new#tearOff(self::C it) → self::E3 /* = self::C */
return self::E3|constructor#(it);
static inline-class-member method E41|constructor#(self::A<Never> it) → self::E41 /* = self::A<Never> */ {
lowered final self::E41 /* = self::A<Never> */ #this = it;
return #this;
}
static inline-class-member method E41|constructor#_#new#tearOff(self::A<Never> it) → self::E41 /* = self::A<Never> */
return self::E41|constructor#(it);
static inline-class-member method E42|constructor#(self::A<Never> it) → self::E42 /* = self::A<Never> */ {
lowered final self::E42 /* = self::A<Never> */ #this = it;
return #this;
}
static inline-class-member method E42|constructor#_#new#tearOff(self::A<Never> it) → self::E42 /* = self::A<Never> */
return self::E42|constructor#(it);
static inline-class-member method E5|constructor#(self::E<Never> /* = Never */ it) → self::E5 /* = Never */ {
lowered final self::E5 /* = Never */ #this = it;
return #this;
}
static inline-class-member method E5|constructor#_#new#tearOff(self::E<Never> /* = Never */ it) → self::E5 /* = Never */
return self::E5|constructor#(it);
static inline-class-member method E61|constructor#(self::E<Never> /* = Never */ it) → self::E61 /* = Never */ {
lowered final self::E61 /* = Never */ #this = it;
return #this;
}
static inline-class-member method E61|constructor#_#new#tearOff(self::E<Never> /* = Never */ it) → self::E61 /* = Never */
return self::E61|constructor#(it);
static inline-class-member method E62|constructor#(self::E<Never> /* = Never */ it) → self::E62 /* = Never */ {
lowered final self::E62 /* = Never */ #this = it;
return #this;
}
static inline-class-member method E62|constructor#_#new#tearOff(self::E<Never> /* = Never */ it) → self::E62 /* = Never */
return self::E62|constructor#(it);
static inline-class-member method E71|constructor#(self::E<Never> /* = Never */ it) → self::E71 /* = Never */ {
lowered final self::E71 /* = Never */ #this = it;
return #this;
}
static inline-class-member method E71|constructor#_#new#tearOff(self::E<Never> /* = Never */ it) → self::E71 /* = Never */
return self::E71|constructor#(it);
static inline-class-member method E72|constructor#(self::E<Never> /* = Never */ it) → self::E72 /* = Never */ {
lowered final self::E72 /* = Never */ #this = it;
return #this;
}
static inline-class-member method E72|constructor#_#new#tearOff(self::E<Never> /* = Never */ it) → self::E72 /* = Never */
return self::E72|constructor#(it);
static inline-class-member method E73|constructor#(self::E<Never> /* = Never */ it) → self::E73 /* = Never */ {
lowered final self::E73 /* = Never */ #this = it;
return #this;
}
static inline-class-member method E73|constructor#_#new#tearOff(self::E<Never> /* = Never */ it) → self::E73 /* = Never */
return self::E73|constructor#(it);
Loading

0 comments on commit 2ea55d4

Please sign in to comment.