Checks whether an interface is implemented multiple times.

It is a compile-time error if an interface appears multiple times
across the extends and implements clauses.

This CL implements a check to detect the aforementioned case. A
previous commit implemented this by expanding and refactoring the
restricted super types check in source_loader.dart
(c.f. checkSemantics method). The restricted super types check decides
whether a type is allowed to appear in an 'extends', 'implements', or
'with' clause. However, it turned out it may have sat too early in the
compilation pipeline as it failed to detect the following case

   class A implements Object {}

I decided that it was somewhat suboptimal to implement a special case
for "Object". Therefore I have moved the check to a later stage in the
pipeline, where classes without a super class have had the Object
class injected as their default super class. The check is now
implemented in kernel_class_builder.dart (c.f. checkSupertypes
method).

Closes https://github.com/dart-lang/sdk/issues/34193

Change-Id: Ie7153c896337b589118cac4b80e9df8ea5a09daa
Reviewed-on: https://dart-review.googlesource.com/70864
Commit-Queue: Daniel Hillerström <hillerstrom@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
This commit is contained in:
Daniel Hillerström
2018-08-23 14:36:40 +00:00
committed by commit-bot@chromium.org
parent b8ee603eb2
commit 23e379d0aa
12 changed files with 142 additions and 71 deletions
@@ -429,42 +429,12 @@ class CompileTimeErrorCodeTest_Kernel extends CompileTimeErrorCodeTest_Driver {
await super.test_implementsNonClass_typeAlias();
}
@override
@failingTest
test_implementsRepeated() async {
await super.test_implementsRepeated();
}
@override
@failingTest
test_implementsRepeated_3times() async {
await super.test_implementsRepeated_3times();
}
@override
@failingTest
test_implementsSuperClass() async {
await super.test_implementsSuperClass();
}
@override
@failingTest
test_implementsSuperClass_Object() async {
await super.test_implementsSuperClass_Object();
}
@override
@failingTest
test_implementsSuperClass_Object_typeAlias() async {
await super.test_implementsSuperClass_Object_typeAlias();
}
@override
@failingTest
test_implementsSuperClass_typeAlias() async {
await super.test_implementsSuperClass_typeAlias();
}
@override
@failingTest
test_implicitThisReferenceInInitializer_field() async {
@@ -3501,6 +3501,54 @@ const MessageCode messageImplementsBeforeWith = const MessageCode(
message: r"""The with clause must be before the implements clause.""",
tip: r"""Try moving the with clause before the implements clause.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String name, int count)>
templateImplementsRepeated =
const Template<Message Function(String name, int count)>(
messageTemplate: r"""'#name' can only be implemented once.""",
tipTemplate: r"""Try removing #count of the occurrences.""",
withArguments: _withArgumentsImplementsRepeated);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(String name, int count)> codeImplementsRepeated =
const Code<Message Function(String name, int count)>(
"ImplementsRepeated", templateImplementsRepeated,
analyzerCode: "IMPLEMENTS_REPEATED", dart2jsCode: "*fatal*");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsImplementsRepeated(String name, int count) {
return new Message(codeImplementsRepeated,
message: """'${name}' can only be implemented once.""",
tip: """Try removing ${count} of the occurrences.""",
arguments: {'name': name, 'count': count});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
String
name)> templateImplementsSuperClass = const Template<
Message Function(String name)>(
messageTemplate:
r"""'#name' can't be used in both 'extends' and 'implements' clauses.""",
tipTemplate: r"""Try removing one of the occurrences.""",
withArguments: _withArgumentsImplementsSuperClass);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(String name)> codeImplementsSuperClass =
const Code<Message Function(String name)>(
"ImplementsSuperClass", templateImplementsSuperClass,
analyzerCode: "IMPLEMENTS_SUPER_CLASS", dart2jsCode: "*fatal*");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsImplementsSuperClass(String name) {
return new Message(codeImplementsSuperClass,
message:
"""'${name}' can't be used in both 'extends' and 'implements' clauses.""",
tip: """Try removing one of the occurrences.""",
arguments: {'name': name});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
@@ -52,6 +52,8 @@ import '../fasta_codes.dart'
messagePatchDeclarationMismatch,
messagePatchDeclarationOrigin,
noLength,
templateImplementsRepeated,
templateImplementsSuperClass,
templateMissingImplementationCause,
templateMissingImplementationNotAbstract,
templateOverriddenMethodCause,
@@ -79,6 +81,7 @@ import 'kernel_builder.dart'
KernelLibraryBuilder,
KernelProcedureBuilder,
KernelRedirectingFactoryBuilder,
KernelNamedTypeBuilder,
KernelTypeBuilder,
KernelTypeVariableBuilder,
LibraryBuilder,
@@ -194,6 +197,61 @@ abstract class KernelClassBuilder
}
}
void checkSupertypes() {
// This method determines whether the class (that's being built) its super
// class appears both in 'extends' and 'implements' clauses and whether any
// interface appears multiple times in the 'implements' clause.
if (interfaces == null) return;
// Extract super class (if it exists).
ClassBuilder superClass;
KernelTypeBuilder superClassType = supertype;
if (superClassType is KernelNamedTypeBuilder) {
Declaration decl = superClassType.declaration;
if (decl is ClassBuilder) {
superClass = decl;
}
}
// Validate interfaces.
Map<ClassBuilder, int> problems;
Map<ClassBuilder, int> problemsOffsets;
Set<ClassBuilder> implemented = new Set<ClassBuilder>();
for (KernelTypeBuilder type in interfaces) {
if (type is KernelNamedTypeBuilder) {
Declaration decl = type.declaration;
if (decl is ClassBuilder) {
ClassBuilder interface = decl;
if (superClass == interface) {
addCompileTimeError(
templateImplementsSuperClass.withArguments(interface.name),
type.charOffset,
noLength);
} else if (implemented.contains(interface)) {
// Aggregate repetitions.
problems ??= new Map<ClassBuilder, int>();
problems[interface] ??= 0;
problems[interface] += 1;
problemsOffsets ??= new Map<ClassBuilder, int>();
problemsOffsets[interface] ??= type.charOffset;
} else {
implemented.add(interface);
}
}
}
}
if (problems != null) {
problems.forEach((ClassBuilder interface, int repetitions) {
addCompileTimeError(
templateImplementsRepeated.withArguments(
interface.name, repetitions),
problemsOffsets[interface],
noLength);
});
}
}
@override
int resolveConstructors(LibraryBuilder library) {
int count = super.resolveConstructors(library);
@@ -261,6 +261,7 @@ class KernelTarget extends TargetImplementation {
computeCoreTypes();
loader.computeHierarchy();
loader.performTopLevelInference(myClasses);
loader.checkSupertypes(myClasses);
loader.checkOverrides(myClasses);
loader.checkAbstractMembers(myClasses);
loader.addNoSuchMethodForwarders(myClasses);
@@ -707,6 +707,15 @@ class SourceLoader<L> extends Loader<L> {
ticker.logMs("Computed core types");
}
void checkSupertypes(List<SourceClassBuilder> sourceClasses) {
for (SourceClassBuilder builder in sourceClasses) {
if (builder.library.loader == this) {
builder.checkSupertypes();
}
}
ticker.logMs("Checked overrides");
}
void checkOverrides(List<SourceClassBuilder> sourceClasses) {
assert(hierarchy != null);
for (SourceClassBuilder builder in sourceClasses) {
+21
View File
@@ -303,6 +303,27 @@ ImplementsBeforeWith:
dart2jsCode: "*ignored*"
script: "class A extends B implements C with D {}"
ImplementsRepeated:
template: "'#name' can only be implemented once."
analyzerCode: IMPLEMENTS_REPEATED
dart2jsCode: "*fatal*"
tip: "Try removing #count of the occurrences."
script:
- >-
abstract class I {}
abstract class J {}
class K implements I, J, I {}
ImplementsSuperClass:
template: "'#name' can't be used in both 'extends' and 'implements' clauses."
analyzerCode: IMPLEMENTS_SUPER_CLASS
dart2jsCode: "*fatal*"
tip: "Try removing one of the occurrences."
script:
- >-
abstract class A {}
class C extends A implements A {}
MultipleImplements:
template: "Each class definition can have at most one implements clause."
tip: "Try combining all of the implements clauses into a single clause."
-6
View File
@@ -4,7 +4,6 @@
[ $compiler == fasta ]
Language/Classes/Constructors/Generative_Constructors/final_variables_t01: CompileTimeError # Expects a warning, but this is an error in Dart 2
Language/Classes/definition_t24: MissingCompileTimeError
Language/Functions/Formal_Parameters/Optional_Formals/default_value_t01: MissingCompileTimeError
Language/Functions/Formal_Parameters/Optional_Formals/default_value_t02: MissingCompileTimeError
Language/Types/Type_Void/syntax_t08: MissingCompileTimeError
@@ -74,8 +73,6 @@ Language/Classes/Setters/override_t02: CompileTimeError
Language/Classes/Setters/static_setter_t05: CompileTimeError
Language/Classes/Setters/static_setter_t06: CompileTimeError
Language/Classes/Static_Methods/same_name_method_and_setter_t01: CompileTimeError
Language/Classes/Superinterfaces/more_than_once_t01: MissingCompileTimeError
Language/Classes/Superinterfaces/superclass_as_superinterface_t01: MissingCompileTimeError
Language/Classes/same_name_instance_and_static_members_t02: MissingCompileTimeError
Language/Classes/same_name_instance_and_static_members_t04: MissingCompileTimeError
Language/Expressions/Constants/exception_t01: MissingCompileTimeError
@@ -104,8 +101,6 @@ Language/Classes/Getters/same_name_method_t03: MissingCompileTimeError
Language/Classes/Getters/same_name_method_t04: MissingCompileTimeError
Language/Classes/Getters/same_name_method_t05: MissingCompileTimeError
Language/Classes/Getters/same_name_method_t07: MissingCompileTimeError
Language/Classes/Superinterfaces/more_than_once_t01: MissingCompileTimeError
Language/Classes/Superinterfaces/superclass_as_superinterface_t01: MissingCompileTimeError
Language/Classes/same_name_instance_and_static_members_t02: MissingCompileTimeError
Language/Classes/same_name_instance_and_static_members_t04: MissingCompileTimeError
Language/Expressions/Constants/bitwise_operators_t05: MissingCompileTimeError
@@ -226,7 +221,6 @@ Language/Classes/Superinterfaces/no_member_t01: CompileTimeError
Language/Classes/Superinterfaces/no_member_t02: CompileTimeError
Language/Classes/Superinterfaces/no_member_t05: CompileTimeError
Language/Classes/Superinterfaces/wrong_type_t05: MissingCompileTimeError
Language/Classes/definition_t24: MissingCompileTimeError
Language/Classes/method_definition_t03: CompileTimeError
Language/Classes/method_definition_t04: CompileTimeError
Language/Classes/method_definition_t05: CompileTimeError
+3 -7
View File
@@ -57,12 +57,9 @@ Language/Classes/Setters/instance_setter_t06: MissingCompileTimeError # Legal, s
Language/Classes/Setters/name_t06: CompileTimeError
Language/Classes/Setters/name_t07: CompileTimeError
Language/Classes/Static_Methods/same_name_method_and_setter_t01: CompileTimeError
Language/Classes/Superclasses/wrong_superclass_t08: MissingCompileTimeError
Language/Classes/Superinterfaces/more_than_once_t01: MissingCompileTimeError
Language/Classes/Superinterfaces/superclass_as_superinterface_t01: MissingCompileTimeError
Language/Classes/Superinterfaces/wrong_type_t05: MissingCompileTimeError
Language/Classes/definition_t24: MissingCompileTimeError
Language/Classes/method_definition_t06: MissingCompileTimeError
Language/Classes/Superclasses/wrong_superclass_t08: MissingCompileTimeError # Issue 30273
Language/Classes/Superinterfaces/wrong_type_t05: MissingCompileTimeError # Issue 30273
Language/Classes/method_definition_t06: MissingCompileTimeError # Legal
Language/Enums/syntax_t08: CompileTimeError
Language/Enums/syntax_t09: CompileTimeError
Language/Expressions/Assignable_Expressions/syntax_t01: CompileTimeError
@@ -257,7 +254,6 @@ LanguageFeatures/Instantiate-to-bound/function/function_ret_extends_neg_l1_t01:
LanguageFeatures/Instantiate-to-bound/function/function_ret_extends_neg_l1_t02: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/interface/interface_neg_assign_l2_t01: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/interface/interface_neg_assign_l2_t02: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/interface/interface_neg_l1_t06: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/mixin/mixin_extends_neg_l1_t01: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/mixin/mixin_neg_assign_l2_t01: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/mixin/mixin_neg_l1_t02: MissingCompileTimeError
@@ -57,8 +57,6 @@ class_cycle2_test/01: Crash # Issue #34043 - Error recovery in outline (class hi
class_cycle2_test/02: Crash # Issue #34043 - Error recovery in outline (class hierarchy cycle - see also #33756)
class_cycle_test/00: Crash # Issue #34043 - Error recovery in outline (class hierarchy cycle - see also #33756)
class_cycle_test/01: Crash # Issue #34043 - Error recovery in outline (class hierarchy cycle - see also #33756)
class_cycle_test/02: MissingCompileTimeError
class_cycle_test/03: MissingCompileTimeError
compile_time_constant_static5_test/11: CompileTimeError # Issue 31537
compile_time_constant_static5_test/16: CompileTimeError # Issue 31537
compile_time_constant_static5_test/21: CompileTimeError # Issue 31537
@@ -81,9 +79,6 @@ deep_nesting_statement_test/01: Crash # Error recovery in method body (deep nest
deferred_load_library_wrong_args_test/01: CompileTimeError # Issue 34047
duplicate_constructor_test/01: Crash # Issue 33686 - No core library found
duplicate_field_with_initializer_test/01: Crash # Issue 33686 - No core library found
duplicate_implements_test/01: MissingCompileTimeError
duplicate_implements_test/02: MissingCompileTimeError
duplicate_interface_implements_test/01: MissingCompileTimeError
dynamic_prefix_core_test/none: CompileTimeError # Issue 34047
emit_const_fields_test: CompileTimeError # Issue 34047
enum_syntax_test/02: Crash # Issue #34043 - Error recovery in outline (duplicate enum name)
@@ -26,7 +26,6 @@ const_dynamic_type_literal_test/03: Pass # but it shouldn't until we fix issue 1
deopt_inlined_function_lazy_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
deopt_smi_op_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
double_identical_test: RuntimeError # Negative and positive zero are distinct, but not in dart2js; bug #11551.
duplicate_interface_implements_test/01: MissingCompileTimeError
external_test/10: CompileTimeError # External non-js-interop function are treated as compile-time errors.
external_test/13: CompileTimeError # External non-js-interop function are treated as compile-time errors.
external_test/20: CompileTimeError # External non-js-interop function are treated as compile-time errors.
@@ -256,10 +255,6 @@ deferred_load_library_wrong_args_test/01: MissingRuntimeError
deferred_not_loaded_check_test: RuntimeError # Test out of date. Issue 31933
deferred_redirecting_factory_test: RuntimeError
double_int_to_string_test: RuntimeError, OK # non JS number semantics
duplicate_implements_test/01: MissingCompileTimeError
duplicate_implements_test/02: MissingCompileTimeError
duplicate_implements_test/03: MissingCompileTimeError
duplicate_implements_test/04: MissingCompileTimeError
dynamic_prefix_core_test/none: RuntimeError
enum_mirror_test: RuntimeError
expect_test: RuntimeError, OK # Issue 13080
@@ -545,8 +540,6 @@ async_star_test/02: RuntimeError
bit_operations_test: RuntimeError
branch_canonicalization_test: RuntimeError
canonical_const2_test: RuntimeError, OK # non JS number semantics
class_cycle_test/02: MissingCompileTimeError
class_cycle_test/03: MissingCompileTimeError
compile_time_constant_o_test/01: MissingCompileTimeError
compile_time_constant_o_test/02: MissingCompileTimeError
compile_time_constant_static5_test/11: CompileTimeError
@@ -573,8 +566,6 @@ deferred_load_library_wrong_args_test/01: CompileTimeError
deferred_not_loaded_check_test: RuntimeError # Test out of date. Issue 31933
deferred_redirecting_factory_test: RuntimeError
double_int_to_string_test: RuntimeError, OK # non JS number semantics
duplicate_implements_test/01: MissingCompileTimeError
duplicate_implements_test/02: MissingCompileTimeError
dynamic_prefix_core_test/none: CompileTimeError
emit_const_fields_test: CompileTimeError
enum_mirror_test: RuntimeError
+2 -5
View File
@@ -241,8 +241,8 @@ call_method_implicit_tear_off_implements_function_test/05: RuntimeError # Kernel
call_method_implicit_tear_off_implements_function_test/06: RuntimeError # Kernel is missing the implicit `call` tearoff for assignment `Function`
call_method_must_not_be_field_test/06: RuntimeError # Kernel does not distinguish `d()` from `d.call()`
call_method_must_not_be_getter_test/06: RuntimeError # Kernel does not distinguish `d()` from `d.call()`
class_cycle_test/02: MissingCompileTimeError
class_cycle_test/03: MissingCompileTimeError
call_non_method_field_test/01: MissingCompileTimeError
call_non_method_field_test/02: MissingCompileTimeError
compile_time_constant_c_test/02: MissingCompileTimeError
compile_time_constant_k_test/01: MissingCompileTimeError
compile_time_constant_k_test/02: MissingCompileTimeError
@@ -274,9 +274,6 @@ constants_test/05: MissingCompileTimeError
covariant_subtyping_test: RuntimeError
deferred_load_library_wrong_args_test/01: CompileTimeError
double_identical_test: RuntimeError # Negative and positive zero are distinct, but not in ddk
duplicate_implements_test/01: MissingCompileTimeError
duplicate_implements_test/02: MissingCompileTimeError
duplicate_interface_implements_test/01: MissingCompileTimeError
dynamic_prefix_core_test/none: CompileTimeError
emit_const_fields_test: CompileTimeError # Issue 31533
export_ambiguous_main_test: MissingCompileTimeError
@@ -1053,8 +1053,6 @@ recursive_generic_test: RuntimeError # Compares a (dynamic) toString call to 'C<
tearoff_dynamic_test: RuntimeError # Compares call to "foo" (noSuchMethod) with string "foo"
[ $compiler == fasta && $strong ]
class_cycle_test/02: MissingCompileTimeError
class_cycle_test/03: MissingCompileTimeError
compile_time_constant_static4_test/02: MissingCompileTimeError
compile_time_constant_static4_test/03: MissingCompileTimeError
compile_time_constant_static5_test/11: CompileTimeError
@@ -1068,8 +1066,6 @@ config_import_test: Crash
const_constructor3_test/04: MissingCompileTimeError
constants_test/05: MissingCompileTimeError
deferred_load_library_wrong_args_test/01: CompileTimeError
duplicate_implements_test/01: MissingCompileTimeError
duplicate_implements_test/02: MissingCompileTimeError
dynamic_prefix_core_test/none: CompileTimeError
emit_const_fields_test: CompileTimeError
export_ambiguous_main_test: MissingCompileTimeError
@@ -1799,8 +1795,6 @@ deferred_constraints_type_annotation_test/type_annotation_generic3: MissingCompi
deferred_constraints_type_annotation_test/type_annotation_generic4: MissingCompileTimeError
deferred_constraints_type_annotation_test/type_annotation_null: MissingCompileTimeError
deferred_constraints_type_annotation_test/type_annotation_top_level: MissingCompileTimeError
duplicate_implements_test/01: MissingCompileTimeError
duplicate_implements_test/02: MissingCompileTimeError
duplicate_implements_test/03: MissingCompileTimeError
duplicate_implements_test/04: MissingCompileTimeError
dynamic_field_test/01: MissingCompileTimeError
@@ -2435,6 +2429,3 @@ async_star_test/none: Skip # Timeout
[ $compiler == dartk || $compiler == dartkb || $compiler == dartkp ]
generic_function_bounds_test: RuntimeError # Issue 32076
generic_test/01: MissingCompileTimeError
[ $compiler == dartkp || $compiler == fasta ]
duplicate_interface_implements_test/01: MissingCompileTimeError