Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(484)

Side by Side Diff: pkg/front_end/lib/src/fasta/kernel/body_builder.dart

Issue 2800083002: Complain about incorrect this/super constructor initializers. (Closed)
Patch Set: Address comments. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library fasta.body_builder; 5 library fasta.body_builder;
6 6
7 import '../fasta_codes.dart' 7 import '../fasta_codes.dart'
8 show FastaMessage, codeExpectedButGot, codeExpectedFunctionBody; 8 show FastaMessage, codeExpectedButGot, codeExpectedFunctionBody;
9 9
10 import '../parser/parser.dart' show FormalParameterType, optional; 10 import '../parser/parser.dart' show FormalParameterType, optional;
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 final Map<String, FieldInitializer> fieldInitializers = 72 final Map<String, FieldInitializer> fieldInitializers =
73 <String, FieldInitializer>{}; 73 <String, FieldInitializer>{};
74 74
75 final Scope enclosingScope; 75 final Scope enclosingScope;
76 76
77 final bool isDartLibrary; 77 final bool isDartLibrary;
78 78
79 @override 79 @override
80 final Uri uri; 80 final Uri uri;
81 81
82 /// Only used when [member] is a constructor. It tracks if an implicit super
83 /// initializer is needed.
84 ///
85 /// An implicit super initializer isn't needed
86 ///
87 /// 1. if the current class is Object,
88 /// 2. if there is an explicit super initializer,
89 /// 3. if there is a redirecting (this) initializer, or
90 /// 4. if a compile-time error prevented us from generating code for an
91 /// initializer. This avoids cascading errors.
92 bool needsImplicitSuperInitializer;
93
82 Scope formalParameterScope; 94 Scope formalParameterScope;
83 95
84 bool inInitializer = false; 96 bool inInitializer = false;
85 97
86 bool inCatchClause = false; 98 bool inCatchClause = false;
87 99
88 bool inCatchBlock = false; 100 bool inCatchBlock = false;
89 101
90 int functionNestingLevel = 0; 102 int functionNestingLevel = 0;
91 103
(...skipping 19 matching lines...) Expand all
111 Scope scope, 123 Scope scope,
112 this.formalParameterScope, 124 this.formalParameterScope,
113 this.hierarchy, 125 this.hierarchy,
114 this.coreTypes, 126 this.coreTypes,
115 this.classBuilder, 127 this.classBuilder,
116 this.isInstanceMember, 128 this.isInstanceMember,
117 this.uri) 129 this.uri)
118 : enclosingScope = scope, 130 : enclosingScope = scope,
119 library = library, 131 library = library,
120 isDartLibrary = library.uri.scheme == "dart", 132 isDartLibrary = library.uri.scheme == "dart",
133 needsImplicitSuperInitializer =
134 coreTypes.objectClass != classBuilder?.cls,
121 super(scope); 135 super(scope);
122 136
123 bool get hasParserError => recoverableErrors.isNotEmpty; 137 bool get hasParserError => recoverableErrors.isNotEmpty;
124 138
125 bool get inConstructor { 139 bool get inConstructor {
126 return functionNestingLevel == 0 && member is KernelConstructorBuilder; 140 return functionNestingLevel == 0 && member is KernelConstructorBuilder;
127 } 141 }
128 142
129 bool get isInstanceContext { 143 bool get isInstanceContext {
130 return isInstanceMember || member is KernelConstructorBuilder; 144 return isInstanceMember || member is KernelConstructorBuilder;
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 debugEvent("endInitializer"); 392 debugEvent("endInitializer");
379 assert(!inInitializer); 393 assert(!inInitializer);
380 final member = this.member; 394 final member = this.member;
381 var node = pop(); 395 var node = pop();
382 Initializer initializer; 396 Initializer initializer;
383 if (node is Initializer) { 397 if (node is Initializer) {
384 initializer = node; 398 initializer = node;
385 } else if (node is FastaAccessor) { 399 } else if (node is FastaAccessor) {
386 initializer = node.buildFieldInitializer(fieldInitializers); 400 initializer = node.buildFieldInitializer(fieldInitializers);
387 } else if (node is ConstructorInvocation) { 401 } else if (node is ConstructorInvocation) {
388 initializer = new SuperInitializer(node.target, node.arguments); 402 initializer =
403 buildSuperInitializer(node.target, node.arguments, token.charOffset);
389 } else { 404 } else {
390 if (node is! Throw) { 405 if (node is! Throw) {
406 // TODO(ahe): This is probably an internal error.
407 needsImplicitSuperInitializer = false;
391 node = wrapInvalid(node); 408 node = wrapInvalid(node);
392 } 409 }
393 initializer = 410 initializer = buildInvalidIntializer(node, token.charOffset);
394 new LocalInitializer(new VariableDeclaration.forValue(node));
395 } 411 }
396 if (member is KernelConstructorBuilder) { 412 if (member is KernelConstructorBuilder) {
397 member.addInitializer(initializer); 413 member.addInitializer(initializer);
398 } else { 414 } else {
399 addCompileTimeError( 415 addCompileTimeError(
400 token.charOffset, "Can't have initializers: ${member.name}"); 416 token.charOffset, "Can't have initializers: ${member.name}");
401 } 417 }
402 } 418 }
403 419
404 @override 420 @override
405 void handleNoInitializers() { 421 void handleNoInitializers() {
406 debugEvent("NoInitializers"); 422 debugEvent("NoInitializers");
407 } 423 }
408 424
409 @override 425 @override
410 void endInitializers(int count, Token beginToken, Token endToken) { 426 void endInitializers(int count, Token beginToken, Token endToken) {
411 debugEvent("Initializers"); 427 debugEvent("Initializers");
412 } 428 }
413 429
414 @override 430 @override
415 void finishFunction( 431 void finishFunction(
416 FormalParameters formals, AsyncMarker asyncModifier, Statement body) { 432 FormalParameters formals, AsyncMarker asyncModifier, Statement body) {
417 debugEvent("finishFunction"); 433 debugEvent("finishFunction");
418 KernelFunctionBuilder builder = member; 434 KernelFunctionBuilder builder = member;
419 if (builder is KernelConstructorBuilder) {
420 if (asyncModifier != AsyncMarker.Sync) {
421 // TODO(ahe): Change this to a null check.
422 addCompileTimeError(body?.fileOffset,
423 "Can't be marked as ${asyncModifier}: ${builder.name}");
424 }
425 } else if (builder is KernelProcedureBuilder) {
426 builder.asyncModifier = asyncModifier;
427 } else {
428 internalError("Unhandled: ${builder.runtimeType}");
429 }
430 builder.body = body; 435 builder.body = body;
431 if (formals?.optional != null) { 436 if (formals?.optional != null) {
432 Iterator<FormalParameterBuilder> formalBuilders = 437 Iterator<FormalParameterBuilder> formalBuilders =
433 builder.formals.skip(formals.required.length).iterator; 438 builder.formals.skip(formals.required.length).iterator;
434 for (VariableDeclaration parameter in formals.optional.formals) { 439 for (VariableDeclaration parameter in formals.optional.formals) {
435 bool hasMore = formalBuilders.moveNext(); 440 bool hasMore = formalBuilders.moveNext();
436 assert(hasMore); 441 assert(hasMore);
437 VariableDeclaration realParameter = formalBuilders.current.target; 442 VariableDeclaration realParameter = formalBuilders.current.target;
438 Expression initializer = parameter.initializer ?? new NullLiteral(); 443 Expression initializer = parameter.initializer ?? new NullLiteral();
439 realParameter.initializer = initializer..parent = realParameter; 444 realParameter.initializer = initializer..parent = realParameter;
440 } 445 }
441 } 446 }
447 if (builder is KernelConstructorBuilder) {
448 finishConstructor(builder, asyncModifier);
449 } else if (builder is KernelProcedureBuilder) {
450 builder.asyncModifier = asyncModifier;
451 } else {
452 internalError("Unhandled: ${builder.runtimeType}");
453 }
454 }
455
456 void finishConstructor(
457 KernelConstructorBuilder builder, AsyncMarker asyncModifier) {
458 /// Quotes below are from [Dart Programming Language Specification, 4th
459 /// Edition](
460 /// https://ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf).
461 assert(builder == member);
462 Constructor constructor = builder.constructor;
463 if (asyncModifier != AsyncMarker.Sync) {
464 // TODO(ahe): Change this to a null check.
465 int offset = builder.body?.fileOffset ?? builder.charOffset;
466 constructor.initializers.add(buildInvalidIntializer(
467 buildCompileTimeError(
468 "A constructor can't be '${asyncModifier}'.", offset),
469 offset));
470 }
471 if (needsImplicitSuperInitializer) {
472 /// >If no superinitializer is provided, an implicit superinitializer
473 /// >of the form super() is added at the end of k’s initializer list,
474 /// >unless the enclosing class is class Object.
475 Constructor superTarget = lookupConstructor(emptyName, isSuper: true);
476 Initializer initializer;
477 Arguments arguments = new Arguments.empty();
478 if (superTarget == null ||
479 !checkArguments(
480 superTarget.function, arguments, const <TypeParameter>[])) {
481 String superclass = classBuilder.supertype.fullNameForErrors;
482 String message = superTarget == null
483 ? "'$superclass' doesn't have an unnamed constructor."
484 : "The unnamed constructor in '$superclass' requires arguments.";
485 initializer = buildInvalidIntializer(
486 buildCompileTimeError(message, builder.charOffset),
487 builder.charOffset);
488 } else {
489 initializer =
490 buildSuperInitializer(superTarget, arguments, builder.charOffset);
491 }
492 constructor.initializers.add(initializer);
493 }
494 setParents(constructor.initializers, constructor);
495 if (constructor.function.body == null) {
496 /// >If a generative constructor c is not a redirecting constructor
497 /// >and no body is provided, then c implicitly has an empty body {}.
498 /// We use an empty statement instead.
499 constructor.function.body = new EmptyStatement();
500 constructor.function.body.parent = constructor.function;
501 }
442 } 502 }
443 503
444 @override 504 @override
445 void endExpressionStatement(Token token) { 505 void endExpressionStatement(Token token) {
446 debugEvent("ExpressionStatement"); 506 debugEvent("ExpressionStatement");
447 push(new ExpressionStatement(popForEffect())); 507 push(new ExpressionStatement(popForEffect()));
448 } 508 }
449 509
450 @override 510 @override
451 void endArguments(int count, Token beginToken, Token endToken) { 511 void endArguments(int count, Token beginToken, Token endToken) {
(...skipping 1272 matching lines...) Expand 10 before | Expand all | Expand 10 after
1724 return new ConstructorInvocation(target, arguments) 1784 return new ConstructorInvocation(target, arguments)
1725 ..isConst = isConst 1785 ..isConst = isConst
1726 ..fileOffset = charOffset; 1786 ..fileOffset = charOffset;
1727 } else { 1787 } else {
1728 return new StaticInvocation(target, arguments) 1788 return new StaticInvocation(target, arguments)
1729 ..isConst = isConst 1789 ..isConst = isConst
1730 ..fileOffset = charOffset; 1790 ..fileOffset = charOffset;
1731 } 1791 }
1732 } 1792 }
1733 1793
1794 @override
1734 bool checkArguments(FunctionNode function, Arguments arguments, 1795 bool checkArguments(FunctionNode function, Arguments arguments,
1735 List<TypeParameter> typeParameters) { 1796 List<TypeParameter> typeParameters) {
1736 if (arguments.positional.length < function.requiredParameterCount || 1797 if (arguments.positional.length < function.requiredParameterCount ||
1737 arguments.positional.length > function.positionalParameters.length) { 1798 arguments.positional.length > function.positionalParameters.length) {
1738 return false; 1799 return false;
1739 } 1800 }
1740 Map<String, VariableDeclaration> names; 1801 Map<String, VariableDeclaration> names;
1741 if (function.namedParameters.isNotEmpty) { 1802 if (function.namedParameters.isNotEmpty) {
1742 names = <String, VariableDeclaration>{}; 1803 names = <String, VariableDeclaration>{};
1743 for (VariableDeclaration parameter in function.namedParameters) { 1804 for (VariableDeclaration parameter in function.namedParameters) {
(...skipping 678 matching lines...) Expand 10 before | Expand all | Expand 10 after
2422 Builder constructor = library.loader.getAbstractClassInstantiationError(); 2483 Builder constructor = library.loader.getAbstractClassInstantiationError();
2423 return new Throw(buildStaticInvocation(constructor.target, 2484 return new Throw(buildStaticInvocation(constructor.target,
2424 new Arguments(<Expression>[new StringLiteral(className)]))); 2485 new Arguments(<Expression>[new StringLiteral(className)])));
2425 } 2486 }
2426 2487
2427 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) { 2488 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) {
2428 return new ExpressionStatement(buildCompileTimeError(error, charOffset)); 2489 return new ExpressionStatement(buildCompileTimeError(error, charOffset));
2429 } 2490 }
2430 2491
2431 @override 2492 @override
2432 Initializer buildCompileTimeErrorIntializer(error, [int charOffset = -1]) { 2493 Initializer buildInvalidIntializer(Expression expression,
2433 return new LocalInitializer(new VariableDeclaration.forValue( 2494 [int charOffset = -1]) {
2434 buildCompileTimeError(error, charOffset))); 2495 needsImplicitSuperInitializer = false;
2496 return new LocalInitializer(new VariableDeclaration.forValue(expression))
2497 ..fileOffset = charOffset;
2435 } 2498 }
2436 2499
2437 @override 2500 @override
2501 Initializer buildSuperInitializer(
2502 Constructor constructor, Arguments arguments,
2503 [int charOffset = -1]) {
2504 needsImplicitSuperInitializer = false;
2505 return new SuperInitializer(constructor, arguments)
2506 ..fileOffset = charOffset;
2507 }
2508
2509 @override
2510 Initializer buildRedirectingInitializer(
2511 Constructor constructor, Arguments arguments,
2512 [int charOffset = -1]) {
2513 needsImplicitSuperInitializer = false;
2514 return new RedirectingInitializer(constructor, arguments)
2515 ..fileOffset = charOffset;
2516 }
2517
2518 @override
2438 Expression buildProblemExpression(ProblemBuilder builder, int charOffset) { 2519 Expression buildProblemExpression(ProblemBuilder builder, int charOffset) {
2439 return buildCompileTimeError(builder.message, charOffset); 2520 return buildCompileTimeError(builder.message, charOffset);
2440 } 2521 }
2441 2522
2442 @override 2523 @override
2443 void handleOperator(Token token) { 2524 void handleOperator(Token token) {
2444 debugEvent("Operator"); 2525 debugEvent("Operator");
2445 push(new Operator(token.stringValue)..fileOffset = token.charOffset); 2526 push(new Operator(token.stringValue)..fileOffset = token.charOffset);
2446 } 2527 }
2447 2528
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after
2961 } else if (node is PrefixBuilder) { 3042 } else if (node is PrefixBuilder) {
2962 return node.name; 3043 return node.name;
2963 } else if (node is ThisAccessor) { 3044 } else if (node is ThisAccessor) {
2964 return node.isSuper ? "super" : "this"; 3045 return node.isSuper ? "super" : "this";
2965 } else if (node is FastaAccessor) { 3046 } else if (node is FastaAccessor) {
2966 return node.plainNameForRead; 3047 return node.plainNameForRead;
2967 } else { 3048 } else {
2968 return internalError("Unhandled: ${node.runtimeType}"); 3049 return internalError("Unhandled: ${node.runtimeType}");
2969 } 3050 }
2970 } 3051 }
OLDNEW
« no previous file with comments | « pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart ('k') | pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698