Skip to content

Commit 6c9873b

Browse files
kallentuCommit Queue
authored andcommitted
[cfe] Report error when using a class as a mixin when sealed-class is enabled.
From the changes in dart-lang/language#2674 that specify from a certain language version, we would like classes to not be used as mixins unless specified as a 'mixin class'. Currently, this behaviour is under the sealed-class flag. May be subject to change as the other modifiers are added, but I'd at least like to make sure this works for sealed classes. Change-Id: I5754b383327dde06d49175fe2d05c8ba7462145f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/273082 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Kallen Tu <[email protected]>
1 parent 70b994e commit 6c9873b

22 files changed

+1096
-42
lines changed

pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,27 @@ Message _withArgumentsCantReadFile(Uri uri_, String string) {
905905
arguments: {'uri': uri_, 'string': string});
906906
}
907907

908+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
909+
const Template<Message Function(String name)> templateCantUseClassAsMixin =
910+
const Template<Message Function(String name)>(
911+
problemMessageTemplate: r"""Class '#name' can't be used as a mixin.""",
912+
withArguments: _withArgumentsCantUseClassAsMixin);
913+
914+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
915+
const Code<Message Function(String name)> codeCantUseClassAsMixin =
916+
const Code<Message Function(String name)>(
917+
"CantUseClassAsMixin",
918+
);
919+
920+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
921+
Message _withArgumentsCantUseClassAsMixin(String name) {
922+
if (name.isEmpty) throw 'No name provided';
923+
name = demangleMixinApplicationName(name);
924+
return new Message(codeCantUseClassAsMixin,
925+
problemMessage: """Class '${name}' can't be used as a mixin.""",
926+
arguments: {'name': name});
927+
}
928+
908929
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
909930
const Template<Message Function(Token token)>
910931
templateCantUseControlFlowOrSpreadAsConstant =

pkg/front_end/lib/src/fasta/source/source_loader.dart

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2069,44 +2069,60 @@ severity: $severity
20692069
noLength);
20702070
}
20712071
} else if (supertype is ClassBuilder &&
2072-
supertype.isSealed &&
2073-
supertype.libraryBuilder.origin != cls.libraryBuilder.origin) {
2074-
// If the class is a mixin declaration with an `on` clause which is the
2075-
// supertype we are evaluating right now, we want to avoid reporting an
2076-
// error.
2077-
bool superTypeIsOnClause = false;
2078-
if (cls.cls.isAnonymousMixin && !cls.cls.isEliminatedMixin) {
2079-
// The class has multiple 'on' clauses.
2080-
List<TypeBuilder>? classInterfaces = cls.interfaceBuilders;
2081-
if (classInterfaces != null) {
2082-
for (TypeBuilder interface in classInterfaces) {
2083-
if (interface.declaration == supertype) {
2084-
superTypeIsOnClause = true;
2085-
break;
2072+
cls.libraryBuilder.libraryFeatures.sealedClass.isEnabled) {
2073+
// Check for implicit class mixins.
2074+
TypeBuilder? mixedInType = cls.mixedInTypeBuilder;
2075+
if (cls.isMixinApplication &&
2076+
mixedInType != null &&
2077+
mixedInType.declaration == supertype &&
2078+
!supertype.isMixinDeclaration) {
2079+
cls.addProblem(
2080+
templateCantUseClassAsMixin
2081+
.withArguments(supertype.fullNameForErrors),
2082+
cls.charOffset,
2083+
noLength);
2084+
}
2085+
2086+
// Report error for subtyping outside of sealed supertype's library.
2087+
if (supertype.isSealed &&
2088+
supertype.libraryBuilder.origin != cls.libraryBuilder.origin) {
2089+
// If the class is a mixin declaration with an `on` clause which is
2090+
// the supertype we are evaluating right now, we want to avoid
2091+
// reporting an error.
2092+
bool superTypeIsOnClause = false;
2093+
if (cls.cls.isAnonymousMixin && !cls.cls.isEliminatedMixin) {
2094+
// The class has multiple 'on' clauses.
2095+
List<TypeBuilder>? classInterfaces = cls.interfaceBuilders;
2096+
if (classInterfaces != null) {
2097+
for (TypeBuilder interface in classInterfaces) {
2098+
if (interface.declaration == supertype) {
2099+
superTypeIsOnClause = true;
2100+
break;
2101+
}
20862102
}
20872103
}
2104+
} else if (cls.isMixinDeclaration) {
2105+
// The class has up to one 'on' clause.
2106+
TypeBuilder? classSuperType = cls.supertypeBuilder;
2107+
if (classSuperType != null &&
2108+
classSuperType.declaration == supertype) {
2109+
superTypeIsOnClause = true;
2110+
}
20882111
}
2089-
} else if (cls.isMixinDeclaration) {
2090-
// The class has up to one 'on' clause.
2091-
TypeBuilder? classSuperType = cls.supertypeBuilder;
2092-
if (classSuperType != null &&
2093-
classSuperType.declaration == supertype) {
2094-
superTypeIsOnClause = true;
2095-
}
2096-
}
2097-
if (!superTypeIsOnClause) {
2098-
if (supertype.isMixinDeclaration) {
2099-
cls.addProblem(
2100-
templateSealedMixinSubtypeOutsideOfLibrary
2101-
.withArguments(supertype.fullNameForErrors),
2102-
cls.charOffset,
2103-
noLength);
2104-
} else {
2105-
cls.addProblem(
2106-
templateSealedClassSubtypeOutsideOfLibrary
2107-
.withArguments(supertype.fullNameForErrors),
2108-
cls.charOffset,
2109-
noLength);
2112+
if (!superTypeIsOnClause) {
2113+
if (supertype.isMixinDeclaration) {
2114+
cls.addProblem(
2115+
templateSealedMixinSubtypeOutsideOfLibrary
2116+
.withArguments(supertype.fullNameForErrors),
2117+
cls.charOffset,
2118+
noLength);
2119+
} else {
2120+
cls.addProblem(
2121+
templateSealedClassSubtypeOutsideOfLibrary
2122+
.withArguments(supertype.fullNameForErrors),
2123+
cls.charOffset,
2124+
noLength);
2125+
}
21102126
}
21112127
}
21122128
}

pkg/front_end/messages.status

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ CantInferPackagesFromPackageUri/analyzerCode: Fail
6464
CantInferPackagesFromPackageUri/example: Fail
6565
CantInferTypeDueToCircularity/example: Fail
6666
CantReadFile/part_wrapped_script: Fail # Importing file in the (now) part.
67+
CantUseClassAsMixin/analyzerCode: Fail
6768
CantUseControlFlowOrSpreadAsConstant/example: Fail
6869
CantUseDeferredPrefixAsConstant/part_wrapped_script: Fail # Importing file in the (now) part.
6970
CantUsePrefixAsExpression/part_wrapped_script: Fail # Importing file in the (now) part.

pkg/front_end/messages.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6021,3 +6021,10 @@ SealedMixinSubtypeOutsideOfLibrary:
60216021
class B with M {}
60226022
lib.dart:
60236023
sealed mixin M {}
6024+
6025+
CantUseClassAsMixin:
6026+
problemMessage: "Class '#name' can't be used as a mixin."
6027+
experiments: sealed-class
6028+
script: |
6029+
class A {}
6030+
class B with A {}

pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart.strong.expect

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ library /*isNonNullableByDefault*/;
1010
// class Class2 implements Sealed {}
1111
// ^
1212
//
13+
// pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart:11:7: Error: Class 'Sealed' can't be used as a mixin.
14+
// class Class3 with Sealed {}
15+
// ^
16+
//
1317
// pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart:11:7: Error: Sealed class 'Sealed' can't be extended, implemented, or mixed in outside of its library.
1418
// class Class3 with Sealed {}
1519
// ^

pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart.strong.transformed.expect

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ library /*isNonNullableByDefault*/;
1010
// class Class2 implements Sealed {}
1111
// ^
1212
//
13+
// pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart:11:7: Error: Class 'Sealed' can't be used as a mixin.
14+
// class Class3 with Sealed {}
15+
// ^
16+
//
1317
// pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart:11:7: Error: Sealed class 'Sealed' can't be extended, implemented, or mixed in outside of its library.
1418
// class Class3 with Sealed {}
1519
// ^

pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart.weak.expect

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ library /*isNonNullableByDefault*/;
1010
// class Class2 implements Sealed {}
1111
// ^
1212
//
13+
// pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart:11:7: Error: Class 'Sealed' can't be used as a mixin.
14+
// class Class3 with Sealed {}
15+
// ^
16+
//
1317
// pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart:11:7: Error: Sealed class 'Sealed' can't be extended, implemented, or mixed in outside of its library.
1418
// class Class3 with Sealed {}
1519
// ^

pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart.weak.modular.expect

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ library /*isNonNullableByDefault*/;
1010
// class Class2 implements Sealed {}
1111
// ^
1212
//
13+
// pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart:11:7: Error: Class 'Sealed' can't be used as a mixin.
14+
// class Class3 with Sealed {}
15+
// ^
16+
//
1317
// pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart:11:7: Error: Sealed class 'Sealed' can't be extended, implemented, or mixed in outside of its library.
1418
// class Class3 with Sealed {}
1519
// ^

pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart.weak.outline.expect

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ library /*isNonNullableByDefault*/;
1010
// class Class2 implements Sealed {}
1111
// ^
1212
//
13+
// pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart:11:7: Error: Class 'Sealed' can't be used as a mixin.
14+
// class Class3 with Sealed {}
15+
// ^
16+
//
1317
// pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart:11:7: Error: Sealed class 'Sealed' can't be extended, implemented, or mixed in outside of its library.
1418
// class Class3 with Sealed {}
1519
// ^

pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart.weak.transformed.expect

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ library /*isNonNullableByDefault*/;
1010
// class Class2 implements Sealed {}
1111
// ^
1212
//
13+
// pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart:11:7: Error: Class 'Sealed' can't be used as a mixin.
14+
// class Class3 with Sealed {}
15+
// ^
16+
//
1317
// pkg/front_end/testcases/sealed_class/extends_implements_with/main.dart:11:7: Error: Sealed class 'Sealed' can't be extended, implemented, or mixed in outside of its library.
1418
// class Class3 with Sealed {}
1519
// ^

0 commit comments

Comments
 (0)