[kernel] Add instance creation kernel node.

This is used in constant evaluation to represent const constructor
invocations with unevaluated field values or asserts.

Change-Id: I1d2d60a18f967a4dd195b3b5895db9a126c47803
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/98561
Reviewed-by: Kevin Millikin <kmillikin@google.com>
This commit is contained in:
Aske Simon Christensen 2019-04-04 12:22:50 +00:00 committed by commit-bot@chromium.org
parent 395e5f6037
commit f63eaab3af
17 changed files with 186 additions and 12 deletions

View file

@ -4744,6 +4744,12 @@ class ProgramCompiler extends Object
return _emitConstMap(node.keyType, node.valueType, entries);
}
@override
visitInstanceCreation(InstanceCreation node) {
// Only occurs inside unevaluated constants.
throw new UnsupportedError("Instance creation");
}
@override
visitIsExpression(IsExpression node) {
return _emitIsExpression(node.operand, node.type);

View file

@ -139,7 +139,7 @@ type CanonicalName {
type ComponentFile {
UInt32 magic = 0x90ABCDEF;
UInt32 formatVersion = 22;
UInt32 formatVersion = 23;
List<String> problemsAsJson; // Described in problems.md.
Library[] libraries;
UriSource sourceMap;
@ -720,6 +720,15 @@ type MapConcatenation extends Expression {
List<Expression> maps;
}
type InstanceCreation extends Expression {
Byte tag = 114;
FileOffset fileOffset;
CanonicalNameReference class;
List<DartType> typeArguments;
List<[FieldReference, Expression]> fieldValues;
List<AssertStatement> asserts;
}
type IsExpression extends Expression {
Byte tag = 37;
FileOffset fileOffset;

View file

@ -3314,6 +3314,56 @@ class MapConcatenation extends Expression {
}
}
/// Create an instance directly from the field values.
///
/// This expression arises from const constructor calls when one or more field
/// initializing expressions, field initializers or assert initializers contain
/// unevaluated expressions. They only ever occur within unevaluated constants
/// in constant expressions.
class InstanceCreation extends Expression {
final Reference classReference;
final List<DartType> typeArguments;
final Map<Reference, Expression> fieldValues;
final List<AssertStatement> asserts;
InstanceCreation(
this.classReference, this.typeArguments, this.fieldValues, this.asserts);
Class get classNode => classReference.asClass;
DartType getStaticType(TypeEnvironment types) {
return typeArguments.isEmpty
? classNode.rawType
: new InterfaceType(classNode, typeArguments);
}
accept(ExpressionVisitor v) => v.visitInstanceCreation(this);
accept1(ExpressionVisitor1 v, arg) => v.visitInstanceCreation(this, arg);
visitChildren(Visitor v) {
classReference.asClass.acceptReference(v);
visitList(typeArguments, v);
for (final Reference reference in fieldValues.keys) {
reference.asField.acceptReference(v);
}
for (final Expression value in fieldValues.values) {
value.accept(v);
}
visitList(asserts, v);
}
transformChildren(Transformer v) {
fieldValues.forEach((Reference fieldRef, Expression value) {
Expression transformed = value.accept(v);
if (transformed != null && !identical(value, transformed)) {
fieldValues[fieldRef] = transformed;
transformed.parent = this;
}
});
transformList(asserts, v, this);
}
}
/// Expression of form `x is T`.
class IsExpression extends Expression {
Expression operand;

View file

@ -1534,6 +1534,26 @@ class BinaryBuilder {
return new MapConcatenation(readExpressionList(),
keyType: keyType, valueType: valueType)
..fileOffset = offset;
case Tag.InstanceCreation:
int offset = readOffset();
Reference classReference = readClassReference();
List<DartType> typeArguments = readDartTypeList();
int fieldValueCount = readUInt();
Map<Reference, Expression> fieldValues = <Reference, Expression>{};
for (int i = 0; i < fieldValueCount; i++) {
final Reference fieldRef =
readCanonicalNameReference().getReference();
final Expression value = readExpression();
fieldValues[fieldRef] = value;
}
int assertCount = readUInt();
List<AssertStatement> asserts = new List<AssertStatement>(assertCount);
for (int i = 0; i < assertCount; i++) {
asserts[i] = readStatement();
}
return new InstanceCreation(
classReference, typeArguments, fieldValues, asserts)
..fileOffset = offset;
case Tag.IsExpression:
int offset = readOffset();
return new IsExpression(readExpression(), readDartType())

View file

@ -1502,6 +1502,20 @@ class BinaryPrinter implements Visitor<void>, BinarySink {
writeNodeList(node.maps);
}
@override
void visitInstanceCreation(InstanceCreation node) {
writeByte(Tag.InstanceCreation);
writeOffset(node.fileOffset);
writeNonNullReference(node.classReference);
writeNodeList(node.typeArguments);
writeUInt30(node.fieldValues.length);
node.fieldValues.forEach((Reference fieldRef, Expression value) {
writeNonNullReference(fieldRef);
writeNode(value);
});
writeNodeList(node.asserts);
}
@override
void visitIsExpression(IsExpression node) {
writeByte(Tag.IsExpression);

View file

@ -53,6 +53,7 @@ class Tag {
static const int ListConcatenation = 111;
static const int SetConcatenation = 112;
static const int MapConcatenation = 113;
static const int InstanceCreation = 114;
static const int IsExpression = 37;
static const int AsExpression = 38;
static const int StringLiteral = 39;
@ -129,6 +130,7 @@ class Tag {
/// 111 is occupied by [ListConcatenation] (expression).
/// 112 is occupied by [SetConcatenation] (expression).
/// 113 is occupied by [MapConcatenation] (expression).
/// 114 is occupied by [InstanceCreation] (expression).
static const int SpecializedTagHighBit = 0x80; // 10000000
static const int SpecializedTagMask = 0xF8; // 11111000
@ -145,7 +147,7 @@ class Tag {
/// Internal version of kernel binary format.
/// Bump it when making incompatible changes in kernel binaries.
/// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
static const int BinaryFormatVersion = 22;
static const int BinaryFormatVersion = 23;
}
abstract class ConstantTag {

View file

@ -205,6 +205,18 @@ class CloneVisitor implements TreeVisitor {
keyType: visitType(node.keyType), valueType: visitType(node.valueType));
}
visitInstanceCreation(InstanceCreation node) {
final Map<Reference, Expression> fieldValues = <Reference, Expression>{};
node.fieldValues.forEach((Reference fieldRef, Expression value) {
fieldValues[fieldRef] = clone(value);
});
return new InstanceCreation(
node.classReference,
node.typeArguments.map(visitType).toList(),
fieldValues,
node.asserts.map(clone).toList());
}
visitIsExpression(IsExpression node) {
return new IsExpression(clone(node.operand), visitType(node.type));
}

View file

@ -1302,6 +1302,39 @@ class Printer extends Visitor<Null> {
}
}
visitInstanceCreation(InstanceCreation node) {
write('${node.classNode}');
if (node.typeArguments.isNotEmpty) {
writeSymbol('<');
writeList(node.typeArguments, writeType);
writeSymbol('>');
}
write(' {');
bool first = true;
node.fieldValues.forEach((Reference fieldRef, Expression value) {
if (!first) {
writeComma();
}
write('${fieldRef.asField.name}: ');
writeExpression(value);
first = false;
});
for (AssertStatement assert_ in node.asserts) {
if (!first) {
writeComma();
}
write('assert(');
writeExpression(assert_.condition);
if (assert_.message != null) {
writeComma();
writeExpression(assert_.message);
}
write(')');
}
write('}');
}
visitIsExpression(IsExpression node) {
writeExpression(node.operand, Precedence.BITWISE_OR);
writeSpaced('is');
@ -2014,10 +2047,10 @@ class Printer extends Visitor<Null> {
node.fieldValues.forEach((Reference fieldRef, Constant constant) {
final String name = syntheticNames.nameConstant(constant);
if (!first) {
first = false;
sb.write(', ');
}
sb.write('${fieldRef.asField.name}: $name');
first = false;
});
sb.write('}');
endLine(sb.toString());

View file

@ -389,6 +389,12 @@ class TextSerializationVerifier implements Visitor<void> {
node.visitChildren(this);
}
@override
void visitInstanceCreation(InstanceCreation node) {
storeLastSeenUriAndOffset(node);
node.visitChildren(this);
}
@override
void visitSymbolConstant(SymbolConstant node) {
storeLastSeenUriAndOffset(node);

View file

@ -712,6 +712,18 @@ class TypeCheckingVisitor
return type;
}
@override
DartType visitInstanceCreation(InstanceCreation node) {
Substitution substitution = Substitution.fromPairs(
node.classNode.typeParameters, node.typeArguments);
node.fieldValues.forEach((Reference fieldRef, Expression value) {
DartType fieldType = substitution.substituteType(fieldRef.asField.type);
DartType valueType = visitExpression(value);
checkAssignable(node, fieldType, valueType);
});
return new InterfaceType(node.classNode, node.typeArguments);
}
@override
DartType visitStringLiteral(StringLiteral node) {
return environment.stringType;

View file

@ -41,6 +41,7 @@ abstract class ExpressionVisitor<R> {
R visitListConcatenation(ListConcatenation node) => defaultExpression(node);
R visitSetConcatenation(SetConcatenation node) => defaultExpression(node);
R visitMapConcatenation(MapConcatenation node) => defaultExpression(node);
R visitInstanceCreation(InstanceCreation node) => defaultExpression(node);
R visitIsExpression(IsExpression node) => defaultExpression(node);
R visitAsExpression(AsExpression node) => defaultExpression(node);
R visitSymbolLiteral(SymbolLiteral node) => defaultExpression(node);
@ -167,6 +168,7 @@ class TreeVisitor<R>
R visitListConcatenation(ListConcatenation node) => defaultExpression(node);
R visitSetConcatenation(SetConcatenation node) => defaultExpression(node);
R visitMapConcatenation(MapConcatenation node) => defaultExpression(node);
R visitInstanceCreation(InstanceCreation node) => defaultExpression(node);
R visitIsExpression(IsExpression node) => defaultExpression(node);
R visitAsExpression(AsExpression node) => defaultExpression(node);
R visitSymbolLiteral(SymbolLiteral node) => defaultExpression(node);
@ -510,6 +512,8 @@ abstract class ExpressionVisitor1<R, T> {
defaultExpression(node, arg);
R visitMapConcatenation(MapConcatenation node, T arg) =>
defaultExpression(node, arg);
R visitInstanceCreation(InstanceCreation node, T arg) =>
defaultExpression(node, arg);
R visitIsExpression(IsExpression node, T arg) => defaultExpression(node, arg);
R visitAsExpression(AsExpression node, T arg) => defaultExpression(node, arg);
R visitSymbolLiteral(SymbolLiteral node, T arg) =>

View file

@ -97,6 +97,7 @@ RawInstance* ConstantEvaluator::EvaluateExpression(intptr_t offset,
case kListConcatenation:
case kSetConcatenation:
case kMapConcatenation:
case kInstanceCreation:
// These only occur inside unevaluated constants, so if we decide to
// remove support for late evaluation of environment constants from
// dill files in the VM, an implementation here will not be necessary.

View file

@ -1159,8 +1159,9 @@ Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) {
case kListConcatenation:
case kSetConcatenation:
case kMapConcatenation:
// Collection concatenation operations are removed by the constant
// evaluator.
case kInstanceCreation:
// Collection concatenation and instance creation operations are removed
// by the constant evaluator.
UNREACHABLE();
break;
case kIsExpression:

View file

@ -450,8 +450,9 @@ void KernelFingerprintHelper::CalculateExpressionFingerprint() {
case kListConcatenation:
case kSetConcatenation:
case kMapConcatenation:
// Collection concatenation operations are removed by the constant
// evaluator.
case kInstanceCreation:
// Collection concatenation and instance creation operations are removed
// by the constant evaluator.
UNREACHABLE();
break;
case kIsExpression:

View file

@ -2237,8 +2237,9 @@ void KernelReaderHelper::SkipExpression() {
case kListConcatenation:
case kSetConcatenation:
case kMapConcatenation:
// Collection concatenation operations are removed by the constant
// evaluator.
case kInstanceCreation:
// Collection concatenation and instance creation operations are removed
// by the constant evaluator.
UNREACHABLE();
break;
case kIsExpression:

View file

@ -765,8 +765,9 @@ void ScopeBuilder::VisitExpression() {
case kListConcatenation:
case kSetConcatenation:
case kMapConcatenation:
// Collection concatenation operations are removed by the constant
// evaluator.
case kInstanceCreation:
// Collection concatenation and instance creation operations are removed
// by the constant evaluator.
UNREACHABLE();
break;
case kIsExpression:

View file

@ -20,7 +20,7 @@ static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
// Both version numbers are inclusive.
static const uint32_t kMinSupportedKernelFormatVersion = 18;
static const uint32_t kMaxSupportedKernelFormatVersion = 22;
static const uint32_t kMaxSupportedKernelFormatVersion = 23;
// Keep in sync with package:kernel/lib/binary/tag.dart
#define KERNEL_TAG_LIST(V) \
@ -65,6 +65,7 @@ static const uint32_t kMaxSupportedKernelFormatVersion = 22;
V(ListConcatenation, 111) \
V(SetConcatenation, 112) \
V(MapConcatenation, 113) \
V(InstanceCreation, 114) \
V(IsExpression, 37) \
V(AsExpression, 38) \
V(StringLiteral, 39) \