[analyzer] Avoid reporting subtype modifier errors on final supertypes outside of library.

Change-Id: If4fba1c08d7dc9d4f65ea56760298e47c65742fa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/287340
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Kallen Tu <kallentu@google.com>
This commit is contained in:
Kallen Tu 2023-03-09 18:09:34 +00:00 committed by Commit Queue
parent d029b866f4
commit 919eb05b27
14 changed files with 691 additions and 727 deletions

View file

@ -1059,7 +1059,9 @@ CompileTimeErrorCode.SPREAD_EXPRESSION_FROM_DEFERRED_LIBRARY:
status: needsEvaluation
CompileTimeErrorCode.STATIC_ACCESS_TO_INSTANCE_MEMBER:
status: needsEvaluation
CompileTimeErrorCode.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED:
CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED:
status: needsEvaluation
CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED:
status: needsEvaluation
CompileTimeErrorCode.SUPER_FORMAL_PARAMETER_TYPE_IS_NOT_SUBTYPE_OF_ASSOCIATED:
status: hasFix

View file

@ -4,7 +4,6 @@
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/src/dart/error/ffi_code.g.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@ -55,13 +54,9 @@ class ExtendsDisallowedClassTest extends FixProcessorTest {
await resolveTestCode('''
class C extends String {}
''');
await assertHasFix(
'''
await assertHasFix('''
class C {}
''',
errorFilter: (error) =>
error.errorCode == CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
);
''');
}
}
@ -106,26 +101,18 @@ class ImplementsDisallowedClassTest extends FixProcessorTest {
await resolveTestCode('''
class C implements String {}
''');
await assertHasFix(
'''
await assertHasFix('''
class C {}
''',
errorFilter: (error) =>
error.errorCode == CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS,
);
''');
}
Future<void> test_twoNames() async {
await resolveTestCode('''
abstract class C implements String, List<int> {}
''');
await assertHasFix(
'''
await assertHasFix('''
abstract class C implements List<int> {}
''',
errorFilter: (error) =>
error.errorCode == CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS,
);
''');
}
}
@ -189,13 +176,9 @@ class MixinOfDisallowedClassTest extends FixProcessorTest {
await resolveTestCode('''
abstract class C with String {}
''');
await assertHasFix(
'''
await assertHasFix('''
abstract class C {}
''',
errorFilter: (error) =>
error.errorCode == CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS,
);
''');
}
}

View file

@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/diagnostic/diagnostic.dart';
@ -11,7 +10,6 @@ import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/diagnostic/diagnostic.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/utilities/extensions/collection.dart';
/// Helper for verifying that subelements of a base or final element must be
/// base, final, or sealed.
@ -33,8 +31,8 @@ class BaseOrFinalTypeVerifier {
/// Check to ensure the subelement of a base or final element must be base,
/// final, or sealed. Otherwise, an error is reported on that element.
///
/// See [CompileTimeErrorCode.
/// SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED]
/// See [CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED],
/// [CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED]
void checkElement(ClassOrMixinElementImpl element) {
if (_elementToBaseOrFinalSuperElement.containsKey(element)) {
// We've already visited this element. Don't check it again.
@ -43,14 +41,29 @@ class BaseOrFinalTypeVerifier {
_elementToBaseOrFinalSuperElement[element] = null;
}
List<InterfaceType> supertypes = [];
supertypes.addIfNotNull(element.supertype);
supertypes.addAll(element.interfaces);
supertypes.addAll(element.mixins);
if (element is MixinElementImpl) {
supertypes.addAll(element.superclassConstraints);
final supertype = element.supertype;
if (supertype != null && _checkSupertypes([supertype], element)) {
return;
}
if (_checkSupertypes(element.interfaces, element)) {
return;
}
if (_checkSupertypes(element.mixins, element)) {
return;
}
if (_checkSupertypes(element.interfaces, element)) {
return;
}
if (element is MixinElementImpl &&
_checkSupertypes(element.superclassConstraints, element,
areSuperclassConstraints: true)) {
return;
}
}
bool _checkSupertypes(
List<InterfaceType> supertypes, ClassOrMixinElementImpl subElement,
{bool areSuperclassConstraints = false}) {
for (final supertype in supertypes) {
final supertypeElement = supertype.element;
if (supertypeElement is ClassOrMixinElementImpl) {
@ -60,11 +73,13 @@ class BaseOrFinalTypeVerifier {
// Return early if an error has been reported to prevent reporting
// multiple errors on one element.
if (_reportRestrictionError(element, supertypeElement)) {
return;
if (_reportRestrictionError(subElement, supertypeElement,
isSuperclassConstraint: areSuperclassConstraints)) {
return true;
}
}
}
return false;
}
/// Checks whether a `final`, `base` or `interface` modifier can be ignored.
@ -91,7 +106,8 @@ class BaseOrFinalTypeVerifier {
///
/// Reports an error based on the modifier of the superElement.
bool _reportRestrictionError(
ClassOrMixinElementImpl element, ClassOrMixinElementImpl superElement) {
ClassOrMixinElementImpl element, ClassOrMixinElementImpl superElement,
{bool isSuperclassConstraint = false}) {
final cachedBaseOrFinalSuperElement =
_elementToBaseOrFinalSuperElement[superElement];
final hasCachedBaseOrFinalSuperElement =
@ -133,19 +149,28 @@ class BaseOrFinalTypeVerifier {
)
];
_errorReporter.reportErrorForElement(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
element,
[
element.displayName,
baseOrFinalSuperElement.displayName,
baseOrFinalSuperElement.isBase
? Keyword.BASE.lexeme
: Keyword.FINAL.lexeme
],
hasCachedBaseOrFinalSuperElement ? contextMessage : null);
return true;
if (baseOrFinalSuperElement.isFinal) {
if (!isSuperclassConstraint &&
baseOrFinalSuperElement.library != element.library) {
// If you can't extend, implement or mix in a final element outside of
// its library anyways, it's not helpful to report a subelement
// modifier error.
return false;
}
_errorReporter.reportErrorForElement(
CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
element,
[element.displayName, baseOrFinalSuperElement.displayName],
hasCachedBaseOrFinalSuperElement ? contextMessage : null);
return true;
} else if (baseOrFinalSuperElement.isBase) {
_errorReporter.reportErrorForElement(
CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
element,
[element.displayName, baseOrFinalSuperElement.displayName],
hasCachedBaseOrFinalSuperElement ? contextMessage : null);
return true;
}
}
return false;

View file

@ -4449,14 +4449,24 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
/// Parameters:
/// 0: the name of the subtype that is not 'base', 'final', or 'sealed'
/// 1: the name of the supertype which is 'base' or 'final'
/// 2: the modifier on the supertype
/// 1: the name of the 'base' supertype
static const CompileTimeErrorCode
SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED =
CompileTimeErrorCode(
SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED = CompileTimeErrorCode(
'SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED',
"The type '{0}' must be 'base', 'final' or 'sealed' because the supertype "
"'{1}' is '{2}'.",
"'{1}' is 'base'.",
uniqueName: 'SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED',
);
/// Parameters:
/// 0: the name of the subtype that is not 'base', 'final', or 'sealed'
/// 1: the name of the 'final' supertype
static const CompileTimeErrorCode
SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED = CompileTimeErrorCode(
'SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED',
"The type '{0}' must be 'base', 'final' or 'sealed' because the supertype "
"'{1}' is 'final'.",
uniqueName: 'SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED',
);
/// Parameters:

View file

@ -451,7 +451,8 @@ const List<ErrorCode> errorCodeValues = [
CompileTimeErrorCode.SHARED_DEFERRED_PREFIX,
CompileTimeErrorCode.SPREAD_EXPRESSION_FROM_DEFERRED_LIBRARY,
CompileTimeErrorCode.STATIC_ACCESS_TO_INSTANCE_MEMBER,
CompileTimeErrorCode.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
CompileTimeErrorCode.SUPER_FORMAL_PARAMETER_TYPE_IS_NOT_SUBTYPE_OF_ASSOCIATED,
CompileTimeErrorCode.SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_NAMED,
CompileTimeErrorCode.SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_POSITIONAL,

View file

@ -12902,13 +12902,20 @@ CompileTimeErrorCode:
int f(C c) => c.b;
```
SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED:
problemMessage: "The type '{0}' must be 'base', 'final' or 'sealed' because the supertype '{1}' is '{2}'."
SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED:
sharedName: SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED
problemMessage: "The type '{0}' must be 'base', 'final' or 'sealed' because the supertype '{1}' is 'base'."
comment: |-
Parameters:
0: the name of the subtype that is not 'base', 'final', or 'sealed'
1: the name of the supertype which is 'base' or 'final'
2: the modifier on the supertype
1: the name of the 'base' supertype
SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED:
sharedName: SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED
problemMessage: "The type '{0}' must be 'base', 'final' or 'sealed' because the supertype '{1}' is 'final'."
comment: |-
Parameters:
0: the name of the subtype that is not 'base', 'final', or 'sealed'
1: the name of the 'final' supertype
SUPER_FORMAL_PARAMETER_TYPE_IS_NOT_SUBTYPE_OF_ASSOCIATED:
problemMessage: The type '{0}' of this parameter isn't a subtype of the type '{1}' of the associated super constructor parameter.
correctionMessage: Try removing the explicit type annotation from the parameter.

View file

@ -19,11 +19,6 @@ class ExtendsDisallowedClassTest extends PubPackageResolutionTest {
await assertErrorsInCode('''
class A extends bool {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS, 16, 4),
]);
}
@ -32,11 +27,6 @@ class A extends bool {}
await assertErrorsInCode('''
class A extends double {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS, 16, 6),
]);
}
@ -82,11 +72,6 @@ class A<T> extends FutureOr<T> {}
await assertErrorsInCode('''
class A extends int {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS, 16, 3),
]);
}
@ -111,11 +96,6 @@ class A extends num {}
await assertErrorsInCode('''
class A extends Record {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS, 16, 6),
]);
}
@ -124,11 +104,6 @@ class A extends Record {}
await assertErrorsInCode('''
class A extends String {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS, 16, 6),
]);
}

View file

@ -19,11 +19,6 @@ class ImplementsDisallowedClassTest extends PubPackageResolutionTest {
await assertErrorsInCode('''
class A implements bool {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 4),
]);
}
@ -56,11 +51,6 @@ class A implements Enum {}
await assertErrorsInCode('''
class A implements double {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 6),
]);
}
@ -106,11 +96,6 @@ class A<T> implements FutureOr<T> {}
await assertErrorsInCode('''
class A implements int {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 3),
]);
}
@ -135,11 +120,6 @@ class A implements num {}
await assertErrorsInCode('''
class A implements Record {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 6),
]);
}
@ -148,11 +128,6 @@ class A implements Record {}
await assertErrorsInCode('''
class A implements String {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 6),
]);
}
@ -161,11 +136,6 @@ class A implements String {}
await assertErrorsInCode('''
class A implements String, num {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 6),
error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 27, 3),
]);
@ -309,11 +279,6 @@ mixin M implements Enum {}
await assertErrorsInCode(r'''
mixin M implements int {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 3),
]);

View file

@ -19,11 +19,6 @@ class MixinOfDisallowedClassTest extends PubPackageResolutionTest {
await assertErrorsInCode('''
class A extends Object with bool {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS, 28, 4),
]);
}
@ -32,11 +27,6 @@ class A extends Object with bool {}
await assertErrorsInCode('''
class A extends Object with double {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS, 28, 6),
]);
}
@ -72,11 +62,6 @@ class A<T> extends Object with FutureOr<T> {}
await assertErrorsInCode('''
class A extends Object with int {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS, 28, 3),
]);
}
@ -101,11 +86,6 @@ class A extends Object with num {}
await assertErrorsInCode('''
class A extends Object with Record {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS, 28, 6),
]);
}
@ -114,11 +94,6 @@ class A extends Object with Record {}
await assertErrorsInCode('''
class A extends Object with String {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS, 28, 6),
]);
}

View file

@ -46,11 +46,8 @@ mixin M on Enum {}
await assertErrorsInCode(r'''
mixin M on int {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1),
error(CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6, 1),
error(CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_DISALLOWED_CLASS,
11, 3),
]);

View file

@ -0,0 +1,352 @@
// 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.
import 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../generated/test_support.dart';
import '../dart/resolution/context_collection_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(SubtypeOfBaseIsNotBaseFinalOrSealedTest);
});
}
@reflectiveTest
class SubtypeOfBaseIsNotBaseFinalOrSealedTest extends PubPackageResolutionTest {
test_class_extends() async {
await assertErrorsInCode(r'''
base class A {}
class B extends A {}
''', [
error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
22, 1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_class_extends_multiple() async {
await assertErrorsInCode(r'''
base class A {}
base class B extends A {}
class C extends A {}
''', [
error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
48, 1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_class_extends_multiple_files() async {
final a = newFile('$testPackageLibPath/a.dart', r'''
base class A {}
class B extends A {}
''');
await assertErrorsInFile2(a.path, [
error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
22, 1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
await assertErrorsInCode(r'''
import 'a.dart';
class C extends B {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
23,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage(a.path, 22, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_extends_outside() async {
newFile('$testPackageLibPath/a.dart', r'''
base class A {}
''');
await assertErrorsInCode(r'''
import 'a.dart';
class B extends A {}
''', [
error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
23, 1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_class_implements() async {
await assertErrorsInCode(r'''
base class A {}
class B implements A {}
''', [
error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
22, 1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_class_mixin_mixedIn() async {
await assertErrorsInCode(r'''
base mixin class A {}
class B with A {}
''', [
error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
28, 1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_class_mixin_mixedIn_outside() async {
newFile('$testPackageLibPath/a.dart', r'''
base mixin class A {}
''');
await assertErrorsInCode(r'''
import 'a.dart';
class B with A {}
''', [
error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
23, 1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_class_sealed_extends() async {
await assertErrorsInCode(r'''
base class A {}
sealed class B extends A {}
class C extends B {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
50,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 29, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_extends_multiple() async {
await assertErrorsInCode(r'''
base class A {}
sealed class B extends A {}
sealed class C extends B {}
class D extends C {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
78,
1,
text:
"The type 'D' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 57, 1,
text:
"The type 'C' is a subtype of 'A', and 'C' is defined here.")
],
),
]);
}
test_class_sealed_extends_outside() async {
newFile('$testPackageLibPath/a.dart', r'''
base class A {}
''');
await assertErrorsInCode(r'''
import 'a.dart';
sealed class B extends A {}
class C extends B {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
51,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 30, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_extends_unordered() async {
await assertErrorsInCode(r'''
class C extends B {}
sealed class B extends A {}
base class A {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 34, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_implements() async {
await assertErrorsInCode(r'''
base class A {}
sealed class B implements A {}
class C implements B {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
53,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 29, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_mixin_mixedIn() async {
await assertErrorsInCode(r'''
base mixin class A {}
sealed class B with A {}
class C extends B {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
53,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 35, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_mixin_mixedIn_outside() async {
newFile('$testPackageLibPath/a.dart', r'''
base mixin class A {}
''');
await assertErrorsInCode(r'''
import 'a.dart';
sealed class B with A {}
class C extends B {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
48,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 30, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_mixin_implements() async {
await assertErrorsInCode(r'''
base class A {}
mixin B implements A {}
''', [
error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
22, 1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_mixin_on() async {
await assertErrorsInCode(r'''
base class A {}
mixin B on A {}
''', [
error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
22, 1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_mixin_sealed_implements() async {
await assertErrorsInCode(r'''
base class A {}
sealed mixin B implements A {}
mixin C implements B {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
53,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 29, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_mixin_sealed_on() async {
await assertErrorsInCode(r'''
base class A {}
sealed mixin B on A {}
mixin C on B {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED,
45,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 29, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
}

View file

@ -1,572 +0,0 @@
// 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.
import 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../generated/test_support.dart';
import '../dart/resolution/context_collection_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(SubtypeOfBaseOrFinalIsNotBaseFinalOrSealedTest);
});
}
@reflectiveTest
class SubtypeOfBaseOrFinalIsNotBaseFinalOrSealedTest
extends PubPackageResolutionTest {
test_class_base_extends() async {
await assertErrorsInCode(r'''
base class A {}
class B extends A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
22,
1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_class_base_extends_multiple() async {
await assertErrorsInCode(r'''
base class A {}
base class B extends A {}
class C extends A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
48,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_class_base_extends_multiple_files() async {
await assertErrorsInFile(
resourceProvider.convertPath('$testPackageLibPath/a.dart'), r'''
base class A {}
class B extends A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
22,
1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
await assertErrorsInFile(
resourceProvider.convertPath('$testPackageLibPath/c.dart'), r'''
import 'a.dart';
class C extends B {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
23,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/a.dart', 22, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
await assertErrorsInCode(r'''
import 'a.dart';
class D extends B {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
23,
1,
text:
"The type 'D' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/a.dart', 22, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_base_extends_outside() async {
newFile('$testPackageLibPath/foo.dart', r'''
base class A {}
''');
await assertErrorsInCode(r'''
import 'foo.dart';
class B extends A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
25,
1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_class_base_implements() async {
await assertErrorsInCode(r'''
base class A {}
class B implements A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
22,
1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_class_base_mixin_mixedIn() async {
await assertErrorsInCode(r'''
base mixin class A {}
class B with A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
28,
1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_class_base_mixin_mixedIn_outside() async {
newFile('$testPackageLibPath/foo.dart', r'''
base mixin class A {}
''');
await assertErrorsInCode(r'''
import 'foo.dart';
class B with A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
25,
1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_class_base_multiple() async {
await assertErrorsInCode(r'''
base class A {}
final class B {}
class C extends B implements A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
39,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'B' is 'final'."),
]);
}
test_class_final_extends() async {
await assertErrorsInCode(r'''
final class A {}
class B extends A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
23,
1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."),
]);
}
test_class_final_implements() async {
await assertErrorsInCode(r'''
final class A {}
class B implements A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
23,
1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."),
]);
}
test_class_sealed_base_extends() async {
await assertErrorsInCode(r'''
base class A {}
sealed class B extends A {}
class C extends B {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
50,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/test.dart', 29, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_base_extends_multiple() async {
await assertErrorsInCode(r'''
base class A {}
sealed class B extends A {}
sealed class C extends B {}
class D extends C {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
78,
1,
text:
"The type 'D' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/test.dart', 57, 1,
text:
"The type 'C' is a subtype of 'A', and 'C' is defined here.")
],
),
]);
}
test_class_sealed_base_extends_outside() async {
newFile('$testPackageLibPath/foo.dart', r'''
base class A {}
''');
await assertErrorsInCode(r'''
import 'foo.dart';
sealed class B extends A {}
class C extends B {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
53,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/test.dart', 32, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_base_extends_unordered() async {
await assertErrorsInCode(r'''
class C extends B {}
sealed class B extends A {}
base class A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/test.dart', 34, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_base_implements() async {
await assertErrorsInCode(r'''
base class A {}
sealed class B implements A {}
class C implements B {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
53,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/test.dart', 29, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_base_mixin_mixedIn() async {
await assertErrorsInCode(r'''
base mixin class A {}
sealed class B with A {}
class C extends B {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
53,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/test.dart', 35, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_base_mixin_mixedIn_outside() async {
newFile('$testPackageLibPath/foo.dart', r'''
base mixin class A {}
''');
await assertErrorsInCode(r'''
import 'foo.dart';
sealed class B with A {}
class C extends B {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
50,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/test.dart', 32, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_final_extends() async {
await assertErrorsInCode(r'''
final class A {}
sealed class B extends A {}
class C extends B {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
51,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/test.dart', 30, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_final_implements() async {
await assertErrorsInCode(r'''
final class A {}
sealed class B implements A {}
class C implements B {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
54,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/test.dart', 30, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_mixin_base_implements() async {
await assertErrorsInCode(r'''
base class A {}
mixin B implements A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
22,
1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_mixin_base_on() async {
await assertErrorsInCode(r'''
base class A {}
mixin B on A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
22,
1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."),
]);
}
test_mixin_final_implements() async {
await assertErrorsInCode(r'''
final class A {}
mixin B implements A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
23,
1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."),
]);
}
test_mixin_final_on() async {
await assertErrorsInCode(r'''
final class A {}
mixin B on A {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
23,
1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."),
]);
}
test_mixin_sealed_base_implements() async {
await assertErrorsInCode(r'''
base class A {}
sealed mixin B implements A {}
mixin C implements B {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
53,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/test.dart', 29, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_mixin_sealed_base_on() async {
await assertErrorsInCode(r'''
base class A {}
sealed mixin B on A {}
mixin C on B {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
45,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/test.dart', 29, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_mixin_sealed_final_implements() async {
await assertErrorsInCode(r'''
final class A {}
sealed mixin B implements A {}
mixin C implements B {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
54,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/test.dart', 30, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_mixin_sealed_final_on() async {
await assertErrorsInCode(r'''
final class A {}
sealed mixin B on A {}
mixin C on B {}
''', [
error(
CompileTimeErrorCode
.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
46,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.",
contextMessages: [
ExpectedContextMessage('/home/test/lib/test.dart', 30, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
}

View file

@ -0,0 +1,241 @@
// 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.
import 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../generated/test_support.dart';
import '../dart/resolution/context_collection_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(SubtypeOfFinalIsNotBaseFinalOrSealedTest);
});
}
@reflectiveTest
class SubtypeOfFinalIsNotBaseFinalOrSealedTest
extends PubPackageResolutionTest {
test_class_extends() async {
await assertErrorsInCode(r'''
final class A {}
class B extends A {}
''', [
error(CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
23, 1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."),
]);
}
test_class_implements() async {
await assertErrorsInCode(r'''
final class A {}
class B implements A {}
''', [
error(CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
23, 1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."),
]);
}
test_class_outside() async {
// No [SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED] reported outside of
// library.
newFile('$testPackageLibPath/a.dart', r'''
final class A {}
''');
await assertErrorsInCode(r'''
import 'a.dart';
class B extends A {}
''', [
error(
CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY, 33, 1),
]);
}
test_class_outside_on() async {
newFile('$testPackageLibPath/a.dart', r'''
final mixin A {}
''');
await assertErrorsInCode(r'''
import 'a.dart';
mixin B on A {}
''', [
error(CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
23, 1),
]);
}
test_class_sealed_extends() async {
await assertErrorsInCode(r'''
final class A {}
sealed class B extends A {}
class C extends B {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
51,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 30, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_extends_multiple() async {
await assertErrorsInCode(r'''
final class A {}
sealed class B extends A {}
sealed class C extends B {}
class D extends C {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
79,
1,
text:
"The type 'D' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 58, 1,
text:
"The type 'C' is a subtype of 'A', and 'C' is defined here.")
],
),
]);
}
test_class_sealed_extends_outside() async {
// No [SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED] reported outside of
// library.
newFile('$testPackageLibPath/a.dart', r'''
final class A {}
''');
await assertErrorsInCode(r'''
import 'a.dart';
sealed class B extends A {}
class C extends B {}
''', [
error(
CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY, 40, 1),
]);
}
test_class_sealed_extends_unordered() async {
await assertErrorsInCode(r'''
class C extends B {}
sealed class B extends A {}
final class A {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
6,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 34, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_class_sealed_implements() async {
await assertErrorsInCode(r'''
final class A {}
sealed class B implements A {}
class C implements B {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
54,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 30, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_mixin_implements() async {
await assertErrorsInCode(r'''
final class A {}
mixin B implements A {}
''', [
error(CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
23, 1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."),
]);
}
test_mixin_on() async {
await assertErrorsInCode(r'''
final class A {}
mixin B on A {}
''', [
error(CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
23, 1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."),
]);
}
test_mixin_sealed_implements() async {
await assertErrorsInCode(r'''
final class A {}
sealed mixin B implements A {}
mixin C implements B {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
54,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 30, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
test_mixin_sealed_on() async {
await assertErrorsInCode(r'''
final class A {}
sealed mixin B on A {}
mixin C on B {}
''', [
error(
CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED,
46,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.",
contextMessages: [
ExpectedContextMessage(testFile.path, 30, 1,
text:
"The type 'B' is a subtype of 'A', and 'B' is defined here.")
],
),
]);
}
}

View file

@ -741,9 +741,11 @@ import 'spread_expression_from_deferred_library_test.dart'
import 'static_access_to_instance_member_test.dart'
as static_access_to_instance_member;
import 'strict_raw_type_test.dart' as strict_raw_type;
import 'subtype_of_base_or_final_is_not_base_final_or_sealed_test.dart'
as subtype_of_base_or_final_is_not_base_final_or_sealed;
import 'subtype_of_base_is_not_base_final_or_sealed_test.dart'
as subtype_of_base_is_not_base_final_or_sealed;
import 'subtype_of_ffi_class_test.dart' as subtype_of_ffi_class;
import 'subtype_of_final_is_not_base_final_or_sealed_test.dart'
as subtype_of_final_is_not_base_final_or_sealed;
import 'subtype_of_sealed_class_test.dart' as subtype_of_sealed_class;
import 'subtype_of_struct_class_test.dart' as subtype_of_struct_class;
import 'super_formal_parameter_type_is_not_subtype_of_associated_test.dart'
@ -1353,8 +1355,9 @@ main() {
spread_expression_from_deferred_library.main();
static_access_to_instance_member.main();
strict_raw_type.main();
subtype_of_base_or_final_is_not_base_final_or_sealed.main();
subtype_of_base_is_not_base_final_or_sealed.main();
subtype_of_ffi_class.main();
subtype_of_final_is_not_base_final_or_sealed.main();
subtype_of_sealed_class.main();
subtype_of_struct_class.main();
super_formal_parameter_type_is_not_subtype_of_associated.main();