mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 03:27:43 +00:00
Include constants in deferred computation.
This ensures that in-code constants are included in the deferred computation. Currently the set of live constants is not computed in itself, so the constants used in the computation are not the same - and they are generally larger than needed. R=het@google.com Review URL: https://codereview.chromium.org/2194173002 .
This commit is contained in:
parent
b036a29cbf
commit
e6241bc12d
|
@ -133,7 +133,7 @@ abstract class ConstantExpression {
|
|||
/// if it contains positional or named references, used to define constant
|
||||
/// constructors.
|
||||
// TODO(johnniwinther): Maybe make this final if we use it outside assertions.
|
||||
bool get isPotential => true;
|
||||
bool get isPotential => false;
|
||||
}
|
||||
|
||||
/// A synthetic constant used to recover from errors.
|
||||
|
@ -194,9 +194,6 @@ class SyntheticConstantExpression extends ConstantExpression {
|
|||
|
||||
ConstantExpressionKind get kind => ConstantExpressionKind.SYNTHETIC;
|
||||
|
||||
@override
|
||||
bool get isPotential => false;
|
||||
|
||||
@override
|
||||
bool get isImplicit => false;
|
||||
}
|
||||
|
@ -1270,9 +1267,7 @@ class PositionalArgumentReference extends ConstantExpression {
|
|||
}
|
||||
|
||||
@override
|
||||
bool get isPotential {
|
||||
return true;
|
||||
}
|
||||
bool get isPotential => true;
|
||||
}
|
||||
|
||||
/// A reference to a named parameter.
|
||||
|
@ -1311,9 +1306,7 @@ class NamedArgumentReference extends ConstantExpression {
|
|||
}
|
||||
|
||||
@override
|
||||
bool get isPotential {
|
||||
return true;
|
||||
}
|
||||
bool get isPotential => true;
|
||||
}
|
||||
|
||||
abstract class FromEnvironmentConstantExpression extends ConstantExpression {
|
||||
|
|
|
@ -180,12 +180,22 @@ class DeferredLoadTask extends CompilerTask {
|
|||
return _elementToOutputUnit[element];
|
||||
}
|
||||
|
||||
/// Direct access to the output-unit to element relation used for testing.
|
||||
OutputUnit getOutputUnitForElementForTesting(Element element) {
|
||||
return _elementToOutputUnit[element];
|
||||
}
|
||||
|
||||
/// Returns the [OutputUnit] where [constant] belongs.
|
||||
OutputUnit outputUnitForConstant(ConstantValue constant) {
|
||||
if (!isProgramSplit) return mainOutputUnit;
|
||||
return _constantToOutputUnit[constant];
|
||||
}
|
||||
|
||||
/// Direct access to the output-unit to constants map used for testing.
|
||||
Map<ConstantValue, OutputUnit> get outputUnitForConstantsForTesting {
|
||||
return _constantToOutputUnit;
|
||||
}
|
||||
|
||||
bool isDeferred(Element element) {
|
||||
return outputUnitForElement(element) != mainOutputUnit;
|
||||
}
|
||||
|
@ -348,7 +358,7 @@ class DeferredLoadTask extends CompilerTask {
|
|||
treeElements.forEachConstantNode(
|
||||
(ast.Node node, ConstantExpression expression) {
|
||||
if (compiler.serialization.isDeserialized(analyzableElement)) {
|
||||
if (!expression.isImplicit && !expression.isPotential) {
|
||||
if (!expression.isPotential) {
|
||||
// Enforce evaluation of [expression].
|
||||
backend.constants.getConstantValue(expression);
|
||||
}
|
||||
|
@ -926,7 +936,8 @@ class DeferredLoadTask extends CompilerTask {
|
|||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (OutputUnit outputUnit in allOutputUnits) {
|
||||
sb.write(outputUnit.name);
|
||||
sb.write('\n-------------------------------\n');
|
||||
sb.write('Output unit: ${outputUnit.name}');
|
||||
List<String> elements = elementMap[outputUnit];
|
||||
if (elements != null) {
|
||||
sb.write('\n elements:');
|
||||
|
|
|
@ -10,6 +10,7 @@ import '../closure.dart';
|
|||
import '../common.dart';
|
||||
import '../common/resolution.dart';
|
||||
import '../constants/expressions.dart';
|
||||
import '../constants/values.dart';
|
||||
import '../dart_types.dart';
|
||||
import '../elements/elements.dart';
|
||||
import '../elements/visitor.dart';
|
||||
|
@ -63,6 +64,31 @@ bool areSetsEquivalent(Iterable set1, Iterable set2,
|
|||
return remaining.isEmpty;
|
||||
}
|
||||
|
||||
/// Returns `true` if the content of [map1] and [map2] is equivalent using
|
||||
/// [keyEquivalence] and [valueEquivalence] to determine key/value equivalence.
|
||||
bool areMapsEquivalent(Map map1, Map map2,
|
||||
[bool keyEquivalence(a, b) = equality,
|
||||
bool valueEquivalence(a, b) = equality]) {
|
||||
Set remaining = map2.keys.toSet();
|
||||
for (var key1 in map1.keys) {
|
||||
bool found = false;
|
||||
for (var key2 in map2.keys) {
|
||||
if (keyEquivalence(key2, key2)) {
|
||||
found = true;
|
||||
remaining.remove(key2);
|
||||
if (!valueEquivalence(map1[key1], map2[key2])) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return remaining.isEmpty;
|
||||
}
|
||||
|
||||
/// Returns `true` if elements [a] and [b] are equivalent.
|
||||
bool areElementsEquivalent(Element a, Element b) {
|
||||
if (identical(a, b)) return true;
|
||||
|
@ -77,13 +103,20 @@ bool areTypesEquivalent(DartType a, DartType b) {
|
|||
return const TypeEquivalence().visit(a, b);
|
||||
}
|
||||
|
||||
/// Returns `true` if constants [a] and [b] are equivalent.
|
||||
/// Returns `true` if constants [exp1] and [exp2] are equivalent.
|
||||
bool areConstantsEquivalent(ConstantExpression exp1, ConstantExpression exp2) {
|
||||
if (identical(exp1, exp2)) return true;
|
||||
if (exp1 == null || exp2 == null) return false;
|
||||
return const ConstantEquivalence().visit(exp1, exp2);
|
||||
}
|
||||
|
||||
/// Returns `true` if constant values [value1] and [value2] are equivalent.
|
||||
bool areConstantValuesEquivalent(ConstantValue value1, ConstantValue value2) {
|
||||
if (identical(value1, value2)) return true;
|
||||
if (value1 == null || value2 == null) return false;
|
||||
return const ConstantValueEquivalence().visit(value1, value2);
|
||||
}
|
||||
|
||||
/// Returns `true` if the lists of elements, [a] and [b], are equivalent.
|
||||
bool areElementListsEquivalent(List<Element> a, List<Element> b) {
|
||||
return areListsEquivalent(a, b, areElementsEquivalent);
|
||||
|
@ -100,6 +133,12 @@ bool areConstantListsEquivalent(
|
|||
return areListsEquivalent(a, b, areConstantsEquivalent);
|
||||
}
|
||||
|
||||
/// Returns `true` if the lists of constant values, [a] and [b], are equivalent.
|
||||
bool areConstantValueListsEquivalent(
|
||||
List<ConstantValue> a, List<ConstantValue> b) {
|
||||
return areListsEquivalent(a, b, areConstantValuesEquivalent);
|
||||
}
|
||||
|
||||
/// Returns `true` if the selectors [a] and [b] are equivalent.
|
||||
bool areSelectorsEquivalent(Selector a, Selector b) {
|
||||
if (identical(a, b)) return true;
|
||||
|
@ -307,6 +346,12 @@ class TestStrategy {
|
|||
return areSetsEquivalent(set1, set2, elementEquivalence);
|
||||
}
|
||||
|
||||
bool testMaps(var object1, var object2, String property, Map map1, Map map2,
|
||||
[bool keyEquivalence(a, b) = equality,
|
||||
bool valueEquivalence(a, b) = equality]) {
|
||||
return areMapsEquivalent(map1, map2, keyEquivalence, valueEquivalence);
|
||||
}
|
||||
|
||||
bool testElements(Object object1, Object object2, String property,
|
||||
Element element1, Element element2) {
|
||||
return areElementsEquivalent(element1, element2);
|
||||
|
@ -322,6 +367,11 @@ class TestStrategy {
|
|||
return areConstantsEquivalent(exp1, exp2);
|
||||
}
|
||||
|
||||
bool testConstantValues(Object object1, Object object2, String property,
|
||||
ConstantValue value1, ConstantValue value2) {
|
||||
return areConstantValuesEquivalent(value1, value2);
|
||||
}
|
||||
|
||||
bool testTypeLists(Object object1, Object object2, String property,
|
||||
List<DartType> list1, List<DartType> list2) {
|
||||
return areTypeListsEquivalent(list1, list2);
|
||||
|
@ -332,6 +382,11 @@ class TestStrategy {
|
|||
return areConstantListsEquivalent(list1, list2);
|
||||
}
|
||||
|
||||
bool testConstantValueLists(Object object1, Object object2, String property,
|
||||
List<ConstantValue> list1, List<ConstantValue> list2) {
|
||||
return areConstantValueListsEquivalent(list1, list2);
|
||||
}
|
||||
|
||||
bool testNodes(
|
||||
Object object1, Object object2, String property, Node node1, Node node2) {
|
||||
return areNodesEquivalent(node1, node2);
|
||||
|
@ -780,9 +835,130 @@ class ConstantEquivalence
|
|||
@override
|
||||
bool visitDeferred(
|
||||
DeferredConstantExpression exp1, DeferredConstantExpression exp2) {
|
||||
// TODO(johnniwinther): Implement this.
|
||||
return strategy.testElements(
|
||||
exp1, exp2, 'prefix', exp1.prefix, exp2.prefix) &&
|
||||
strategy.testConstants(
|
||||
exp1, exp2, 'expression', exp1.expression, exp2.expression);
|
||||
}
|
||||
}
|
||||
|
||||
/// Visitor that checks for structural equivalence of [ConstantValue]s.
|
||||
class ConstantValueEquivalence
|
||||
implements ConstantValueVisitor<bool, ConstantValue> {
|
||||
final TestStrategy strategy;
|
||||
|
||||
const ConstantValueEquivalence([this.strategy = const TestStrategy()]);
|
||||
|
||||
bool visit(ConstantValue value1, ConstantValue value2) {
|
||||
if (identical(value1, value2)) return true;
|
||||
return strategy.test(value1, value2, 'kind', value1.kind, value2.kind) &&
|
||||
value1.accept(this, value2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitConstructed(
|
||||
ConstructedConstantValue value1, ConstructedConstantValue value2) {
|
||||
return strategy.testTypes(
|
||||
value1, value2, 'type', value1.type, value2.type) &&
|
||||
strategy.testMaps(
|
||||
value1,
|
||||
value2,
|
||||
'fields',
|
||||
value1.fields,
|
||||
value2.fields,
|
||||
areElementsEquivalent,
|
||||
(a, b) => strategy.testConstantValues(
|
||||
value1, value2, 'fields.values', a, b));
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitFunction(
|
||||
FunctionConstantValue value1, FunctionConstantValue value2) {
|
||||
return strategy.testElements(
|
||||
value1, value2, 'element', value1.element, value2.element);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitList(ListConstantValue value1, ListConstantValue value2) {
|
||||
return strategy.testTypes(
|
||||
value1, value2, 'type', value1.type, value2.type) &&
|
||||
strategy.testConstantValueLists(
|
||||
value1, value2, 'entries', value1.entries, value2.entries);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitMap(MapConstantValue value1, MapConstantValue value2) {
|
||||
return strategy.testTypes(
|
||||
value1, value2, 'type', value1.type, value2.type) &&
|
||||
strategy.testConstantValueLists(
|
||||
value1, value2, 'keys', value1.keys, value2.keys) &&
|
||||
strategy.testConstantValueLists(
|
||||
value1, value2, 'values', value1.values, value2.values);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitType(TypeConstantValue value1, TypeConstantValue value2) {
|
||||
return strategy.testTypes(value1, value2, 'type', value1.type, value2.type);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitBool(BoolConstantValue value1, BoolConstantValue value2) {
|
||||
return strategy.test(value1, value2, 'primitiveValue',
|
||||
value1.primitiveValue, value2.primitiveValue);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitDouble(DoubleConstantValue value1, DoubleConstantValue value2) {
|
||||
return strategy.test(value1, value2, 'primitiveValue',
|
||||
value1.primitiveValue, value2.primitiveValue);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitInt(IntConstantValue value1, IntConstantValue value2) {
|
||||
return strategy.test(value1, value2, 'primitiveValue',
|
||||
value1.primitiveValue, value2.primitiveValue);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitNull(NullConstantValue value1, NullConstantValue value2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitString(StringConstantValue value1, StringConstantValue value2) {
|
||||
return strategy.test(value1, value2, 'primitiveValue',
|
||||
value1.primitiveValue, value2.primitiveValue);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitDeferred(
|
||||
DeferredConstantValue value1, DeferredConstantValue value2) {
|
||||
return strategy.testElements(
|
||||
value1, value2, 'prefix', value1.prefix, value2.prefix) &&
|
||||
strategy.testConstantValues(
|
||||
value1, value2, 'referenced', value1.referenced, value2.referenced);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitNonConstant(NonConstantValue value1, NonConstantValue value2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitSynthetic(
|
||||
SyntheticConstantValue value1, SyntheticConstantValue value2) {
|
||||
return strategy.test(
|
||||
value1, value2, 'payload', value1.payload, value2.payload) &&
|
||||
strategy.test(
|
||||
value1, value2, 'valueKind', value1.valueKind, value2.valueKind);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitInterceptor(
|
||||
InterceptorConstantValue value1, InterceptorConstantValue value2) {
|
||||
return strategy.testTypes(value1, value2, 'dispatchedType',
|
||||
value1.dispatchedType, value2.dispatchedType);
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests the equivalence of [impact1] and [impact2] using [strategy].
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:expect/expect.dart';
|
|||
import 'package:compiler/src/closure.dart';
|
||||
import 'package:compiler/src/commandline_options.dart';
|
||||
import 'package:compiler/src/common.dart';
|
||||
import 'package:compiler/src/constants/values.dart';
|
||||
import 'package:compiler/src/compiler.dart';
|
||||
import 'package:compiler/src/deferred_load.dart';
|
||||
import 'package:compiler/src/elements/elements.dart';
|
||||
|
@ -161,6 +162,38 @@ Future checkModels(
|
|||
compilerNormal.deferredLoadTask.isProgramSplit,
|
||||
compilerDeserialized.deferredLoadTask.isProgramSplit,
|
||||
"isProgramSplit mismatch");
|
||||
|
||||
Map<ConstantValue, OutputUnit> constants1 =
|
||||
compilerNormal.deferredLoadTask.outputUnitForConstantsForTesting;
|
||||
Map<ConstantValue, OutputUnit> constants2 =
|
||||
compilerDeserialized.deferredLoadTask.outputUnitForConstantsForTesting;
|
||||
checkSets(
|
||||
constants1.keys,
|
||||
constants2.keys,
|
||||
'deferredLoadTask._outputUnitForConstants.keys',
|
||||
areConstantValuesEquivalent,
|
||||
failOnUnfound: false,
|
||||
failOnExtra: false,
|
||||
onSameElement: (ConstantValue value1, ConstantValue value2) {
|
||||
OutputUnit outputUnit1 = constants1[value1];
|
||||
OutputUnit outputUnit2 = constants2[value2];
|
||||
checkOutputUnits(outputUnit1, outputUnit2,
|
||||
'for ${value1.toStructuredText()} '
|
||||
'vs ${value2.toStructuredText()}');
|
||||
},
|
||||
onUnfoundElement: (ConstantValue value1) {
|
||||
OutputUnit outputUnit1 = constants1[value1];
|
||||
Expect.isTrue(outputUnit1.isMainOutput,
|
||||
"Missing deferred constant: ${value1.toStructuredText()}");
|
||||
},
|
||||
onExtraElement: (ConstantValue value2) {
|
||||
OutputUnit outputUnit2 = constants2[value2];
|
||||
Expect.isTrue(outputUnit2.isMainOutput,
|
||||
"Extra deferred constant: ${value2.toStructuredText()}");
|
||||
},
|
||||
elementToString: (a) {
|
||||
return '${a.toStructuredText()} -> ${constants1[a]}/${constants2[a]}';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -244,7 +277,7 @@ void checkElements(
|
|||
backend2.inlineCache.getCurrentCacheDecisionForTesting(element2),
|
||||
"Inline cache decision mismatch for $element1 vs $element2");
|
||||
|
||||
checkOutputUnits(compiler1, compiler2, element1, element2);
|
||||
checkElementOutputUnits(compiler1, compiler2, element1, element2);
|
||||
}
|
||||
|
||||
void checkMixinUses(
|
||||
|
@ -360,17 +393,24 @@ String nodeToString(Node node) {
|
|||
return '(${node.runtimeType}) $text';
|
||||
}
|
||||
|
||||
void checkOutputUnits(Compiler compiler1, Compiler compiler2, Element element1,
|
||||
Element element2) {
|
||||
void checkElementOutputUnits(
|
||||
Compiler compiler1, Compiler compiler2,
|
||||
Element element1, Element element2) {
|
||||
OutputUnit outputUnit1 =
|
||||
compiler1.deferredLoadTask.outputUnitForElement(element1);
|
||||
compiler1.deferredLoadTask.getOutputUnitForElementForTesting(element1);
|
||||
OutputUnit outputUnit2 =
|
||||
compiler2.deferredLoadTask.outputUnitForElement(element2);
|
||||
compiler2.deferredLoadTask.getOutputUnitForElementForTesting(element2);
|
||||
checkOutputUnits(outputUnit1, outputUnit2, 'for $element1 vs $element2');
|
||||
}
|
||||
|
||||
void checkOutputUnits(
|
||||
OutputUnit outputUnit1, OutputUnit outputUnit2, String message) {
|
||||
if (outputUnit1 == null && outputUnit2 == null) return;
|
||||
check(outputUnit1, outputUnit2,
|
||||
'OutputUnit.isMainOutput for $element1 vs $element2',
|
||||
'OutputUnit.isMainOutput $message',
|
||||
outputUnit1.isMainOutput, outputUnit2.isMainOutput);
|
||||
checkSetEquivalence(outputUnit1, outputUnit2,
|
||||
'OutputUnit.imports for $element1 vs $element2',
|
||||
'OutputUnit.imports $message',
|
||||
outputUnit1.imports, outputUnit2.imports,
|
||||
(a, b) => areElementsEquivalent(a.declaration, b.declaration));
|
||||
}
|
|
@ -642,6 +642,35 @@ import "dart:core" deferred as core;
|
|||
test() {
|
||||
core.loadLibrary().then((_) => null);
|
||||
}
|
||||
''',
|
||||
}),
|
||||
|
||||
const Test('Use of dart:indexed_db', const {
|
||||
'main.dart': '''
|
||||
import 'a.dart';
|
||||
|
||||
main() {}
|
||||
''',
|
||||
}, preserializedSourceFiles: const {
|
||||
'a.dart': '''
|
||||
import 'dart:indexed_db';
|
||||
''',
|
||||
}),
|
||||
|
||||
const Test('Deferred static access', const {},
|
||||
preserializedSourceFiles: const {
|
||||
'main.dart': '''
|
||||
import 'b.dart' deferred as prefix;
|
||||
|
||||
main() => prefix.loadLibrary().then((_) => prefix.test2());
|
||||
''',
|
||||
'b.dart': '''
|
||||
test2() => x;
|
||||
var x = const ConstClass(const ConstClass(1));
|
||||
class ConstClass {
|
||||
final x;
|
||||
const ConstClass(this.x);
|
||||
}
|
||||
''',
|
||||
}),
|
||||
];
|
||||
|
|
|
@ -7,6 +7,7 @@ library dart2js.serialization_test_helper;
|
|||
import 'dart:collection';
|
||||
import 'package:compiler/src/common/resolution.dart';
|
||||
import 'package:compiler/src/constants/expressions.dart';
|
||||
import 'package:compiler/src/constants/values.dart';
|
||||
import 'package:compiler/src/dart_types.dart';
|
||||
import 'package:compiler/src/compiler.dart';
|
||||
import 'package:compiler/src/elements/elements.dart';
|
||||
|
@ -87,6 +88,15 @@ class CheckStrategy implements TestStrategy {
|
|||
object1, object2,property, set1, set2, elementEquivalence);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testMaps(
|
||||
var object1, var object2, String property, Map map1, Map map2,
|
||||
[bool keyEquivalence(a, b) = equality,
|
||||
bool valueEquivalence(a, b) = equality]) {
|
||||
return checkMapEquivalence(object1, object2, property,
|
||||
map1, map2, keyEquivalence, valueEquivalence);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testElements(
|
||||
Object object1, Object object2, String property,
|
||||
|
@ -109,6 +119,12 @@ class CheckStrategy implements TestStrategy {
|
|||
return checkConstants(object1, object2, property, exp1, exp2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testConstantValues(Object object1, Object object2, String property,
|
||||
ConstantValue value1, ConstantValue value2) {
|
||||
return areConstantValuesEquivalent(value1, value2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testTypeLists(
|
||||
Object object1, Object object2, String property,
|
||||
|
@ -124,6 +140,12 @@ class CheckStrategy implements TestStrategy {
|
|||
return checkConstantLists(object1, object2, property, list1, list2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testConstantValueLists(Object object1, Object object2, String property,
|
||||
List<ConstantValue> list1, List<ConstantValue> list2) {
|
||||
return checkConstantValueLists(object1, object2, property, list1, list2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testNodes(Object object1, Object object2, String property,
|
||||
Node node1, Node node2) {
|
||||
|
@ -247,6 +269,38 @@ bool checkSetEquivalence(
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Check equivalence of the two iterables, [set1] and [set1], as sets using
|
||||
/// [elementEquivalence] to compute the pair-wise equivalence.
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkMapEquivalence(
|
||||
var object1,
|
||||
var object2,
|
||||
String property,
|
||||
Map map1,
|
||||
Map map2,
|
||||
bool sameKey(a, b),
|
||||
bool sameValue(a, b)) {
|
||||
List<List> common = <List>[];
|
||||
List unfound = [];
|
||||
Set remaining =
|
||||
computeSetDifference(map1.keys, map2.keys, common, unfound,
|
||||
sameElement: sameKey);
|
||||
if (unfound.isNotEmpty || remaining.isNotEmpty) {
|
||||
String message =
|
||||
"Map key mismatch for `$property` on $object1 vs $object2: \n"
|
||||
"Common:\n ${common.join('\n ')}\n"
|
||||
"Unfound:\n ${unfound.join('\n ')}\n"
|
||||
"Extra: \n ${remaining.join('\n ')}";
|
||||
throw message;
|
||||
}
|
||||
for (List pair in common) {
|
||||
check(object1, object2, 'Map value for `$property`',
|
||||
map1[pair[0]], map2[pair[1]], sameValue);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Checks the equivalence of the identity (but not properties) of [element1]
|
||||
/// and [element2].
|
||||
///
|
||||
|
@ -311,7 +365,23 @@ bool checkConstants(
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks the pair-wise equivalence of the contants in [list1] and [list2].
|
||||
/// Checks the equivalence of [value1] and [value2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkConstantValues(
|
||||
Object object1, Object object2, String property,
|
||||
ConstantValue value1, ConstantValue value2) {
|
||||
if (identical(value1, value2)) return true;
|
||||
if (value1 == null || value2 == null) {
|
||||
return check(object1, object2, property, value1, value2);
|
||||
} else {
|
||||
return check(object1, object2, property, value1, value2,
|
||||
(a, b) => const ConstantValueEquivalence(
|
||||
const CheckStrategy()).visit(a, b));
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the pair-wise equivalence of the constants in [list1] and [list2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkConstantLists(
|
||||
|
@ -323,6 +393,18 @@ bool checkConstantLists(
|
|||
list1, list2, checkConstants);
|
||||
}
|
||||
|
||||
/// Checks the pair-wise equivalence of the constants values in [list1] and
|
||||
/// [list2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkConstantValueLists(
|
||||
Object object1, Object object2, String property,
|
||||
List<ConstantValue> list1,
|
||||
List<ConstantValue> list2) {
|
||||
return checkListEquivalence(
|
||||
object1, object2, property,
|
||||
list1, list2, checkConstantValues);
|
||||
}
|
||||
|
||||
/// Check member property equivalence between all members common to [compiler1]
|
||||
/// and [compiler2].
|
||||
|
@ -439,27 +521,41 @@ void checkSets(
|
|||
{bool failOnUnfound: true,
|
||||
bool failOnExtra: true,
|
||||
bool verbose: false,
|
||||
void onSameElement(a, b)}) {
|
||||
void onSameElement(a, b),
|
||||
void onUnfoundElement(a),
|
||||
void onExtraElement(b),
|
||||
String elementToString(key): defaultToString}) {
|
||||
List<List> common = <List>[];
|
||||
List unfound = [];
|
||||
Set remaining = computeSetDifference(
|
||||
set1, set2, common, unfound,
|
||||
sameElement: sameElement,
|
||||
checkElements: onSameElement);
|
||||
if (onUnfoundElement != null) {
|
||||
unfound.forEach(onUnfoundElement);
|
||||
}
|
||||
if (onExtraElement != null) {
|
||||
remaining.forEach(onExtraElement);
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.write("$messagePrefix:");
|
||||
if (verbose) {
|
||||
sb.write("\n Common:\n ${common.join('\n ')}");
|
||||
sb.write("\n Common: \n");
|
||||
for (List pair in common) {
|
||||
var element1 = pair[0];
|
||||
var element2 = pair[1];
|
||||
sb.write(" [${elementToString(element1)},"
|
||||
"${elementToString(element2)}]\n");
|
||||
}
|
||||
}
|
||||
if (unfound.isNotEmpty || verbose) {
|
||||
sb.write("\n Unfound:\n ${unfound.join('\n ')}");
|
||||
sb.write("\n Unfound:\n ${unfound.map(elementToString).join('\n ')}");
|
||||
}
|
||||
if (remaining.isNotEmpty || verbose) {
|
||||
sb.write("\n Extra: \n ${remaining.join('\n ')}");
|
||||
sb.write("\n Extra: \n ${remaining.map(elementToString).join('\n ')}");
|
||||
}
|
||||
String message = sb.toString();
|
||||
if (unfound.isNotEmpty || remaining.isNotEmpty) {
|
||||
|
||||
if ((failOnUnfound && unfound.isNotEmpty) ||
|
||||
(failOnExtra && remaining.isNotEmpty)) {
|
||||
Expect.fail(message);
|
||||
|
|
Loading…
Reference in a new issue