| Index: pkg/front_end/lib/src/fasta/kernel/body_builder.dart
|
| diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
|
| index 70ba073f995587f99f56683c9ab4f979d50fe57d..c292c8b7017a0abd15fa5b29bcc0833f6b0c4044 100644
|
| --- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
|
| +++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
|
| @@ -79,6 +79,18 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| @override
|
| final Uri uri;
|
|
|
| + /// Only used when [member] is a constructor. It tracks if an implicit super
|
| + /// initializer is needed.
|
| + ///
|
| + /// An implicit super initializer isn't needed
|
| + ///
|
| + /// 1. if the current class is Object,
|
| + /// 2. if there is an explicit super initializer,
|
| + /// 3. if there is a redirecting (this) initializer, or
|
| + /// 4. if a compile-time error prevented us from generating code for an
|
| + /// initializer. This avoids cascading errors.
|
| + bool needsImplicitSuperInitializer;
|
| +
|
| Scope formalParameterScope;
|
|
|
| bool inInitializer = false;
|
| @@ -118,6 +130,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| : enclosingScope = scope,
|
| library = library,
|
| isDartLibrary = library.uri.scheme == "dart",
|
| + needsImplicitSuperInitializer =
|
| + coreTypes.objectClass != classBuilder?.cls,
|
| super(scope);
|
|
|
| bool get hasParserError => recoverableErrors.isNotEmpty;
|
| @@ -385,13 +399,15 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| } else if (node is FastaAccessor) {
|
| initializer = node.buildFieldInitializer(fieldInitializers);
|
| } else if (node is ConstructorInvocation) {
|
| - initializer = new SuperInitializer(node.target, node.arguments);
|
| + initializer =
|
| + buildSuperInitializer(node.target, node.arguments, token.charOffset);
|
| } else {
|
| if (node is! Throw) {
|
| + // TODO(ahe): This is probably an internal error.
|
| + needsImplicitSuperInitializer = false;
|
| node = wrapInvalid(node);
|
| }
|
| - initializer =
|
| - new LocalInitializer(new VariableDeclaration.forValue(node));
|
| + initializer = buildInvalidIntializer(node, token.charOffset);
|
| }
|
| if (member is KernelConstructorBuilder) {
|
| member.addInitializer(initializer);
|
| @@ -416,17 +432,6 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| FormalParameters formals, AsyncMarker asyncModifier, Statement body) {
|
| debugEvent("finishFunction");
|
| KernelFunctionBuilder builder = member;
|
| - if (builder is KernelConstructorBuilder) {
|
| - if (asyncModifier != AsyncMarker.Sync) {
|
| - // TODO(ahe): Change this to a null check.
|
| - addCompileTimeError(body?.fileOffset,
|
| - "Can't be marked as ${asyncModifier}: ${builder.name}");
|
| - }
|
| - } else if (builder is KernelProcedureBuilder) {
|
| - builder.asyncModifier = asyncModifier;
|
| - } else {
|
| - internalError("Unhandled: ${builder.runtimeType}");
|
| - }
|
| builder.body = body;
|
| if (formals?.optional != null) {
|
| Iterator<FormalParameterBuilder> formalBuilders =
|
| @@ -439,6 +444,61 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| realParameter.initializer = initializer..parent = realParameter;
|
| }
|
| }
|
| + if (builder is KernelConstructorBuilder) {
|
| + finishConstructor(builder, asyncModifier);
|
| + } else if (builder is KernelProcedureBuilder) {
|
| + builder.asyncModifier = asyncModifier;
|
| + } else {
|
| + internalError("Unhandled: ${builder.runtimeType}");
|
| + }
|
| + }
|
| +
|
| + void finishConstructor(
|
| + KernelConstructorBuilder builder, AsyncMarker asyncModifier) {
|
| + /// Quotes below are from [Dart Programming Language Specification, 4th
|
| + /// Edition](
|
| + /// https://ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf).
|
| + assert(builder == member);
|
| + Constructor constructor = builder.constructor;
|
| + if (asyncModifier != AsyncMarker.Sync) {
|
| + // TODO(ahe): Change this to a null check.
|
| + int offset = builder.body?.fileOffset ?? builder.charOffset;
|
| + constructor.initializers.add(buildInvalidIntializer(
|
| + buildCompileTimeError(
|
| + "A constructor can't be '${asyncModifier}'.", offset),
|
| + offset));
|
| + }
|
| + if (needsImplicitSuperInitializer) {
|
| + /// >If no superinitializer is provided, an implicit superinitializer
|
| + /// >of the form super() is added at the end of k’s initializer list,
|
| + /// >unless the enclosing class is class Object.
|
| + Constructor superTarget = lookupConstructor(emptyName, isSuper: true);
|
| + Initializer initializer;
|
| + Arguments arguments = new Arguments.empty();
|
| + if (superTarget == null ||
|
| + !checkArguments(
|
| + superTarget.function, arguments, const <TypeParameter>[])) {
|
| + String superclass = classBuilder.supertype.fullNameForErrors;
|
| + String message = superTarget == null
|
| + ? "'$superclass' doesn't have an unnamed constructor."
|
| + : "The unnamed constructor in '$superclass' requires arguments.";
|
| + initializer = buildInvalidIntializer(
|
| + buildCompileTimeError(message, builder.charOffset),
|
| + builder.charOffset);
|
| + } else {
|
| + initializer =
|
| + buildSuperInitializer(superTarget, arguments, builder.charOffset);
|
| + }
|
| + constructor.initializers.add(initializer);
|
| + }
|
| + setParents(constructor.initializers, constructor);
|
| + if (constructor.function.body == null) {
|
| + /// >If a generative constructor c is not a redirecting constructor
|
| + /// >and no body is provided, then c implicitly has an empty body {}.
|
| + /// We use an empty statement instead.
|
| + constructor.function.body = new EmptyStatement();
|
| + constructor.function.body.parent = constructor.function;
|
| + }
|
| }
|
|
|
| @override
|
| @@ -1731,6 +1791,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| }
|
| }
|
|
|
| + @override
|
| bool checkArguments(FunctionNode function, Arguments arguments,
|
| List<TypeParameter> typeParameters) {
|
| if (arguments.positional.length < function.requiredParameterCount ||
|
| @@ -2429,9 +2490,29 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| }
|
|
|
| @override
|
| - Initializer buildCompileTimeErrorIntializer(error, [int charOffset = -1]) {
|
| - return new LocalInitializer(new VariableDeclaration.forValue(
|
| - buildCompileTimeError(error, charOffset)));
|
| + Initializer buildInvalidIntializer(Expression expression,
|
| + [int charOffset = -1]) {
|
| + needsImplicitSuperInitializer = false;
|
| + return new LocalInitializer(new VariableDeclaration.forValue(expression))
|
| + ..fileOffset = charOffset;
|
| + }
|
| +
|
| + @override
|
| + Initializer buildSuperInitializer(
|
| + Constructor constructor, Arguments arguments,
|
| + [int charOffset = -1]) {
|
| + needsImplicitSuperInitializer = false;
|
| + return new SuperInitializer(constructor, arguments)
|
| + ..fileOffset = charOffset;
|
| + }
|
| +
|
| + @override
|
| + Initializer buildRedirectingInitializer(
|
| + Constructor constructor, Arguments arguments,
|
| + [int charOffset = -1]) {
|
| + needsImplicitSuperInitializer = false;
|
| + return new RedirectingInitializer(constructor, arguments)
|
| + ..fileOffset = charOffset;
|
| }
|
|
|
| @override
|
|
|