Version 2.12.0-64.0.dev
Merge commit '149d7ff4151d83d53eb1fe7e1b5c8cf4cbcc3924' into 'dev'
diff --git a/DEPS b/DEPS
index 8e475fa..40aa610 100644
--- a/DEPS
+++ b/DEPS
@@ -98,10 +98,10 @@
# and land the review.
#
# For more details, see https://github.com/dart-lang/sdk/issues/30164
-"dart_style_tag": "1.3.9", # Please see the note above before updating.
+"dart_style_tag": "1.3.10", # Please see the note above before updating.
"chromedriver_tag": "83.0.4103.39",
- "dartdoc_rev" : "6935dcd8f2d78cf1797e6365b4b71505e6579659",
+ "dartdoc_rev" : "d79877d0764ce23ffea7055049f8da5dffce0308",
"ffi_rev": "a5d4232cd38562c75a3ed847baa340e399538028",
"fixnum_rev": "16d3890c6dc82ca629659da1934e412292508bba",
"glob_rev": "e9f4e6b7ae8abe5071461cf8f47191bb19cf7ef6",
diff --git a/pkg/dartdev/lib/src/commands/fix.dart b/pkg/dartdev/lib/src/commands/fix.dart
index 6cb007f..f93be4c 100644
--- a/pkg/dartdev/lib/src/commands/fix.dart
+++ b/pkg/dartdev/lib/src/commands/fix.dart
@@ -25,6 +25,11 @@
abbr: 'n',
defaultsTo: false,
help: 'Show which files would be modified but make no changes.');
+ argParser.addFlag('compare-to-golden',
+ defaultsTo: false,
+ help:
+ 'Compare the result of applying fixes to a golden file for testing.',
+ hide: true);
}
@override
@@ -33,13 +38,15 @@
'provisional and subject to change or removal in future releases.\n');
var dryRun = argResults['dry-run'];
- if (argResults.rest.length - (dryRun ? 1 : 0) > 1) {
+ var testMode = argResults['compare-to-golden'];
+ var arguments = argResults.rest;
+ var argumentCount = arguments.length;
+ if (argumentCount > 1) {
usageException('Only one file or directory is expected.');
}
- var dir = argResults.rest.isEmpty
- ? io.Directory.current
- : io.Directory(argResults.rest.single);
+ var dir =
+ argumentCount == 0 ? io.Directory.current : io.Directory(arguments[0]);
if (!dir.existsSync()) {
usageException("Directory doesn't exist: ${dir.path}");
}
@@ -73,7 +80,11 @@
progress.finish(showTiming: true);
- if (edits.isEmpty) {
+ if (testMode) {
+ if (_compareFixes(edits)) {
+ return 1;
+ }
+ } else if (edits.isEmpty) {
log.stdout('Nothing to fix!');
} else {
var details = fixes.details;
@@ -119,6 +130,34 @@
}
}
+ /// Return `true` if any of the fixes fail to create the same content as is
+ /// found in the golden file.
+ bool _compareFixes(List<SourceFileEdit> edits) {
+ var passCount = 0;
+ var failCount = 0;
+ for (var edit in edits) {
+ var filePath = edit.file;
+ var baseName = path.basename(filePath);
+ var expectFileName = baseName + '.expect';
+ var expectFilePath = path.join(path.dirname(filePath), expectFileName);
+ try {
+ var originalCode = io.File(filePath).readAsStringSync();
+ var expectedCode = io.File(expectFilePath).readAsStringSync();
+ var actualCode = SourceEdit.applySequence(originalCode, edit.edits);
+ if (actualCode != expectedCode) {
+ failCount++;
+ _reportFailure(filePath, actualCode, expectedCode);
+ } else {
+ passCount++;
+ }
+ } on io.FileSystemException {
+ // Ignored for now.
+ }
+ }
+ log.stdout('Passed: $passCount, Failed: $failCount');
+ return failCount > 0;
+ }
+
String _pluralFix(int count) => count == 1 ? 'fix' : 'fixes';
void _printDetails(List<BulkFix> details, io.Directory workingDir) {
@@ -138,5 +177,16 @@
}
}
+ /// Report that the [actualCode] produced by applying fixes to the content of
+ /// [filePath] did not match the [expectedCode].
+ void _reportFailure(String filePath, String actualCode, String expectedCode) {
+ log.stdout('Failed when applying fixes to $filePath');
+ log.stdout('Expected:');
+ log.stdout(expectedCode);
+ log.stdout('');
+ log.stdout('Actual:');
+ log.stdout(actualCode);
+ }
+
static String _format(int value) => _numberFormat.format(value);
}
diff --git a/pkg/dartdev/test/commands/fix_test.dart b/pkg/dartdev/test/commands/fix_test.dart
index 3303da3..b0a1a70 100644
--- a/pkg/dartdev/test/commands/fix_test.dart
+++ b/pkg/dartdev/test/commands/fix_test.dart
@@ -145,4 +145,73 @@
expect(result.stderr, isEmpty);
expect(result.stdout, contains('Nothing to fix!'));
});
+
+ group('compare-to-golden', () {
+ test('different', () {
+ p = project(
+ mainSrc: '''
+class A {
+ String a() => "";
+}
+
+class B extends A {
+ String a() => "";
+}
+''',
+ analysisOptions: '''
+linter:
+ rules:
+ - annotate_overrides
+ - prefer_single_quotes
+''',
+ );
+ p.file('lib/main.dart.expect', '''
+class A {
+ String a() => '';
+}
+
+class B extends A {
+ String a() => '';
+}
+''');
+ var result =
+ p.runSync('fix', ['--compare-to-golden', '.'], workingDir: p.dirPath);
+ expect(result.exitCode, 1);
+ expect(result.stderr, isEmpty);
+ });
+
+ test('same', () {
+ p = project(
+ mainSrc: '''
+class A {
+ String a() => "";
+}
+
+class B extends A {
+ String a() => "";
+}
+''',
+ analysisOptions: '''
+linter:
+ rules:
+ - annotate_overrides
+ - prefer_single_quotes
+''',
+ );
+ p.file('lib/main.dart.expect', '''
+class A {
+ String a() => '';
+}
+
+class B extends A {
+ @override
+ String a() => '';
+}
+''');
+ var result =
+ p.runSync('fix', ['--compare-to-golden', '.'], workingDir: p.dirPath);
+ expect(result.exitCode, 0);
+ expect(result.stderr, isEmpty);
+ });
+ });
}
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 906d5f6..3caa919 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -1165,8 +1165,8 @@
if (!Isolate::Current()->use_field_guards()) {
for (intptr_t i = start_index_; i < stop_index_; i++) {
field ^= refs.At(i);
- field.set_guarded_cid(kDynamicCid);
- field.set_is_nullable(true);
+ field.set_guarded_cid_unsafe(kDynamicCid);
+ field.set_is_nullable_unsafe(true);
field.set_guarded_list_length(Field::kNoFixedLength);
field.set_guarded_list_length_in_object_offset(
Field::kUnknownLengthOffset);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 20428a1..b8b18c7 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -174,11 +174,13 @@
// The `field.is_non_nullable_integer()` is set in the kernel loader and can
// only be set if we consume a AOT kernel (annotated with inferred types).
ASSERT(!field.is_non_nullable_integer() || FLAG_precompiled_mode);
+ // Unboxed fields in JIT lightweight isolates mode are not supported yet.
const bool valid_class =
- (SupportsUnboxedDoubles() && (field.guarded_cid() == kDoubleCid)) ||
- (SupportsUnboxedSimd128() && (field.guarded_cid() == kFloat32x4Cid)) ||
- (SupportsUnboxedSimd128() && (field.guarded_cid() == kFloat64x2Cid)) ||
- field.is_non_nullable_integer();
+ (FLAG_precompiled_mode || !FLAG_enable_isolate_groups) &&
+ ((SupportsUnboxedDoubles() && (field.guarded_cid() == kDoubleCid)) ||
+ (SupportsUnboxedSimd128() && (field.guarded_cid() == kFloat32x4Cid)) ||
+ (SupportsUnboxedSimd128() && (field.guarded_cid() == kFloat64x2Cid)) ||
+ field.is_non_nullable_integer());
return field.is_unboxing_candidate() && !field.is_nullable() && valid_class;
}
@@ -189,7 +191,8 @@
// proven to be correct.
return IsUnboxedField(field);
}
- return field.is_unboxing_candidate() &&
+ // Unboxed fields in JIT lightweight isolates mode are not supported yet.
+ return !FLAG_enable_isolate_groups && field.is_unboxing_candidate() &&
(FlowGraphCompiler::IsUnboxedField(field) ||
(field.guarded_cid() == kIllegalCid));
}
diff --git a/runtime/vm/compiler/backend/slot_test.cc b/runtime/vm/compiler/backend/slot_test.cc
index a506698..8c4b620 100644
--- a/runtime/vm/compiler/backend/slot_test.cc
+++ b/runtime/vm/compiler/backend/slot_test.cc
@@ -59,8 +59,8 @@
TokenPosition::kMinSource));
// Set non-trivial guarded state on the field.
- field.set_guarded_cid(kSmiCid);
- field.set_is_nullable(false);
+ field.set_guarded_cid_unsafe(kSmiCid);
+ field.set_is_nullable_unsafe(false);
// Enter compiler state.
CompilerState compiler_state(thread, /*is_aot=*/false);
@@ -87,8 +87,8 @@
// Change the guarded state of the field to "unknown" - emulating concurrent
// modification of the guarded state in mutator) and create a new clone of
// the field.
- field.set_guarded_cid(kDynamicCid);
- field.set_is_nullable(true);
+ field.set_guarded_cid_unsafe(kDynamicCid);
+ field.set_is_nullable_unsafe(true);
const Field& field_clone_3 = Field::ZoneHandle(field.CloneFromOriginal());
// Slot::Get must return the same slot and add the field from which it
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 2e907af..aff7bc5 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -10128,8 +10128,8 @@
FLAG_precompiled_mode ||
(isolate->use_field_guards() && !isolate->HasAttemptedReload());
#endif // !defined(PRODUCT)
- result.set_guarded_cid(use_guarded_cid ? kIllegalCid : kDynamicCid);
- result.set_is_nullable(use_guarded_cid ? false : true);
+ result.set_guarded_cid_unsafe(use_guarded_cid ? kIllegalCid : kDynamicCid);
+ result.set_is_nullable_unsafe(use_guarded_cid ? false : true);
result.set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
// Presently, we only attempt to remember the list length for final fields.
if (is_final && use_guarded_cid) {
@@ -10961,6 +10961,8 @@
// We should never try to record a sentinel.
ASSERT(value.raw() != Object::sentinel().raw());
+ Thread* const thread = Thread::Current();
+ SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
if ((guarded_cid() == kDynamicCid) ||
(is_nullable() && value.raw() == Object::null())) {
// Nothing to do: the field is not guarded or we are storing null into
@@ -10986,8 +10988,6 @@
THR_Print(" => %s\n", GuardedPropertiesAsCString());
}
- Thread* const thread = Thread::Current();
- SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
DeoptimizeDependentCode();
}
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 6538625..a950136 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -4162,6 +4162,11 @@
}
void set_guarded_cid(intptr_t cid) const {
+ DEBUG_ASSERT(
+ IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
+ set_guarded_cid_unsafe(cid);
+ }
+ void set_guarded_cid_unsafe(intptr_t cid) const {
#if defined(DEBUG)
Thread* thread = Thread::Current();
ASSERT(!IsOriginal() || is_static() || thread->IsMutatorThread() ||
@@ -4246,6 +4251,11 @@
return raw_ptr()->is_nullable_ == kNullCid;
}
void set_is_nullable(bool val) const {
+ DEBUG_ASSERT(
+ IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
+ set_is_nullable_unsafe(val);
+ }
+ void set_is_nullable_unsafe(bool val) const {
ASSERT(Thread::Current()->IsMutatorThread());
StoreNonPointer(&raw_ptr()->is_nullable_, val ? kNullCid : kIllegalCid);
}
diff --git a/tools/VERSION b/tools/VERSION
index 3f6c997..2069731 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 12
PATCH 0
-PRERELEASE 63
+PRERELEASE 64
PRERELEASE_PATCH 0
\ No newline at end of file