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 '../parser/parser.dart' show FormalParameterType, optional; | 7 import '../parser/parser.dart' show FormalParameterType, optional; |
| 8 | 8 |
| 9 import '../parser/error_kind.dart' show ErrorKind; | 9 import '../parser/error_kind.dart' show ErrorKind; |
| 10 | 10 |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 node.name.name, new Arguments.empty(), node.fileOffset, | 175 node.name.name, new Arguments.empty(), node.fileOffset, |
| 176 isGetter: true); | 176 isGetter: true); |
| 177 } else if (node is BuilderAccessor) { | 177 } else if (node is BuilderAccessor) { |
| 178 return node.buildSimpleRead(); | 178 return node.buildSimpleRead(); |
| 179 } else if (node is TypeVariableBuilder) { | 179 } else if (node is TypeVariableBuilder) { |
| 180 TypeParameterType type = node.buildTypesWithBuiltArguments(library, null); | 180 TypeParameterType type = node.buildTypesWithBuiltArguments(library, null); |
| 181 if (!isInstanceContext && type.parameter.parent is Class) { | 181 if (!isInstanceContext && type.parameter.parent is Class) { |
| 182 return buildCompileTimeError( | 182 return buildCompileTimeError( |
| 183 "Type variables can only be used in instance methods."); | 183 "Type variables can only be used in instance methods."); |
| 184 } else { | 184 } else { |
| 185 if (constantExpressionRequired) { | |
| 186 addCompileTimeError(-1, | |
| 187 "Type variable can't be used as a constant expression $type."); | |
|
Paul Berry
2017/03/22 16:18:04
I have two concerns about how this technique for d
ahe
2017/03/22 16:58:02
I'm aware of that, and I've started work on error
| |
| 188 } | |
| 185 return new TypeLiteral(type); | 189 return new TypeLiteral(type); |
| 186 } | 190 } |
| 187 } else if (node is TypeDeclarationBuilder) { | 191 } else if (node is TypeDeclarationBuilder) { |
| 188 return new TypeLiteral(node.buildTypesWithBuiltArguments(library, null)); | 192 return new TypeLiteral(node.buildTypesWithBuiltArguments(library, null)); |
| 189 } else if (node is KernelTypeBuilder) { | 193 } else if (node is KernelTypeBuilder) { |
| 190 return new TypeLiteral(node.build(library)); | 194 return new TypeLiteral(node.build(library)); |
| 191 } else if (node is Expression) { | 195 } else if (node is Expression) { |
| 192 return node; | 196 return node; |
| 193 } else if (node is PrefixBuilder) { | 197 } else if (node is PrefixBuilder) { |
| 194 return buildCompileTimeError("A library can't be used as an expression."); | 198 return buildCompileTimeError("A library can't be used as an expression."); |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 527 } else if (arguments == null) { | 531 } else if (arguments == null) { |
| 528 push(receiver); | 532 push(receiver); |
| 529 } else { | 533 } else { |
| 530 push(finishSend(receiver, arguments, beginToken.charOffset)); | 534 push(finishSend(receiver, arguments, beginToken.charOffset)); |
| 531 } | 535 } |
| 532 } | 536 } |
| 533 | 537 |
| 534 @override | 538 @override |
| 535 finishSend(Object receiver, Arguments arguments, int charOffset) { | 539 finishSend(Object receiver, Arguments arguments, int charOffset) { |
| 536 if (receiver is BuilderAccessor) { | 540 if (receiver is BuilderAccessor) { |
| 541 if (constantExpressionRequired) { | |
| 542 addCompileTimeError(charOffset, "Not a constant expression."); | |
|
Paul Berry
2017/03/22 16:18:04
Idea: when we report a "Not a constant expression"
ahe
2017/03/22 16:58:02
That's probably a good idea.
ahe
2017/03/23 12:22:13
I'm going to follow up on this in separate CL.
| |
| 543 } | |
| 537 return receiver.doInvocation(charOffset, arguments); | 544 return receiver.doInvocation(charOffset, arguments); |
| 538 } else if (receiver is UnresolvedIdentifier) { | 545 } else if (receiver is UnresolvedIdentifier) { |
| 539 return throwNoSuchMethodError( | 546 return throwNoSuchMethodError( |
| 540 receiver.name.name, arguments, receiver.fileOffset); | 547 receiver.name.name, arguments, receiver.fileOffset); |
| 541 } else { | 548 } else { |
| 542 return buildMethodInvocation( | 549 return buildMethodInvocation( |
| 543 toValue(receiver), callName, arguments, charOffset); | 550 toValue(receiver), callName, arguments, charOffset); |
| 544 } | 551 } |
| 545 } | 552 } |
| 546 | 553 |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 734 String name = token.lexeme; | 741 String name = token.lexeme; |
| 735 if (context.isScopeReference) { | 742 if (context.isScopeReference) { |
| 736 assert(!inInitializer || | 743 assert(!inInitializer || |
| 737 this.scope == enclosingScope || | 744 this.scope == enclosingScope || |
| 738 this.scope.parent == enclosingScope); | 745 this.scope.parent == enclosingScope); |
| 739 // This deals with this kind of initializer: `C(a) : a = a;` | 746 // This deals with this kind of initializer: `C(a) : a = a;` |
| 740 Scope scope = inInitializer ? enclosingScope : this.scope; | 747 Scope scope = inInitializer ? enclosingScope : this.scope; |
| 741 Builder builder = scope.lookup(name, token.charOffset, uri); | 748 Builder builder = scope.lookup(name, token.charOffset, uri); |
| 742 push(builderToFirstExpression(builder, name, token.charOffset)); | 749 push(builderToFirstExpression(builder, name, token.charOffset)); |
| 743 } else { | 750 } else { |
| 751 if (constantExpressionRequired) { | |
| 752 if (context != IdentifierContext.namedArgumentReference && | |
|
Paul Berry
2017/03/22 16:18:05
Rather than a bunch of != checks, we should add a
ahe
2017/03/22 16:58:02
Good idea.
ahe
2017/03/23 12:22:13
I'll do this in a separate CL.
| |
| 753 context != IdentifierContext.constructorReferenceContinuation && | |
| 754 context != IdentifierContext.expressionContinuation && | |
| 755 context != IdentifierContext.typeReferenceContinuation && | |
| 756 context != | |
| 757 IdentifierContext | |
| 758 .constructorReferenceContinuationAfterTypeArguments) { | |
| 759 addCompileTimeError( | |
| 760 token.charOffset, "Not a constant expression: $context"); | |
| 761 } | |
| 762 } | |
| 744 push(new Identifier(name)..fileOffset = token.charOffset); | 763 push(new Identifier(name)..fileOffset = token.charOffset); |
| 745 } | 764 } |
| 746 } | 765 } |
| 747 | 766 |
| 748 @override | 767 @override |
| 749 builderToFirstExpression(Builder builder, String name, int charOffset, | 768 builderToFirstExpression(Builder builder, String name, int charOffset, |
| 750 {bool isPrefix: false}) { | 769 {bool isPrefix: false}) { |
| 751 if (builder == null || (!isInstanceContext && builder.isInstanceMember)) { | 770 if (builder == null || (!isInstanceContext && builder.isInstanceMember)) { |
| 752 Name n = new Name(name, library.library); | 771 Name n = new Name(name, library.library); |
| 753 if (!isPrefix && isInstanceContext) { | 772 if (!isPrefix && isInstanceContext) { |
| 754 assert(builder == null); | 773 assert(builder == null); |
| 774 if (constantExpressionRequired) { | |
| 775 addCompileTimeError(charOffset, "Not a constant expression."); | |
| 776 } | |
| 755 return new ThisPropertyAccessor(this, charOffset, n, null, null); | 777 return new ThisPropertyAccessor(this, charOffset, n, null, null); |
| 756 } else { | 778 } else { |
| 779 if (constantExpressionRequired) { | |
| 780 addCompileTimeError(charOffset, "Not a constant expression."); | |
| 781 } | |
| 757 return new UnresolvedIdentifier(n)..fileOffset = charOffset; | 782 return new UnresolvedIdentifier(n)..fileOffset = charOffset; |
| 758 } | 783 } |
| 759 } else if (builder.isTypeDeclaration) { | 784 } else if (builder.isTypeDeclaration) { |
| 785 if (constantExpressionRequired && builder.isTypeVariable) { | |
| 786 addCompileTimeError(charOffset, "Not a constant expression."); | |
| 787 } | |
| 760 return builder; | 788 return builder; |
| 761 } else if (builder.isLocal) { | 789 } else if (builder.isLocal) { |
| 790 if (constantExpressionRequired && !builder.isConst) { | |
| 791 addCompileTimeError(charOffset, "Not a constant expression."); | |
| 792 } | |
| 762 return new VariableAccessor(this, charOffset, builder.target); | 793 return new VariableAccessor(this, charOffset, builder.target); |
| 763 } else if (builder.isInstanceMember) { | 794 } else if (builder.isInstanceMember) { |
| 795 if (constantExpressionRequired) { | |
| 796 addCompileTimeError(charOffset, "Not a constant expression."); | |
| 797 } | |
| 764 return new ThisPropertyAccessor( | 798 return new ThisPropertyAccessor( |
| 765 this, charOffset, new Name(name, library.library), null, null); | 799 this, charOffset, new Name(name, library.library), null, null); |
| 766 } else if (builder.isRegularMethod) { | 800 } else if (builder.isRegularMethod) { |
| 767 assert(builder.isStatic || builder.isTopLevel); | 801 assert(builder.isStatic || builder.isTopLevel); |
| 768 return new StaticAccessor(this, charOffset, builder.target, null); | 802 return new StaticAccessor(this, charOffset, builder.target, null); |
| 769 } else if (builder is PrefixBuilder) { | 803 } else if (builder is PrefixBuilder) { |
| 770 return builder; | 804 return builder; |
| 771 } else if (builder is MixedAccessor) { | 805 } else if (builder is MixedAccessor) { |
| 806 if (constantExpressionRequired && !builder.getter.target.isConst) { | |
| 807 addCompileTimeError(charOffset, "Not a constant expression."); | |
| 808 } | |
| 772 return new StaticAccessor( | 809 return new StaticAccessor( |
| 773 this, charOffset, builder.getter.target, builder.setter.target); | 810 this, charOffset, builder.getter.target, builder.setter.target); |
| 774 } else { | 811 } else { |
| 775 if (builder.hasProblem && builder is! AccessErrorBuilder) return builder; | 812 if (builder.hasProblem && builder is! AccessErrorBuilder) return builder; |
| 776 Builder setter; | 813 Builder setter; |
| 777 if (builder.isSetter) { | 814 if (builder.isSetter) { |
| 778 setter = builder; | 815 setter = builder; |
| 779 } else if (builder.isGetter) { | 816 } else if (builder.isGetter) { |
| 780 setter = scope.lookupSetter(name, charOffset, uri); | 817 setter = scope.lookupSetter(name, charOffset, uri); |
| 781 } else if (builder.isField && !builder.isFinal) { | 818 } else if (builder.isField && !builder.isFinal) { |
| 782 setter = builder; | 819 setter = builder; |
| 783 } | 820 } |
| 784 return new StaticAccessor.fromBuilder(this, builder, charOffset, setter); | 821 StaticAccessor accessor = |
| 822 new StaticAccessor.fromBuilder(this, builder, charOffset, setter); | |
| 823 if (constantExpressionRequired) { | |
| 824 Member readTarget = accessor.readTarget; | |
| 825 if (!(readTarget is Field && readTarget.isConst)) { | |
| 826 addCompileTimeError(charOffset, "Not a constant expression."); | |
| 827 } | |
| 828 } | |
| 829 return accessor; | |
| 785 } | 830 } |
| 786 } | 831 } |
| 787 | 832 |
| 788 @override | 833 @override |
| 789 void handleQualified(Token period) { | 834 void handleQualified(Token period) { |
| 790 debugEvent("Qualified"); | 835 debugEvent("Qualified"); |
| 791 Identifier name = pop(); | 836 Identifier name = pop(); |
| 792 var receiver = pop(); | 837 var receiver = pop(); |
| 793 push([receiver, name]); | 838 push([receiver, name]); |
| 794 } | 839 } |
| (...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1194 if (builder == null) { | 1239 if (builder == null) { |
| 1195 warning("Type not found: '$name'.", charOffset); | 1240 warning("Type not found: '$name'.", charOffset); |
| 1196 return const DynamicType(); | 1241 return const DynamicType(); |
| 1197 } else { | 1242 } else { |
| 1198 return kernelTypeFromBuilder(builder, arguments, charOffset); | 1243 return kernelTypeFromBuilder(builder, arguments, charOffset); |
| 1199 } | 1244 } |
| 1200 } | 1245 } |
| 1201 | 1246 |
| 1202 DartType kernelTypeFromBuilder( | 1247 DartType kernelTypeFromBuilder( |
| 1203 Builder builder, List<DartType> arguments, int charOffset) { | 1248 Builder builder, List<DartType> arguments, int charOffset) { |
| 1249 if (constantExpressionRequired && builder is TypeVariableBuilder) { | |
| 1250 addCompileTimeError(charOffset, "Not a constant expression."); | |
| 1251 } | |
| 1204 if (builder is TypeDeclarationBuilder) { | 1252 if (builder is TypeDeclarationBuilder) { |
| 1205 return builder.buildTypesWithBuiltArguments(library, arguments); | 1253 return builder.buildTypesWithBuiltArguments(library, arguments); |
| 1206 } else if (builder.hasProblem) { | 1254 } else if (builder.hasProblem) { |
| 1207 ProblemBuilder problem = builder; | 1255 ProblemBuilder problem = builder; |
| 1208 addCompileTimeError(charOffset, problem.message); | 1256 addCompileTimeError(charOffset, problem.message); |
| 1209 } else { | 1257 } else { |
| 1210 warning("Not a type: '${builder.fullNameForErrors}'.", charOffset); | 1258 warning("Not a type: '${builder.fullNameForErrors}'.", charOffset); |
| 1211 } | 1259 } |
| 1212 // TODO(ahe): Create an error somehow. | 1260 // TODO(ahe): Create an error somehow. |
| 1213 return const DynamicType(); | 1261 return const DynamicType(); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1251 if (name is Identifier) { | 1299 if (name is Identifier) { |
| 1252 name = name.name; | 1300 name = name.name; |
| 1253 } | 1301 } |
| 1254 if (name is BuilderAccessor) { | 1302 if (name is BuilderAccessor) { |
| 1255 warning("'${beginToken.lexeme}' isn't a type.", beginToken.charOffset); | 1303 warning("'${beginToken.lexeme}' isn't a type.", beginToken.charOffset); |
| 1256 push(const DynamicType()); | 1304 push(const DynamicType()); |
| 1257 } else if (name is UnresolvedIdentifier) { | 1305 } else if (name is UnresolvedIdentifier) { |
| 1258 warning("'${name.name}' isn't a type.", beginToken.charOffset); | 1306 warning("'${name.name}' isn't a type.", beginToken.charOffset); |
| 1259 push(const DynamicType()); | 1307 push(const DynamicType()); |
| 1260 } else if (name is TypeVariableBuilder) { | 1308 } else if (name is TypeVariableBuilder) { |
| 1309 if (constantExpressionRequired) { | |
| 1310 addCompileTimeError( | |
| 1311 beginToken.charOffset, "Not a constant expression."); | |
| 1312 } | |
| 1261 push(name.buildTypesWithBuiltArguments(library, arguments)); | 1313 push(name.buildTypesWithBuiltArguments(library, arguments)); |
| 1262 } else if (name is TypeDeclarationBuilder) { | 1314 } else if (name is TypeDeclarationBuilder) { |
| 1263 push(name.buildTypesWithBuiltArguments(library, arguments)); | 1315 push(name.buildTypesWithBuiltArguments(library, arguments)); |
| 1264 } else if (name is TypeBuilder) { | 1316 } else if (name is TypeBuilder) { |
| 1265 push(name.build(library)); | 1317 push(name.build(library)); |
| 1266 } else if (name is Builder) { | 1318 } else if (name is Builder) { |
| 1267 push(kernelTypeFromBuilder(name, arguments, beginToken.charOffset)); | 1319 push(kernelTypeFromBuilder(name, arguments, beginToken.charOffset)); |
| 1268 } else if (name is String) { | 1320 } else if (name is String) { |
| 1269 push(kernelTypeFromString(name, arguments, beginToken.charOffset)); | 1321 push(kernelTypeFromString(name, arguments, beginToken.charOffset)); |
| 1270 } else { | 1322 } else { |
| (...skipping 1069 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2340 @override | 2392 @override |
| 2341 void handleInvalidFunctionBody(Token token) { | 2393 void handleInvalidFunctionBody(Token token) { |
| 2342 if (member.isNative) { | 2394 if (member.isNative) { |
| 2343 push(NullValue.FunctionBody); | 2395 push(NullValue.FunctionBody); |
| 2344 } else { | 2396 } else { |
| 2345 push(new Block(<Statement>[new InvalidStatement()])); | 2397 push(new Block(<Statement>[new InvalidStatement()])); |
| 2346 } | 2398 } |
| 2347 } | 2399 } |
| 2348 | 2400 |
| 2349 @override | 2401 @override |
| 2402 void warning(String message, [int charOffset = -1]) { | |
| 2403 if (constantExpressionRequired) { | |
| 2404 addCompileTimeError(charOffset, message); | |
|
Paul Berry
2017/03/22 16:18:04
This seems really scary to me. Are we sure that a
ahe
2017/03/22 16:58:02
There are a few warnings that don't follow this ru
| |
| 2405 } else { | |
| 2406 super.warning(message, charOffset); | |
| 2407 } | |
| 2408 } | |
| 2409 | |
| 2410 @override | |
| 2350 void debugEvent(String name) { | 2411 void debugEvent(String name) { |
| 2351 // printEvent(name); | 2412 // printEvent(name); |
| 2352 } | 2413 } |
| 2353 } | 2414 } |
| 2354 | 2415 |
| 2355 // TODO(ahe): Shouldn't need to be an expression. | 2416 // TODO(ahe): Shouldn't need to be an expression. |
| 2356 class UnresolvedIdentifier extends InvalidExpression { | 2417 class UnresolvedIdentifier extends InvalidExpression { |
| 2357 final Name name; | 2418 final Name name; |
| 2358 | 2419 |
| 2359 UnresolvedIdentifier(this.name); | 2420 UnresolvedIdentifier(this.name); |
| (...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2798 } else if (node is PrefixBuilder) { | 2859 } else if (node is PrefixBuilder) { |
| 2799 return node.name; | 2860 return node.name; |
| 2800 } else if (node is ThisAccessor) { | 2861 } else if (node is ThisAccessor) { |
| 2801 return node.isSuper ? "super" : "this"; | 2862 return node.isSuper ? "super" : "this"; |
| 2802 } else if (node is BuilderAccessor) { | 2863 } else if (node is BuilderAccessor) { |
| 2803 return node.plainNameForRead; | 2864 return node.plainNameForRead; |
| 2804 } else { | 2865 } else { |
| 2805 return internalError("Unhandled: ${node.runtimeType}"); | 2866 return internalError("Unhandled: ${node.runtimeType}"); |
| 2806 } | 2867 } |
| 2807 } | 2868 } |
| OLD | NEW |