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 170 matching lines...) Loading... |
181 node.name.name, new Arguments.empty(), node.fileOffset, | 181 node.name.name, new Arguments.empty(), node.fileOffset, |
182 isGetter: true); | 182 isGetter: true); |
183 } else if (node is BuilderAccessor) { | 183 } else if (node is BuilderAccessor) { |
184 return node.buildSimpleRead(); | 184 return node.buildSimpleRead(); |
185 } else if (node is TypeVariableBuilder) { | 185 } else if (node is TypeVariableBuilder) { |
186 TypeParameterType type = node.buildTypesWithBuiltArguments(library, null); | 186 TypeParameterType type = node.buildTypesWithBuiltArguments(library, null); |
187 if (!isInstanceContext && type.parameter.parent is Class) { | 187 if (!isInstanceContext && type.parameter.parent is Class) { |
188 return buildCompileTimeError( | 188 return buildCompileTimeError( |
189 "Type variables can only be used in instance methods."); | 189 "Type variables can only be used in instance methods."); |
190 } else { | 190 } else { |
| 191 if (constantExpressionRequired) { |
| 192 addCompileTimeError(-1, |
| 193 "Type variable can't be used as a constant expression $type."); |
| 194 } |
191 return new TypeLiteral(type); | 195 return new TypeLiteral(type); |
192 } | 196 } |
193 } else if (node is TypeDeclarationBuilder) { | 197 } else if (node is TypeDeclarationBuilder) { |
194 return new TypeLiteral(node.buildTypesWithBuiltArguments(library, null)); | 198 return new TypeLiteral(node.buildTypesWithBuiltArguments(library, null)); |
195 } else if (node is KernelTypeBuilder) { | 199 } else if (node is KernelTypeBuilder) { |
196 return new TypeLiteral(node.build(library)); | 200 return new TypeLiteral(node.build(library)); |
197 } else if (node is Expression) { | 201 } else if (node is Expression) { |
198 return node; | 202 return node; |
199 } else if (node is PrefixBuilder) { | 203 } else if (node is PrefixBuilder) { |
200 return buildCompileTimeError("A library can't be used as an expression."); | 204 return buildCompileTimeError("A library can't be used as an expression."); |
(...skipping 332 matching lines...) Loading... |
533 } else if (arguments == null) { | 537 } else if (arguments == null) { |
534 push(receiver); | 538 push(receiver); |
535 } else { | 539 } else { |
536 push(finishSend(receiver, arguments, beginToken.charOffset)); | 540 push(finishSend(receiver, arguments, beginToken.charOffset)); |
537 } | 541 } |
538 } | 542 } |
539 | 543 |
540 @override | 544 @override |
541 finishSend(Object receiver, Arguments arguments, int charOffset) { | 545 finishSend(Object receiver, Arguments arguments, int charOffset) { |
542 if (receiver is BuilderAccessor) { | 546 if (receiver is BuilderAccessor) { |
| 547 if (constantExpressionRequired) { |
| 548 addCompileTimeError(charOffset, "Not a constant expression."); |
| 549 } |
543 return receiver.doInvocation(charOffset, arguments); | 550 return receiver.doInvocation(charOffset, arguments); |
544 } else if (receiver is UnresolvedIdentifier) { | 551 } else if (receiver is UnresolvedIdentifier) { |
545 return throwNoSuchMethodError( | 552 return throwNoSuchMethodError( |
546 receiver.name.name, arguments, receiver.fileOffset); | 553 receiver.name.name, arguments, receiver.fileOffset); |
547 } else { | 554 } else { |
548 return buildMethodInvocation( | 555 return buildMethodInvocation( |
549 toValue(receiver), callName, arguments, charOffset); | 556 toValue(receiver), callName, arguments, charOffset); |
550 } | 557 } |
551 } | 558 } |
552 | 559 |
(...skipping 187 matching lines...) Loading... |
740 String name = token.lexeme; | 747 String name = token.lexeme; |
741 if (context.isScopeReference) { | 748 if (context.isScopeReference) { |
742 assert(!inInitializer || | 749 assert(!inInitializer || |
743 this.scope == enclosingScope || | 750 this.scope == enclosingScope || |
744 this.scope.parent == enclosingScope); | 751 this.scope.parent == enclosingScope); |
745 // This deals with this kind of initializer: `C(a) : a = a;` | 752 // This deals with this kind of initializer: `C(a) : a = a;` |
746 Scope scope = inInitializer ? enclosingScope : this.scope; | 753 Scope scope = inInitializer ? enclosingScope : this.scope; |
747 Builder builder = scope.lookup(name, token.charOffset, uri); | 754 Builder builder = scope.lookup(name, token.charOffset, uri); |
748 push(builderToFirstExpression(builder, name, token.charOffset)); | 755 push(builderToFirstExpression(builder, name, token.charOffset)); |
749 } else { | 756 } else { |
| 757 if (constantExpressionRequired) { |
| 758 if (context != IdentifierContext.namedArgumentReference && |
| 759 context != IdentifierContext.constructorReferenceContinuation && |
| 760 context != IdentifierContext.expressionContinuation && |
| 761 context != IdentifierContext.typeReferenceContinuation && |
| 762 context != IdentifierContext.localVariableDeclaration && |
| 763 context != |
| 764 IdentifierContext |
| 765 .constructorReferenceContinuationAfterTypeArguments) { |
| 766 addCompileTimeError( |
| 767 token.charOffset, "Not a constant expression: $context"); |
| 768 } |
| 769 } |
750 push(new Identifier(name)..fileOffset = token.charOffset); | 770 push(new Identifier(name)..fileOffset = token.charOffset); |
751 } | 771 } |
752 } | 772 } |
753 | 773 |
754 @override | 774 @override |
755 builderToFirstExpression(Builder builder, String name, int charOffset, | 775 builderToFirstExpression(Builder builder, String name, int charOffset, |
756 {bool isPrefix: false}) { | 776 {bool isPrefix: false}) { |
757 if (builder == null || (!isInstanceContext && builder.isInstanceMember)) { | 777 if (builder == null || (!isInstanceContext && builder.isInstanceMember)) { |
758 Name n = new Name(name, library.library); | 778 Name n = new Name(name, library.library); |
759 if (!isPrefix && isInstanceContext) { | 779 if (!isPrefix && isInstanceContext) { |
760 assert(builder == null); | 780 assert(builder == null); |
| 781 if (constantExpressionRequired) { |
| 782 addCompileTimeError(charOffset, "Not a constant expression."); |
| 783 } |
761 return new ThisPropertyAccessor(this, charOffset, n, null, null); | 784 return new ThisPropertyAccessor(this, charOffset, n, null, null); |
762 } else { | 785 } else { |
| 786 if (constantExpressionRequired) { |
| 787 addCompileTimeError(charOffset, "Not a constant expression."); |
| 788 } |
763 return new UnresolvedIdentifier(n)..fileOffset = charOffset; | 789 return new UnresolvedIdentifier(n)..fileOffset = charOffset; |
764 } | 790 } |
765 } else if (builder.isTypeDeclaration) { | 791 } else if (builder.isTypeDeclaration) { |
| 792 if (constantExpressionRequired && builder.isTypeVariable) { |
| 793 addCompileTimeError(charOffset, "Not a constant expression."); |
| 794 } |
766 return builder; | 795 return builder; |
767 } else if (builder.isLocal) { | 796 } else if (builder.isLocal) { |
| 797 if (constantExpressionRequired && !builder.isConst) { |
| 798 addCompileTimeError(charOffset, "Not a constant expression."); |
| 799 } |
768 return new VariableAccessor(this, charOffset, builder.target); | 800 return new VariableAccessor(this, charOffset, builder.target); |
769 } else if (builder.isInstanceMember) { | 801 } else if (builder.isInstanceMember) { |
| 802 if (constantExpressionRequired) { |
| 803 addCompileTimeError(charOffset, "Not a constant expression."); |
| 804 } |
770 return new ThisPropertyAccessor( | 805 return new ThisPropertyAccessor( |
771 this, charOffset, new Name(name, library.library), null, null); | 806 this, charOffset, new Name(name, library.library), null, null); |
772 } else if (builder.isRegularMethod) { | 807 } else if (builder.isRegularMethod) { |
773 assert(builder.isStatic || builder.isTopLevel); | 808 assert(builder.isStatic || builder.isTopLevel); |
774 return new StaticAccessor(this, charOffset, builder.target, null); | 809 return new StaticAccessor(this, charOffset, builder.target, null); |
775 } else if (builder is PrefixBuilder) { | 810 } else if (builder is PrefixBuilder) { |
776 return builder; | 811 return builder; |
777 } else if (builder is MixedAccessor) { | 812 } else if (builder is MixedAccessor) { |
| 813 if (constantExpressionRequired && !builder.getter.target.isConst) { |
| 814 addCompileTimeError(charOffset, "Not a constant expression."); |
| 815 } |
778 return new StaticAccessor( | 816 return new StaticAccessor( |
779 this, charOffset, builder.getter.target, builder.setter.target); | 817 this, charOffset, builder.getter.target, builder.setter.target); |
780 } else { | 818 } else { |
781 if (builder.hasProblem && builder is! AccessErrorBuilder) return builder; | 819 if (builder.hasProblem && builder is! AccessErrorBuilder) return builder; |
782 Builder setter; | 820 Builder setter; |
783 if (builder.isSetter) { | 821 if (builder.isSetter) { |
784 setter = builder; | 822 setter = builder; |
785 } else if (builder.isGetter) { | 823 } else if (builder.isGetter) { |
786 setter = scope.lookupSetter(name, charOffset, uri); | 824 setter = scope.lookupSetter(name, charOffset, uri); |
787 } else if (builder.isField && !builder.isFinal) { | 825 } else if (builder.isField && !builder.isFinal) { |
788 setter = builder; | 826 setter = builder; |
789 } | 827 } |
790 return new StaticAccessor.fromBuilder(this, builder, charOffset, setter); | 828 StaticAccessor accessor = |
| 829 new StaticAccessor.fromBuilder(this, builder, charOffset, setter); |
| 830 if (constantExpressionRequired) { |
| 831 Member readTarget = accessor.readTarget; |
| 832 if (!(readTarget is Field && readTarget.isConst)) { |
| 833 addCompileTimeError(charOffset, "Not a constant expression."); |
| 834 } |
| 835 } |
| 836 return accessor; |
791 } | 837 } |
792 } | 838 } |
793 | 839 |
794 @override | 840 @override |
795 void handleQualified(Token period) { | 841 void handleQualified(Token period) { |
796 debugEvent("Qualified"); | 842 debugEvent("Qualified"); |
797 Identifier name = pop(); | 843 Identifier name = pop(); |
798 var receiver = pop(); | 844 var receiver = pop(); |
799 push([receiver, name]); | 845 push([receiver, name]); |
800 } | 846 } |
(...skipping 407 matching lines...) Loading... |
1208 if (builder == null) { | 1254 if (builder == null) { |
1209 warning("Type not found: '$name'.", charOffset); | 1255 warning("Type not found: '$name'.", charOffset); |
1210 return const DynamicType(); | 1256 return const DynamicType(); |
1211 } else { | 1257 } else { |
1212 return kernelTypeFromBuilder(builder, arguments, charOffset); | 1258 return kernelTypeFromBuilder(builder, arguments, charOffset); |
1213 } | 1259 } |
1214 } | 1260 } |
1215 | 1261 |
1216 DartType kernelTypeFromBuilder( | 1262 DartType kernelTypeFromBuilder( |
1217 Builder builder, List<DartType> arguments, int charOffset) { | 1263 Builder builder, List<DartType> arguments, int charOffset) { |
| 1264 if (constantExpressionRequired && builder is TypeVariableBuilder) { |
| 1265 addCompileTimeError(charOffset, "Not a constant expression."); |
| 1266 } |
1218 if (builder is TypeDeclarationBuilder) { | 1267 if (builder is TypeDeclarationBuilder) { |
1219 return builder.buildTypesWithBuiltArguments(library, arguments); | 1268 return builder.buildTypesWithBuiltArguments(library, arguments); |
1220 } else if (builder.hasProblem) { | 1269 } else if (builder.hasProblem) { |
1221 ProblemBuilder problem = builder; | 1270 ProblemBuilder problem = builder; |
1222 addCompileTimeError(charOffset, problem.message); | 1271 addCompileTimeError(charOffset, problem.message); |
1223 } else { | 1272 } else { |
1224 warning("Not a type: '${builder.fullNameForErrors}'.", charOffset); | 1273 warning("Not a type: '${builder.fullNameForErrors}'.", charOffset); |
1225 } | 1274 } |
1226 // TODO(ahe): Create an error somehow. | 1275 // TODO(ahe): Create an error somehow. |
1227 return const DynamicType(); | 1276 return const DynamicType(); |
(...skipping 37 matching lines...) Loading... |
1265 if (name is Identifier) { | 1314 if (name is Identifier) { |
1266 name = name.name; | 1315 name = name.name; |
1267 } | 1316 } |
1268 if (name is BuilderAccessor) { | 1317 if (name is BuilderAccessor) { |
1269 warning("'${beginToken.lexeme}' isn't a type.", beginToken.charOffset); | 1318 warning("'${beginToken.lexeme}' isn't a type.", beginToken.charOffset); |
1270 push(const DynamicType()); | 1319 push(const DynamicType()); |
1271 } else if (name is UnresolvedIdentifier) { | 1320 } else if (name is UnresolvedIdentifier) { |
1272 warning("'${name.name}' isn't a type.", beginToken.charOffset); | 1321 warning("'${name.name}' isn't a type.", beginToken.charOffset); |
1273 push(const DynamicType()); | 1322 push(const DynamicType()); |
1274 } else if (name is TypeVariableBuilder) { | 1323 } else if (name is TypeVariableBuilder) { |
| 1324 if (constantExpressionRequired) { |
| 1325 addCompileTimeError( |
| 1326 beginToken.charOffset, "Not a constant expression."); |
| 1327 } |
1275 push(name.buildTypesWithBuiltArguments(library, arguments)); | 1328 push(name.buildTypesWithBuiltArguments(library, arguments)); |
1276 } else if (name is TypeDeclarationBuilder) { | 1329 } else if (name is TypeDeclarationBuilder) { |
1277 push(name.buildTypesWithBuiltArguments(library, arguments)); | 1330 push(name.buildTypesWithBuiltArguments(library, arguments)); |
1278 } else if (name is TypeBuilder) { | 1331 } else if (name is TypeBuilder) { |
1279 push(name.build(library)); | 1332 push(name.build(library)); |
1280 } else if (name is Builder) { | 1333 } else if (name is Builder) { |
1281 push(kernelTypeFromBuilder(name, arguments, beginToken.charOffset)); | 1334 push(kernelTypeFromBuilder(name, arguments, beginToken.charOffset)); |
1282 } else if (name is String) { | 1335 } else if (name is String) { |
1283 push(kernelTypeFromString(name, arguments, beginToken.charOffset)); | 1336 push(kernelTypeFromString(name, arguments, beginToken.charOffset)); |
1284 } else { | 1337 } else { |
(...skipping 1056 matching lines...) Loading... |
2341 push(new Operator(token.stringValue)..fileOffset = token.charOffset); | 2394 push(new Operator(token.stringValue)..fileOffset = token.charOffset); |
2342 } | 2395 } |
2343 | 2396 |
2344 @override | 2397 @override |
2345 void handleSymbolVoid(Token token) { | 2398 void handleSymbolVoid(Token token) { |
2346 logEvent("SymbolVoid"); | 2399 logEvent("SymbolVoid"); |
2347 } | 2400 } |
2348 | 2401 |
2349 dynamic addCompileTimeError(int charOffset, String message, | 2402 dynamic addCompileTimeError(int charOffset, String message, |
2350 {bool silent: false}) { | 2403 {bool silent: false}) { |
| 2404 // TODO(ahe): If constantExpressionRequired is set, set it to false to |
| 2405 // avoid a long list of errors. |
2351 return library.addCompileTimeError(charOffset, message, fileUri: uri); | 2406 return library.addCompileTimeError(charOffset, message, fileUri: uri); |
2352 } | 2407 } |
2353 | 2408 |
2354 @override | 2409 @override |
2355 void handleInvalidFunctionBody(Token token) { | 2410 void handleInvalidFunctionBody(Token token) { |
2356 if (member.isNative) { | 2411 if (member.isNative) { |
2357 push(NullValue.FunctionBody); | 2412 push(NullValue.FunctionBody); |
2358 } else { | 2413 } else { |
2359 push(new Block(<Statement>[new InvalidStatement()])); | 2414 push(new Block(<Statement>[new InvalidStatement()])); |
2360 } | 2415 } |
2361 } | 2416 } |
2362 | 2417 |
2363 @override | 2418 @override |
| 2419 void warning(String message, [int charOffset = -1]) { |
| 2420 if (constantExpressionRequired) { |
| 2421 addCompileTimeError(charOffset, message); |
| 2422 } else { |
| 2423 super.warning(message, charOffset); |
| 2424 } |
| 2425 } |
| 2426 |
| 2427 @override |
2364 void debugEvent(String name) { | 2428 void debugEvent(String name) { |
2365 // printEvent(name); | 2429 // printEvent(name); |
2366 } | 2430 } |
2367 } | 2431 } |
2368 | 2432 |
2369 // TODO(ahe): Shouldn't need to be an expression. | 2433 // TODO(ahe): Shouldn't need to be an expression. |
2370 class UnresolvedIdentifier extends InvalidExpression { | 2434 class UnresolvedIdentifier extends InvalidExpression { |
2371 final Name name; | 2435 final Name name; |
2372 | 2436 |
2373 UnresolvedIdentifier(this.name); | 2437 UnresolvedIdentifier(this.name); |
(...skipping 438 matching lines...) Loading... |
2812 } else if (node is PrefixBuilder) { | 2876 } else if (node is PrefixBuilder) { |
2813 return node.name; | 2877 return node.name; |
2814 } else if (node is ThisAccessor) { | 2878 } else if (node is ThisAccessor) { |
2815 return node.isSuper ? "super" : "this"; | 2879 return node.isSuper ? "super" : "this"; |
2816 } else if (node is BuilderAccessor) { | 2880 } else if (node is BuilderAccessor) { |
2817 return node.plainNameForRead; | 2881 return node.plainNameForRead; |
2818 } else { | 2882 } else { |
2819 return internalError("Unhandled: ${node.runtimeType}"); | 2883 return internalError("Unhandled: ${node.runtimeType}"); |
2820 } | 2884 } |
2821 } | 2885 } |
OLD | NEW |