Version 2.13.0-181.0.dev
Merge commit 'fbc25f3dfff942a7513fd328793373bd3677377e' into 'dev'
diff --git a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
index eb3b8ec..a14d9f4 100644
--- a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
+++ b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
@@ -444,6 +444,7 @@
if (parent is WithClause) return false;
if (parent is ConstructorName) return false;
if (parent is ImplementsClause) return false;
+ if (parent is GenericTypeAlias) return false;
return true;
}
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 291ac76..307171d 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -3821,15 +3821,15 @@
int count = typeNames.length;
List<bool> detectedRepeatOnIndex = List<bool>.filled(count, false);
- for (int i = 0; i < detectedRepeatOnIndex.length; i++) {
- detectedRepeatOnIndex[i] = false;
- }
for (int i = 0; i < count; i++) {
if (!detectedRepeatOnIndex[i]) {
- var element = typeNames[i].name.staticElement;
+ var iType = typeNames[i].type;
for (int j = i + 1; j < count; j++) {
TypeName typeName = typeNames[j];
- if (typeName.name.staticElement == element) {
+ var jType = typeName.type;
+ if (iType is InterfaceType &&
+ jType is InterfaceType &&
+ iType.element == jType.element) {
detectedRepeatOnIndex[j] = true;
errorReporter
.reportErrorForNode(errorCode, typeName, [typeName.name.name]);
diff --git a/pkg/analyzer/test/src/dart/resolution/class_test.dart b/pkg/analyzer/test/src/dart/resolution/class_test.dart
index da64df0..f58dbf4 100644
--- a/pkg/analyzer/test/src/dart/resolution/class_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/class_test.dart
@@ -432,30 +432,6 @@
assertType(a.supertype, 'Object');
}
- test_error_implementsRepeated() async {
- await assertErrorsInCode(r'''
-class A {}
-class B implements A, A {} // ref
-''', [
- error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 33, 1),
- ]);
-
- var a = findElement.class_('A');
- assertTypeName(findNode.typeName('A, A {} // ref'), a, 'A');
- assertTypeName(findNode.typeName('A {} // ref'), a, 'A');
- }
-
- test_error_implementsRepeated_3times() async {
- await assertErrorsInCode(r'''
-class A {} class C{}
-class B implements A, A, A, A {}
-''', [
- error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 43, 1),
- error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 46, 1),
- error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 49, 1),
- ]);
- }
-
test_error_memberWithClassName_field() async {
await assertErrorsInCode(r'''
class C {
diff --git a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
index 7c8bd6a..71db9f6 100644
--- a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
@@ -359,15 +359,6 @@
assertTypeName(typeRef, null, 'void');
}
- test_error_implementsRepeated() async {
- await assertErrorsInCode(r'''
-class A {}
-mixin M implements A, A {}
-''', [
- error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 33, 1),
- ]);
- }
-
test_error_memberWithClassName_getter() async {
await assertErrorsInCode(r'''
mixin M {
@@ -939,15 +930,6 @@
]);
}
- test_error_onRepeated() async {
- await assertErrorsInCode(r'''
-class A {}
-mixin M on A, A {}
-''', [
- error(CompileTimeErrorCode.ON_REPEATED, 25, 1),
- ]);
- }
-
test_error_undefinedSuperMethod() async {
await assertErrorsInCode(r'''
class A {}
diff --git a/pkg/analyzer/test/src/diagnostics/implements_repeated_test.dart b/pkg/analyzer/test/src/diagnostics/implements_repeated_test.dart
new file mode 100644
index 0000000..01da5dc
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/implements_repeated_test.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2021, 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.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ImplementsRepeatedTest);
+ });
+}
+
+@reflectiveTest
+class ImplementsRepeatedTest extends PubPackageResolutionTest {
+ test_class_implements_2times() async {
+ await assertErrorsInCode(r'''
+class A {}
+class B implements A, A {} // ref
+''', [
+ error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 33, 1),
+ ]);
+
+ var A = findElement.class_('A');
+ assertTypeName(findNode.typeName('A, A {} // ref'), A, 'A');
+ assertTypeName(findNode.typeName('A {} // ref'), A, 'A');
+ }
+
+ test_class_implements_2times_viaTypeAlias() async {
+ await assertErrorsInCode(r'''
+class A {}
+typedef B = A;
+class C implements A, B {} // ref
+''', [
+ error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 48, 1),
+ ]);
+
+ assertTypeName(
+ findNode.typeName('A, B {} // ref'),
+ findElement.class_('A'),
+ 'A',
+ );
+
+ assertTypeName(
+ findNode.typeName('B {} // ref'),
+ findElement.typeAlias('B'),
+ 'A',
+ );
+ }
+
+ test_class_implements_4times() async {
+ await assertErrorsInCode(r'''
+class A {} class C{}
+class B implements A, A, A, A {}
+''', [
+ error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 43, 1),
+ error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 46, 1),
+ error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 49, 1),
+ ]);
+ }
+
+ test_mixin_implements_2times() async {
+ await assertErrorsInCode(r'''
+class A {}
+mixin M implements A, A {}
+''', [
+ error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 33, 1),
+ ]);
+ }
+
+ test_mixin_implements_4times() async {
+ await assertErrorsInCode(r'''
+class A {}
+mixin M implements A, A, A, A {}
+''', [
+ error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 33, 1),
+ error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 36, 1),
+ error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 39, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/on_repeated_test.dart b/pkg/analyzer/test/src/diagnostics/on_repeated_test.dart
new file mode 100644
index 0000000..41c3a90
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/on_repeated_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2021, 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.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(OnRepeatedTest);
+ });
+}
+
+@reflectiveTest
+class OnRepeatedTest extends PubPackageResolutionTest {
+ test_2times() async {
+ await assertErrorsInCode(r'''
+class A {}
+mixin M on A, A {}
+''', [
+ error(CompileTimeErrorCode.ON_REPEATED, 25, 1),
+ ]);
+ }
+
+ test_2times_viaTypeAlias() async {
+ await assertErrorsInCode(r'''
+class A {}
+typedef B = A;
+mixin M on A, B {}
+''', [
+ error(CompileTimeErrorCode.ON_REPEATED, 40, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index a227e93..6bd56ae 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -231,6 +231,7 @@
import 'implements_deferred_class_test.dart' as implements_deferred_class;
import 'implements_disallowed_class_test.dart' as implements_disallowed_class;
import 'implements_non_class_test.dart' as implements_non_class;
+import 'implements_repeated_test.dart' as implements_repeated;
import 'implements_super_class_test.dart' as implements_super_class;
import 'implements_type_alias_expands_to_type_parameter_test.dart'
as implements_type_alias_expands_to_type_parameter;
@@ -497,6 +498,7 @@
import 'nullable_type_in_with_clause_test.dart' as nullable_type_in_with_clause;
import 'object_cannot_extend_another_class_test.dart'
as object_cannot_extend_another_class;
+import 'on_repeated_test.dart' as on_repeated;
import 'optional_parameter_in_operator_test.dart'
as optional_parameter_in_operator;
import 'override_on_non_overriding_field_test.dart'
@@ -838,6 +840,7 @@
implements_deferred_class.main();
implements_disallowed_class.main();
implements_non_class.main();
+ implements_repeated.main();
implements_super_class.main();
implements_type_alias_expands_to_type_parameter.main();
implicit_this_reference_in_initializer.main();
@@ -1013,6 +1016,7 @@
nullable_type_in_on_clause.main();
nullable_type_in_with_clause.main();
object_cannot_extend_another_class.main();
+ on_repeated.main();
optional_parameter_in_operator.main();
override_on_non_overriding_field.main();
override_on_non_overriding_getter.main();
diff --git a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
index b8c2b5c..9d407aa 100644
--- a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
@@ -495,6 +495,60 @@
]);
}
+ test_nonFunctionTypeAlias_body_typeArgument_mismatch() async {
+ await assertErrorsInCode(r'''
+class A {}
+class B {}
+class G<T extends A> {}
+typedef X = G<B>;
+''', [
+ error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 60, 1),
+ ]);
+ }
+
+ test_nonFunctionTypeAlias_body_typeArgument_regularBounded() async {
+ await assertNoErrorsInCode(r'''
+class A {}
+class B extends A {}
+class G<T extends A> {}
+typedef X = G<B>;
+''');
+ }
+
+ test_nonFunctionTypeAlias_body_typeArgument_superBounded() async {
+ await assertNoErrorsInCode(r'''
+class A<T extends A<T>> {}
+typedef X = List<A>;
+''');
+ }
+
+ test_nonFunctionTypeAlias_interfaceType_body_mismatch() async {
+ await assertErrorsInCode(r'''
+class A {}
+class B {}
+class G<T extends A> {}
+typedef X = G<B>;
+''', [
+ error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 60, 1),
+ ]);
+ }
+
+ test_nonFunctionTypeAlias_interfaceType_body_regularBounded() async {
+ await assertNoErrorsInCode(r'''
+class A<T> {}
+typedef X<T> = A;
+''');
+ }
+
+ test_nonFunctionTypeAlias_interfaceType_body_superBounded() async {
+ await assertErrorsInCode(r'''
+class A<T extends A<T>> {}
+typedef X<T> = A;
+''', [
+ error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 42, 1),
+ ]);
+ }
+
test_nonFunctionTypeAlias_interfaceType_parameter() async {
await assertErrorsInCode(r'''
class A {}
@@ -514,15 +568,7 @@
''');
}
- test_nonFunctionTypeAlias_interfaceType_parameter_superBounded() async {
- await assertNoErrorsInCode(r'''
-class A {}
-typedef X<T extends A> = Map<int, T>;
-void f(X<Never> a) {}
-''');
- }
-
- test_notRegularBounded_notSuperBounded_invariant() async {
+ test_notRegularBounded_notSuperBounded_parameter_invariant() async {
await assertErrorsInCode(r'''
typedef A<X> = X Function(X);
typedef G<X extends A<X>> = void Function<Y extends X>();
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index e0c45c8..45b02a0 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -106,6 +106,7 @@
static const String dillDependencies = '--dill-dependencies';
static const String readData = '--read-data';
static const String writeData = '--write-data';
+ static const String noClosedWorldInData = '--no-closed-world-in-data';
static const String writeClosedWorld = '--write-closed-world';
static const String readClosedWorld = '--read-closed-world';
static const String readCodegen = '--read-codegen';
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 571e8ce..687c158 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -236,6 +236,10 @@
options.readCodegenUri == null;
}
+ bool get onlyPerformCodegen {
+ return options.readClosedWorldUri != null && options.readDataUri != null;
+ }
+
Future runInternal(Uri uri) async {
clearState();
assert(uri != null);
@@ -250,30 +254,32 @@
GlobalTypeInferenceResults globalTypeInferenceResults =
performGlobalTypeInference(closedWorld);
if (options.writeDataUri != null) {
- serializationTask
- .serializeGlobalTypeInference(globalTypeInferenceResults);
+ if (options.noClosedWorldInData) {
+ serializationTask
+ .serializeGlobalTypeInference(globalTypeInferenceResults);
+ } else {
+ serializationTask
+ .serializeGlobalTypeInferenceLegacy(globalTypeInferenceResults);
+ }
return;
}
await generateJavaScriptCode(globalTypeInferenceResults);
- } else if (options.readDataUri != null) {
+ } else if (onlyPerformCodegen) {
GlobalTypeInferenceResults globalTypeInferenceResults;
- if (options.readClosedWorldUri != null) {
- ir.Component component =
- await serializationTask.deserializeComponentAndUpdateOptions();
- JsClosedWorld closedWorld =
- await serializationTask.deserializeClosedWorld(
- environment, abstractValueStrategy, component);
- globalTypeInferenceResults =
- await serializationTask.deserializeGlobalAnalysis(
- environment, abstractValueStrategy, component, closedWorld);
- } else {
- globalTypeInferenceResults = await serializationTask
- .deserializeGlobalTypeInference(environment, abstractValueStrategy);
- }
- if (options.debugGlobalInference) {
- performGlobalTypeInference(globalTypeInferenceResults.closedWorld);
- return;
- }
+ ir.Component component =
+ await serializationTask.deserializeComponentAndUpdateOptions();
+ JsClosedWorld closedWorld =
+ await serializationTask.deserializeClosedWorld(
+ environment, abstractValueStrategy, component);
+ globalTypeInferenceResults =
+ await serializationTask.deserializeGlobalTypeInferenceResults(
+ environment, abstractValueStrategy, component, closedWorld);
+ await generateJavaScriptCode(globalTypeInferenceResults);
+ } else if (options.readDataUri != null) {
+ // TODO(joshualitt) delete and clean up after google3 roll
+ var globalTypeInferenceResults =
+ await serializationTask.deserializeGlobalTypeInferenceLegacy(
+ environment, abstractValueStrategy);
await generateJavaScriptCode(globalTypeInferenceResults);
} else {
KernelResult result = await kernelLoader.load(uri);
@@ -444,14 +450,18 @@
GlobalTypeInferenceResults results) {
SerializationStrategy strategy = const BytesInMemorySerializationStrategy();
List<int> irData = strategy.unpackAndSerializeComponent(results);
- List worldData = strategy.serializeGlobalTypeInferenceResults(results);
+ List<int> closedWorldData =
+ strategy.serializeClosedWorld(results.closedWorld);
+ List<int> globalTypeInferenceResultsData =
+ strategy.serializeGlobalTypeInferenceResults(results);
return strategy.deserializeGlobalTypeInferenceResults(
options,
reporter,
environment,
abstractValueStrategy,
strategy.deserializeComponent(irData),
- worldData);
+ closedWorldData,
+ globalTypeInferenceResultsData);
}
void compileFromKernel(Uri rootLibraryUri, Iterable<Uri> libraries) {
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index d4a9558..b96bd5d 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -277,8 +277,15 @@
if (argument != Flags.readData) {
readDataUri = fe.nativeToUri(extractPath(argument, isDirectory: false));
}
- if (readStrategy != ReadStrategy.fromCodegen) {
+
+ if (readStrategy == ReadStrategy.fromDart) {
readStrategy = ReadStrategy.fromData;
+ } else if (readStrategy == ReadStrategy.fromClosedWorld) {
+ readStrategy = ReadStrategy.fromDataAndClosedWorld;
+ } else if (readStrategy == ReadStrategy.fromCodegen) {
+ readStrategy = ReadStrategy.fromCodegenAndData;
+ } else if (readStrategy == ReadStrategy.fromCodegenAndClosedWorld) {
+ readStrategy = ReadStrategy.fromCodegenAndClosedWorldAndData;
}
}
@@ -287,7 +294,16 @@
readClosedWorldUri =
fe.nativeToUri(extractPath(argument, isDirectory: false));
}
- readStrategy = ReadStrategy.fromClosedWorld;
+
+ if (readStrategy == ReadStrategy.fromDart) {
+ readStrategy = ReadStrategy.fromClosedWorld;
+ } else if (readStrategy == ReadStrategy.fromData) {
+ readStrategy = ReadStrategy.fromDataAndClosedWorld;
+ } else if (readStrategy == ReadStrategy.fromCodegen) {
+ readStrategy = ReadStrategy.fromCodegenAndClosedWorld;
+ } else if (readStrategy == ReadStrategy.fromCodegenAndData) {
+ readStrategy = ReadStrategy.fromCodegenAndClosedWorldAndData;
+ }
}
void setDillDependencies(String argument) {
@@ -318,7 +334,16 @@
readCodegenUri =
fe.nativeToUri(extractPath(argument, isDirectory: false));
}
- readStrategy = ReadStrategy.fromCodegen;
+
+ if (readStrategy == ReadStrategy.fromDart) {
+ readStrategy = ReadStrategy.fromCodegen;
+ } else if (readStrategy == ReadStrategy.fromClosedWorld) {
+ readStrategy = ReadStrategy.fromCodegenAndClosedWorld;
+ } else if (readStrategy == ReadStrategy.fromData) {
+ readStrategy = ReadStrategy.fromCodegenAndData;
+ } else if (readStrategy == ReadStrategy.fromDataAndClosedWorld) {
+ readStrategy = ReadStrategy.fromCodegenAndClosedWorldAndData;
+ }
}
void setWriteData(String argument) {
@@ -466,6 +491,7 @@
new OptionHandler('${Flags.dillDependencies}=.+', setDillDependencies),
new OptionHandler('${Flags.readData}|${Flags.readData}=.+', setReadData),
new OptionHandler('${Flags.writeData}|${Flags.writeData}=.+', setWriteData),
+ new OptionHandler(Flags.noClosedWorldInData, passThrough),
new OptionHandler('${Flags.readClosedWorld}|${Flags.readClosedWorld}=.+',
setReadClosedWorld),
new OptionHandler('${Flags.writeClosedWorld}|${Flags.writeClosedWorld}=.+',
@@ -709,7 +735,9 @@
if (readStrategy == ReadStrategy.fromCodegen) {
fail("Cannot read and write serialized codegen simultaneously.");
}
- if (readStrategy != ReadStrategy.fromData) {
+ // TODO(joshualitt) cleanup after google3 roll.
+ if (readStrategy != ReadStrategy.fromData &&
+ readStrategy != ReadStrategy.fromDataAndClosedWorld) {
fail("Can only write serialized codegen from serialized data.");
}
if (codegenShards == null) {
@@ -737,6 +765,8 @@
options.add('${Flags.readClosedWorld}=${readClosedWorldUri}');
break;
case ReadStrategy.fromData:
+ // TODO(joshualitt): fail after Google3 roll.
+ // fail("Must read from closed world and data.");
readDataUri ??= Uri.base.resolve('$scriptName.data');
options.add('${Flags.readData}=${readDataUri}');
break;
@@ -747,6 +777,8 @@
options.add('${Flags.readData}=${readDataUri}');
break;
case ReadStrategy.fromCodegen:
+ case ReadStrategy.fromCodegenAndData:
+ // TODO(joshualitt): fall through to fail after google3 roll.
readDataUri ??= Uri.base.resolve('$scriptName.data');
options.add('${Flags.readData}=${readDataUri}');
readCodegenUri ??= Uri.base.resolve('$scriptName.code');
@@ -760,6 +792,9 @@
options.add('${Flags.codegenShards}=$codegenShards');
break;
case ReadStrategy.fromCodegenAndClosedWorld:
+ fail("Must read from closed world, data, and codegen");
+ break;
+ case ReadStrategy.fromCodegenAndClosedWorldAndData:
readClosedWorldUri ??= Uri.base.resolve('$scriptName.world');
options.add('${Flags.readClosedWorld}=${readClosedWorldUri}');
readDataUri ??= Uri.base.resolve('$scriptName.data');
@@ -816,6 +851,8 @@
summary = 'Data files $input and $dataInput ';
break;
case ReadStrategy.fromData:
+ // TODO(joshualitt): fail after google3 roll.
+ //fail("Must read from closed world and data.");
inputName = 'bytes data';
inputSize = inputProvider.dartCharactersRead;
String dataInput =
@@ -832,6 +869,8 @@
summary = 'Data files $input, $worldInput, and $dataInput ';
break;
case ReadStrategy.fromCodegen:
+ case ReadStrategy.fromCodegenAndData:
+ // TODO(joshualitt): Fall through to fail after google3 roll.
inputName = 'bytes data';
inputSize = inputProvider.dartCharactersRead;
String dataInput =
@@ -842,6 +881,9 @@
'${codeInput}[0-${codegenShards - 1}] ';
break;
case ReadStrategy.fromCodegenAndClosedWorld:
+ fail("Must read from closed world, data, and codegen");
+ break;
+ case ReadStrategy.fromCodegenAndClosedWorldAndData:
inputName = 'bytes data';
inputSize = inputProvider.dartCharactersRead;
String worldInput =
@@ -1373,12 +1415,17 @@
});
}
+// TODO(joshualitt): Clean up the combinatorial explosion of read strategies.
+// Right now only fromClosedWorld, fromDataAndClosedWorld, and
+// fromCodegenAndClosedWorldAndData are valid.
enum ReadStrategy {
fromDart,
fromClosedWorld,
fromData,
fromDataAndClosedWorld,
fromCodegen,
- fromCodegenAndClosedWorld
+ fromCodegenAndClosedWorld,
+ fromCodegenAndData,
+ fromCodegenAndClosedWorldAndData,
}
enum WriteStrategy { toKernel, toClosedWorld, toData, toCodegen, toJs }
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 03edd91..ce9cddb 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -77,6 +77,11 @@
/// If this is set, the compilation stops after type inference.
Uri writeDataUri;
+ /// Serialize data without the closed world.
+ /// TODO(joshualitt) make this the default right after landing in Google3 and
+ /// clean up.
+ bool noClosedWorldInData = false;
+
/// Location from which the serialized closed world is read.
///
/// If this is set, the [entryPoint] is expected to be a .dill file and the
@@ -542,6 +547,7 @@
_extractUriListOption(options, '${Flags.dillDependencies}')
..readDataUri = _extractUriOption(options, '${Flags.readData}=')
..writeDataUri = _extractUriOption(options, '${Flags.writeData}=')
+ ..noClosedWorldInData = _hasOption(options, Flags.noClosedWorldInData)
..readClosedWorldUri =
_extractUriOption(options, '${Flags.readClosedWorld}=')
..writeClosedWorldUri =
diff --git a/pkg/compiler/lib/src/serialization/strategies.dart b/pkg/compiler/lib/src/serialization/strategies.dart
index 37fbe89..9269eed 100644
--- a/pkg/compiler/lib/src/serialization/strategies.dart
+++ b/pkg/compiler/lib/src/serialization/strategies.dart
@@ -49,7 +49,8 @@
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
- List<T> data);
+ List<T> closedWorldData,
+ List<T> globalTypeInferenceResultsData);
List<T> serializeClosedWorld(JsClosedWorld closedWorld);
@@ -83,10 +84,28 @@
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
- List<int> data) {
- DataSource source = new BinarySourceImpl(data, useDataKinds: useDataKinds);
- return deserializeGlobalTypeInferenceResultsFromSource(options, reporter,
- environment, abstractValueStrategy, component, source);
+ List<int> closedWorldData,
+ List<int> globalTypeInferenceResultsData) {
+ DataSource closedWorldSource =
+ BinarySourceImpl(closedWorldData, useDataKinds: useDataKinds);
+ DataSource globalTypeInferenceResultsSource = BinarySourceImpl(
+ globalTypeInferenceResultsData,
+ useDataKinds: useDataKinds);
+ JsClosedWorld closedWorld = deserializeClosedWorldFromSource(
+ options,
+ reporter,
+ environment,
+ abstractValueStrategy,
+ component,
+ closedWorldSource);
+ return deserializeGlobalTypeInferenceResultsFromSource(
+ options,
+ reporter,
+ environment,
+ abstractValueStrategy,
+ component,
+ closedWorld,
+ globalTypeInferenceResultsSource);
}
@override
@@ -134,10 +153,28 @@
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
- List<int> data) {
- DataSource source = new BinarySourceImpl(data, useDataKinds: useDataKinds);
- return deserializeGlobalTypeInferenceResultsFromSource(options, reporter,
- environment, abstractValueStrategy, component, source);
+ List<int> closedWorldData,
+ List<int> globalTypeInferenceResultsData) {
+ DataSource closedWorldSource =
+ BinarySourceImpl(closedWorldData, useDataKinds: useDataKinds);
+ DataSource globalTypeInferenceResultsSource = BinarySourceImpl(
+ globalTypeInferenceResultsData,
+ useDataKinds: useDataKinds);
+ JsClosedWorld closedWorld = deserializeClosedWorldFromSource(
+ options,
+ reporter,
+ environment,
+ abstractValueStrategy,
+ component,
+ closedWorldSource);
+ return deserializeGlobalTypeInferenceResultsFromSource(
+ options,
+ reporter,
+ environment,
+ abstractValueStrategy,
+ component,
+ closedWorld,
+ globalTypeInferenceResultsSource);
}
@override
@@ -186,10 +223,28 @@
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
- List<Object> data) {
- DataSource source = new ObjectSource(data, useDataKinds: useDataKinds);
- return deserializeGlobalTypeInferenceResultsFromSource(options, reporter,
- environment, abstractValueStrategy, component, source);
+ List<Object> closedWorldData,
+ List<Object> globalTypeInferenceResultsData) {
+ DataSource closedWorldSource =
+ ObjectSource(closedWorldData, useDataKinds: useDataKinds);
+ DataSource globalTypeInferenceResultsSource = ObjectSource(
+ globalTypeInferenceResultsData,
+ useDataKinds: useDataKinds);
+ JsClosedWorld closedWorld = deserializeClosedWorldFromSource(
+ options,
+ reporter,
+ environment,
+ abstractValueStrategy,
+ component,
+ closedWorldSource);
+ return deserializeGlobalTypeInferenceResultsFromSource(
+ options,
+ reporter,
+ environment,
+ abstractValueStrategy,
+ component,
+ closedWorld,
+ globalTypeInferenceResultsSource);
}
@override
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index 6e5c4c8..cfc2b0d 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -19,6 +19,7 @@
import '../js_backend/backend.dart';
import '../js_backend/inferred_data.dart';
import '../js_model/js_world.dart';
+import '../js_model/element_map_impl.dart';
import '../js_model/locals.dart';
import '../options.dart';
import '../util/sink_adapter.dart';
@@ -30,40 +31,50 @@
JsClosedWorld closedWorld = results.closedWorld;
GlobalLocalsMap globalLocalsMap = results.globalLocalsMap;
InferredData inferredData = results.inferredData;
- closedWorld.writeToDataSink(sink);
globalLocalsMap.writeToDataSink(sink);
inferredData.writeToDataSink(sink);
results.writeToDataSink(sink, closedWorld.elementMap);
sink.close();
}
-GlobalTypeInferenceResults deserializeGlobalAnalysisFromSource(
- CompilerOptions options,
- DiagnosticReporter reporter,
- Environment environment,
- AbstractValueStrategy abstractValueStrategy,
- ir.Component component,
- JsClosedWorld newClosedWorld,
- DataSource source) {
- GlobalLocalsMap newGlobalLocalsMap = GlobalLocalsMap.readFromDataSource(
- newClosedWorld.closureDataLookup.getEnclosingMember, source);
- InferredData newInferredData =
- InferredData.readFromDataSource(source, newClosedWorld);
- return GlobalTypeInferenceResults.readFromDataSource(
- source,
- newClosedWorld.elementMap,
- newClosedWorld,
- newGlobalLocalsMap,
- newInferredData);
-}
-
GlobalTypeInferenceResults deserializeGlobalTypeInferenceResultsFromSource(
CompilerOptions options,
DiagnosticReporter reporter,
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
+ JsClosedWorld closedWorld,
DataSource source) {
+ source.registerComponentLookup(ComponentLookup(component));
+ source.registerEntityLookup(ClosedEntityLookup(closedWorld.elementMap));
+ GlobalLocalsMap globalLocalsMap = GlobalLocalsMap.readFromDataSource(
+ closedWorld.closureDataLookup.getEnclosingMember, source);
+ InferredData inferredData =
+ InferredData.readFromDataSource(source, closedWorld);
+ return GlobalTypeInferenceResults.readFromDataSource(source,
+ closedWorld.elementMap, closedWorld, globalLocalsMap, inferredData);
+}
+
+void serializeGlobalTypeInferenceResultsToSinkLegacy(
+ GlobalTypeInferenceResults results, DataSink sink) {
+ JsClosedWorld closedWorld = results.closedWorld;
+ GlobalLocalsMap globalLocalsMap = results.globalLocalsMap;
+ InferredData inferredData = results.inferredData;
+ closedWorld.writeToDataSink(sink);
+ globalLocalsMap.writeToDataSink(sink);
+ inferredData.writeToDataSink(sink);
+ results.writeToDataSink(sink, closedWorld.elementMap);
+ sink.close();
+}
+
+GlobalTypeInferenceResults
+ deserializeGlobalTypeInferenceResultsFromSourceLegacy(
+ CompilerOptions options,
+ DiagnosticReporter reporter,
+ Environment environment,
+ AbstractValueStrategy abstractValueStrategy,
+ ir.Component component,
+ DataSource source) {
JsClosedWorld newClosedWorld = new JsClosedWorld.readFromDataSource(
options, reporter, environment, abstractValueStrategy, component, source);
GlobalLocalsMap newGlobalLocalsMap = GlobalLocalsMap.readFromDataSource(
@@ -213,23 +224,7 @@
});
}
- Future<GlobalTypeInferenceResults> deserializeGlobalTypeInference(
- Environment environment,
- AbstractValueStrategy abstractValueStrategy) async {
- ir.Component component = await deserializeComponentAndUpdateOptions();
-
- return await measureIoSubtask('deserialize data', () async {
- _reporter.log('Reading data from ${_options.readDataUri}');
- api.Input<List<int>> dataInput = await _provider
- .readFromUri(_options.readDataUri, inputKind: api.InputKind.binary);
- DataSource source =
- BinarySourceImpl(dataInput.data, stringInterner: _stringInterner);
- return deserializeGlobalTypeInferenceResultsFromSource(_options,
- _reporter, environment, abstractValueStrategy, component, source);
- });
- }
-
- Future<GlobalTypeInferenceResults> deserializeGlobalAnalysis(
+ Future<GlobalTypeInferenceResults> deserializeGlobalTypeInferenceResults(
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
@@ -240,8 +235,45 @@
.readFromUri(_options.readDataUri, inputKind: api.InputKind.binary);
DataSource source =
BinarySourceImpl(dataInput.data, stringInterner: _stringInterner);
- return deserializeGlobalAnalysisFromSource(_options, _reporter,
- environment, abstractValueStrategy, component, closedWorld, source);
+ return deserializeGlobalTypeInferenceResultsFromSource(
+ _options,
+ _reporter,
+ environment,
+ abstractValueStrategy,
+ component,
+ closedWorld,
+ source);
+ });
+ }
+
+ // TODO(joshualitt) get rid of legacy functions after Google3 roll.
+ void serializeGlobalTypeInferenceLegacy(GlobalTypeInferenceResults results) {
+ JsClosedWorld closedWorld = results.closedWorld;
+ ir.Component component = closedWorld.elementMap.programEnv.mainComponent;
+ serializeComponent(component);
+
+ measureSubtask('serialize data', () {
+ _reporter.log('Writing data to ${_options.writeDataUri}');
+ api.BinaryOutputSink dataOutput =
+ _outputProvider.createBinarySink(_options.writeDataUri);
+ DataSink sink = new BinarySink(new BinaryOutputSinkAdapter(dataOutput));
+ serializeGlobalTypeInferenceResultsToSinkLegacy(results, sink);
+ });
+ }
+
+ Future<GlobalTypeInferenceResults> deserializeGlobalTypeInferenceLegacy(
+ Environment environment,
+ AbstractValueStrategy abstractValueStrategy) async {
+ ir.Component component = await deserializeComponentAndUpdateOptions();
+
+ return await measureIoSubtask('deserialize data', () async {
+ _reporter.log('Reading data from ${_options.readDataUri}');
+ api.Input<List<int>> dataInput = await _provider
+ .readFromUri(_options.readDataUri, inputKind: api.InputKind.binary);
+ DataSource source =
+ BinarySourceImpl(dataInput.data, stringInterner: _stringInterner);
+ return deserializeGlobalTypeInferenceResultsFromSourceLegacy(_options,
+ _reporter, environment, abstractValueStrategy, component, source);
});
}
diff --git a/pkg/compiler/test/serialization/on_disk_split_test.dart b/pkg/compiler/test/serialization/on_disk_split_test.dart
index 00ce798..22cedb1 100644
--- a/pkg/compiler/test/serialization/on_disk_split_test.dart
+++ b/pkg/compiler/test/serialization/on_disk_split_test.dart
@@ -17,17 +17,19 @@
Uri dillUri = dir.uri.resolve('out.dill');
Uri outUri = dir.uri.resolve('out.js');
var commonArgs = [
- Flags.writeData,
Flags.verbose,
'--libraries-spec=$sdkLibrariesSpecificationUri',
];
await internalMain([
'samples-dev/swarm/swarm.dart',
+ Flags.writeClosedWorld,
'--out=${dillUri}',
] +
commonArgs);
await internalMain([
'${dillUri}',
+ Flags.readClosedWorld,
+ Flags.writeData,
'--out=${outUri}',
] +
commonArgs);
diff --git a/pkg/compiler/test/serialization/serialization_test_helper.dart b/pkg/compiler/test/serialization/serialization_test_helper.dart
index b429960..b7b771c 100644
--- a/pkg/compiler/test/serialization/serialization_test_helper.dart
+++ b/pkg/compiler/test/serialization/serialization_test_helper.dart
@@ -184,7 +184,8 @@
GlobalTypeInferenceResults cloneInferenceResults(Compiler compiler,
GlobalTypeInferenceResults results, SerializationStrategy strategy) {
List<int> irData = strategy.unpackAndSerializeComponent(results);
-
+ List<int> closedWorldData =
+ strategy.serializeClosedWorld(results.closedWorld);
List<int> worldData = strategy.serializeGlobalTypeInferenceResults(results);
print('data size: ${worldData.length}');
@@ -196,6 +197,7 @@
compiler.environment,
compiler.abstractValueStrategy,
newComponent,
+ closedWorldData,
worldData);
List<int> newWorldData =
strategy.serializeGlobalTypeInferenceResults(newResults);
diff --git a/pkg/compiler/tool/modular_test_suite.dart b/pkg/compiler/tool/modular_test_suite.dart
index 0aa6ebe..780c182 100644
--- a/pkg/compiler/tool/modular_test_suite.dart
+++ b/pkg/compiler/tool/modular_test_suite.dart
@@ -54,7 +54,7 @@
new IOPipeline([
SourceToDillStep(),
ComputeClosedWorldStep(),
- GlobalAnalysisStep(),
+ LegacyGlobalAnalysisStep(),
LegacyDart2jsCodegenStep(codeId0),
LegacyDart2jsCodegenStep(codeId1),
LegacyDart2jsEmissionStep(),
@@ -312,6 +312,8 @@
for (String flag in flags) '--enable-experiment=$flag',
'${Flags.readClosedWorld}=${toUri(module, closedWorldId)}',
'${Flags.writeData}=${toUri(module, globalDataId)}',
+ // TODO(joshualitt): delete this flag after google3 roll
+ '${Flags.noClosedWorldInData}',
];
var result =
await _runProcess(Platform.resolvedExecutable, args, root.toFilePath());
@@ -425,6 +427,50 @@
}
}
+// TODO(joshualitt): delete after google3 roll.
+class LegacyGlobalAnalysisStep implements IOModularStep {
+ @override
+ List<DataId> get resultData => const [globalDataId];
+
+ @override
+ bool get needsSources => false;
+
+ @override
+ List<DataId> get dependencyDataNeeded => const [updatedDillId];
+
+ @override
+ List<DataId> get moduleDataNeeded => const [closedWorldId, updatedDillId];
+
+ @override
+ bool get onlyOnMain => true;
+
+ @override
+ Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
+ List<String> flags) async {
+ if (_options.verbose) print("\nstep: dart2js global analysis on $module");
+ List<String> args = [
+ '--packages=${sdkRoot.toFilePath()}/.packages',
+ _dart2jsScript,
+ // TODO(sigmund): remove this dependency on libraries.json
+ if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot',
+ '${toUri(module, updatedDillId)}',
+ for (String flag in flags) '--enable-experiment=$flag',
+ '${Flags.readClosedWorld}=${toUri(module, closedWorldId)}',
+ '${Flags.writeData}=${toUri(module, globalDataId)}',
+ ];
+ var result =
+ await _runProcess(Platform.resolvedExecutable, args, root.toFilePath());
+
+ _checkExitCode(result, this, module);
+ }
+
+ @override
+ void notifyCached(Module module) {
+ if (_options.verbose)
+ print("\ncached step: dart2js global analysis on $module");
+ }
+}
+
// Step that invokes the dart2js code generation on the main module given the
// results of the global analysis step and produces one shard of the codegen
// output.
diff --git a/pkg/test_runner/lib/src/command_output.dart b/pkg/test_runner/lib/src/command_output.dart
index 4c953dd..0e85567 100644
--- a/pkg/test_runner/lib/src/command_output.dart
+++ b/pkg/test_runner/lib/src/command_output.dart
@@ -552,7 +552,7 @@
static void parseErrors(String stderr, List<StaticError> errors,
[List<StaticError> warnings]) {
for (var error in AnalyzerError.parseStderr(stderr)) {
- var staticError = StaticError({ErrorSource.analyzer: error.errorCode},
+ var staticError = StaticError(ErrorSource.analyzer, error.errorCode,
line: error.line, column: error.column, length: error.length);
if (error.severity == 'ERROR') {
@@ -1315,8 +1315,7 @@
var line = int.parse(match.group(2));
var column = int.parse(match.group(3));
var message = match.group(4);
- errors
- .add(StaticError({errorSource: message}, line: line, column: column));
+ errors.add(StaticError(errorSource, message, line: line, column: column));
}
}
@@ -1417,7 +1416,7 @@
assert(errorSource != null);
var expected = testCase.testFile.expectedErrors
- .where((error) => error.hasError(errorSource));
+ .where((error) => error.source == errorSource);
var validation = StaticError.validateExpectations(
expected,
diff --git a/pkg/test_runner/lib/src/static_error.dart b/pkg/test_runner/lib/src/static_error.dart
index 08104d7..d8ede3a 100644
--- a/pkg/test_runner/lib/src/static_error.dart
+++ b/pkg/test_runner/lib/src/static_error.dart
@@ -36,7 +36,7 @@
const ErrorSource._(this.name);
}
-/// Describes one or more static errors that should be reported at a specific
+/// Describes a single static error reported by a single front end at a specific
/// location.
///
/// These can be parsed from comments in [TestFile]s, in which case they
@@ -45,11 +45,6 @@
/// produces the expected compile-time errors. This same class is also used for
/// *reported* errors when parsing the output of a front end.
///
-/// Because there are multiple front ends that each report errors somewhat
-/// differently, each [StaticError] has a map to associate an error message
-/// with each front end. If there is no message for a given front end, it means
-/// the error is not reported by that front end.
-///
/// For analyzer errors, the error "message" is actually the constant name for
/// the error code, like "CompileTimeErrorCode.WRONG_TYPE".
class StaticError implements Comparable<StaticError> {
@@ -98,85 +93,6 @@
static List<StaticError> parseExpectations(String source) =>
_ErrorExpectationParser(source)._parse();
- /// Collapses overlapping [errors] into a shorter list of errors where
- /// possible.
- ///
- /// Errors on the same location can be collapsed if none of them both define
- /// a message for the same front end.
- static List<StaticError> simplify(List<StaticError> errors) {
- var result = errors.toList();
- result.sort();
-
- for (var i = 0; i < result.length - 1; i++) {
- var a = result[i];
-
- // Look for a later error we can merge with this one. Usually, it will be
- // adjacent to this one, but if there are multiple errors with no length
- // on the same location, those will all be next to each other and their
- // merge targets will come later. This happens when CFE reports multiple
- // errors at the same location (messages but no length) and analyzer does
- // too (codes and lengths but no messages).
- for (var j = i + 1; j < result.length; j++) {
- var b = result[j];
-
- // Position must be the same. If the position is different, we can
- // stop looking because all same-position errors will be adjacent.
- if (a.line != b.line) break;
- if (a.column != b.column) break;
-
- // If they both have lengths that are different, we can't discard that
- // information.
- if (a.length != null && b.length != null && a.length != b.length) {
- continue;
- }
-
- // Can't lose any messages.
- if (ErrorSource.all
- .any((source) => a.hasError(source) && b.hasError(source))) {
- continue;
- }
-
- // TODO(rnystrom): Now that there are more than two front ends, this
- // isn't as smart as it could be. It could try to pack all of the
- // messages in a given location into as few errors as possible by
- // taking only the non-colliding messages from one error. But that's
- // weird.
- //
- // A cleaner model is to have each StaticError represent a unique error
- // location. It would have an open-ended list of every message that
- // occurs at that location, across the various front-ends, including
- // multiple messages for the same front end. But that would change how
- // the existing static error tests look since something like:
- //
- // // ^^^
- // // [cfe] Message 1.
- // // ^^^
- // // [cfe] Message 2.
- //
- // Would turn into:
- //
- // // ^^^
- // // [cfe] Message 1.
- // // [cfe] Message 2.
- //
- // That's a good change to do, but should probably wait until after
- // NNBD.
-
- // Merge the two errors.
- result[i] = StaticError({...a._errors, ...b._errors},
- line: a.line, column: a.column, length: a.length ?? b.length);
-
- // Continue trying to merge this merged error with more since multiple
- // errors might collapse into a single one.
- result.removeAt(j);
- a = result[i];
- j--;
- }
- }
-
- return result;
- }
-
/// Determines whether all [actualErrors] match the given [expectedErrors].
///
/// If they match, returns `null`. Otherwise returns a string describing the
@@ -185,88 +101,118 @@
/// An expected error that is completely identical to an actual error is
/// treated as a match. Everything else is a failure.
///
- /// It treats line number as the "identity" of an error. So if there are two
- /// errors on the same line that differ in other properties, it reports that
- /// as a "wrong" error. Any expected error on a line containing no actual
- /// error is reported as a "missing" error. Conversely, an actual error on a
- /// line containing no expected error is an "unexpected" error.
+ /// It has a few heuristics to try to determine what the discrepancies mean,
+ /// which it applies in order:
///
- /// By not treating the error's index in the list to be its identity, we
- /// gracefully handle extra or missing errors without causing cascading
- /// failures for later errors in the lists.
+ /// * If it sees an actual errors with the same message but different
+ /// location as expected ones, it considers those to be the same error
+ /// but with the wrong location.
+ ///
+ /// * If it sees an actual errors at the same location as expected ones,
+ /// it considers those to be wrong messages.
+ ///
+ /// * Otherwise, any remaining expected errors are considered missing
+ /// errors and remaining actual errors are considered unexpected.
static String validateExpectations(Iterable<StaticError> expectedErrors,
Iterable<StaticError> actualErrors) {
- // Don't require the test or front end to output in any specific order.
- var sortedExpected = expectedErrors.toList();
- var sortedActual = actualErrors.toList();
- sortedExpected.sort();
- sortedActual.sort();
+ var expected = expectedErrors.toList();
+ var actual = actualErrors.toList();
+
+ // Put them in a deterministic order.
+ expected.sort();
+ actual.sort();
+
+ // Discard matched errors.
+ for (var i = 0; i < expected.length; i++) {
+ var matchedExpected = false;
+
+ for (var j = 0; j < actual.length; j++) {
+ if (actual[j] == null) continue;
+
+ if (expected[i]._matchLocation(actual[j]) == null &&
+ (expected[i].message == actual[j].message ||
+ !expected[i].isSpecified)) {
+ actual[j] = null;
+ matchedExpected = true;
+
+ // If the expected error is unspecified, keep going so that it can
+ // consume multiple errors on the same line.
+ if (expected[i].isSpecified) break;
+ }
+ }
+
+ if (matchedExpected) expected[i] = null;
+ }
+
+ expected.removeWhere((error) => error == null);
+ actual.removeWhere((error) => error == null);
+
+ // If everything matched, we're done.
+ if (expected.isEmpty && actual.isEmpty) return null;
var buffer = StringBuffer();
- describeError(String adjective, StaticError error, String verb) {
- buffer.writeln("$adjective static error at ${error.location}:");
-
- for (var source in ErrorSource.all) {
- var sourceError = error._errors[source];
- if (sourceError == _unspecified) {
- buffer.writeln("- $verb unspecified ${source.name} error.");
- } else if (sourceError != null) {
- buffer.writeln("- $verb ${source.name} error '$sourceError'.");
- }
+ void fail(StaticError error, String label, [String secondary]) {
+ if (error.isSpecified) {
+ buffer.writeln("- $label ${error.location}: ${error.message}");
+ } else {
+ label = label.replaceAll("error", "unspecified error");
+ buffer.writeln("- $label ${error.location}.");
}
+ if (secondary != null) buffer.writeln(" $secondary");
buffer.writeln();
}
- var expectedIndex = 0;
- var actualIndex = 0;
- for (;
- expectedIndex < sortedExpected.length &&
- actualIndex < sortedActual.length;) {
- var expected = sortedExpected[expectedIndex];
- var actual = sortedActual[actualIndex];
+ // Look for matching messages, which means a wrong location.
+ for (var i = 0; i < expected.length; i++) {
+ if (expected[i] == null) continue;
- var differences = expected.describeDifferences(actual);
- if (differences == null) {
- // Consume this actual error.
- actualIndex++;
+ for (var j = 0; j < actual.length; j++) {
+ if (actual[j] == null) continue;
- // Consume the expectation, unless it's an unspecified error that can
- // match more actual errors.
- if (expected.isSpecifiedFor(actual) ||
- actualIndex == sortedActual.length ||
- sortedActual[actualIndex].line != expected.line) {
- expectedIndex++;
+ if (expected[i].message == actual[j].message) {
+ fail(expected[i], "Wrong error location",
+ expected[i]._matchLocation(actual[j]));
+
+ // Only report this mismatch once.
+ expected[i] = null;
+ actual[j] = null;
+ break;
}
- } else if (expected.line == actual.line) {
- buffer.writeln("Wrong static error at ${expected.location}:");
- for (var difference in differences) {
- buffer.writeln("- $difference");
- }
- buffer.writeln();
- expectedIndex++;
- actualIndex++;
- } else if (expected.line < actual.line) {
- describeError("Missing", expected, "Expected");
- expectedIndex++;
- } else {
- describeError("Unexpected", actual, "Had");
- actualIndex++;
}
}
- // Output any trailing expected or actual errors if the lengths of the
- // lists differ.
- for (; expectedIndex < sortedExpected.length; expectedIndex++) {
- describeError("Missing", sortedExpected[expectedIndex], "Expected");
+ // Look for matching locations, which means a wrong message.
+ for (var i = 0; i < expected.length; i++) {
+ if (expected[i] == null) continue;
+ for (var j = 0; j < actual.length; j++) {
+ if (actual[j] == null) continue;
+
+ if (expected[i]._matchLocation(actual[j]) == null) {
+ fail(actual[j], "Wrong message at",
+ "Expected: ${expected[i].message}");
+
+ // Only report this mismatch once.
+ expected[i] = null;
+ actual[j] = null;
+ break;
+ }
+ }
}
- for (; actualIndex < sortedActual.length; actualIndex++) {
- describeError("Unexpected", sortedActual[actualIndex], "Had");
+ // Any remaining expected errors are missing.
+ for (var i = 0; i < expected.length; i++) {
+ if (expected[i] == null) continue;
+ fail(expected[i], "Missing expected error at");
}
- if (buffer.isEmpty) return null;
+ // Any remaining actual errors are unexpected.
+ for (var j = 0; j < actual.length; j++) {
+ if (actual[j] == null) continue;
+ fail(actual[j], "Unexpected error at");
+ }
+
return buffer.toString().trimRight();
}
@@ -281,27 +227,18 @@
/// This is optional. The CFE only reports error location, but not length.
final int length;
- /// The error messages that should be or were reported by each front end.
- final Map<ErrorSource, String> _errors;
+ /// The front end this error is for.
+ final ErrorSource source;
- /// Whether this static error exists for [source].
- bool hasError(ErrorSource source) => _errors.containsKey(source);
+ final String message;
- /// The error for [source] or `null` if this error isn't expected to
- /// reported by that source.
- String errorFor(ErrorSource source) => _errors[source];
-
- /// The zero-based index of the first line in the [TestFile] containing the
- /// marker comments that define this error.
+ /// The zero-based numbers of the lines in the [TestFile] containing comments
+ /// that were parsed to produce this error.
///
- /// If this error was not parsed from a file, this may be `null`.
- final int markerStartLine;
-
- /// The zero-based index of the last line in the [TestFile] containing the
- /// marker comments that define this error, inclusive.
- ///
- /// If this error was not parsed from a file, this may be `null`.
- final int markerEndLine;
+ /// This includes a line for the location comment, as well as lines for the
+ /// error message. Note that lines may not be contiguous and multiple errors
+ /// may share the same line number for a shared location marker.
+ final Set<int> sourceLines;
/// Creates a new StaticError at the given location with the given expected
/// error code and message.
@@ -312,19 +249,12 @@
/// code or message be the special string "unspecified". When an unspecified
/// error is tested, a front end is expected to report *some* error on that
/// error's line, but it can be any location, error code, or message.
- StaticError(Map<ErrorSource, String> errors,
- {this.line,
- this.column,
- this.length,
- this.markerStartLine,
- this.markerEndLine})
- : _errors = errors {
+ StaticError(this.source, this.message,
+ {this.line, this.column, this.length, Set<int> sourceLines})
+ : sourceLines = {...?sourceLines} {
// Must have a location.
assert(line != null);
assert(column != null);
-
- // Must have at least one piece of description.
- assert(_errors.isNotEmpty);
}
/// A textual description of this error's location.
@@ -334,37 +264,33 @@
return result;
}
+ /// True if this error has a specific expected message and location.
+ ///
+ /// Otherwise, it is an "unspecified error", which means that as long as some
+ /// actual error is reported on this error's line, then the expectation is
+ /// met.
+ bool get isSpecified => message != _unspecified;
+
/// Whether this error is only considered a warning on all front ends that
/// report it.
bool get isWarning {
- var analyzer = _errors[ErrorSource.analyzer];
- if (analyzer != null && !_analyzerWarningCodes.contains(analyzer)) {
- return false;
+ switch (source) {
+ case ErrorSource.analyzer:
+ return _analyzerWarningCodes.contains(message);
+ case ErrorSource.cfe:
+ // TODO(42787): Once CFE starts reporting warnings, encode that in the
+ // message somehow and then look for it here.
+ return false;
+ case ErrorSource.web:
+ // TODO(rnystrom): If the web compilers report warnings, encode that in
+ // the message somehow and then look for it here.
+ return false;
}
- // TODO(42787): Once CFE starts reporting warnings, encode that in the
- // message somehow and then look for it here.
- if (hasError(ErrorSource.cfe)) return false;
-
- // TODO(rnystrom): If the web compilers report warnings, encode that in the
- // message somehow and then look for it here.
- if (hasError(ErrorSource.web)) return false;
-
- return true;
+ throw FallThroughError();
}
- String toString() {
- var result = "Error at $location";
-
- for (var source in ErrorSource.all) {
- var sourceError = _errors[source];
- if (sourceError != null) {
- result += "\n[${source.name.toLowerCase()}] $sourceError";
- }
- }
-
- return result;
- }
+ String toString() => "[${source.marker} $location] $message";
/// Orders errors primarily by location, then by other fields if needed.
@override
@@ -377,15 +303,11 @@
if (length != null && other.length == null) return -1;
if (length != other.length) return length.compareTo(other.length);
- for (var source in ErrorSource.all) {
- var thisError = _errors[source] ?? "";
- var otherError = other._errors[source] ?? "";
- if (thisError != otherError) {
- return thisError.compareTo(otherError);
- }
+ if (source != other.source) {
+ return source.marker.compareTo(other.source.marker);
}
- return 0;
+ return message.compareTo(other.message);
}
@override
@@ -396,73 +318,43 @@
3 * line.hashCode +
5 * column.hashCode +
7 * (length ?? 0).hashCode +
- 11 * (_errors[ErrorSource.analyzer] ?? "").hashCode +
- 13 * (_errors[ErrorSource.cfe] ?? "").hashCode +
- 17 * (_errors[ErrorSource.web] ?? "").hashCode;
+ 11 * source.hashCode +
+ 13 * message.hashCode;
- /// Whether this error expectation is a specified error for the front end
- /// reported by [actual].
- bool isSpecifiedFor(StaticError actual) {
- assert(actual._errors.length == 1,
- "Actual error should only have one source.");
-
- for (var source in ErrorSource.all) {
- if (actual.hasError(source)) {
- return hasError(source) && _errors[source] != _unspecified;
- }
- }
-
- return false;
- }
-
- /// Compares this error expectation to [actual].
+ /// Returns a string describing how this error's expected location differs
+ /// from [actual], or `null` if [actual]'s location matches this one.
///
- /// If this error correctly matches [actual], returns `null`. Otherwise
- /// returns a list of strings describing the mismatch.
- ///
- /// Note that this does *not* check to see that [actual] matches the front
- /// ends that this error expects. For example, if [actual] only reports an
- /// analyzer error and this error only specifies a CFE error, this will still
- /// report differences in location information. This method expects that error
- /// expectations have already been filtered by platform so this will only be
- /// called in cases where the platforms do match.
- List<String> describeDifferences(StaticError actual) {
- var differences = <String>[];
+ /// Takes into account unspecified errors and errors without lengths.
+ String _matchLocation(StaticError actual) {
+ var expectedMismatches = <String>[];
+ var actualMismatches = <String>[];
if (line != actual.line) {
- differences.add("Expected on line $line but was on ${actual.line}.");
+ expectedMismatches.add("line $line");
+ actualMismatches.add("line ${actual.line}");
}
- // If the error is unspecified on the front end being tested, the column
- // and length can be any values.
- if (isSpecifiedFor(actual)) {
+ // Ignore column and length for unspecified errors.
+ if (isSpecified) {
if (column != actual.column) {
- differences
- .add("Expected on column $column but was on ${actual.column}.");
+ expectedMismatches.add("column $column");
+ actualMismatches.add("column ${actual.column}");
}
- // This error represents an expectation, so should have a length.
- assert(length != null);
if (actual.length != null && length != actual.length) {
- differences.add("Expected length $length but was ${actual.length}.");
+ expectedMismatches.add("length $column");
+ actualMismatches.add("length ${actual.column}");
}
}
- for (var source in ErrorSource.all) {
- var error = _errors[source];
- var actualError = actual._errors[source];
-
- if (error != null &&
- error != _unspecified &&
- actualError != null &&
- error != actualError) {
- differences.add("Expected ${source.name} error '$error' "
- "but was '$actualError'.");
- }
+ if (expectedMismatches.isEmpty) {
+ // Everything matches.
+ return null;
}
- if (differences.isNotEmpty) return differences;
- return null;
+ var expectedList = expectedMismatches.join(", ");
+ var actualList = actualMismatches.join(", ");
+ return "Expected $expectedList but was $actualList.";
}
}
@@ -500,9 +392,6 @@
/// are part of it.
static final _errorMessageRestRegExp = RegExp(r"^\s*//\s*(.*)");
- /// Matches the multitest marker and yields the preceding content.
- final _stripMultitestRegExp = RegExp(r"(.*)//#");
-
final List<String> _lines;
final List<StaticError> _errors = [];
int _currentLine = 0;
@@ -522,7 +411,7 @@
_fail("An error expectation must follow some code.");
}
- _parseErrorMessages(
+ _parseErrors(
line: _lastRealLine,
column: sourceLine.indexOf("^") + 1,
length: match.group(1).length);
@@ -532,7 +421,7 @@
match = _explicitLocationAndLengthRegExp.firstMatch(sourceLine);
if (match != null) {
- _parseErrorMessages(
+ _parseErrors(
line: int.parse(match.group(1)),
column: int.parse(match.group(2)),
length: int.parse(match.group(3)));
@@ -542,7 +431,7 @@
match = _explicitLocationRegExp.firstMatch(sourceLine);
if (match != null) {
- _parseErrorMessages(
+ _parseErrors(
line: int.parse(match.group(1)), column: int.parse(match.group(2)));
_advance();
continue;
@@ -555,12 +444,12 @@
return _errors;
}
- /// Finishes parsing an error expectation after parsing the location.
- void _parseErrorMessages({int line, int column, int length}) {
- var errors = <ErrorSource, String>{};
+ /// Finishes parsing a series of error expectations after parsing a location.
+ void _parseErrors({int line, int column, int length}) {
+ var locationLine = _currentLine;
+ var parsedError = false;
- var startLine = _currentLine;
-
+ // Allow errors for multiple front-ends to share the same location marker.
while (_canPeek(1)) {
var match = _errorMessageRegExp.firstMatch(_peek(1));
if (match == null) break;
@@ -571,6 +460,7 @@
var message = match.group(2);
_advance();
+ var sourceLines = {locationLine, _currentLine};
// Consume as many additional error message lines as we find.
while (_canPeek(1)) {
@@ -589,6 +479,7 @@
message += "\n" + messageMatch.group(1);
_advance();
+ sourceLines.add(_currentLine);
}
if (source == ErrorSource.analyzer &&
@@ -596,35 +487,28 @@
_fail("An analyzer error expectation should be a dotted identifier.");
}
- if (errors.containsKey(source)) {
- _fail("Already have an error for ${source.name}:\n${errors[source]}");
+ // Hack: If the error is CFE-only and the length is one, treat it as no
+ // length. The CFE does not output length information, and when the update
+ // tool writes a CFE-only error, it implicitly uses a length of one. Thus,
+ // when we parse back in a length one CFE error, we ignore the length so
+ // that the error round-trips correctly.
+ // TODO(rnystrom): Stop doing this when the CFE reports error lengths.
+ var errorLength = length;
+ if (errorLength == 1 && source == ErrorSource.cfe) {
+ errorLength = null;
}
- errors[source] = message;
+ _errors.add(StaticError(source, message,
+ line: line,
+ column: column,
+ length: errorLength,
+ sourceLines: sourceLines));
+ parsedError = true;
}
- if (errors.isEmpty) {
+ if (!parsedError) {
_fail("An error expectation must specify at least one error message.");
}
-
- // Hack: If the error is CFE-only and the length is one, treat it as no
- // length. The CFE does not output length information, and when the update
- // tool writes a CFE-only error, it implicitly uses a length of one. Thus,
- // when we parse back in a length one CFE error, we ignore the length so
- // that the error round-trips correctly.
- // TODO(rnystrom): Stop doing this when the CFE reports error lengths.
- if (length == 1 &&
- errors.length == 1 &&
- errors.containsKey(ErrorSource.cfe)) {
- length = null;
- }
-
- _errors.add(StaticError(errors,
- line: line,
- column: column,
- length: length,
- markerStartLine: startLine,
- markerEndLine: _currentLine));
}
bool _canPeek(int offset) => _currentLine + offset < _lines.length;
@@ -637,9 +521,9 @@
var line = _lines[_currentLine + offset];
// Strip off any multitest marker.
- var multitestMatch = _stripMultitestRegExp.firstMatch(line);
- if (multitestMatch != null) {
- line = multitestMatch.group(1).trimRight();
+ var index = line.indexOf("//#");
+ if (index != -1) {
+ line = line.substring(0, index).trimRight();
}
return line;
diff --git a/pkg/test_runner/lib/src/test_file.dart b/pkg/test_runner/lib/src/test_file.dart
index 01afcd9..7b92bc9 100644
--- a/pkg/test_runner/lib/src/test_file.dart
+++ b/pkg/test_runner/lib/src/test_file.dart
@@ -78,7 +78,7 @@
/// These tests exist to validate that a Dart web compiler reports the right
/// expected errors.
bool get isWebStaticErrorTest =>
- expectedErrors.any((error) => error.hasError(ErrorSource.web));
+ expectedErrors.any((error) => error.source == ErrorSource.web);
/// If the tests has no static error expectations, or all of the expectations
/// are warnings, then the test tests runtime semantics.
diff --git a/pkg/test_runner/lib/src/update_errors.dart b/pkg/test_runner/lib/src/update_errors.dart
index a961ea9a..5003a52 100644
--- a/pkg/test_runner/lib/src/update_errors.dart
+++ b/pkg/test_runner/lib/src/update_errors.dart
@@ -18,39 +18,43 @@
{Set<ErrorSource> remove}) {
remove ??= {};
+ // Split the existing errors into kept and deleted lists.
var existingErrors = StaticError.parseExpectations(source);
+ var keptErrors = <StaticError>[];
+ var removedErrors = <StaticError>[];
+ for (var error in existingErrors) {
+ if (remove.contains(error.source)) {
+ removedErrors.add(error);
+ } else {
+ keptErrors.add(error);
+ }
+ }
+
var lines = source.split("\n");
// Keep track of the indentation on any existing expectation markers. If
// found, it will try to preserve that indentation.
var indentation = <int, int>{};
- // Remove existing markers that should be removed.
- var preservedErrors = <StaticError>[];
+ // Remove all existing marker comments in the file, even for errors we are
+ // preserving. We will regenerate marker comments for those errors too so
+ // they can properly share location comments with new errors if needed.
for (var error in existingErrors) {
- for (var i = error.markerStartLine; i <= error.markerEndLine; i++) {
- indentation[i] = _countIndentation(lines[i]);
+ for (var line in error.sourceLines) {
+ if (lines[line] == null) continue;
+
+ indentation[line] = _countIndentation(lines[line]);
// Null the line instead of removing it so that line numbers in the
// reported errors are still correct.
- lines[i] = null;
- }
-
- // Re-add errors for the portions we intend to preserve.
- var keptErrors = {
- for (var source in ErrorSource.all.toSet().difference(remove))
- if (error.hasError(source)) source: error.errorFor(source)
- };
-
- if (keptErrors.isNotEmpty) {
- preservedErrors.add(StaticError(keptErrors,
- line: error.line, column: error.column, length: error.length));
+ lines[line] = null;
}
}
// Merge the new errors with the preserved ones.
- errors = StaticError.simplify([...errors, ...preservedErrors]);
+ errors = [...errors, ...keptErrors];
+ // Group errors by the line where they appear.
var errorMap = <int, List<StaticError>>{};
for (var error in errors) {
// -1 to translate from one-based to zero-based index.
@@ -63,6 +67,7 @@
errorList.sort();
}
+ // Rebuild the source file a line at a time.
var previousIndent = 0;
var codeLine = 1;
var result = <String>[];
@@ -82,6 +87,10 @@
// Add expectations for any errors reported on this line.
var errorsHere = errorMap[i];
if (errorsHere == null) continue;
+
+ var previousColumn = -1;
+ var previousLength = -1;
+
for (var error in errorsHere) {
// Try to indent the line nicely to match either the existing expectation
// that is being regenerated, or, barring that, the previous line of code.
@@ -90,44 +99,50 @@
// If the error is to the left of the indent and the "//", sacrifice the
// indentation.
if (error.column - 1 < indent + 2) indent = 0;
-
var comment = (" " * indent) + "//";
- // If the error can't fit in a line comment, or no source location is
- // sepcified, use an explicit location.
- if (error.column <= 2 || error.length == 0) {
- if (error.length == null) {
- result.add("$comment [error line $codeLine, column "
- "${error.column}]");
+ // Write the location line, unless we already have an identical one. Allow
+ // sharing locations between errors with and without explicit lengths.
+ if (error.column != previousColumn ||
+ (previousLength != null &&
+ error.length != null &&
+ error.length != previousLength)) {
+ // If the error can't fit in a line comment, or no source location is
+ // sepcified, use an explicit location.
+ if (error.column <= 2 || error.length == 0) {
+ if (error.length == null) {
+ result.add("$comment [error line $codeLine, column "
+ "${error.column}]");
+ } else {
+ result.add("$comment [error line $codeLine, column "
+ "${error.column}, length ${error.length}]");
+ }
} else {
- result.add("$comment [error line $codeLine, column "
- "${error.column}, length ${error.length}]");
+ var spacing = " " * (error.column - 1 - 2 - indent);
+ // A CFE-only error may not have a length, so treat it as length 1.
+ var carets = "^" * (error.length ?? 1);
+ result.add("$comment$spacing$carets");
}
- } else {
- var spacing = " " * (error.column - 1 - 2 - indent);
- // A CFE-only error may not have a length, so treat it as length 1.
- var carets = "^" * (error.length ?? 1);
- result.add("$comment$spacing$carets");
}
- for (var source in ErrorSource.all) {
- var sourceError = error.errorFor(source);
- if (sourceError == null) continue;
+ // If multiple errors share the same location, let them share a location
+ // marker.
+ previousColumn = error.column;
+ previousLength = error.length;
- var errorLines = sourceError.split("\n");
- result.add("$comment [${source.marker}] ${errorLines[0]}");
- for (var errorLine in errorLines.skip(1)) {
- result.add("$comment $errorLine");
- }
+ var errorLines = error.message.split("\n");
+ result.add("$comment [${error.source.marker}] ${errorLines[0]}");
+ for (var errorLine in errorLines.skip(1)) {
+ result.add("$comment $errorLine");
+ }
- // If the very next line in the source is a line comment, it would
- // become part of the inserted message. To prevent that, insert a blank
- // line.
- if (i < lines.length - 1 &&
- lines[i + 1] != null &&
- _lineCommentRegExp.hasMatch(lines[i + 1])) {
- result.add("");
- }
+ // If the very next line in the source is a line comment, it would
+ // become part of the inserted message. To prevent that, insert a blank
+ // line.
+ if (i < lines.length - 1 &&
+ lines[i + 1] != null &&
+ _lineCommentRegExp.hasMatch(lines[i + 1])) {
+ result.add("");
}
}
}
diff --git a/pkg/test_runner/test/static_error_test.dart b/pkg/test_runner/test/static_error_test.dart
index a3e9897..891db234 100644
--- a/pkg/test_runner/test/static_error_test.dart
+++ b/pkg/test_runner/test/static_error_test.dart
@@ -9,74 +9,36 @@
import 'utils.dart';
void main() {
- testHasError();
- testErrorFor();
+ testProperties();
testIsWarning();
- testIsSpecifiedFor();
testCompareTo();
- testDescribeDifferences();
- testSimplify();
+ // testDescribeDifferences();
testValidate();
}
-void testHasError() {
- var analyzer =
- makeError(line: 1, column: 2, length: 3, analyzerError: "E.CODE");
- var cfe = makeError(line: 1, column: 2, length: 3, cfeError: "Error.");
- var web = makeError(line: 1, column: 2, length: 3, webError: "Web.");
- var all = makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "E.CODE",
- cfeError: "Error.",
- webError: "Web.");
+void testProperties() {
+ var analyzer = StaticError(ErrorSource.analyzer, "E.CODE",
+ line: 1, column: 2, length: 3, sourceLines: {1, 3, 5});
+ Expect.equals(analyzer.source, ErrorSource.analyzer);
+ Expect.equals(analyzer.message, "E.CODE");
+ Expect.equals(analyzer.line, 1);
+ Expect.equals(analyzer.column, 2);
+ Expect.equals(analyzer.length, 3);
+ Expect.isTrue(analyzer.isSpecified);
+ Expect.setEquals({1, 3, 5}, analyzer.sourceLines);
- Expect.isTrue(analyzer.hasError(ErrorSource.analyzer));
- Expect.isFalse(analyzer.hasError(ErrorSource.cfe));
- Expect.isFalse(analyzer.hasError(ErrorSource.web));
+ var cfe = StaticError(ErrorSource.cfe, "Error.", line: 4, column: 5);
+ Expect.equals(cfe.source, ErrorSource.cfe);
+ Expect.equals(cfe.message, "Error.");
+ Expect.equals(cfe.line, 4);
+ Expect.equals(cfe.column, 5);
+ Expect.isNull(cfe.length);
+ Expect.isTrue(cfe.isSpecified);
+ Expect.isTrue(cfe.sourceLines.isEmpty);
- Expect.isFalse(cfe.hasError(ErrorSource.analyzer));
- Expect.isTrue(cfe.hasError(ErrorSource.cfe));
- Expect.isFalse(cfe.hasError(ErrorSource.web));
-
- Expect.isFalse(web.hasError(ErrorSource.analyzer));
- Expect.isFalse(web.hasError(ErrorSource.cfe));
- Expect.isTrue(web.hasError(ErrorSource.web));
-
- Expect.isTrue(all.hasError(ErrorSource.analyzer));
- Expect.isTrue(all.hasError(ErrorSource.cfe));
- Expect.isTrue(all.hasError(ErrorSource.web));
-}
-
-void testErrorFor() {
- var analyzer =
- makeError(line: 1, column: 2, length: 3, analyzerError: "E.CODE");
- var cfe = makeError(line: 1, column: 2, length: 3, cfeError: "Error.");
- var web = makeError(line: 1, column: 2, length: 3, webError: "Web.");
- var all = makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "E.CODE",
- cfeError: "Error.",
- webError: "Web.");
-
- Expect.equals("E.CODE", analyzer.errorFor(ErrorSource.analyzer));
- Expect.isNull(analyzer.errorFor(ErrorSource.cfe));
- Expect.isNull(analyzer.errorFor(ErrorSource.web));
-
- Expect.isNull(cfe.errorFor(ErrorSource.analyzer));
- Expect.equals("Error.", cfe.errorFor(ErrorSource.cfe));
- Expect.isNull(cfe.errorFor(ErrorSource.web));
-
- Expect.isNull(web.errorFor(ErrorSource.analyzer));
- Expect.isNull(web.errorFor(ErrorSource.cfe));
- Expect.equals("Web.", web.errorFor(ErrorSource.web));
-
- Expect.equals("E.CODE", all.errorFor(ErrorSource.analyzer));
- Expect.equals("Error.", all.errorFor(ErrorSource.cfe));
- Expect.equals("Web.", all.errorFor(ErrorSource.web));
+ var unspecified =
+ StaticError(ErrorSource.web, "unspecified", line: 1, column: 2);
+ Expect.isFalse(unspecified.isSpecified);
}
void testIsWarning() {
@@ -95,180 +57,29 @@
// Web only.
Expect.isFalse(makeError(webError: "Any error message.").isWarning);
-
- // Multiple front ends.
- Expect.isFalse(makeError(
- analyzerError: "STATIC_WARNING.INVALID_OPTION",
- cfeError: "Any error message.")
- .isWarning);
- Expect.isFalse(
- makeError(cfeError: "Any error message.", webError: "Any error message.")
- .isWarning);
- Expect.isFalse(makeError(
- analyzerError: "STATIC_WARNING.INVALID_OPTION",
- webError: "Any error message.")
- .isWarning);
- Expect.isFalse(makeError(
- analyzerError: "STATIC_WARNING.INVALID_OPTION",
- cfeError: "Any error message.",
- webError: "Any error message.")
- .isWarning);
-}
-
-void testIsSpecifiedFor() {
- var specifiedAll = makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "ERR.CODE",
- cfeError: "Message.",
- webError: "Web.");
- var unspecifiedAll = makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "unspecified",
- cfeError: "unspecified",
- webError: "unspecified");
- var specifiedAnalyzer = makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "ERR.CODE",
- cfeError: "unspecified",
- webError: "unspecified");
- var specifiedCfe = makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "unspecified",
- cfeError: "Message.",
- webError: "unspecified");
- var specifiedWeb = makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "unspecified",
- cfeError: "unspecified",
- webError: "Web.");
-
- var specifiedAnalyzerOnly =
- makeError(line: 1, column: 2, length: 3, analyzerError: "ERR.CODE");
- var specifiedCfeOnly =
- makeError(line: 1, column: 2, length: 3, cfeError: "Message.");
- var specifiedWebOnly =
- makeError(line: 1, column: 2, length: 3, webError: "Web.");
-
- var unspecifiedAnalyzerOnly =
- makeError(line: 1, column: 2, length: 3, analyzerError: "unspecified");
- var unspecifiedCfeOnly =
- makeError(line: 1, column: 2, length: 3, cfeError: "unspecified");
- var unspecifiedWebOnly =
- makeError(line: 1, column: 2, length: 3, webError: "unspecified");
-
- var analyzer =
- makeError(line: 1, column: 2, length: 3, analyzerError: "E.CODE");
- var cfe = makeError(line: 1, column: 2, length: 3, cfeError: "E.");
- var web = makeError(line: 1, column: 2, length: 3, webError: "E.");
-
- // isSpecifiedFor().
- Expect.isTrue(specifiedAll.isSpecifiedFor(analyzer));
- Expect.isTrue(specifiedAll.isSpecifiedFor(cfe));
- Expect.isTrue(specifiedAll.isSpecifiedFor(web));
-
- Expect.isFalse(unspecifiedAll.isSpecifiedFor(analyzer));
- Expect.isFalse(unspecifiedAll.isSpecifiedFor(cfe));
- Expect.isFalse(unspecifiedAll.isSpecifiedFor(web));
-
- Expect.isTrue(specifiedAnalyzer.isSpecifiedFor(analyzer));
- Expect.isFalse(specifiedAnalyzer.isSpecifiedFor(cfe));
- Expect.isFalse(specifiedAnalyzer.isSpecifiedFor(web));
-
- Expect.isFalse(specifiedCfe.isSpecifiedFor(analyzer));
- Expect.isTrue(specifiedCfe.isSpecifiedFor(cfe));
- Expect.isFalse(specifiedCfe.isSpecifiedFor(web));
-
- Expect.isFalse(specifiedWeb.isSpecifiedFor(analyzer));
- Expect.isFalse(specifiedWeb.isSpecifiedFor(cfe));
- Expect.isTrue(specifiedWeb.isSpecifiedFor(web));
-
- Expect.isTrue(specifiedAnalyzerOnly.isSpecifiedFor(analyzer));
- Expect.isFalse(specifiedAnalyzerOnly.isSpecifiedFor(cfe));
- Expect.isFalse(specifiedAnalyzerOnly.isSpecifiedFor(web));
-
- Expect.isFalse(specifiedCfeOnly.isSpecifiedFor(analyzer));
- Expect.isTrue(specifiedCfeOnly.isSpecifiedFor(cfe));
- Expect.isFalse(specifiedCfeOnly.isSpecifiedFor(web));
-
- Expect.isFalse(specifiedWebOnly.isSpecifiedFor(analyzer));
- Expect.isFalse(specifiedWebOnly.isSpecifiedFor(cfe));
- Expect.isTrue(specifiedWebOnly.isSpecifiedFor(web));
-
- Expect.isFalse(unspecifiedAnalyzerOnly.isSpecifiedFor(analyzer));
- Expect.isFalse(unspecifiedAnalyzerOnly.isSpecifiedFor(cfe));
- Expect.isFalse(unspecifiedAnalyzerOnly.isSpecifiedFor(web));
-
- Expect.isFalse(unspecifiedCfeOnly.isSpecifiedFor(analyzer));
- Expect.isFalse(unspecifiedCfeOnly.isSpecifiedFor(cfe));
- Expect.isFalse(unspecifiedCfeOnly.isSpecifiedFor(web));
-
- Expect.isFalse(unspecifiedWebOnly.isSpecifiedFor(analyzer));
- Expect.isFalse(unspecifiedWebOnly.isSpecifiedFor(cfe));
- Expect.isFalse(unspecifiedWebOnly.isSpecifiedFor(web));
}
void testCompareTo() {
var errors = [
// Order by line.
- makeError(
- line: 1, column: 2, length: 2, analyzerError: "E.CODE", cfeError: "E."),
- makeError(
- line: 2, column: 1, length: 1, analyzerError: "E.CODE", cfeError: "E."),
+ makeError(line: 1, column: 2, length: 2, cfeError: "E."),
+ makeError(line: 2, column: 1, length: 1, cfeError: "E."),
// Then column.
- makeError(
- line: 3, column: 1, length: 2, analyzerError: "E.CODE", cfeError: "E."),
- makeError(
- line: 3,
- column: 2,
- length: 1,
- analyzerError: "Error.CODE",
- cfeError: "E."),
+ makeError(line: 3, column: 1, length: 2, cfeError: "E."),
+ makeError(line: 3, column: 2, length: 1, cfeError: "E."),
// Then length.
- makeError(
- line: 4, column: 1, length: 1, analyzerError: "Z.CODE", cfeError: "Z."),
- makeError(
- line: 4, column: 1, length: 2, analyzerError: "A.CODE", cfeError: "A."),
+ makeError(line: 4, column: 1, length: 1, cfeError: "Z."),
+ makeError(line: 4, column: 1, length: 2, cfeError: "A."),
- // Then analyzer error.
- makeError(line: 5, column: 1, length: 1, cfeError: "Z."),
- makeError(
- line: 5, column: 1, length: 1, analyzerError: "A.CODE", cfeError: "Z."),
- makeError(
- line: 5, column: 1, length: 1, analyzerError: "Z.CODE", cfeError: "Z."),
+ // Then source.
+ makeError(line: 5, column: 1, length: 1, analyzerError: "Z.CODE"),
+ makeError(line: 5, column: 1, length: 1, cfeError: "A."),
- // Then CFE error.
- makeError(line: 6, column: 1, length: 1, analyzerError: "E.CODE"),
- makeError(
- line: 6,
- column: 1,
- length: 1,
- analyzerError: "E.CODE",
- cfeError: "A.",
- webError: "Z."),
- makeError(
- line: 6,
- column: 1,
- length: 1,
- analyzerError: "E.CODE",
- cfeError: "Z.",
- webError: "A."),
-
- // Then web error.
- makeError(line: 7, column: 1, length: 1, cfeError: "E."),
- makeError(line: 7, column: 1, length: 1, cfeError: "E.", webError: "A."),
- makeError(line: 7, column: 1, length: 1, cfeError: "E.", webError: "Z."),
+ // Then message.
+ makeError(line: 6, column: 1, length: 1, cfeError: "A."),
+ makeError(line: 6, column: 1, length: 1, cfeError: "Z."),
];
// Every pair of errors in the array should be ordered correctly.
@@ -281,347 +92,15 @@
}
}
-void testDescribeDifferences() {
- var precise = makeError(
- line: 2,
- column: 3,
- length: 4,
- analyzerError: "Error.CODE",
- cfeError: "Error message.",
- webError: "Web error.");
-
- // Perfect match.
- expectNoDifferences(precise,
- makeError(line: 2, column: 3, length: 4, analyzerError: "Error.CODE"));
- expectNoDifferences(precise,
- makeError(line: 2, column: 3, length: 4, cfeError: "Error message."));
- expectNoDifferences(precise,
- makeError(line: 2, column: 3, length: 4, webError: "Web error."));
-
- // Ignore null analyzer error.
- expectNoDifferences(
- makeError(
- line: 2,
- column: 3,
- length: 4,
- cfeError: "Error message.",
- webError: "Web error."),
- makeError(line: 2, column: 3, length: 4, cfeError: "Error message."));
-
- // Ignore null CFE error.
- expectNoDifferences(
- makeError(
- line: 2,
- column: 3,
- length: 4,
- analyzerError: "Error.CODE",
- webError: "Web error."),
- makeError(line: 2, column: 3, length: 4, analyzerError: "Error.CODE"));
-
- // Ignore null web error.
- expectNoDifferences(
- makeError(
- line: 2,
- column: 3,
- length: 4,
- analyzerError: "Error.CODE",
- cfeError: "Error message."),
- makeError(line: 2, column: 3, length: 4, cfeError: "Error message."));
-
- // Different line.
- expectDifferences(precise,
- makeError(line: 4, column: 3, length: 4, analyzerError: "Error.CODE"), """
- Expected on line 2 but was on 4.
- """);
-
- // Different column.
- expectDifferences(precise,
- makeError(line: 2, column: 5, length: 4, cfeError: "Error message."), """
- Expected on column 3 but was on 5.
- """);
-
- // Different length.
- expectDifferences(precise,
- makeError(line: 2, column: 3, length: 6, webError: "Web error."), """
- Expected length 4 but was 6.
- """);
-
- // Different analyzer error.
- expectDifferences(
- precise,
- makeError(line: 2, column: 3, length: 4, analyzerError: "Weird.ERROR"),
- """
- Expected analyzer error 'Error.CODE' but was 'Weird.ERROR'.
- """);
-
- // Different CFE error.
- expectDifferences(precise,
- makeError(line: 2, column: 3, length: 4, cfeError: "Funny story."), """
- Expected CFE error 'Error message.' but was 'Funny story.'.
- """);
-
- // Different web error.
- expectDifferences(precise,
- makeError(line: 2, column: 3, length: 4, webError: "Funny story."), """
- Expected web error 'Web error.' but was 'Funny story.'.
- """);
-
- // Multiple differences.
- expectDifferences(
- precise,
- makeError(line: 4, column: 3, length: 6, analyzerError: "Weird.ERROR"),
- """
- Expected on line 2 but was on 4.
- Expected length 4 but was 6.
- Expected analyzer error 'Error.CODE' but was 'Weird.ERROR'.
- """);
-
- // Unspecified errors.
- var unspecified = makeError(
- line: 2,
- column: 3,
- length: 4,
- analyzerError: "unspecified",
- cfeError: "unspecified",
- webError: "unspecified");
- var specifiedAnalyzer = makeError(
- line: 2,
- column: 3,
- length: 4,
- analyzerError: "Error.CODE",
- cfeError: "unspecified",
- webError: "unspecified");
- var specifiedCfe = makeError(
- line: 2,
- column: 3,
- length: 4,
- analyzerError: "unspecified",
- cfeError: "Error message.",
- webError: "unspecified");
- var specifiedWeb = makeError(
- line: 2,
- column: 3,
- length: 4,
- analyzerError: "unspecified",
- cfeError: "unspecified",
- webError: "Web error.");
-
- // Matches if line is right.
- expectNoDifferences(unspecified,
- makeError(line: 2, column: 3, length: 4, analyzerError: "Error.CODE"));
-
- // Does not match if lines differ.
- expectDifferences(unspecified,
- makeError(line: 3, column: 3, length: 4, cfeError: "Error message."), """
- Expected on line 2 but was on 3.
- """);
-
- // If error is specified on analyzer, must match fields when actual is
- // analyzer error.
- expectDifferences(
- specifiedAnalyzer,
- makeError(line: 2, column: 5, length: 6, analyzerError: "Weird.ERROR"),
- """
- Expected on column 3 but was on 5.
- Expected length 4 but was 6.
- Expected analyzer error 'Error.CODE' but was 'Weird.ERROR'.
- """);
- expectNoDifferences(specifiedAnalyzer,
- makeError(line: 2, column: 3, length: 4, analyzerError: "Error.CODE"));
-
- // If error is specified on CFE, must match fields when actual is
- // CFE error.
- expectDifferences(
- specifiedCfe,
- makeError(line: 2, column: 5, length: 6, cfeError: "Different message."),
- """
- Expected on column 3 but was on 5.
- Expected length 4 but was 6.
- Expected CFE error 'Error message.' but was 'Different message.'.
- """);
- expectNoDifferences(specifiedCfe,
- makeError(line: 2, column: 3, length: 4, cfeError: "Error message."));
-
- // If error is specified on web, must match fields when actual is web error.
- expectDifferences(
- specifiedWeb,
- makeError(line: 2, column: 5, length: 6, webError: "Different message."),
- """
- Expected on column 3 but was on 5.
- Expected length 4 but was 6.
- Expected web error 'Web error.' but was 'Different message.'.
- """);
- expectNoDifferences(specifiedWeb,
- makeError(line: 2, column: 3, length: 4, webError: "Web error."));
-}
-
-void testSimplify() {
- // Merges errors if each has only one error.
- expectSimplify([
- makeError(line: 1, column: 2, length: 3, analyzerError: "Weird.ERROR"),
- makeError(line: 1, column: 2, length: 3, cfeError: "Message."),
- makeError(line: 1, column: 2, length: 3, webError: "Web.")
- ], [
- makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "Weird.ERROR",
- cfeError: "Message.",
- webError: "Web.")
- ]);
-
- // Merges if length is null.
- expectSimplify([
- makeError(line: 1, column: 1, analyzerError: "A.ERR"),
- makeError(line: 1, column: 1, length: 3, cfeError: "A."),
- makeError(line: 2, column: 1, length: 4, analyzerError: "B.ERR"),
- makeError(line: 2, column: 1, webError: "B."),
- makeError(line: 3, column: 1, analyzerError: "C.ERR"),
- makeError(line: 3, column: 1, cfeError: "C."),
- ], [
- makeError(
- line: 1, column: 1, length: 3, analyzerError: "A.ERR", cfeError: "A."),
- makeError(
- line: 2, column: 1, length: 4, analyzerError: "B.ERR", webError: "B."),
- makeError(line: 3, column: 1, analyzerError: "C.ERR", cfeError: "C."),
- ]);
-
- // Merges multiple errors with no length with errors that have length.
- expectSimplify([
- makeError(line: 1, column: 2, length: 3, analyzerError: "ERROR.A"),
- makeError(line: 1, column: 4, length: 3, analyzerError: "ERROR.C"),
- makeError(line: 1, column: 2, length: 5, analyzerError: "ERROR.B"),
- makeError(line: 1, column: 2, cfeError: "One."),
- makeError(line: 1, column: 4, cfeError: "Three."),
- makeError(line: 1, column: 2, cfeError: "Two."),
- makeError(line: 1, column: 2, webError: "Web 1."),
- makeError(line: 1, column: 2, webError: "Web 2."),
- ], [
- makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "ERROR.A",
- cfeError: "One.",
- webError: "Web 1."),
- makeError(
- line: 1,
- column: 2,
- length: 5,
- analyzerError: "ERROR.B",
- cfeError: "Two.",
- webError: "Web 2."),
- makeError(
- line: 1,
- column: 4,
- length: 3,
- analyzerError: "ERROR.C",
- cfeError: "Three."),
- ]);
-
- // Merges even if not adjacent in input array.
- expectSimplify([
- makeError(line: 1, column: 2, length: 3, analyzerError: "Some.ERROR"),
- makeError(line: 10, column: 2, length: 3, analyzerError: "Other.ERROR"),
- makeError(line: 1, column: 2, length: 3, cfeError: "Message."),
- makeError(line: 10, column: 2, length: 3, webError: "Web two."),
- makeError(line: 1, column: 2, length: 3, webError: "Web."),
- ], [
- makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "Some.ERROR",
- cfeError: "Message.",
- webError: "Web."),
- makeError(
- line: 10,
- column: 2,
- length: 3,
- analyzerError: "Other.ERROR",
- webError: "Web two.")
- ]);
-
- // Does not merge if positions differ.
- expectSimplify([
- makeError(line: 1, column: 1, length: 1, analyzerError: "A.ERR"),
- makeError(line: 2, column: 1, length: 1, cfeError: "A."),
- ], [
- makeError(line: 1, column: 1, length: 1, analyzerError: "A.ERR"),
- makeError(line: 2, column: 1, length: 1, cfeError: "A."),
- ]);
- expectSimplify([
- makeError(line: 1, column: 1, length: 1, analyzerError: "A.ERR"),
- makeError(line: 1, column: 2, length: 1, webError: "A."),
- ], [
- makeError(line: 1, column: 1, length: 1, analyzerError: "A.ERR"),
- makeError(line: 1, column: 2, length: 1, webError: "A."),
- ]);
- expectSimplify([
- makeError(line: 1, column: 1, length: 1, cfeError: "A."),
- makeError(line: 1, column: 1, length: 2, webError: "W."),
- ], [
- makeError(line: 1, column: 1, length: 1, cfeError: "A."),
- makeError(line: 1, column: 1, length: 2, webError: "W."),
- ]);
-
- // Does not merge if it would lose a message.
- expectSimplify([
- makeError(line: 1, column: 1, length: 1, analyzerError: "ERR.ONE"),
- makeError(line: 1, column: 1, length: 1, analyzerError: "ERR.TWO"),
- makeError(line: 2, column: 1, length: 1, cfeError: "One."),
- makeError(line: 2, column: 1, length: 1, cfeError: "Two."),
- makeError(line: 3, column: 1, length: 1, webError: "One."),
- makeError(line: 3, column: 1, length: 1, webError: "Two."),
- ], [
- makeError(line: 1, column: 1, length: 1, analyzerError: "ERR.ONE"),
- makeError(line: 1, column: 1, length: 1, analyzerError: "ERR.TWO"),
- makeError(line: 2, column: 1, length: 1, cfeError: "One."),
- makeError(line: 2, column: 1, length: 1, cfeError: "Two."),
- makeError(line: 3, column: 1, length: 1, webError: "One."),
- makeError(line: 3, column: 1, length: 1, webError: "Two."),
- ]);
-
- // Orders output.
- expectSimplify([
- makeError(line: 2, column: 1, length: 1, cfeError: "Two."),
- makeError(line: 3, column: 1, length: 1, cfeError: "Three."),
- makeError(line: 1, column: 1, length: 1, cfeError: "One."),
- ], [
- makeError(line: 1, column: 1, length: 1, cfeError: "One."),
- makeError(line: 2, column: 1, length: 1, cfeError: "Two."),
- makeError(line: 3, column: 1, length: 1, cfeError: "Three."),
- ]);
-}
-
void testValidate() {
// No errors.
expectValidate([], [], null);
// Same errors.
expectValidate([
- makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "ERR.A",
- cfeError: "One.",
- webError: "Web 1."),
- makeError(
- line: 2,
- column: 2,
- length: 3,
- analyzerError: "ERR.B",
- cfeError: "Two.",
- webError: "Web 2."),
- makeError(
- line: 3,
- column: 2,
- length: 3,
- analyzerError: "ERR.C",
- cfeError: "Tres.",
- webError: "Web 3."),
+ makeError(line: 1, column: 2, length: 3, analyzerError: "ERR.A"),
+ makeError(line: 2, column: 2, length: 3, analyzerError: "ERR.B"),
+ makeError(line: 3, column: 2, length: 3, analyzerError: "ERR.C"),
], [
// Order doesn't matter.
makeError(line: 3, column: 2, length: 3, analyzerError: "ERR.C"),
@@ -629,35 +108,6 @@
makeError(line: 2, column: 2, length: 3, analyzerError: "ERR.B"),
], null);
- // Ignore fields that aren't in actual errors.
- expectValidate([
- makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "ERR.A",
- cfeError: "One.",
- webError: "Web 1."),
- makeError(
- line: 2,
- column: 2,
- length: 3,
- analyzerError: "ERR.B",
- cfeError: "Two.",
- webError: "Web 2."),
- makeError(
- line: 3,
- column: 2,
- length: 3,
- analyzerError: "ERR.C",
- cfeError: "Tres.",
- webError: "Web 3."),
- ], [
- makeError(line: 1, column: 2, cfeError: "One."),
- makeError(line: 2, column: 2, length: 3, cfeError: "Two."),
- makeError(line: 3, column: 2, length: 3, cfeError: "Tres."),
- ], null);
-
// Catches differences in any field.
expectValidate([
makeError(line: 1, column: 2, length: 3, analyzerError: "ERR.A"),
@@ -668,52 +118,36 @@
makeError(line: 2, column: 2, length: 9, analyzerError: "ERR.B"),
makeError(line: 3, column: 2, length: 3, analyzerError: "ERR.Z"),
], """
-Wrong static error at line 1, column 2, length 3:
-- Expected on column 2 but was on 9.
+- Wrong error location line 1, column 2, length 3: ERR.A
+ Expected column 2 but was column 9.
-Wrong static error at line 2, column 2, length 3:
-- Expected length 3 but was 9.
+- Wrong error location line 2, column 2, length 3: ERR.B
+ Expected length 2 but was length 2.
-Wrong static error at line 3, column 2, length 3:
-- Expected analyzer error 'ERR.C' but was 'ERR.Z'.""");
+- Wrong message at line 3, column 2, length 3: ERR.Z
+ Expected: ERR.C""");
expectValidate([
makeError(line: 4, column: 2, length: 3, cfeError: "Four."),
], [
makeError(line: 4, column: 2, length: 3, cfeError: "Zzz."),
], """
-Wrong static error at line 4, column 2, length 3:
-- Expected CFE error 'Four.' but was 'Zzz.'.""");
+- Wrong message at line 4, column 2, length 3: Zzz.
+ Expected: Four.""");
expectValidate([
makeError(line: 5, column: 2, length: 3, webError: "Web 5."),
], [
makeError(line: 5, column: 2, length: 3, webError: "Web Z."),
], """
-Wrong static error at line 5, column 2, length 3:
-- Expected web error 'Web 5.' but was 'Web Z.'.""");
+- Wrong message at line 5, column 2, length 3: Web Z.
+ Expected: Web 5.""");
// Unexpected errors.
expectValidate([
- makeError(
- line: 2,
- column: 2,
- length: 3,
- analyzerError: "ERR.A",
- cfeError: "One."),
- makeError(
- line: 4,
- column: 2,
- length: 3,
- analyzerError: "ERR.B",
- cfeError: "Two.",
- webError: "Web 2."),
- makeError(
- line: 6,
- column: 2,
- length: 3,
- analyzerError: "ERR.C",
- cfeError: "Tres."),
+ makeError(line: 2, column: 2, length: 3, cfeError: "One."),
+ makeError(line: 4, column: 2, length: 3, cfeError: "Two."),
+ makeError(line: 6, column: 2, length: 3, cfeError: "Tres."),
], [
makeError(line: 1, column: 2, length: 3, cfeError: "1."),
makeError(line: 2, column: 2, length: 3, cfeError: "One."),
@@ -723,17 +157,13 @@
makeError(line: 6, column: 2, length: 3, cfeError: "Tres."),
makeError(line: 7, column: 2, length: 3, cfeError: "7."),
], """
-Unexpected static error at line 1, column 2, length 3:
-- Had CFE error '1.'.
+- Unexpected error at line 1, column 2, length 3: 1.
-Unexpected static error at line 3, column 2, length 3:
-- Had CFE error '3.'.
+- Unexpected error at line 3, column 2, length 3: 3.
-Unexpected static error at line 5, column 2, length 3:
-- Had CFE error '5.'.
+- Unexpected error at line 5, column 2, length 3: 5.
-Unexpected static error at line 7, column 2, length 3:
-- Had CFE error '7.'.""");
+- Unexpected error at line 7, column 2, length 3: 7.""");
// Missing errors.
expectValidate([
@@ -746,14 +176,11 @@
makeError(line: 2, column: 2, length: 3, analyzerError: "ERR.B"),
makeError(line: 4, column: 2, length: 3, analyzerError: "ERR.D"),
], """
-Missing static error at line 1, column 2, length 3:
-- Expected analyzer error 'ERR.A'.
+- Missing expected error at line 1, column 2, length 3: ERR.A
-Missing static error at line 3, column 2, length 3:
-- Expected analyzer error 'ERR.C'.
+- Missing expected error at line 3, column 2, length 3: ERR.C
-Missing static error at line 5, column 2, length 3:
-- Expected analyzer error 'ERR.E'.""");
+- Missing expected error at line 5, column 2, length 3: ERR.E""");
// Unspecified errors.
expectValidate([
@@ -768,161 +195,34 @@
// Unexpected.
makeError(line: 9, column: 9, length: 3, cfeError: "Actual 2."),
], """
-Missing static error at line 2, column 2, length 3:
-- Expected unspecified CFE error.
+- Missing expected unspecified error at line 2, column 2, length 3.
-Unexpected static error at line 9, column 9, length 3:
-- Had CFE error 'Actual 2.'.""");
+- Unexpected error at line 9, column 9, length 3: Actual 2.""");
// Unspecified errors can match multiple errors on the same line.
- var actualAnalyzer = [
+ expectValidate([
+ makeError(line: 1, column: 2, length: 3, analyzerError: "unspecified"),
+ ], [
makeError(line: 1, column: 1, length: 3, analyzerError: "ERROR.CODE1"),
makeError(line: 1, column: 2, length: 3, analyzerError: "ERROR.CODE2"),
makeError(line: 1, column: 3, length: 3, analyzerError: "ERROR.CODE3"),
- ];
-
- var actualCfe = [
- makeError(line: 1, column: 1, length: 3, cfeError: "Actual 1."),
- makeError(line: 1, column: 2, length: 3, cfeError: "Actual 2."),
- makeError(line: 1, column: 3, length: 3, cfeError: "Actual 3."),
- ];
-
- var actualWeb = [
- makeError(line: 1, column: 1, length: 3, webError: "Web 1."),
- makeError(line: 1, column: 2, length: 3, webError: "Web 2."),
- makeError(line: 1, column: 3, length: 3, webError: "Web 3."),
- ];
-
- // Unspecified error specific to one front end.
- expectValidate([
- makeError(line: 1, column: 2, length: 3, analyzerError: "unspecified"),
- ], actualAnalyzer, null);
+ ], null);
expectValidate([
makeError(line: 1, column: 2, length: 3, cfeError: "unspecified"),
- ], actualCfe, null);
+ ], [
+ makeError(line: 1, column: 1, length: 3, cfeError: "Actual 1."),
+ makeError(line: 1, column: 2, length: 3, cfeError: "Actual 2."),
+ makeError(line: 1, column: 3, length: 3, cfeError: "Actual 3."),
+ ], null);
expectValidate([
makeError(line: 1, column: 2, length: 3, webError: "unspecified"),
- ], actualWeb, null);
-
- // Unspecified error on multiple front ends.
- expectValidate([
- makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "unspecified",
- cfeError: "unspecified"),
- ], actualAnalyzer, null);
-
- expectValidate([
- makeError(
- line: 1,
- column: 2,
- length: 3,
- cfeError: "unspecified",
- webError: "unspecified"),
- ], actualCfe, null);
-
- expectValidate([
- makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "unspecified",
- webError: "unspecified"),
- ], actualWeb, null);
-
- expectValidate([
- makeError(
- line: 1,
- column: 2,
- length: 3,
- analyzerError: "unspecified",
- cfeError: "unspecified",
- webError: "unspecified"),
- ], actualAnalyzer, null);
-
- // Specified on one, unspecified on another, no error at all on the third.
- var specifiedAnalyzer = [
- makeError(
- line: 1,
- column: 1,
- length: 3,
- analyzerError: "ERROR.CODE1",
- cfeError: "unspecified")
- ];
-
- var specifiedCfe = [
- makeError(
- line: 1,
- column: 1,
- length: 3,
- cfeError: "Actual 1.",
- webError: "unspecified")
- ];
-
- var specifiedWeb = [
- makeError(
- line: 1,
- column: 1,
- length: 3,
- analyzerError: "unspecified",
- webError: "Web 1.")
- ];
-
- expectValidate(specifiedAnalyzer, actualCfe, null);
- expectValidate(specifiedCfe, actualWeb, null);
- expectValidate(specifiedWeb, actualAnalyzer, null);
-
- expectValidate(specifiedAnalyzer, actualAnalyzer, """
-Unexpected static error at line 1, column 2, length 3:
-- Had analyzer error 'ERROR.CODE2'.
-
-Unexpected static error at line 1, column 3, length 3:
-- Had analyzer error 'ERROR.CODE3'.""");
-
- expectValidate(specifiedCfe, actualCfe, """
-Unexpected static error at line 1, column 2, length 3:
-- Had CFE error 'Actual 2.'.
-
-Unexpected static error at line 1, column 3, length 3:
-- Had CFE error 'Actual 3.'.""");
-
- expectValidate(specifiedWeb, actualWeb, """
-Unexpected static error at line 1, column 2, length 3:
-- Had web error 'Web 2.'.
-
-Unexpected static error at line 1, column 3, length 3:
-- Had web error 'Web 3.'.""");
-}
-
-void expectNoDifferences(StaticError expectedError, StaticError actualError) {
- var actualLines = expectedError.describeDifferences(actualError);
- if (actualLines != null) {
- Expect.fail("Expected no differences, but got:\n${actualLines.join('\n')}");
- }
-}
-
-void expectDifferences(StaticError expectedError, StaticError actualError,
- String expectedDifferences) {
- var expectedLines = expectedDifferences
- .split("\n")
- .map((line) => line.trim())
- .where((line) => line.isNotEmpty)
- .toList();
- var actualLines = expectedError.describeDifferences(actualError);
- if (actualLines == null) {
- Expect.fail("Got no differences, but expected:\n$expectedDifferences");
- }
- Expect.listEquals(expectedLines, actualLines);
-}
-
-void expectSimplify(List<StaticError> input, List<StaticError> expected) {
- var actual = StaticError.simplify(input);
- Expect.listEquals(expected.map((error) => error.toString()).toList(),
- actual.map((error) => error.toString()).toList());
+ ], [
+ makeError(line: 1, column: 1, length: 3, webError: "Web 1."),
+ makeError(line: 1, column: 2, length: 3, webError: "Web 2."),
+ makeError(line: 1, column: 3, length: 3, webError: "Web 3."),
+ ], null);
}
void expectValidate(List<StaticError> expected, List<StaticError> actual,
diff --git a/pkg/test_runner/test/test_file_test.dart b/pkg/test_runner/test/test_file_test.dart
index 251f60d..1e793ef 100644
--- a/pkg/test_runner/test/test_file_test.dart
+++ b/pkg/test_runner/test/test_file_test.dart
@@ -299,6 +299,7 @@
/\/ ^^^
/\/ [analyzer] CompileTimeErrorCode.WRONG_TYPE
/\/ [cfe] Error: Can't assign a string to an int.
+/\/ [cfe] Another CFE error.
/\/ [web] Web-specific error.
num j = "str";
@@ -311,16 +312,25 @@
line: 1,
column: 9,
length: 3,
- analyzerError: "CompileTimeErrorCode.WRONG_TYPE",
- cfeError: "Error: Can't assign a string to an int.",
- webError: "Web-specific error."),
+ analyzerError: "CompileTimeErrorCode.WRONG_TYPE"),
makeError(
- line: 7,
+ line: 1,
+ column: 9,
+ length: 3,
+ cfeError: "Error: Can't assign a string to an int."),
+ makeError(line: 1, column: 9, length: 3, cfeError: "Another CFE error."),
+ makeError(line: 1, column: 9, length: 3, webError: "Web-specific error."),
+ makeError(
+ line: 8,
column: 9,
length: 5,
- analyzerError: "CompileTimeErrorCode.ALSO_WRONG_TYPE",
- cfeError: "Error: Can't assign a string to a num.",
- webError: "Another web error.")
+ analyzerError: "CompileTimeErrorCode.ALSO_WRONG_TYPE"),
+ makeError(
+ line: 8,
+ column: 9,
+ length: 5,
+ cfeError: "Error: Can't assign a string to a num."),
+ makeError(line: 8, column: 9, length: 5, webError: "Another web error.")
]);
// Explicit error location.
@@ -341,15 +351,15 @@
line: 123,
column: 45,
length: 678,
- analyzerError: "CompileTimeErrorCode.FIRST",
- cfeError: "First error."),
+ analyzerError: "CompileTimeErrorCode.FIRST"),
+ makeError(line: 123, column: 45, length: 678, cfeError: "First error."),
makeError(
line: 23,
column: 5,
length: 78,
- analyzerError: "CompileTimeErrorCode.SECOND",
- cfeError: "Second error.",
- webError: "Second web error."),
+ analyzerError: "CompileTimeErrorCode.SECOND"),
+ makeError(line: 23, column: 5, length: 78, cfeError: "Second error."),
+ makeError(line: 23, column: 5, length: 78, webError: "Second web error."),
makeError(line: 9, column: 8, length: 7, cfeError: "Third."),
makeError(line: 10, column: 9, cfeError: "No length.")
]);
@@ -372,8 +382,16 @@
line: 1,
column: 9,
length: 3,
- analyzerError: "CompileTimeErrorCode.WRONG_TYPE",
- cfeError: "First line.\nSecond line.\nThird line.",
+ analyzerError: "CompileTimeErrorCode.WRONG_TYPE"),
+ makeError(
+ line: 1,
+ column: 9,
+ length: 3,
+ cfeError: "First line.\nSecond line.\nThird line."),
+ makeError(
+ line: 1,
+ column: 9,
+ length: 3,
webError: "Web first line.\nWeb second line.\nWeb third line.")
]);
@@ -418,25 +436,13 @@
/\/ ^^^
// [web] unspecified
""", [
- makeError(
- line: 1,
- column: 8,
- length: 3,
- analyzerError: "unspecified",
- cfeError: "unspecified",
- webError: "unspecified"),
- makeError(
- line: 6,
- column: 8,
- length: 3,
- analyzerError: "unspecified",
- cfeError: "Message."),
- makeError(
- line: 10,
- column: 8,
- length: 3,
- analyzerError: "Error.CODE",
- cfeError: "unspecified"),
+ makeError(line: 1, column: 8, length: 3, analyzerError: "unspecified"),
+ makeError(line: 1, column: 8, length: 3, cfeError: "unspecified"),
+ makeError(line: 1, column: 8, length: 3, webError: "unspecified"),
+ makeError(line: 6, column: 8, length: 3, analyzerError: "unspecified"),
+ makeError(line: 6, column: 8, length: 3, cfeError: "Message."),
+ makeError(line: 10, column: 8, length: 3, analyzerError: "Error.CODE"),
+ makeError(line: 10, column: 8, length: 3, cfeError: "unspecified"),
makeError(line: 14, column: 8, length: 3, analyzerError: "unspecified"),
makeError(line: 17, column: 8, length: 3, cfeError: "unspecified"),
makeError(line: 20, column: 8, length: 3, webError: "unspecified"),
@@ -453,11 +459,9 @@
/\/ [cfe] Message.
""", [
makeError(
- line: 1,
- column: 9,
- length: 3,
- analyzerError: "ErrorCode.BAD_THING",
- cfeError: "Message.\nMore message."),
+ line: 1, column: 9, length: 3, analyzerError: "ErrorCode.BAD_THING"),
+ makeError(
+ line: 1, column: 9, length: 3, cfeError: "Message.\nMore message."),
makeError(line: 12, column: 34, length: 56, cfeError: "Message."),
]);
@@ -468,12 +472,9 @@
/\/ [cfe] Error message.
/\/ [analyzer] ErrorCode.BAD_THING
""", [
+ makeError(line: 1, column: 9, length: 3, cfeError: "Error message."),
makeError(
- line: 1,
- column: 9,
- length: 3,
- analyzerError: "ErrorCode.BAD_THING",
- cfeError: "Error message."),
+ line: 1, column: 9, length: 3, analyzerError: "ErrorCode.BAD_THING"),
]);
expectParseErrorExpectations("""
int i = "s";
@@ -481,12 +482,9 @@
/\/ [web] Web message.
/\/ [analyzer] ErrorCode.BAD_THING
""", [
+ makeError(line: 1, column: 9, length: 3, webError: "Web message."),
makeError(
- line: 1,
- column: 9,
- length: 3,
- analyzerError: "ErrorCode.BAD_THING",
- webError: "Web message."),
+ line: 1, column: 9, length: 3, analyzerError: "ErrorCode.BAD_THING"),
]);
expectParseErrorExpectations("""
int i = "s";
@@ -494,12 +492,8 @@
/\/ [web] Web message.
/\/ [cfe] Error message.
""", [
- makeError(
- line: 1,
- column: 9,
- length: 3,
- cfeError: "Error message.",
- webError: "Web message."),
+ makeError(line: 1, column: 9, length: 3, webError: "Web message."),
+ makeError(line: 1, column: 9, length: 3, cfeError: "Error message."),
]);
// Must have at least one error message.
@@ -538,7 +532,7 @@
/\/ [analyzer] Not error code.
""");
- // A CFE-only error with length one is treated as having no length.
+ // A CFE error with length one is treated as having no length.
expectParseErrorExpectations("""
int i = "s";
/\/ ^
@@ -555,40 +549,11 @@
/\/ [web] Web message.
""", [
makeError(line: 1, column: 9, length: null, cfeError: "Message."),
- makeError(
- line: 5,
- column: 9,
- length: 1,
- analyzerError: "Error.BAD",
- cfeError: "Message."),
- makeError(
- line: 10,
- column: 9,
- length: 1,
- cfeError: "Message.",
- webError: "Web message.",
- ),
+ makeError(line: 5, column: 9, length: 1, analyzerError: "Error.BAD"),
+ makeError(line: 5, column: 9, length: null, cfeError: "Message."),
+ makeError(line: 10, column: 9, length: null, cfeError: "Message."),
+ makeError(line: 10, column: 9, length: 1, webError: "Web message."),
]);
-
- // Cannot have the same front end more than once.
- expectFormatError("""
-int i = "s";
-/\/ ^^^
-/\/ [analyzer] ErrorCode.BAD_THING
-/\/ [analyzer] ErrorCode.ANOTHER_THING
-""");
- expectFormatError("""
-int i = "s";
-/\/ ^^^
-/\/ [cfe] Message 1.
-/\/ [cfe] Message 2.
-""");
- expectFormatError("""
-int i = "s";
-/\/ ^^^
-/\/ [web] Web 1.
-/\/ [web] Web 2.
-""");
}
void testIsRuntimeTest() {
diff --git a/pkg/test_runner/test/update_errors_test.dart b/pkg/test_runner/test/update_errors_test.dart
index 6c433625..1d459d4 100644
--- a/pkg/test_runner/test/update_errors_test.dart
+++ b/pkg/test_runner/test/update_errors_test.dart
@@ -53,31 +53,15 @@
int last = "oops";
""", errors: [
- makeError(
- line: 1,
- column: 9,
- length: 5,
- analyzerError: "some.error",
- cfeError: "Bad."),
- makeError(
- line: 3,
- column: 15,
- length: 7,
- cfeError: "Another bad.",
- webError: "Web.\nError."),
- makeError(
- line: 5,
- column: 13,
- length: 5,
- analyzerError: "third.error",
- webError: "Web error."),
- makeError(
- line: 7,
- column: 12,
- length: 6,
- analyzerError: "last.error",
- cfeError: "Final.\nError.",
- webError: "Web error."),
+ makeError(line: 1, column: 9, length: 5, analyzerError: "some.error"),
+ makeError(line: 1, column: 9, length: 5, cfeError: "Bad."),
+ makeError(line: 3, column: 15, length: 7, cfeError: "Another bad."),
+ makeError(line: 3, column: 15, length: 7, webError: "Web.\nError."),
+ makeError(line: 5, column: 13, length: 5, analyzerError: "third.error"),
+ makeError(line: 5, column: 13, length: 5, webError: "Web error."),
+ makeError(line: 7, column: 12, length: 6, analyzerError: "last.error"),
+ makeError(line: 7, column: 12, length: 6, cfeError: "Final.\nError."),
+ makeError(line: 7, column: 12, length: 6, webError: "Web error."),
], expected: """
int i = "bad";
/\/ ^^^^^
@@ -215,12 +199,9 @@
/\/ ^^
/\/ [analyzer] previous.error
""", errors: [
+ makeError(line: 1, column: 9, length: 5, analyzerError: "updated.error"),
makeError(
- line: 1,
- column: 9,
- length: 5,
- analyzerError: "updated.error",
- cfeError: "Long.\nError.\nMessage."),
+ line: 1, column: 9, length: 5, cfeError: "Long.\nError.\nMessage."),
], expected: """
int i = "bad";
/\/ ^^^^^
@@ -389,6 +370,28 @@
/\/ [cfe] Wrong 1.
""");
+ // Shared locations between errors with and without length.
+ expectUpdate("""
+someBadCode(arg);
+
+moreBadCode(arg);
+""", errors: [
+ makeError(line: 1, column: 13, length: 3, analyzerError: "Error.CODE"),
+ makeError(line: 1, column: 13, cfeError: "Wrong 1."),
+ makeError(line: 3, column: 13, cfeError: "Wrong 2."),
+ makeError(line: 3, column: 13, length: 3, webError: "Web error."),
+ ], expected: """
+someBadCode(arg);
+/\/ ^^^
+/\/ [analyzer] Error.CODE
+/\/ [cfe] Wrong 1.
+
+moreBadCode(arg);
+/\/ ^^^
+/\/ [web] Web error.
+/\/ [cfe] Wrong 2.
+""");
+
// Doesn't crash with RangeError.
expectUpdate("""
x
diff --git a/pkg/test_runner/test/utils.dart b/pkg/test_runner/test/utils.dart
index b88d7ab..2a9152d 100644
--- a/pkg/test_runner/test/utils.dart
+++ b/pkg/test_runner/test/utils.dart
@@ -26,6 +26,9 @@
List<TestFile> testFiles, String suite) =>
_MockTestSuite(configuration, testFiles, suite);
+/// Creates a [StaticError].
+///
+/// Only one of [analyzerError], [cfeError], or [webError] may be passed.
StaticError makeError(
{int line = 1,
int column = 2,
@@ -33,12 +36,19 @@
String analyzerError,
String cfeError,
String webError}) {
- var errors = {
- if (analyzerError != null) ErrorSource.analyzer: analyzerError,
- if (cfeError != null) ErrorSource.cfe: cfeError,
- if (webError != null) ErrorSource.web: webError,
- };
- return StaticError(errors, line: line, column: column, length: length);
+ if (analyzerError != null) {
+ assert(cfeError == null && webError == null);
+ return StaticError(ErrorSource.analyzer, analyzerError,
+ line: line, column: column, length: length);
+ } else if (cfeError != null) {
+ assert(webError == null);
+ return StaticError(ErrorSource.cfe, cfeError,
+ line: line, column: column, length: length);
+ } else {
+ assert(webError != null);
+ return StaticError(ErrorSource.web, webError,
+ line: line, column: column, length: length);
+ }
}
class _MockTestSuite extends StandardTestSuite {
diff --git a/pkg/test_runner/tool/update_static_error_tests.dart b/pkg/test_runner/tool/update_static_error_tests.dart
index 20ed7f5..96e521e 100644
--- a/pkg/test_runner/tool/update_static_error_tests.dart
+++ b/pkg/test_runner/tool/update_static_error_tests.dart
@@ -203,8 +203,6 @@
}
}
- errors = StaticError.simplify(errors);
-
var result = updateErrorExpectations(source, errors, remove: remove);
stdout.writeln("\r${file.path} (Updated with ${errors.length} errors)");
@@ -291,8 +289,7 @@
return dart2jsError.line == cfeError.line &&
dart2jsError.column == cfeError.column &&
dart2jsError.length == cfeError.length &&
- dart2jsError.errorFor(ErrorSource.web) ==
- cfeError.errorFor(ErrorSource.cfe);
+ dart2jsError.message == cfeError.message;
});
});
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index 788dd2a..a381505 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -292,6 +292,13 @@
return static_cast<T>(static_cast<Unsigned>(a) * static_cast<Unsigned>(b));
}
+ template <typename T = int64_t>
+ static inline T NegWithWrapAround(T a) {
+ // Avoid undefined behavior by doing arithmetic in the unsigned type.
+ using Unsigned = typename std::make_unsigned<T>::type;
+ return static_cast<T>(-static_cast<Unsigned>(a));
+ }
+
// Shifts int64_t value left. Supports any non-negative number of bits and
// silently discards shifted out bits.
static inline int64_t ShiftLeftWithTruncation(int64_t a, int64_t b) {
diff --git a/runtime/vm/compiler/backend/loops.cc b/runtime/vm/compiler/backend/loops.cc
index 4ff2dc8..f28ae39 100644
--- a/runtime/vm/compiler/backend/loops.cc
+++ b/runtime/vm/compiler/backend/loops.cc
@@ -723,13 +723,16 @@
// Invariant + Invariant : only for same or just one instruction.
if (x->def_ == y->def_) {
return new (zone_)
- InductionVar(x->offset_ + y->offset_, x->mult_ + y->mult_, x->def_);
+ InductionVar(Utils::AddWithWrapAround(x->offset_, y->offset_),
+ Utils::AddWithWrapAround(x->mult_, y->mult_), x->def_);
} else if (y->mult_ == 0) {
return new (zone_)
- InductionVar(x->offset_ + y->offset_, x->mult_, x->def_);
+ InductionVar(Utils::AddWithWrapAround(x->offset_, y->offset_),
+ x->mult_, x->def_);
} else if (x->mult_ == 0) {
return new (zone_)
- InductionVar(x->offset_ + y->offset_, y->mult_, y->def_);
+ InductionVar(Utils::AddWithWrapAround(x->offset_, y->offset_),
+ y->mult_, y->def_);
}
} else if (y != nullptr) {
// Invariant + Induction.
@@ -768,13 +771,16 @@
// Invariant + Invariant : only for same or just one instruction.
if (x->def_ == y->def_) {
return new (zone_)
- InductionVar(x->offset_ - y->offset_, x->mult_ - y->mult_, x->def_);
+ InductionVar(Utils::SubWithWrapAround(x->offset_, y->offset_),
+ Utils::SubWithWrapAround(x->mult_, y->mult_), x->def_);
} else if (y->mult_ == 0) {
return new (zone_)
- InductionVar(x->offset_ - y->offset_, x->mult_, x->def_);
+ InductionVar(Utils::SubWithWrapAround(x->offset_, y->offset_),
+ x->mult_, x->def_);
} else if (x->mult_ == 0) {
return new (zone_)
- InductionVar(x->offset_ - y->offset_, -y->mult_, y->def_);
+ InductionVar(Utils::SubWithWrapAround(x->offset_, y->offset_),
+ Utils::NegWithWrapAround(y->mult_), y->def_);
}
} else if (y != nullptr) {
// Invariant - Induction.
@@ -823,7 +829,8 @@
if (InductionVar::IsConstant(x) && y != nullptr) {
if (y->kind_ == InductionVar::kInvariant) {
return new (zone_)
- InductionVar(x->offset_ * y->offset_, x->offset_ * y->mult_, y->def_);
+ InductionVar(Utils::MulWithWrapAround(x->offset_, y->offset_),
+ Utils::MulWithWrapAround(x->offset_, y->mult_), y->def_);
}
return new (zone_)
InductionVar(y->kind_, Mul(x, y->initial_), Mul(x, y->next_));
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index baf4965..d66d5fd 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -4,4 +4,3 @@
LibTest/ffi/Array/PointerArray_A01_t01: Skip # https://github.com/dart-lang/co19/issues/1018
LibTest/io/RawDatagramSocket/*: Skip # https://github.com/dart-lang/co19/issues/195
-
diff --git a/tools/VERSION b/tools/VERSION
index 2abc5be..2715580 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 180
+PRERELEASE 181
PRERELEASE_PATCH 0
\ No newline at end of file