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 |