Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 an initializer will always throw. | |
|
Paul Berry
2017/04/07 15:56:38
It sounds like you're talking about a case like th
ahe
2017/04/07 18:19:18
Will do.
| |
| 91 bool needsImplicitSuperInitializer; | |
| 92 | |
| 82 Scope formalParameterScope; | 93 Scope formalParameterScope; |
| 83 | 94 |
| 84 bool inInitializer = false; | 95 bool inInitializer = false; |
| 85 | 96 |
| 86 bool inCatchClause = false; | 97 bool inCatchClause = false; |
| 87 | 98 |
| 88 bool inCatchBlock = false; | 99 bool inCatchBlock = false; |
| 89 | 100 |
| 90 int functionNestingLevel = 0; | 101 int functionNestingLevel = 0; |
| 91 | 102 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 111 Scope scope, | 122 Scope scope, |
| 112 this.formalParameterScope, | 123 this.formalParameterScope, |
| 113 this.hierarchy, | 124 this.hierarchy, |
| 114 this.coreTypes, | 125 this.coreTypes, |
| 115 this.classBuilder, | 126 this.classBuilder, |
| 116 this.isInstanceMember, | 127 this.isInstanceMember, |
| 117 this.uri) | 128 this.uri) |
| 118 : enclosingScope = scope, | 129 : enclosingScope = scope, |
| 119 library = library, | 130 library = library, |
| 120 isDartLibrary = library.uri.scheme == "dart", | 131 isDartLibrary = library.uri.scheme == "dart", |
| 132 needsImplicitSuperInitializer = | |
| 133 coreTypes.objectClass != classBuilder?.cls, | |
| 121 super(scope); | 134 super(scope); |
| 122 | 135 |
| 123 bool get hasParserError => recoverableErrors.isNotEmpty; | 136 bool get hasParserError => recoverableErrors.isNotEmpty; |
| 124 | 137 |
| 125 bool get inConstructor { | 138 bool get inConstructor { |
| 126 return functionNestingLevel == 0 && member is KernelConstructorBuilder; | 139 return functionNestingLevel == 0 && member is KernelConstructorBuilder; |
| 127 } | 140 } |
| 128 | 141 |
| 129 bool get isInstanceContext { | 142 bool get isInstanceContext { |
| 130 return isInstanceMember || member is KernelConstructorBuilder; | 143 return isInstanceMember || member is KernelConstructorBuilder; |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 378 debugEvent("endInitializer"); | 391 debugEvent("endInitializer"); |
| 379 assert(!inInitializer); | 392 assert(!inInitializer); |
| 380 final member = this.member; | 393 final member = this.member; |
| 381 var node = pop(); | 394 var node = pop(); |
| 382 Initializer initializer; | 395 Initializer initializer; |
| 383 if (node is Initializer) { | 396 if (node is Initializer) { |
| 384 initializer = node; | 397 initializer = node; |
| 385 } else if (node is FastaAccessor) { | 398 } else if (node is FastaAccessor) { |
| 386 initializer = node.buildFieldInitializer(fieldInitializers); | 399 initializer = node.buildFieldInitializer(fieldInitializers); |
| 387 } else if (node is ConstructorInvocation) { | 400 } else if (node is ConstructorInvocation) { |
| 388 initializer = new SuperInitializer(node.target, node.arguments); | 401 initializer = |
| 402 buildSuperInitializer(node.target, node.arguments, token.charOffset); | |
| 389 } else { | 403 } else { |
| 390 if (node is! Throw) { | 404 if (node is! Throw) { |
| 405 // TODO(ahe): This is probably an internal error. | |
|
Paul Berry
2017/04/07 15:56:38
Why is this a TODO?
ahe
2017/04/07 18:19:18
Because I want to try inserting a call to internal
| |
| 406 needsImplicitSuperInitializer = false; | |
| 391 node = wrapInvalid(node); | 407 node = wrapInvalid(node); |
| 392 } | 408 } |
| 393 initializer = | 409 initializer = buildInvalidIntializer(node, token.charOffset); |
| 394 new LocalInitializer(new VariableDeclaration.forValue(node)); | |
| 395 } | 410 } |
| 396 if (member is KernelConstructorBuilder) { | 411 if (member is KernelConstructorBuilder) { |
| 397 member.addInitializer(initializer); | 412 member.addInitializer(initializer); |
| 398 } else { | 413 } else { |
| 399 addCompileTimeError( | 414 addCompileTimeError( |
| 400 token.charOffset, "Can't have initializers: ${member.name}"); | 415 token.charOffset, "Can't have initializers: ${member.name}"); |
| 401 } | 416 } |
| 402 } | 417 } |
| 403 | 418 |
| 404 @override | 419 @override |
| 405 void handleNoInitializers() { | 420 void handleNoInitializers() { |
| 406 debugEvent("NoInitializers"); | 421 debugEvent("NoInitializers"); |
| 407 } | 422 } |
| 408 | 423 |
| 409 @override | 424 @override |
| 410 void endInitializers(int count, Token beginToken, Token endToken) { | 425 void endInitializers(int count, Token beginToken, Token endToken) { |
| 411 debugEvent("Initializers"); | 426 debugEvent("Initializers"); |
| 412 } | 427 } |
| 413 | 428 |
| 414 @override | 429 @override |
| 415 void finishFunction( | 430 void finishFunction( |
| 416 FormalParameters formals, AsyncMarker asyncModifier, Statement body) { | 431 FormalParameters formals, AsyncMarker asyncModifier, Statement body) { |
| 417 debugEvent("finishFunction"); | 432 debugEvent("finishFunction"); |
| 418 KernelFunctionBuilder builder = member; | 433 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; | 434 builder.body = body; |
| 431 if (formals?.optional != null) { | 435 if (formals?.optional != null) { |
| 432 Iterator<FormalParameterBuilder> formalBuilders = | 436 Iterator<FormalParameterBuilder> formalBuilders = |
| 433 builder.formals.skip(formals.required.length).iterator; | 437 builder.formals.skip(formals.required.length).iterator; |
| 434 for (VariableDeclaration parameter in formals.optional.formals) { | 438 for (VariableDeclaration parameter in formals.optional.formals) { |
| 435 bool hasMore = formalBuilders.moveNext(); | 439 bool hasMore = formalBuilders.moveNext(); |
| 436 assert(hasMore); | 440 assert(hasMore); |
| 437 VariableDeclaration realParameter = formalBuilders.current.target; | 441 VariableDeclaration realParameter = formalBuilders.current.target; |
| 438 Expression initializer = parameter.initializer ?? new NullLiteral(); | 442 Expression initializer = parameter.initializer ?? new NullLiteral(); |
| 439 realParameter.initializer = initializer..parent = realParameter; | 443 realParameter.initializer = initializer..parent = realParameter; |
| 440 } | 444 } |
| 441 } | 445 } |
| 446 if (builder is KernelConstructorBuilder) { | |
| 447 finishConstructor(builder, asyncModifier); | |
| 448 } else if (builder is KernelProcedureBuilder) { | |
| 449 builder.asyncModifier = asyncModifier; | |
| 450 } else { | |
| 451 internalError("Unhandled: ${builder.runtimeType}"); | |
| 452 } | |
| 453 } | |
| 454 | |
| 455 void finishConstructor( | |
| 456 KernelConstructorBuilder builder, AsyncMarker asyncModifier) { | |
| 457 /// Quotes below are from [Dart Programming Language Specification, 4th | |
| 458 /// Edition]( | |
| 459 /// https://ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf). | |
| 460 assert(builder == member); | |
| 461 Constructor constructor = builder.constructor; | |
| 462 if (asyncModifier != AsyncMarker.Sync) { | |
| 463 // TODO(ahe): Change this to a null check. | |
| 464 int offset = builder.body?.fileOffset ?? builder.charOffset; | |
| 465 constructor.initializers.add(buildInvalidIntializer( | |
| 466 buildCompileTimeError( | |
| 467 "A constructor can't be '${asyncModifier}'.", offset), | |
| 468 offset)); | |
| 469 } | |
| 470 if (needsImplicitSuperInitializer) { | |
| 471 /// >If no superinitializer is provided, an implicit superinitializer | |
| 472 /// >of the form super() is added at the end of k’s initializer list, | |
| 473 /// >unless the enclosing class is class Object. | |
| 474 Constructor superTarget = lookupConstructor(emptyName, isSuper: true); | |
| 475 Initializer initializer; | |
| 476 Arguments arguments = new Arguments.empty(); | |
| 477 if (superTarget == null || | |
| 478 !checkArguments( | |
| 479 superTarget.function, arguments, const <TypeParameter>[])) { | |
| 480 String superclass = classBuilder.supertype.fullNameForErrors; | |
| 481 initializer = buildInvalidIntializer( | |
| 482 buildCompileTimeError( | |
| 483 "'$superclass' has no constructor that takes no arguments.", | |
|
Paul Berry
2017/04/07 15:56:38
Given the following code:
class C {
C.foo();
}
ahe
2017/04/07 18:19:18
Will do. Those message are much better.
| |
| 484 builder.charOffset), | |
| 485 builder.charOffset); | |
| 486 } else { | |
| 487 initializer = | |
| 488 buildSuperInitializer(superTarget, arguments, builder.charOffset); | |
| 489 } | |
| 490 constructor.initializers.add(initializer); | |
| 491 } | |
| 492 setParents(constructor.initializers, constructor); | |
| 493 if (constructor.function.body == null) { | |
| 494 /// >If a generative constructor c is not a redirecting constructor | |
| 495 /// >and no body is provided, then c implicitly has an empty body {}. | |
| 496 /// We use an empty statement instead. | |
| 497 constructor.function.body = new EmptyStatement(); | |
| 498 constructor.function.body.parent = constructor.function; | |
| 499 } | |
| 442 } | 500 } |
| 443 | 501 |
| 444 @override | 502 @override |
| 445 void endExpressionStatement(Token token) { | 503 void endExpressionStatement(Token token) { |
| 446 debugEvent("ExpressionStatement"); | 504 debugEvent("ExpressionStatement"); |
| 447 push(new ExpressionStatement(popForEffect())); | 505 push(new ExpressionStatement(popForEffect())); |
| 448 } | 506 } |
| 449 | 507 |
| 450 @override | 508 @override |
| 451 void endArguments(int count, Token beginToken, Token endToken) { | 509 void endArguments(int count, Token beginToken, Token endToken) { |
| (...skipping 1272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1724 return new ConstructorInvocation(target, arguments) | 1782 return new ConstructorInvocation(target, arguments) |
| 1725 ..isConst = isConst | 1783 ..isConst = isConst |
| 1726 ..fileOffset = charOffset; | 1784 ..fileOffset = charOffset; |
| 1727 } else { | 1785 } else { |
| 1728 return new StaticInvocation(target, arguments) | 1786 return new StaticInvocation(target, arguments) |
| 1729 ..isConst = isConst | 1787 ..isConst = isConst |
| 1730 ..fileOffset = charOffset; | 1788 ..fileOffset = charOffset; |
| 1731 } | 1789 } |
| 1732 } | 1790 } |
| 1733 | 1791 |
| 1792 @override | |
| 1734 bool checkArguments(FunctionNode function, Arguments arguments, | 1793 bool checkArguments(FunctionNode function, Arguments arguments, |
| 1735 List<TypeParameter> typeParameters) { | 1794 List<TypeParameter> typeParameters) { |
| 1736 if (arguments.positional.length < function.requiredParameterCount || | 1795 if (arguments.positional.length < function.requiredParameterCount || |
| 1737 arguments.positional.length > function.positionalParameters.length) { | 1796 arguments.positional.length > function.positionalParameters.length) { |
| 1738 return false; | 1797 return false; |
| 1739 } | 1798 } |
| 1740 Map<String, VariableDeclaration> names; | 1799 Map<String, VariableDeclaration> names; |
| 1741 if (function.namedParameters.isNotEmpty) { | 1800 if (function.namedParameters.isNotEmpty) { |
| 1742 names = <String, VariableDeclaration>{}; | 1801 names = <String, VariableDeclaration>{}; |
| 1743 for (VariableDeclaration parameter in function.namedParameters) { | 1802 for (VariableDeclaration parameter in function.namedParameters) { |
| (...skipping 678 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2422 Builder constructor = library.loader.getAbstractClassInstantiationError(); | 2481 Builder constructor = library.loader.getAbstractClassInstantiationError(); |
| 2423 return new Throw(buildStaticInvocation(constructor.target, | 2482 return new Throw(buildStaticInvocation(constructor.target, |
| 2424 new Arguments(<Expression>[new StringLiteral(className)]))); | 2483 new Arguments(<Expression>[new StringLiteral(className)]))); |
| 2425 } | 2484 } |
| 2426 | 2485 |
| 2427 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) { | 2486 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) { |
| 2428 return new ExpressionStatement(buildCompileTimeError(error, charOffset)); | 2487 return new ExpressionStatement(buildCompileTimeError(error, charOffset)); |
| 2429 } | 2488 } |
| 2430 | 2489 |
| 2431 @override | 2490 @override |
| 2432 Initializer buildCompileTimeErrorIntializer(error, [int charOffset = -1]) { | 2491 Initializer buildInvalidIntializer(Expression expression, |
| 2433 return new LocalInitializer(new VariableDeclaration.forValue( | 2492 [int charOffset = -1]) { |
| 2434 buildCompileTimeError(error, charOffset))); | 2493 needsImplicitSuperInitializer = false; |
| 2494 return new LocalInitializer(new VariableDeclaration.forValue(expression)) | |
| 2495 ..fileOffset = charOffset; | |
| 2435 } | 2496 } |
| 2436 | 2497 |
| 2437 @override | 2498 @override |
| 2499 Initializer buildSuperInitializer( | |
| 2500 Constructor constructor, Arguments arguments, | |
| 2501 [int charOffset = -1]) { | |
| 2502 needsImplicitSuperInitializer = false; | |
| 2503 return new SuperInitializer(constructor, arguments) | |
| 2504 ..fileOffset = charOffset; | |
| 2505 } | |
| 2506 | |
| 2507 @override | |
| 2508 Initializer buildRedirectingInitializer( | |
| 2509 Constructor constructor, Arguments arguments, | |
| 2510 [int charOffset = -1]) { | |
| 2511 needsImplicitSuperInitializer = false; | |
| 2512 return new RedirectingInitializer(constructor, arguments) | |
| 2513 ..fileOffset = charOffset; | |
| 2514 } | |
| 2515 | |
| 2516 @override | |
| 2438 Expression buildProblemExpression(ProblemBuilder builder, int charOffset) { | 2517 Expression buildProblemExpression(ProblemBuilder builder, int charOffset) { |
| 2439 return buildCompileTimeError(builder.message, charOffset); | 2518 return buildCompileTimeError(builder.message, charOffset); |
| 2440 } | 2519 } |
| 2441 | 2520 |
| 2442 @override | 2521 @override |
| 2443 void handleOperator(Token token) { | 2522 void handleOperator(Token token) { |
| 2444 debugEvent("Operator"); | 2523 debugEvent("Operator"); |
| 2445 push(new Operator(token.stringValue)..fileOffset = token.charOffset); | 2524 push(new Operator(token.stringValue)..fileOffset = token.charOffset); |
| 2446 } | 2525 } |
| 2447 | 2526 |
| (...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2961 } else if (node is PrefixBuilder) { | 3040 } else if (node is PrefixBuilder) { |
| 2962 return node.name; | 3041 return node.name; |
| 2963 } else if (node is ThisAccessor) { | 3042 } else if (node is ThisAccessor) { |
| 2964 return node.isSuper ? "super" : "this"; | 3043 return node.isSuper ? "super" : "this"; |
| 2965 } else if (node is FastaAccessor) { | 3044 } else if (node is FastaAccessor) { |
| 2966 return node.plainNameForRead; | 3045 return node.plainNameForRead; |
| 2967 } else { | 3046 } else { |
| 2968 return internalError("Unhandled: ${node.runtimeType}"); | 3047 return internalError("Unhandled: ${node.runtimeType}"); |
| 2969 } | 3048 } |
| 2970 } | 3049 } |
| OLD | NEW |