From 8cb7ab95679fa0b89900a534c2da04d7b03562b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20von=20der=20Ahe=CC=81?= Date: Wed, 12 Dec 2018 10:55:29 +0000 Subject: [PATCH] Ensure that Object doesn't have supertypes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ife632785bdac0d26fb6db1463636fd9a1fec51e1 Reviewed-on: https://dart-review.googlesource.com/c/86201 Commit-Queue: Peter von der Ahé Reviewed-by: Dmitry Stefantsov --- .../lib/src/fasta/fasta_codes_generated.dart | 22 ++++ .../fasta/kernel/kernel_class_builder.dart | 6 +- .../lib/src/fasta/kernel/kernel_target.dart | 2 +- .../lib/src/fasta/source/source_loader.dart | 30 +++++- pkg/front_end/messages.yaml | 15 +++ .../test/fasta/object_supertype_test.dart | 101 ++++++++++++++++++ 6 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 pkg/front_end/test/fasta/object_supertype_test.dart diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart index ff290e029b5..0cb1431c7dd 100644 --- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart +++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart @@ -6697,6 +6697,28 @@ Message _withArgumentsNotConstantExpression(String string) { arguments: {'string': string}); } +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Code codeObjectExtends = messageObjectExtends; + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const MessageCode messageObjectExtends = const MessageCode("ObjectExtends", + message: r"""The class 'Object' can't have a superclass."""); + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Code codeObjectImplements = messageObjectImplements; + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const MessageCode messageObjectImplements = const MessageCode( + "ObjectImplements", + message: r"""The class 'Object' can't implement anything."""); + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Code codeObjectMixesIn = messageObjectMixesIn; + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const MessageCode messageObjectMixesIn = const MessageCode("ObjectMixesIn", + message: r"""The class 'Object' can't use mixins."""); + // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. const Code codeOnlyTry = messageOnlyTry; diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart index 873aa85fbd1..bc49b595b27 100644 --- a/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart +++ b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart @@ -646,9 +646,9 @@ abstract class KernelClassBuilder isInterfaceCheck: true); } - bool hasNoSuchMethod = - hierarchy.getDispatchTarget(cls, noSuchMethodName).enclosingClass != - coreTypes.objectClass; + Member noSuchMethod = hierarchy.getDispatchTarget(cls, noSuchMethodName); + bool hasNoSuchMethod = noSuchMethod != null && + noSuchMethod.enclosingClass != coreTypes.objectClass; void findMissingImplementations({bool setters}) { List dispatchTargets = diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart index cea63ebb5b3..ad363887a44 100644 --- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart +++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart @@ -271,7 +271,7 @@ class KernelTarget extends TargetImplementation { loader.resolveTypes(); loader.computeDefaultTypes(dynamicType, bottomType, objectClassBuilder); List myClasses = collectMyClasses(); - loader.checkSemantics(myClasses); + loader.checkSemantics(myClasses, objectClassBuilder); loader.finishTypeVariables(objectClassBuilder, dynamicType); loader.buildComponent(); installDefaultSupertypes(); diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart index a330137d07c..5edde47a039 100644 --- a/pkg/front_end/lib/src/fasta/source/source_loader.dart +++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart @@ -47,6 +47,9 @@ import '../fasta_codes.dart' Message, SummaryTemplate, Template, + messageObjectExtends, + messageObjectImplements, + messageObjectMixesIn, messagePartOrphan, noLength, templateAmbiguousSupertypes, @@ -552,7 +555,32 @@ class SourceLoader extends Loader { return output; } - void checkSemantics(List classes) { + /// Check that [objectClass] has no supertypes. Recover by removing any + /// found. + void checkObjectClassHierarchy(ClassBuilder objectClass) { + if (objectClass is SourceClassBuilder && + objectClass.library.loader == this) { + if (objectClass.supertype != null) { + objectClass.supertype = null; + objectClass.addProblem( + messageObjectExtends, objectClass.charOffset, noLength); + } + if (objectClass.interfaces != null) { + objectClass.addProblem( + messageObjectImplements, objectClass.charOffset, noLength); + objectClass.interfaces = null; + } + if (objectClass.mixedInType != null) { + objectClass.addProblem( + messageObjectMixesIn, objectClass.charOffset, noLength); + objectClass.mixedInType = null; + } + } + } + + void checkSemantics( + List classes, ClassBuilder objectClass) { + checkObjectClassHierarchy(objectClass); Iterable candidates = cyclicCandidates(classes); if (candidates.isNotEmpty) { Map> realCycles = diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml index 00f7e31c891..86aad347b27 100644 --- a/pkg/front_end/messages.yaml +++ b/pkg/front_end/messages.yaml @@ -3364,3 +3364,18 @@ TypeOriginWithFileUri: template: "'#name' is from '#uri' ('#uri2')." frontendInternal: true external: test/type_labeler_test.dart + +ObjectExtends: + template: "The class 'Object' can't have a superclass." + frontendInternal: true + external: test/fasta/object_supertype_test.dart + +ObjectImplements: + template: "The class 'Object' can't implement anything." + frontendInternal: true + external: test/fasta/object_supertype_test.dart + +ObjectMixesIn: + template: "The class 'Object' can't use mixins." + frontendInternal: true + external: test/fasta/object_supertype_test.dart diff --git a/pkg/front_end/test/fasta/object_supertype_test.dart b/pkg/front_end/test/fasta/object_supertype_test.dart new file mode 100644 index 00000000000..fd003007c96 --- /dev/null +++ b/pkg/front_end/test/fasta/object_supertype_test.dart @@ -0,0 +1,101 @@ +// Copyright (c) 2018, 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 "dart:convert" show json; + +import "package:async_helper/async_helper.dart" show asyncTest; + +import "package:expect/expect.dart" show Expect; + +import "package:front_end/src/api_prototype/compiler_options.dart" + show CompilerOptions; + +import "package:front_end/src/api_prototype/diagnostic_message.dart" + show DiagnosticMessage, getMessageCodeObject; + +import "package:front_end/src/api_prototype/memory_file_system.dart" + show MemoryFileSystem; + +import "package:front_end/src/base/processed_options.dart" + show ProcessedOptions; + +import "package:front_end/src/fasta/compiler_context.dart" show CompilerContext; + +import "package:front_end/src/fasta/messages.dart" + show Code, codeObjectExtends, codeObjectImplements, codeObjectMixesIn; + +import "package:front_end/src/fasta/source/source_loader.dart" + show defaultDartCoreSource; + +import "package:front_end/src/fasta/ticker.dart" show Ticker; + +import "../../tool/_fasta/entry_points.dart" show CompileTask; + +Future> outline(String objectHeader) async { + final Ticker ticker = new Ticker(isVerbose: false); + final Uri base = Uri.parse("org-dartlang-test:///"); + + final MemoryFileSystem fs = new MemoryFileSystem(base); + + final Uri librariesSpecificationUri = base.resolve("sdk/libraries.json"); + + fs.entityForUri(librariesSpecificationUri).writeAsStringSync(json.encode({ + "none": { + "libraries": { + "core": { + "uri": "lib/core/core.dart", + }, + }, + }, + })); + + fs.entityForUri(base.resolve("sdk/lib/core/core.dart")).writeAsStringSync( + defaultDartCoreSource.replaceAll("class Object {", "$objectHeader")); + + final List messages = []; + + CompilerContext context = new CompilerContext(new ProcessedOptions( + options: new CompilerOptions() + ..onDiagnostic = messages.add + ..sdkRoot = base.resolve("sdk/") + ..fileSystem = fs + ..compileSdk = true + ..librariesSpecificationUri = librariesSpecificationUri, + inputs: [Uri.parse("dart:core")])); + + await context.runInContext((_) async { + CompileTask task = new CompileTask(context, ticker); + await task.buildOutline(); + }); + return messages; +} + +test() async { + Set normalErrors = (await outline("class Object {")) + .map((DiagnosticMessage message) => getMessageCodeObject(message).name) + .toSet(); + + check(String objectHeader, List expectedCodes) async { + List messages = (await outline(objectHeader)) + .where((DiagnosticMessage message) => + !normalErrors.contains(getMessageCodeObject(message).name)) + .toList(); + Expect.setEquals( + expectedCodes, + messages.map((DiagnosticMessage m) => getMessageCodeObject(m)), + objectHeader); + } + + await check("class Object extends String {", [codeObjectExtends]); + + await check( + "class Object implements String, bool {", [codeObjectImplements]); + + await check("class Object = Object with bool ; class Blah {", + [codeObjectExtends, codeObjectMixesIn]); +} + +main() { + asyncTest(test); +}