mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:49:00 +00:00
[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:
parent
395e5f6037
commit
f63eaab3af
17 changed files with 186 additions and 12 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) =>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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) \
|
||||
|
|
Loading…
Reference in a new issue