blob: 0d0fc883cfc0c8830954b5abc6e13c6bc7c16c4a [file] [log] [blame]
// 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,
EnvironmentBoolConstant,
EnvironmentIntConstant,
EnvironmentStringConstant,
IntConstant,
Library,
ListConstant,
MapConstant,
Member,
NullConstant,
StaticInvocation,
StringConstant,
TreeNode;
import 'package:kernel/type_environment.dart' show TypeEnvironment;
import 'package:kernel/transformations/constants.dart'
show ConstantsBackend, ErrorReporter;
import '../fasta_codes.dart'
show
Message,
noLength,
messageConstEvalFailedAssertion,
templateConstEvalDeferredLibrary,
templateConstEvalDuplicateKey,
templateConstEvalFailedAssertionWithMessage,
templateConstEvalFreeTypeParameter,
templateConstEvalInvalidBinaryOperandType,
templateConstEvalInvalidMethodInvocation,
templateConstEvalInvalidStaticInvocation,
templateConstEvalInvalidStringInterpolationOperand,
templateConstEvalInvalidSymbolName,
templateConstEvalInvalidType,
templateConstEvalNegativeShift,
templateConstEvalNonConstantLiteral,
templateConstEvalNonConstantVariableGet,
templateConstEvalZeroDivisor;
import '../loader.dart' show Loader;
import '../problems.dart' show unexpected, unimplemented;
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) {
return addProblem(
node,
templateConstEvalInvalidStaticInvocation
.withArguments(target.name.toString()));
}
@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));
}
}
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,
void abortEvaluation(String message)) {
// VM-specific names of the fromEnvironment factory constructors.
if (nativeName == 'Bool_fromEnvironment' ||
nativeName == 'Integer_fromEnvironment' ||
nativeName == 'String_fromEnvironment') {
if (positionalArguments.length == 1 &&
positionalArguments.first is StringConstant &&
(namedArguments.length == 0 ||
(namedArguments.length == 1 &&
namedArguments.containsKey('defaultValue')))) {
StringConstant name = positionalArguments.first;
Constant defaultValue =
namedArguments['defaultValue'] ?? new NullConstant();
if (nativeName == 'Bool_fromEnvironment') {
return new EnvironmentBoolConstant(name.value, defaultValue);
}
if (nativeName == 'Integer_fromEnvironment') {
return new EnvironmentIntConstant(name.value, defaultValue);
}
return new EnvironmentStringConstant(name.value, defaultValue);
}
return unexpected('valid constructor invocation', node.toString(),
node.fileOffset, node.location.file);
}
return unimplemented('constant evaluation of ${nativeName}',
node.fileOffset, node.location.file);
}
}