mirror of
https://github.com/dart-lang/sdk
synced 2024-09-20 02:50:20 +00:00
Support deserialization of ResolutionImpact for members of unnamed mixin applications
R=sigmund@google.com Review URL: https://codereview.chromium.org/1901683002 .
This commit is contained in:
parent
553eec6047
commit
4b01f4136e
|
@ -1878,6 +1878,9 @@ class _CompilerResolution implements Resolution {
|
|||
bool hasResolutionImpact(Element element) {
|
||||
assert(invariant(element, element.isDeclaration,
|
||||
message: "Element $element must be the declaration."));
|
||||
if (compiler.serialization.isDeserialized(element)) {
|
||||
return compiler.serialization.hasResolutionImpact(element);
|
||||
}
|
||||
return _resolutionImpactCache.containsKey(element);
|
||||
}
|
||||
|
||||
|
@ -1885,7 +1888,12 @@ class _CompilerResolution implements Resolution {
|
|||
ResolutionImpact getResolutionImpact(Element element) {
|
||||
assert(invariant(element, element.isDeclaration,
|
||||
message: "Element $element must be the declaration."));
|
||||
ResolutionImpact resolutionImpact = _resolutionImpactCache[element];
|
||||
ResolutionImpact resolutionImpact;
|
||||
if (compiler.serialization.isDeserialized(element)) {
|
||||
resolutionImpact = compiler.serialization.getResolutionImpact(element);
|
||||
} else {
|
||||
resolutionImpact = _resolutionImpactCache[element];
|
||||
}
|
||||
assert(invariant(element, resolutionImpact != null,
|
||||
message: "ResolutionImpact not available for $element."));
|
||||
return resolutionImpact;
|
||||
|
@ -1910,6 +1918,7 @@ class _CompilerResolution implements Resolution {
|
|||
Node tree = compiler.parser.parse(element);
|
||||
assert(invariant(element, !element.isSynthesized || tree == null));
|
||||
ResolutionImpact resolutionImpact = compiler.resolver.resolve(element);
|
||||
|
||||
if (compiler.serialization.supportSerialization ||
|
||||
retainCachesForTesting) {
|
||||
// [ResolutionImpact] is currently only used by serialization. The
|
||||
|
|
|
@ -20,7 +20,7 @@ import '../util/util.dart' show Setlet;
|
|||
import '../universe/call_structure.dart' show CallStructure;
|
||||
import '../universe/selector.dart' show Selector;
|
||||
import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
|
||||
import '../universe/world_impact.dart' show WorldImpactBuilder;
|
||||
import '../universe/world_impact.dart' show WorldImpact, WorldImpactBuilder;
|
||||
import '../util/enumset.dart' show EnumSet;
|
||||
import '../world.dart' show World;
|
||||
|
||||
|
@ -104,7 +104,39 @@ class _ResolutionWorldImpact extends ResolutionImpact with WorldImpactBuilder {
|
|||
: const <ConstantExpression>[];
|
||||
}
|
||||
|
||||
String toString() => '_ResolutionWorldImpact($name)';
|
||||
String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.write('_ResolutionWorldImpact($name)');
|
||||
WorldImpact.printOn(sb, this);
|
||||
if (_features != null) {
|
||||
sb.write('\n features:');
|
||||
for (Feature feature in _features.iterable(Feature.values)) {
|
||||
sb.write('\n $feature');
|
||||
}
|
||||
}
|
||||
if (_mapLiterals != null) {
|
||||
sb.write('\n map-literals:');
|
||||
for (MapLiteralUse use in _mapLiterals) {
|
||||
sb.write('\n $use');
|
||||
}
|
||||
}
|
||||
if (_listLiterals != null) {
|
||||
sb.write('\n list-literals:');
|
||||
for (ListLiteralUse use in _listLiterals) {
|
||||
sb.write('\n $use');
|
||||
}
|
||||
}
|
||||
if (_constantLiterals != null) {
|
||||
sb.write('\n const-literals:');
|
||||
for (ConstantExpression constant in _constantLiterals) {
|
||||
sb.write('\n ${constant.getText()}');
|
||||
}
|
||||
}
|
||||
if (_constSymbolNames != null) {
|
||||
sb.write('\n const-symbol-names: $_constSymbolNames');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/// [ResolutionRegistry] collects all resolution information. It stores node
|
||||
|
|
|
@ -753,6 +753,14 @@ bool testResolutionImpactEquivalence(
|
|||
bool testResolvedAstEquivalence(
|
||||
ResolvedAst resolvedAst1, ResolvedAst resolvedAst2,
|
||||
[TestStrategy strategy = const TestStrategy()]) {
|
||||
if (!strategy.test(resolvedAst1, resolvedAst1, 'kind', resolvedAst1.kind,
|
||||
resolvedAst2.kind)) {
|
||||
return false;
|
||||
}
|
||||
if (resolvedAst1.kind != ResolvedAstKind.PARSED) {
|
||||
// Nothing more to check.
|
||||
return true;
|
||||
}
|
||||
return strategy.testElements(resolvedAst1, resolvedAst2, 'element',
|
||||
resolvedAst1.element, resolvedAst2.element) &&
|
||||
new NodeEquivalenceVisitor(strategy).testNodes(resolvedAst1, resolvedAst2,
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
library dart2js.serialization.impact;
|
||||
|
||||
import '../common.dart';
|
||||
import '../common/resolution.dart';
|
||||
import '../constants/expressions.dart';
|
||||
import '../dart_types.dart';
|
||||
|
@ -19,12 +20,13 @@ import 'serialization_util.dart';
|
|||
/// Visitor that serializes a [ResolutionImpact] object using an
|
||||
/// [ObjectEncoder].
|
||||
class ImpactSerializer implements WorldImpactVisitor {
|
||||
final Element element;
|
||||
final ObjectEncoder objectEncoder;
|
||||
final ListEncoder staticUses;
|
||||
final ListEncoder dynamicUses;
|
||||
final ListEncoder typeUses;
|
||||
|
||||
ImpactSerializer(ObjectEncoder objectEncoder)
|
||||
ImpactSerializer(this.element, ObjectEncoder objectEncoder)
|
||||
: this.objectEncoder = objectEncoder,
|
||||
staticUses = objectEncoder.createList(Key.STATIC_USES),
|
||||
dynamicUses = objectEncoder.createList(Key.DYNAMIC_USES),
|
||||
|
@ -64,14 +66,10 @@ class ImpactSerializer implements WorldImpactVisitor {
|
|||
|
||||
@override
|
||||
void visitStaticUse(StaticUse staticUse) {
|
||||
if (staticUse.element.isGenerativeConstructor &&
|
||||
staticUse.element.enclosingClass.isUnnamedMixinApplication) {
|
||||
// TODO(johnniwinther): Handle static use of forwarding constructors.
|
||||
return;
|
||||
}
|
||||
ObjectEncoder object = staticUses.createObject();
|
||||
object.setEnum(Key.KIND, staticUse.kind);
|
||||
object.setElement(Key.ELEMENT, staticUse.element);
|
||||
serializeElementReference(
|
||||
element, Key.ELEMENT, Key.NAME, object, staticUse.element);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -95,29 +93,35 @@ class DeserializedResolutionImpact extends WorldImpact
|
|||
final Iterable<TypeUse> typeUses;
|
||||
|
||||
DeserializedResolutionImpact(
|
||||
{this.constSymbolNames,
|
||||
this.constantLiterals,
|
||||
this.dynamicUses,
|
||||
{this.constSymbolNames: const <String>[],
|
||||
this.constantLiterals: const <ConstantExpression>[],
|
||||
this.dynamicUses: const <DynamicUse>[],
|
||||
EnumSet<Feature> features,
|
||||
this.listLiterals,
|
||||
this.mapLiterals,
|
||||
this.staticUses,
|
||||
this.typeUses})
|
||||
this.listLiterals: const <ListLiteralUse>[],
|
||||
this.mapLiterals: const <MapLiteralUse>[],
|
||||
this.staticUses: const <StaticUse>[],
|
||||
this.typeUses: const <TypeUse>[]})
|
||||
: this._features = features;
|
||||
|
||||
Iterable<Feature> get features => _features.iterable(Feature.values);
|
||||
Iterable<Feature> get features {
|
||||
return _features != null
|
||||
? _features.iterable(Feature.values)
|
||||
: const <Feature>[];
|
||||
}
|
||||
}
|
||||
|
||||
class ImpactDeserializer {
|
||||
/// Deserializes a [WorldImpact] from [objectDecoder].
|
||||
static ResolutionImpact deserializeImpact(ObjectDecoder objectDecoder) {
|
||||
static ResolutionImpact deserializeImpact(
|
||||
Element element, ObjectDecoder objectDecoder) {
|
||||
ListDecoder staticUseDecoder = objectDecoder.getList(Key.STATIC_USES);
|
||||
List<StaticUse> staticUses = <StaticUse>[];
|
||||
for (int index = 0; index < staticUseDecoder.length; index++) {
|
||||
ObjectDecoder object = staticUseDecoder.getObject(index);
|
||||
StaticUseKind kind = object.getEnum(Key.KIND, StaticUseKind.values);
|
||||
Element element = object.getElement(Key.ELEMENT);
|
||||
staticUses.add(new StaticUse.internal(element, kind));
|
||||
Element usedElement =
|
||||
deserializeElementReference(element, Key.ELEMENT, Key.NAME, object);
|
||||
staticUses.add(new StaticUse.internal(usedElement, kind));
|
||||
}
|
||||
|
||||
ListDecoder dynamicUseDecoder = objectDecoder.getList(Key.DYNAMIC_USES);
|
||||
|
|
|
@ -209,13 +209,8 @@ class ResolvedAstSerializer extends Visitor {
|
|||
visitNode(Node node) {
|
||||
Element nodeElement = elements[node];
|
||||
if (nodeElement != null) {
|
||||
if (nodeElement.enclosingClass != null &&
|
||||
nodeElement.enclosingClass.isUnnamedMixinApplication) {
|
||||
// TODO(johnniwinther): Handle references to members of unnamed mixin
|
||||
// applications.
|
||||
} else {
|
||||
getNodeDataEncoder(node).setElement(Key.ELEMENT, nodeElement);
|
||||
}
|
||||
serializeElementReference(element, Key.ELEMENT, Key.NAME,
|
||||
getNodeDataEncoder(node), nodeElement);
|
||||
}
|
||||
DartType type = elements.getType(node);
|
||||
if (type != null) {
|
||||
|
@ -544,8 +539,9 @@ class ResolvedAstDeserializer {
|
|||
ObjectDecoder objectDecoder = dataDecoder.getObject(i);
|
||||
int id = objectDecoder.getInt(Key.ID);
|
||||
Node node = nodeList[id];
|
||||
Element nodeElement =
|
||||
objectDecoder.getElement(Key.ELEMENT, isOptional: true);
|
||||
Element nodeElement = deserializeElementReference(
|
||||
element, Key.ELEMENT, Key.NAME, objectDecoder,
|
||||
isOptional: true);
|
||||
if (nodeElement != null) {
|
||||
elements[node] = nodeElement;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
library dart2js.serialization.util;
|
||||
|
||||
import '../common.dart';
|
||||
import '../constants/expressions.dart';
|
||||
import '../dart_types.dart';
|
||||
import '../elements/elements.dart';
|
||||
|
@ -474,3 +475,45 @@ AccessSemantics deserializeAccessSemantics(ObjectDecoder decoder) {
|
|||
throw new UnsupportedError('Unsupported access kind: $kind');
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize a reference from [context] to an [element] which might be a member
|
||||
/// of an unnamed mixin application. If it is, [element] is by serialized
|
||||
/// indirectly by name in the [nameKey] of [encoder], otherwise [element] is
|
||||
/// serialized directly in [elementKey] in [encoder].
|
||||
void serializeElementReference(Element context, Key elementKey, Key nameKey,
|
||||
ObjectEncoder encoder, Element element) {
|
||||
if (element.isGenerativeConstructor &&
|
||||
element.enclosingClass.isUnnamedMixinApplication) {
|
||||
assert(invariant(element, element.isConstructor,
|
||||
message: "Unexpected reference of forwarding constructor "
|
||||
"${element} from $context."));
|
||||
encoder.setString(nameKey, element.name);
|
||||
} else {
|
||||
encoder.setElement(elementKey, element);
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize a reference from [context] to an [Element] which might be a
|
||||
/// member of an unnamed mixin application. If it is, the [Element] is by
|
||||
/// deserialized indirectly by name from [nameKey] in [decoder], otherwise
|
||||
/// the [Element] is deserialized directly from [elementKey] in [encoder].
|
||||
Element deserializeElementReference(
|
||||
Element context, Key elementKey, Key nameKey, ObjectDecoder decoder,
|
||||
{bool isOptional: false}) {
|
||||
Element element = decoder.getElement(elementKey, isOptional: true);
|
||||
if (element == null) {
|
||||
String elementName = decoder.getString(nameKey, isOptional: isOptional);
|
||||
if (elementName == null) {
|
||||
return null;
|
||||
}
|
||||
assert(invariant(NO_LOCATION_SPANNABLE, context.isConstructor,
|
||||
message: "Unexpected reference of forwarding constructor "
|
||||
"'${elementName}' from $context."));
|
||||
ClassElement superclass = context.enclosingClass.superclass;
|
||||
element = superclass.lookupConstructor(elementName);
|
||||
assert(invariant(NO_LOCATION_SPANNABLE, element != null,
|
||||
message: "Unresolved reference of forwarding constructor "
|
||||
"'${elementName}' from $context."));
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,16 @@ class SerializationTask extends CompilerTask implements LibraryDeserializer {
|
|||
return deserializer != null && deserializer.isDeserialized(element);
|
||||
}
|
||||
|
||||
bool hasResolutionImpact(Element element) {
|
||||
return deserializer != null && deserializer.hasResolutionImpact(element);
|
||||
}
|
||||
|
||||
ResolutionImpact getResolutionImpact(Element element) {
|
||||
return deserializer != null
|
||||
? deserializer.getResolutionImpact(element)
|
||||
: null;
|
||||
}
|
||||
|
||||
/// Creates the [ResolutionWorkItem] for the deserialized [element].
|
||||
ResolutionWorkItem createResolutionWorkItem(
|
||||
Element element, ItemCompilationContext context) {
|
||||
|
@ -94,6 +104,7 @@ abstract class DeserializerSystem {
|
|||
bool isDeserialized(Element element);
|
||||
bool hasResolvedAst(Element element);
|
||||
ResolvedAst getResolvedAst(Element element);
|
||||
bool hasResolutionImpact(Element element);
|
||||
ResolutionImpact getResolutionImpact(Element element);
|
||||
WorldImpact computeWorldImpact(Element element);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,9 @@ import 'package:compiler/src/serialization/resolved_ast_serialization.dart';
|
|||
import 'package:compiler/src/serialization/serialization.dart';
|
||||
import 'package:compiler/src/serialization/task.dart';
|
||||
import 'package:compiler/src/tokens/token.dart';
|
||||
import 'package:compiler/src/universe/call_structure.dart';
|
||||
import 'package:compiler/src/universe/world_impact.dart';
|
||||
import 'package:compiler/src/universe/use.dart';
|
||||
|
||||
import 'memory_compiler.dart';
|
||||
|
||||
|
@ -142,7 +144,7 @@ class ResolutionImpactSerializer extends SerializerPlugin {
|
|||
if (resolution.hasBeenResolved(element)) {
|
||||
ResolutionImpact impact = resolution.getResolutionImpact(element);
|
||||
ObjectEncoder encoder = createEncoder(WORLD_IMPACT_TAG);
|
||||
new ImpactSerializer(encoder).serialize(impact);
|
||||
new ImpactSerializer(element, encoder).serialize(impact);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +156,8 @@ class ResolutionImpactDeserializer extends DeserializerPlugin {
|
|||
void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
|
||||
ObjectDecoder decoder = getDecoder(WORLD_IMPACT_TAG);
|
||||
if (decoder != null) {
|
||||
impactMap[element] = ImpactDeserializer.deserializeImpact(decoder);
|
||||
impactMap[element] =
|
||||
ImpactDeserializer.deserializeImpact(element, decoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -220,8 +223,33 @@ class _DeserializerSystem extends DeserializerSystem {
|
|||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
bool hasResolutionImpact(Element element) {
|
||||
if (element.isConstructor &&
|
||||
element.enclosingClass.isUnnamedMixinApplication) {
|
||||
return true;
|
||||
}
|
||||
return _resolutionImpactDeserializer.impactMap.containsKey(element);
|
||||
}
|
||||
|
||||
@override
|
||||
ResolutionImpact getResolutionImpact(Element element) {
|
||||
if (element.isConstructor &&
|
||||
element.enclosingClass.isUnnamedMixinApplication) {
|
||||
ClassElement superclass = element.enclosingClass.superclass;
|
||||
ConstructorElement superclassConstructor =
|
||||
superclass.lookupConstructor(element.name);
|
||||
assert(invariant(element, superclassConstructor != null,
|
||||
message: "Superclass constructor '${element.name}' called from "
|
||||
"${element} not found in ${superclass}."));
|
||||
// TODO(johnniwinther): Compute callStructure. Currently not used.
|
||||
CallStructure callStructure;
|
||||
return _resolutionImpactDeserializer.impactMap.putIfAbsent(element, () {
|
||||
return new DeserializedResolutionImpact(
|
||||
staticUses: <StaticUse>[new StaticUse.superConstructorInvoke(
|
||||
superclassConstructor, callStructure)]);
|
||||
});
|
||||
}
|
||||
return _resolutionImpactDeserializer.impactMap[element];
|
||||
}
|
||||
|
||||
|
|
|
@ -294,9 +294,20 @@ void checkLoadedLibraryMembers(
|
|||
if (member1.isClass && member2.isClass) {
|
||||
ClassElement class1 = member1;
|
||||
ClassElement class2 = member2;
|
||||
if (!class1.isResolved) return;
|
||||
|
||||
class1.forEachLocalMember((m1) {
|
||||
checkMembers(m1, class2.lookupLocalMember(m1.name));
|
||||
checkMembers(m1, class2.localLookup(m1.name));
|
||||
});
|
||||
ClassElement superclass1 = class1.superclass;
|
||||
ClassElement superclass2 = class2.superclass;
|
||||
while (superclass1 != null && superclass1.isUnnamedMixinApplication) {
|
||||
for (ConstructorElement c1 in superclass1.constructors) {
|
||||
checkMembers(c1, superclass2.lookupConstructor(c1.name));
|
||||
}
|
||||
superclass1 = superclass1.superclass;
|
||||
superclass2 = superclass2.superclass;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -305,7 +316,7 @@ void checkLoadedLibraryMembers(
|
|||
}
|
||||
|
||||
if (member2 == null) {
|
||||
return;
|
||||
throw 'Missing member for ${member1}';
|
||||
}
|
||||
|
||||
if (areElementsEquivalent(member1, member2)) {
|
||||
|
@ -348,14 +359,20 @@ void checkImpacts(Compiler compiler1, Element member1,
|
|||
Compiler compiler2, Element member2,
|
||||
{bool verbose: false}) {
|
||||
ResolutionImpact impact1 = compiler1.resolution.getResolutionImpact(member1);
|
||||
ResolutionImpact impact2 =
|
||||
compiler2.serialization.deserializer.getResolutionImpact(member2);
|
||||
ResolutionImpact impact2 = compiler2.resolution.getResolutionImpact(member2);
|
||||
|
||||
if (impact1 == null || impact2 == null) return;
|
||||
if (impact1 == null && impact2 == null) return;
|
||||
|
||||
if (verbose) {
|
||||
print('Checking impacts for $member1 vs $member2');
|
||||
}
|
||||
|
||||
if (impact1 == null) {
|
||||
throw 'Missing impact for $member1. $member2 has $impact2';
|
||||
}
|
||||
if (impact2 == null) {
|
||||
throw 'Missing impact for $member2. $member1 has $impact1';
|
||||
}
|
||||
|
||||
testResolutionImpactEquivalence(impact1, impact2, const CheckStrategy());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue