| // 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 Constant, DartType, IntConstant, Library, Member, Procedure, TreeNode; |
| |
| import 'package:kernel/type_environment.dart' show TypeEnvironment; |
| |
| 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; |
| |
| import 'constant_evaluator.dart' show ErrorReporter; |
| |
| 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); |
| } |
| } |