| // Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| library fasta.kernel_constants; |
| |
| import 'package:kernel/ast.dart' |
| show |
| Arguments, |
| Constant, |
| DartType, |
| IntConstant, |
| Library, |
| ListConstant, |
| MapConstant, |
| Member, |
| Procedure, |
| StaticInvocation, |
| TreeNode, |
| UnevaluatedConstant; |
| |
| import 'package:kernel/type_environment.dart' show TypeEnvironment; |
| |
| import 'package:kernel/transformations/constants.dart' |
| show ConstantsBackend, ErrorReporter; |
| |
| import '../fasta_codes.dart' |
| show |
| Message, |
| noLength, |
| messageConstEvalCircularity, |
| messageConstEvalFailedAssertion, |
| templateConstEvalDeferredLibrary, |
| templateConstEvalDuplicateKey, |
| templateConstEvalFailedAssertionWithMessage, |
| templateConstEvalFreeTypeParameter, |
| templateConstEvalInvalidBinaryOperandType, |
| templateConstEvalInvalidMethodInvocation, |
| templateConstEvalInvalidStaticInvocation, |
| templateConstEvalInvalidStringInterpolationOperand, |
| templateConstEvalInvalidSymbolName, |
| templateConstEvalInvalidType, |
| templateConstEvalNegativeShift, |
| templateConstEvalNonConstantLiteral, |
| templateConstEvalNonConstantVariableGet, |
| templateConstEvalZeroDivisor; |
| |
| import '../loader.dart' show Loader; |
| |
| class KernelConstantErrorReporter extends ErrorReporter { |
| final Loader<Library> loader; |
| final TypeEnvironment typeEnvironment; |
| |
| KernelConstantErrorReporter(this.loader, this.typeEnvironment); |
| |
| String addProblem(TreeNode node, Message message) { |
| int offset = getFileOffset(node); |
| Uri uri = getFileUri(node); |
| loader.addProblem(message, offset, noLength, uri); |
| return loader.target.context.format( |
| message.withLocation(uri, offset, noLength), message.code.severity); |
| } |
| |
| @override |
| String freeTypeParameter( |
| List<TreeNode> context, TreeNode node, DartType type) { |
| return addProblem( |
| node, templateConstEvalFreeTypeParameter.withArguments(type)); |
| } |
| |
| @override |
| String duplicateKey(List<TreeNode> context, TreeNode node, Constant key) { |
| return addProblem(node, templateConstEvalDuplicateKey.withArguments(key)); |
| } |
| |
| @override |
| String invalidDartType(List<TreeNode> context, TreeNode node, |
| Constant receiver, DartType expectedType) { |
| return addProblem( |
| node, |
| templateConstEvalInvalidType.withArguments( |
| receiver, expectedType, receiver.getType(typeEnvironment))); |
| } |
| |
| @override |
| String invalidBinaryOperandType( |
| List<TreeNode> context, |
| TreeNode node, |
| Constant receiver, |
| String op, |
| DartType expectedType, |
| DartType actualType) { |
| return addProblem( |
| node, |
| templateConstEvalInvalidBinaryOperandType.withArguments( |
| op, receiver, expectedType, actualType)); |
| } |
| |
| @override |
| String invalidMethodInvocation( |
| List<TreeNode> context, TreeNode node, Constant receiver, String op) { |
| return addProblem(node, |
| templateConstEvalInvalidMethodInvocation.withArguments(op, receiver)); |
| } |
| |
| @override |
| String invalidStaticInvocation( |
| List<TreeNode> context, TreeNode node, Member target) { |
| // TODO(kmillikin) For an invalid factory invocation we should adopt a |
| // better message. This will show something like: |
| // |
| // "The invocation of 'List' is not allowed within a const context." |
| // |
| // Which is not quite right when the code was "new List()". |
| String name = target.name.toString(); |
| if (target is Procedure && target.isFactory) { |
| if (name.isEmpty) { |
| name = target.enclosingClass.name; |
| } else { |
| name = '${target.enclosingClass.name}.${name}'; |
| } |
| } |
| return addProblem( |
| node, templateConstEvalInvalidStaticInvocation.withArguments(name)); |
| } |
| |
| @override |
| String invalidStringInterpolationOperand( |
| List<TreeNode> context, TreeNode node, Constant constant) { |
| return addProblem( |
| node, |
| templateConstEvalInvalidStringInterpolationOperand |
| .withArguments(constant)); |
| } |
| |
| @override |
| String invalidSymbolName( |
| List<TreeNode> context, TreeNode node, Constant constant) { |
| return addProblem( |
| node, templateConstEvalInvalidSymbolName.withArguments(constant)); |
| } |
| |
| @override |
| String zeroDivisor( |
| List<TreeNode> context, TreeNode node, IntConstant receiver, String op) { |
| return addProblem(node, |
| templateConstEvalZeroDivisor.withArguments(op, '${receiver.value}')); |
| } |
| |
| @override |
| String negativeShift(List<TreeNode> context, TreeNode node, |
| IntConstant receiver, String op, IntConstant argument) { |
| return addProblem( |
| node, |
| templateConstEvalNegativeShift.withArguments( |
| op, '${receiver.value}', '${argument.value}')); |
| } |
| |
| @override |
| String nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) { |
| return addProblem( |
| node, templateConstEvalNonConstantLiteral.withArguments(klass)); |
| } |
| |
| @override |
| String failedAssertion(List<TreeNode> context, TreeNode node, String string) { |
| return addProblem( |
| node, |
| (string == null) |
| ? messageConstEvalFailedAssertion |
| : templateConstEvalFailedAssertionWithMessage |
| .withArguments(string)); |
| } |
| |
| @override |
| String nonConstantVariableGet( |
| List<TreeNode> context, TreeNode node, String variableName) { |
| return addProblem(node, |
| templateConstEvalNonConstantVariableGet.withArguments(variableName)); |
| } |
| |
| @override |
| String deferredLibrary( |
| List<TreeNode> context, TreeNode node, String importName) { |
| return addProblem( |
| node, templateConstEvalDeferredLibrary.withArguments(importName)); |
| } |
| |
| @override |
| String circularity(List<TreeNode> context, TreeNode node) { |
| return addProblem(node, messageConstEvalCircularity); |
| } |
| } |
| |
| class KernelConstantsBackend extends ConstantsBackend { |
| @override |
| Constant lowerListConstant(ListConstant constant) => constant; |
| |
| @override |
| Constant lowerMapConstant(MapConstant constant) => constant; |
| |
| @override |
| Constant buildConstantForNative( |
| String nativeName, |
| List<DartType> typeArguments, |
| List<Constant> positionalArguments, |
| Map<String, Constant> namedArguments, |
| List<TreeNode> context, |
| StaticInvocation node, |
| ErrorReporter errorReporter, |
| Constant abortEvaluation(String message)) { |
| // VM-specific names of the fromEnvironment factory constructors. |
| if (nativeName == 'Bool_fromEnvironment' || |
| nativeName == 'Integer_fromEnvironment' || |
| nativeName == 'String_fromEnvironment') { |
| // Replace the evaluated arguments. |
| Arguments arguments = node.arguments; |
| for (int i = 0; i < arguments.positional.length; ++i) { |
| Constant constant = positionalArguments[i]; |
| arguments.positional[i] = constant.asExpression()..parent = arguments; |
| } |
| for (int i = 0; i < arguments.named.length; ++i) { |
| Constant constant = namedArguments[arguments.named[i].name]; |
| arguments.named[i].value = constant.asExpression()..parent = arguments; |
| } |
| return new UnevaluatedConstant(node); |
| } |
| return abortEvaluation( |
| errorReporter.invalidStaticInvocation(context, node, node.target)); |
| } |
| } |