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, MemberKind, optional; | 10 import '../parser/parser.dart' show FormalParameterType, MemberKind, optional; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
71 final MemberBuilder member; | 71 final MemberBuilder member; |
72 | 72 |
73 final KernelClassBuilder classBuilder; | 73 final KernelClassBuilder classBuilder; |
74 | 74 |
75 final ClassHierarchy hierarchy; | 75 final ClassHierarchy hierarchy; |
76 | 76 |
77 final CoreTypes coreTypes; | 77 final CoreTypes coreTypes; |
78 | 78 |
79 final bool isInstanceMember; | 79 final bool isInstanceMember; |
80 | 80 |
81 final Map<String, FieldInitializer> fieldInitializers = | |
82 <String, FieldInitializer>{}; | |
83 | |
84 final Scope enclosingScope; | 81 final Scope enclosingScope; |
85 | 82 |
86 final bool enableNative; | 83 final bool enableNative; |
87 | 84 |
88 final bool isPlatformLibrary; | 85 final bool isPlatformLibrary; |
89 | 86 |
90 @override | 87 @override |
91 final Uri uri; | 88 final Uri uri; |
92 | 89 |
93 final TypeInferrer _typeInferrer; | 90 final TypeInferrer _typeInferrer; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
126 CloneVisitor cloner; | 123 CloneVisitor cloner; |
127 | 124 |
128 bool constantExpressionRequired = false; | 125 bool constantExpressionRequired = false; |
129 | 126 |
130 DartType currentLocalVariableType; | 127 DartType currentLocalVariableType; |
131 | 128 |
132 // Using non-null value to initialize this field based on performance advice | 129 // Using non-null value to initialize this field based on performance advice |
133 // from VM engineers. TODO(ahe): Does this still apply? | 130 // from VM engineers. TODO(ahe): Does this still apply? |
134 int currentLocalVariableModifiers = -1; | 131 int currentLocalVariableModifiers = -1; |
135 | 132 |
133 /// If non-null, records instance fields which have already been initialized | |
134 /// and where that was. | |
135 Map<String, int> initializedFields; | |
136 | |
136 BodyBuilder( | 137 BodyBuilder( |
137 KernelLibraryBuilder library, | 138 KernelLibraryBuilder library, |
138 this.member, | 139 this.member, |
139 Scope scope, | 140 Scope scope, |
140 this.formalParameterScope, | 141 this.formalParameterScope, |
141 this.hierarchy, | 142 this.hierarchy, |
142 this.coreTypes, | 143 this.coreTypes, |
143 this.classBuilder, | 144 this.classBuilder, |
144 this.isInstanceMember, | 145 this.isInstanceMember, |
145 this.uri, | 146 this.uri, |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
385 if (beginToken == null) { | 386 if (beginToken == null) { |
386 assert(count == 0); | 387 assert(count == 0); |
387 push(NullValue.Block); | 388 push(NullValue.Block); |
388 } else { | 389 } else { |
389 Block block = popBlock(count, beginToken); | 390 Block block = popBlock(count, beginToken); |
390 exitLocalScope(); | 391 exitLocalScope(); |
391 push(block); | 392 push(block); |
392 } | 393 } |
393 } | 394 } |
394 | 395 |
395 @override | |
396 void prepareInitializers() { | 396 void prepareInitializers() { |
397 scope = formalParameterScope; | 397 ProcedureBuilder member = this.member; |
398 assert(fieldInitializers.isEmpty); | 398 scope = member.computeFormalParameterInitializerScope(scope); |
399 final member = this.member; | |
400 if (member is KernelConstructorBuilder) { | 399 if (member is KernelConstructorBuilder) { |
401 Constructor constructor = member.constructor; | |
402 classBuilder.forEach((String name, Builder builder) { | |
403 if (builder is KernelFieldBuilder && builder.isInstanceMember) { | |
404 // TODO(ahe): Compute initializers (as in `field = initializer`). | |
405 fieldInitializers[name] = new FieldInitializer(builder.field, null) | |
406 ..parent = constructor; | |
407 } | |
408 }); | |
409 if (member.formals != null) { | 400 if (member.formals != null) { |
410 for (KernelFormalParameterBuilder formal in member.formals) { | 401 for (KernelFormalParameterBuilder formal in member.formals) { |
411 if (formal.hasThis) { | 402 if (formal.hasThis) { |
412 FieldInitializer initializer = fieldInitializers[formal.name]; | 403 Initializer initializer; |
413 if (initializer != null) { | 404 if (member.isExternal) { |
414 fieldInitializers.remove(formal.name); | 405 initializer = buildInvalidIntializer( |
415 initializer.value = new VariableGet(formal.declaration) | 406 buildCompileTimeError( |
416 ..parent = initializer; | 407 "An external constructor can't initialize fields.", |
417 member.addInitializer(initializer); | 408 formal.charOffset), |
409 formal.charOffset); | |
410 } else { | |
411 initializer = buildFieldInitializer(formal.name, | |
412 formal.charOffset, new VariableGet(formal.declaration)); | |
418 } | 413 } |
414 member.addInitializer(initializer); | |
419 } | 415 } |
420 } | 416 } |
421 } | 417 } |
422 } | 418 } |
423 } | 419 } |
424 | 420 |
425 @override | 421 @override |
422 void handleNoInitializers() { | |
423 debugEvent("NoInitializers"); | |
424 if (functionNestingLevel == 0) { | |
425 prepareInitializers(); | |
426 scope = formalParameterScope; | |
427 } | |
428 } | |
429 | |
430 @override | |
431 void beginInitializers(Token token) { | |
432 debugEvent("beginInitializers"); | |
433 if (functionNestingLevel == 0) { | |
434 prepareInitializers(); | |
435 } | |
436 } | |
437 | |
438 @override | |
439 void endInitializers(int count, Token beginToken, Token endToken) { | |
440 debugEvent("Initializers"); | |
441 if (functionNestingLevel == 0) { | |
442 scope = formalParameterScope; | |
443 } | |
444 } | |
445 | |
446 @override | |
426 void beginInitializer(Token token) { | 447 void beginInitializer(Token token) { |
427 debugEvent("beginInitializer"); | 448 debugEvent("beginInitializer"); |
428 inInitializer = true; | 449 inInitializer = true; |
429 } | 450 } |
430 | 451 |
431 @override | 452 @override |
432 void endInitializer(Token token) { | 453 void endInitializer(Token token) { |
433 debugEvent("endInitializer"); | 454 debugEvent("endInitializer"); |
434 assert(!inInitializer); | 455 assert(!inInitializer); |
435 final member = this.member; | 456 final member = this.member; |
436 var node = pop(); | 457 var node = pop(); |
437 Initializer initializer; | 458 Initializer initializer; |
438 if (node is Initializer) { | 459 if (node is Initializer) { |
439 initializer = node; | 460 initializer = node; |
440 } else if (node is FastaAccessor) { | 461 } else if (node is FastaAccessor) { |
441 initializer = node.buildFieldInitializer(fieldInitializers); | 462 initializer = node.buildFieldInitializer(initializedFields); |
442 } else if (node is ConstructorInvocation) { | 463 } else if (node is ConstructorInvocation) { |
443 initializer = | 464 initializer = |
444 buildSuperInitializer(node.target, node.arguments, token.charOffset); | 465 buildSuperInitializer(node.target, node.arguments, token.charOffset); |
445 } else { | 466 } else { |
446 Expression value = toValue(node); | 467 Expression value = toValue(node); |
447 if (node is! Throw) { | 468 if (node is! Throw) { |
448 value = wrapInCompileTimeError(value, "Expected an initializer."); | 469 value = wrapInCompileTimeError(value, "Expected an initializer."); |
449 } | 470 } |
450 initializer = buildInvalidIntializer(node, token.charOffset); | 471 initializer = buildInvalidIntializer(node, token.charOffset); |
451 } | 472 } |
452 _typeInferrer.inferInitializer(initializer); | 473 _typeInferrer.inferInitializer(initializer); |
453 if (member is KernelConstructorBuilder) { | 474 if (member is KernelConstructorBuilder) { |
454 member.addInitializer(initializer); | 475 member.addInitializer(initializer); |
455 } else { | 476 } else { |
456 addCompileTimeError( | 477 addCompileTimeError( |
457 token.charOffset, "Can't have initializers: ${member.name}"); | 478 token.charOffset, "Can't have initializers: ${member.name}"); |
458 } | 479 } |
459 } | 480 } |
460 | 481 |
461 @override | |
462 void handleNoInitializers() { | |
463 debugEvent("NoInitializers"); | |
464 } | |
465 | |
466 @override | |
467 void endInitializers(int count, Token beginToken, Token endToken) { | |
468 debugEvent("Initializers"); | |
469 } | |
470 | |
471 DartType _computeReturnTypeContext(MemberBuilder member) { | 482 DartType _computeReturnTypeContext(MemberBuilder member) { |
472 if (member is KernelProcedureBuilder) { | 483 if (member is KernelProcedureBuilder) { |
473 return member.target.function.returnType; | 484 return member.target.function.returnType; |
474 } else { | 485 } else { |
475 assert(member is KernelConstructorBuilder); | 486 assert(member is KernelConstructorBuilder); |
476 return null; | 487 return null; |
477 } | 488 } |
478 } | 489 } |
479 | 490 |
480 @override | 491 @override |
(...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
917 offsetForToken(token), "Not a constant expression."); | 928 offsetForToken(token), "Not a constant expression."); |
918 } | 929 } |
919 return new TypeDeclarationAccessor(this, builder, name, token); | 930 return new TypeDeclarationAccessor(this, builder, name, token); |
920 } else if (builder.isLocal) { | 931 } else if (builder.isLocal) { |
921 if (constantExpressionRequired && | 932 if (constantExpressionRequired && |
922 !builder.isConst && | 933 !builder.isConst && |
923 !member.isConstructor) { | 934 !member.isConstructor) { |
924 addCompileTimeError( | 935 addCompileTimeError( |
925 offsetForToken(token), "Not a constant expression."); | 936 offsetForToken(token), "Not a constant expression."); |
926 } | 937 } |
927 return new VariableAccessor(this, token, builder.target); | 938 // An initializing formal parameter might be final without its |
939 // VariableDeclaration being final. See | |
940 // [ProcedureBuilder.computeFormalParameterInitializerScope]. If that | |
941 // wasn't the case, we could always use VariableAccessor. | |
942 if (builder.isFinal) { | |
943 var fact = | |
944 typePromoter.getFactForAccess(builder.target, functionNestingLevel); | |
945 var scope = typePromoter.currentScope; | |
946 return new ReadOnlyAccessor( | |
947 this, | |
948 new KernelVariableGet(builder.target, fact, scope) | |
949 ..fileOffset = offsetForToken(token), | |
950 name, | |
951 token); | |
952 } else { | |
953 return new VariableAccessor(this, token, builder.target); | |
954 } | |
928 } else if (builder.isInstanceMember) { | 955 } else if (builder.isInstanceMember) { |
929 if (constantExpressionRequired && | 956 if (constantExpressionRequired && |
930 !inInitializer && | 957 !inInitializer && |
931 // TODO(ahe): This is a hack because Fasta sets up the scope | 958 // TODO(ahe): This is a hack because Fasta sets up the scope |
932 // "this.field" parameters according to old semantics. Under the new | 959 // "this.field" parameters according to old semantics. Under the new |
933 // semantics, such parameters introduces a new parameter with that | 960 // semantics, such parameters introduces a new parameter with that |
934 // name that should be resolved here. | 961 // name that should be resolved here. |
935 !member.isConstructor) { | 962 !member.isConstructor) { |
936 addCompileTimeError( | 963 addCompileTimeError( |
937 offsetForToken(token), "Not a constant expression."); | 964 offsetForToken(token), "Not a constant expression."); |
(...skipping 648 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1586 if (inCatchClause) { | 1613 if (inCatchClause) { |
1587 modifiers |= finalMask; | 1614 modifiers |= finalMask; |
1588 } | 1615 } |
1589 bool isConst = (modifiers & constMask) != 0; | 1616 bool isConst = (modifiers & constMask) != 0; |
1590 bool isFinal = (modifiers & finalMask) != 0; | 1617 bool isFinal = (modifiers & finalMask) != 0; |
1591 ignore(Unhandled.Metadata); | 1618 ignore(Unhandled.Metadata); |
1592 VariableDeclaration variable; | 1619 VariableDeclaration variable; |
1593 if (!inCatchClause && | 1620 if (!inCatchClause && |
1594 functionNestingLevel == 0 && | 1621 functionNestingLevel == 0 && |
1595 memberKind != MemberKind.GeneralizedFunctionType) { | 1622 memberKind != MemberKind.GeneralizedFunctionType) { |
1596 dynamic builder = formalParameterScope.lookup( | 1623 ProcedureBuilder member = this.member; |
1597 name.name, offsetForToken(name.token), uri); | 1624 KernelFormalParameterBuilder formal = member.getFormal(name.name); |
1598 if (builder == null) { | 1625 if (formal == null) { |
1599 if (thisKeyword == null) { | 1626 internalError("Internal error: formal missing for '${name.name}'"); |
1600 internalError("Internal error: formal missing for '${name.name}'"); | 1627 } else { |
1601 } else { | 1628 variable = formal.build(library); |
1602 addCompileTimeError(thisKeyword.charOffset, | |
1603 "'${name.name}' isn't a field in this class."); | |
1604 thisKeyword = null; | |
1605 } | |
1606 } else if (thisKeyword == null) { | |
1607 variable = builder.build(library); | |
1608 variable.initializer = name.initializer; | 1629 variable.initializer = name.initializer; |
1609 } else if (builder.isField && builder.parent == classBuilder) { | 1630 } |
1610 FieldBuilder field = builder; | 1631 } else { |
1611 if (type != null) { | 1632 variable = new KernelVariableDeclaration(name?.name, functionNestingLevel, |
1612 nit("Ignoring type on 'this' parameter '${name.name}'.", | 1633 type: type, |
1613 thisKeyword.charOffset); | 1634 initializer: name?.initializer, |
1614 } | 1635 isFinal: isFinal, |
1615 type = field.target.type; | 1636 isConst: isConst); |
1616 variable = new KernelVariableDeclaration( | 1637 if (name != null) { |
1617 name.name, functionNestingLevel, | 1638 // TODO(ahe): Need an offset when name is null. |
1618 type: type, | 1639 variable.fileOffset = offsetForToken(name.token); |
1619 initializer: name.initializer, | |
1620 isFinal: isFinal, | |
1621 isConst: isConst) | |
1622 ..fileOffset = offsetForToken(name.token); | |
1623 } else { | |
1624 addCompileTimeError(offsetForToken(name.token), | |
1625 "'${name.name}' isn't a field in this class."); | |
1626 } | 1640 } |
1627 } | 1641 } |
1628 variable ??= new KernelVariableDeclaration(name?.name, functionNestingLevel, | |
1629 type: type, | |
1630 initializer: name?.initializer, | |
1631 isFinal: isFinal, | |
1632 isConst: isConst) | |
1633 ..fileOffset = offsetForToken(name?.token); | |
1634 push(variable); | 1642 push(variable); |
1635 } | 1643 } |
1636 | 1644 |
1637 @override | 1645 @override |
1638 void endOptionalFormalParameters( | 1646 void endOptionalFormalParameters( |
1639 int count, Token beginToken, Token endToken) { | 1647 int count, Token beginToken, Token endToken) { |
1640 debugEvent("OptionalFormalParameters"); | 1648 debugEvent("OptionalFormalParameters"); |
1641 FormalParameterType kind = optional("{", beginToken) | 1649 FormalParameterType kind = optional("{", beginToken) |
1642 ? FormalParameterType.NAMED | 1650 ? FormalParameterType.NAMED |
1643 : FormalParameterType.POSITIONAL; | 1651 : FormalParameterType.POSITIONAL; |
(...skipping 1031 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2675 } | 2683 } |
2676 | 2684 |
2677 @override | 2685 @override |
2678 Initializer buildInvalidIntializer(Expression expression, | 2686 Initializer buildInvalidIntializer(Expression expression, |
2679 [int charOffset = -1]) { | 2687 [int charOffset = -1]) { |
2680 needsImplicitSuperInitializer = false; | 2688 needsImplicitSuperInitializer = false; |
2681 return new LocalInitializer(new VariableDeclaration.forValue(expression)) | 2689 return new LocalInitializer(new VariableDeclaration.forValue(expression)) |
2682 ..fileOffset = charOffset; | 2690 ..fileOffset = charOffset; |
2683 } | 2691 } |
2684 | 2692 |
2693 Initializer buildDuplicatedInitializer( | |
2694 String name, int offset, int previousInitializerOffset) { | |
2695 Initializer initializer = buildInvalidIntializer( | |
Johnni Winther
2017/06/06 10:35:08
buildInvalidIntializer -> buildInvalidInitializer
ahe
2017/06/06 15:08:24
Done.
| |
2696 buildCompileTimeError("'$name' has already been initialized.", offset), | |
2697 offset); | |
2698 addCompileTimeError( | |
2699 initializedFields[name], "'$name' was initialized here."); | |
2700 return initializer; | |
2701 } | |
2702 | |
2703 @override | |
2704 Initializer buildFieldInitializer( | |
2705 String name, int offset, Expression expression) { | |
2706 Builder builder = classBuilder.scope.local[name]; | |
2707 if (builder is KernelFieldBuilder && builder.isInstanceMember) { | |
2708 initializedFields ??= <String, int>{}; | |
2709 if (initializedFields.containsKey(name)) { | |
2710 return buildDuplicatedInitializer( | |
2711 name, offset, initializedFields[name]); | |
2712 } | |
2713 initializedFields[name] = offset; | |
2714 if (builder.isFinal && builder.hasInitializer) { | |
2715 // TODO(ahe): If CL 2843733002 is landed, this becomes a compile-time | |
2716 // error. Also, this is a compile-time error in strong mode. | |
2717 warningNotError( | |
2718 "'$name' is final instance variable that has already been " | |
2719 "initialized.", | |
2720 offset); | |
2721 warningNotError("'$name' was initialized here.", builder.charOffset); | |
2722 Builder constructor = | |
2723 library.loader.getDuplicatedFieldInitializerError(); | |
2724 return buildInvalidIntializer( | |
2725 new Throw(buildStaticInvocation(constructor.target, | |
2726 new Arguments(<Expression>[new StringLiteral(name)]), | |
2727 charOffset: offset)), | |
2728 offset); | |
2729 } else { | |
2730 return new FieldInitializer(builder.field, expression) | |
2731 ..fileOffset = offset; | |
2732 } | |
2733 } else { | |
2734 return buildInvalidIntializer( | |
2735 buildCompileTimeError( | |
2736 "'$name' isn't an instance field of this class.", offset), | |
2737 offset); | |
2738 } | |
2739 } | |
2740 | |
2685 @override | 2741 @override |
2686 Initializer buildSuperInitializer( | 2742 Initializer buildSuperInitializer( |
2687 Constructor constructor, Arguments arguments, | 2743 Constructor constructor, Arguments arguments, |
2688 [int charOffset = -1]) { | 2744 [int charOffset = -1]) { |
2689 needsImplicitSuperInitializer = false; | 2745 needsImplicitSuperInitializer = false; |
2690 return new SuperInitializer(constructor, arguments) | 2746 return new SuperInitializer(constructor, arguments) |
2691 ..fileOffset = charOffset; | 2747 ..fileOffset = charOffset; |
2692 } | 2748 } |
2693 | 2749 |
2694 @override | 2750 @override |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2981 return accessor.buildCompoundAssignment(barName, value, | 3037 return accessor.buildCompoundAssignment(barName, value, |
2982 offset: offsetForToken(token), voidContext: voidContext); | 3038 offset: offsetForToken(token), voidContext: voidContext); |
2983 } else if (identical("~/=", assignmentOperator)) { | 3039 } else if (identical("~/=", assignmentOperator)) { |
2984 return accessor.buildCompoundAssignment(mustacheName, value, | 3040 return accessor.buildCompoundAssignment(mustacheName, value, |
2985 offset: offsetForToken(token), voidContext: voidContext); | 3041 offset: offsetForToken(token), voidContext: voidContext); |
2986 } else { | 3042 } else { |
2987 return internalError("Unhandled: $assignmentOperator"); | 3043 return internalError("Unhandled: $assignmentOperator"); |
2988 } | 3044 } |
2989 } | 3045 } |
2990 | 3046 |
2991 Initializer buildFieldInitializer( | 3047 @override |
2992 Map<String, FieldInitializer> initializers) { | 3048 Initializer buildFieldInitializer(Map<String, int> initializedFields) { |
2993 if (!identical("=", assignmentOperator) || | 3049 if (!identical("=", assignmentOperator) || |
2994 !accessor.isThisPropertyAccessor) { | 3050 !accessor.isThisPropertyAccessor) { |
2995 return accessor.buildFieldInitializer(initializers); | 3051 return accessor.buildFieldInitializer(initializedFields); |
2996 } | 3052 } |
2997 String name = accessor.plainNameForRead; | 3053 return helper.buildFieldInitializer( |
2998 FieldInitializer initializer = initializers[name]; | 3054 accessor.plainNameForRead, offsetForToken(token), value); |
2999 if (initializer != null && initializer.value == null) { | |
3000 initializers.remove(name); | |
3001 initializer.value = value..parent = initializer; | |
3002 return initializer; | |
3003 } | |
3004 return accessor.buildFieldInitializer(initializers); | |
3005 } | 3055 } |
3006 } | 3056 } |
3007 | 3057 |
3008 class DelayedPostfixIncrement extends ContextAccessor { | 3058 class DelayedPostfixIncrement extends ContextAccessor { |
3009 final Name binaryOperator; | 3059 final Name binaryOperator; |
3010 | 3060 |
3011 final Procedure interfaceTarget; | 3061 final Procedure interfaceTarget; |
3012 | 3062 |
3013 DelayedPostfixIncrement(BuilderHelper helper, Token token, | 3063 DelayedPostfixIncrement(BuilderHelper helper, Token token, |
3014 FastaAccessor accessor, this.binaryOperator, this.interfaceTarget) | 3064 FastaAccessor accessor, this.binaryOperator, this.interfaceTarget) |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3275 if (starToken == null) { | 3325 if (starToken == null) { |
3276 return AsyncMarker.Async; | 3326 return AsyncMarker.Async; |
3277 } else { | 3327 } else { |
3278 assert(identical(starToken.stringValue, "*")); | 3328 assert(identical(starToken.stringValue, "*")); |
3279 return AsyncMarker.AsyncStar; | 3329 return AsyncMarker.AsyncStar; |
3280 } | 3330 } |
3281 } else { | 3331 } else { |
3282 return internalError("Unknown async modifier: $asyncToken"); | 3332 return internalError("Unknown async modifier: $asyncToken"); |
3283 } | 3333 } |
3284 } | 3334 } |
OLD | NEW |