Version 2.10.0-31.0.dev
Merge commit 'ba5aa496f16ef4402d303376c454f877946bcb38' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 5033a79..64c12b9 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -8893,6 +8893,65 @@
@override
Precedence get precedence => Precedence.primary;
+ /// If this identifier is used as an expression to read a value, this
+ /// is the element that provides the value.
+ ///
+ /// In valid code this can be almost any element, usually a
+ /// [LocalVariableElement], a [ParameterElement], or a
+ /// [PropertyAccessorElement] getter.
+ ///
+ /// In invalid code, for recovery, we might use a [PropertyAccessorElement]
+ /// setter `print(mySetter)` even though the setter cannot be used to read a
+ /// value. We do this to help the user to navigate to the setter, and maybe
+ /// add the corresponding getter.
+ ///
+ /// Return `null` if this identifier is not used to read a value, or the
+ /// AST structure has not been resolved, or if this identifier could not be
+ /// resolved.
+ ///
+ /// If this identifier is used as the target for a compound assignment
+ /// `x += 2`, both [readElement] and [writeElement] could be not `null`.
+ ///
+ /// If [referenceElement] is not `null`, then both [readElement] and
+ /// [writeElement] are `null`, because the identifier is not being used to
+ /// read or write a value.
+ ///
+ /// If either [readElement] or [writeElement] are not `null`, the
+ /// [referenceElement] is `null`, because the identifier is being used to
+ /// read or write a value.
+ ///
+ /// All three [readElement], [writeElement], and [referenceElement] can be
+ /// `null` when the AST structure has not been resolved, or this identifier
+ /// could not be resolved.
+ Element get readElement => null;
+
+ /// This element is set when this identifier is used not as an expression,
+ /// but just to reference some element.
+ ///
+ /// Examples are the name of the type in a [TypeName], the name of the method
+ /// in a [MethodInvocation], the name of the constructor in a
+ /// [ConstructorName], the name of the property in a [PropertyAccess], the
+ /// prefix and the identifier in a [PrefixedIdentifier] (which then can be
+ /// used to read or write a value).
+ ///
+ /// In invalid code, for recovery, any element could be used, e.g. a
+ /// setter as a type name `set mySetter(_) {} mySetter topVar;`. We do this
+ /// to help the user to navigate to this element, and maybe change its name,
+ /// add a new declaration, etc.
+ ///
+ /// Return `null` if this identifier is used to either read or write a value,
+ /// or the AST structure has not been resolved, or if this identifier could
+ /// not be resolved.
+ ///
+ /// If either [readElement] or [writeElement] are not `null`, the
+ /// [referenceElement] is `null`, because the identifier is being used to
+ /// read or write a value.
+ ///
+ /// All three [readElement], [writeElement], and [referenceElement] can be
+ /// `null` when the AST structure has not been resolved, or this identifier
+ /// could not be resolved.
+ Element get referenceElement => null;
+
@override
Element get staticElement => _staticElement;
@@ -8901,6 +8960,39 @@
_staticElement = element;
}
+ /// If this identifier is used as a target to assign a value, explicitly
+ /// using an [AssignmentExpression], or implicitly using a [PrefixExpression]
+ /// or [PostfixExpression], this is the element that is used to write the
+ /// value.
+ ///
+ /// In valid code this is a [LocalVariableElement], [ParameterElement], or a
+ /// [PropertyAccessorElement] setter.
+ ///
+ /// In invalid code, for recovery, we might use other elements, for example a
+ /// [PropertyAccessorElement] getter `myGetter = 0` even though the getter
+ /// cannot be used to write a value. We do this to help the user to navigate
+ /// to the getter, and maybe add the corresponding setter.
+ ///
+ /// Return `null` if this identifier is not used to write a value, or the
+ /// AST structure has not been resolved, or if this identifier could not be
+ /// resolved.
+ ///
+ /// If this identifier is used as the target for a compound assignment
+ /// `x += 2`, both [readElement] and [writeElement] could be not `null`.
+ ///
+ /// If [referenceElement] is not `null`, then both [readElement] and
+ /// [writeElement] are `null`, because the identifier is not being used to
+ /// read or write a value.
+ ///
+ /// If either [readElement] or [writeElement] are not `null`, the
+ /// [referenceElement] is `null`, because the identifier is being used to
+ /// read or write a value.
+ ///
+ /// All three [readElement], [writeElement], and [referenceElement] can be
+ /// `null` when the AST structure has not been resolved, or this identifier
+ /// could not be resolved.
+ Element get writeElement => null;
+
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitSimpleIdentifier(this);
diff --git a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
index f974f35..33ce9bf 100644
--- a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
@@ -15,7 +15,10 @@
}
@reflectiveTest
-class BinaryExpressionResolutionTest extends PubPackageResolutionTest {
+class BinaryExpressionResolutionTest extends PubPackageResolutionTest
+ with BinaryExpressionResolutionTestCases {}
+
+mixin BinaryExpressionResolutionTestCases on PubPackageResolutionTest {
test_bangEq() async {
await assertNoErrorsInCode(r'''
f(int a, int b) {
@@ -70,8 +73,9 @@
}
test_ifNull() async {
- await assertNoErrorsInCode(r'''
-f(int a, double b) {
+ var question = typeToStringWithNullability ? '?' : '';
+ await assertNoErrorsInCode('''
+f(int$question a, double b) {
a ?? b;
}
''');
@@ -230,7 +234,8 @@
@reflectiveTest
class BinaryExpressionResolutionWithNullSafetyTest
- extends PubPackageResolutionTest with WithNullSafetyMixin {
+ extends PubPackageResolutionTest
+ with WithNullSafetyMixin, BinaryExpressionResolutionTestCases {
test_ifNull_left_nullableContext() async {
await assertNoErrorsInCode(r'''
T f<T>(T t) => t;
diff --git a/pkg/analyzer/test/verify_diagnostics_test.dart b/pkg/analyzer/test/verify_diagnostics_test.dart
index 462c895..57b16e8 100644
--- a/pkg/analyzer/test/verify_diagnostics_test.dart
+++ b/pkg/analyzer/test/verify_diagnostics_test.dart
@@ -53,6 +53,9 @@
'CompileTimeErrorCode.UNDEFINED_IDENTIFIER_AWAIT',
// The code has been replaced but is not yet removed.
'HintCode.DEPRECATED_MEMBER_USE',
+ // Produces two diagnostics when it should only produce one (see
+ // https://github.com/dart-lang/sdk/issues/43051)
+ 'HintCode.UNNECESSARY_NULL_COMPARISON_FALSE',
];
/// The prefix used on directive lines to specify the experiments that should
diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart
index 3056ea5..f5b9ef8 100644
--- a/pkg/dartdev/lib/dartdev.dart
+++ b/pkg/dartdev/lib/dartdev.dart
@@ -47,10 +47,14 @@
analytics =
createAnalyticsInstance(args.contains('--disable-dartdev-analytics'));
- // On the first run, print the message to alert users that anonymous data will
- // be collected by default.
- if (analytics.firstRun) {
+ // If we have not printed the analyticsNoticeOnFirstRunMessage to stdout,
+ // and the user is on a terminal, then print the disclosure and set
+ // analytics.disclosureShownOnTerminal.
+ if (analytics is DartdevAnalytics &&
+ !analytics.disclosureShownOnTerminal &&
+ io.stdout.hasTerminal) {
print(analyticsNoticeOnFirstRunMessage);
+ analytics.disclosureShownOnTerminal = true;
}
// When `--disable-analytics` or `--enable-analytics` are called we perform
@@ -152,8 +156,9 @@
timeout: const Duration(milliseconds: 200));
}
- // As the notification to the user read on the first run, analytics are
- // enabled by default, on the first run only.
+ // Set the enabled flag in the analytics object to true. Note: this will not
+ // enable the analytics unless the disclosure was shown (terminal
+ // detected), and the machine is not detected to be a bot.
if (analytics.firstRun) {
analytics.enabled = true;
}
diff --git a/pkg/dartdev/lib/src/analytics.dart b/pkg/dartdev/lib/src/analytics.dart
index b00dca4..18369cf 100644
--- a/pkg/dartdev/lib/src/analytics.dart
+++ b/pkg/dartdev/lib/src/analytics.dart
@@ -46,7 +46,9 @@
}
// Dartdev tests pass a hidden 'disable-dartdev-analytics' flag which is
- // handled here
+ // handled here.
+ // Also, stdout.hasTerminal is checked, if there is no terminal we infer that
+ // a machine is running dartdev so we return analytics shouldn't be set.
if (disableAnalytics) {
instance = DisabledAnalytics(_trackingId, _appName);
return instance;
@@ -136,13 +138,22 @@
@override
bool get enabled {
- if (telemetry.isRunningOnBot()) {
+ // Don't enable if the user hasn't been shown the disclosure or if this
+ // machine is bot.
+ if (!disclosureShownOnTerminal || telemetry.isRunningOnBot()) {
return false;
}
// If there's no explicit setting (enabled or disabled) then we don't send.
return (properties['enabled'] as bool) ?? false;
}
+
+ bool get disclosureShownOnTerminal =>
+ (properties['disclosureShown'] as bool) ?? false;
+
+ void set disclosureShownOnTerminal(bool value) {
+ properties['disclosureShown'] = value;
+ }
}
class DisabledAnalytics extends AnalyticsMock {
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index f535c91..34cc58e 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -213,12 +213,6 @@
}
}
- if (FLAG_print_classes) {
- for (intptr_t i = 0; i < class_array.Length(); i++) {
- cls ^= class_array.At(i);
- PrintClassInformation(cls);
- }
- }
// Clear pending classes array.
class_array = GrowableObjectArray::New();
object_store->set_pending_classes(class_array);
@@ -1161,6 +1155,9 @@
}
// Mark as loaded and finalized.
cls.Finalize();
+ if (FLAG_print_classes) {
+ PrintClassInformation(cls);
+ }
FinalizeMemberTypes(cls);
if (cls.is_enum_class()) {
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 8b3cc81..92bc408 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -5528,6 +5528,7 @@
DECLARE_INSTRUCTION(LoadIndexed)
virtual CompileType ComputeType() const;
+ virtual bool RecomputeType();
virtual Representation RequiredInputRepresentation(intptr_t idx) const {
ASSERT(idx == 0 || idx == 1);
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index f3fcd25..ba9529b 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -1701,6 +1701,61 @@
return CompileType::FromCid(definition_cid_);
}
+static AbstractTypePtr ExtractElementTypeFromArrayType(
+ const AbstractType& array_type) {
+ if (array_type.IsTypeParameter()) {
+ return ExtractElementTypeFromArrayType(
+ AbstractType::Handle(TypeParameter::Cast(array_type).bound()));
+ }
+ if (!array_type.IsType()) {
+ return Object::dynamic_type().raw();
+ }
+ const intptr_t cid = array_type.type_class_id();
+ if (cid == kGrowableObjectArrayCid || cid == kArrayCid ||
+ cid == kImmutableArrayCid ||
+ array_type.type_class() ==
+ Isolate::Current()->object_store()->list_class()) {
+ const auto& type_args = TypeArguments::Handle(array_type.arguments());
+ return type_args.TypeAtNullSafe(Array::kElementTypeTypeArgPos);
+ }
+ return Object::dynamic_type().raw();
+}
+
+static AbstractTypePtr GetElementTypeFromArray(Value* array) {
+ return ExtractElementTypeFromArrayType(*(array->Type()->ToAbstractType()));
+}
+
+static CompileType ComputeArrayElementType(Value* array) {
+ // 1. Try to extract element type from array value.
+ auto& elem_type = AbstractType::Handle(GetElementTypeFromArray(array));
+ if (!elem_type.IsDynamicType()) {
+ return CompileType::FromAbstractType(elem_type);
+ }
+
+ // 2. Array value may be loaded from GrowableObjectArray.data.
+ // Unwrap and try again.
+ if (auto* load_field = array->definition()->AsLoadField()) {
+ if (load_field->slot().IsIdentical(Slot::GrowableObjectArray_data())) {
+ array = load_field->instance();
+ elem_type = GetElementTypeFromArray(array);
+ if (!elem_type.IsDynamicType()) {
+ return CompileType::FromAbstractType(elem_type);
+ }
+ }
+ }
+
+ // 3. If array was loaded from a Dart field, use field's static type.
+ // Unlike propagated type (which could be cid), static type may contain
+ // type arguments which can be used to figure out element type.
+ if (auto* load_field = array->definition()->AsLoadField()) {
+ if (load_field->slot().IsDartField()) {
+ elem_type =
+ ExtractElementTypeFromArrayType(load_field->slot().static_type());
+ }
+ }
+ return CompileType::FromAbstractType(elem_type);
+}
+
CompileType LoadIndexedInstr::ComputeType() const {
switch (class_id_) {
case kArrayCid:
@@ -1709,7 +1764,7 @@
// The original call knew something.
return *result_type_;
}
- return CompileType::Dynamic();
+ return ComputeArrayElementType(array());
case kTypedDataFloat32ArrayCid:
case kTypedDataFloat64ArrayCid:
@@ -1751,4 +1806,13 @@
}
}
+bool LoadIndexedInstr::RecomputeType() {
+ if ((class_id_ == kArrayCid) || (class_id_ == kImmutableArrayCid)) {
+ // Array element type computation depends on computed
+ // types of other instructions and may change over time.
+ return UpdateType(ComputeType());
+ }
+ return false;
+}
+
} // namespace dart
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 718c6df..1785105 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -2002,8 +2002,11 @@
NameIndex KernelReaderHelper::ReadInterfaceMemberNameReference() {
NameIndex name_index = reader_.ReadCanonicalNameReference();
- reader_
- .ReadCanonicalNameReference(); // read interface target origin reference
+ NameIndex origin_name_index = reader_.ReadCanonicalNameReference();
+ if (!FLAG_precompiled_mode && origin_name_index != NameIndex::kInvalidName) {
+ // Reference to a skipped member signature target, return the origin target.
+ return origin_name_index;
+ }
return name_index;
}
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
index f22bcc1..eac771f 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -4710,6 +4710,58 @@
"with matching arguments declared in class 'A'.");
}
+TEST_CASE(IsolateReload_SuperGetterReboundToMethod) {
+ const char* kScript = R"(
+ import 'file:///test:isolate_reload_helper';
+
+ class A {
+ get x => "123";
+ }
+
+ class B extends A {
+ f() {
+ var old_x = super.x;
+ reloadTest();
+ var new_x = super.x;
+ return "$old_x:$new_x";
+ }
+ }
+
+ main() {
+ return B().f().toString();
+ }
+ )";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript = R"(
+ import 'file:///test:isolate_reload_helper';
+
+ class A {
+ x() => "123";
+ }
+
+ class B extends A {
+ f() {
+ var old_x = super.x;
+ reloadTest();
+ var new_x = super.x;
+ return "$old_x:$new_x";
+ }
+ }
+
+ main() {
+ return B().f();
+ }
+ )";
+
+ EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
+
+ EXPECT_STREQ("123:Closure: () => dynamic from Function 'x':.",
+ SimpleInvokeStr(lib, "main"));
+}
+
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
} // namespace dart
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 092af49..a992ff3 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -1947,7 +1947,16 @@
ProcedureHelper procedure_helper(&helper_);
procedure_helper.ReadUntilExcluding(ProcedureHelper::kAnnotations);
- if (procedure_helper.IsRedirectingFactoryConstructor()) {
+ // CFE adds 'member signature' abstract functions to a legacy class deriving
+ // or implementing an opted-in interface. The signature of these functions is
+ // legacy erased and used as the target of interface calls. They are used for
+ // static reasoning about the program by CFE, but not really needed by the VM.
+ // In certain situations (e.g. issue 162073826), a large number of these
+ // additional functions can cause strain on the VM. They are therefore skipped
+ // in jit mode and their associated origin function is used instead as
+ // interface call target.
+ if (procedure_helper.IsRedirectingFactoryConstructor() ||
+ (!FLAG_precompiled_mode && procedure_helper.IsMemberSignature())) {
helper_.SetOffset(procedure_end);
return;
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 533eb68..28b6ca2 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -9572,6 +9572,9 @@
bool IsImmutable() const { return raw()->GetClassId() == kImmutableArrayCid; }
+ // Position of element type in type arguments.
+ static const intptr_t kElementTypeTypeArgPos = 0;
+
virtual TypeArgumentsPtr GetTypeArguments() const {
return raw_ptr()->type_arguments_;
}
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index cc6f720..847d1a4 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -992,17 +992,8 @@
ASSERT(!caller_.is_static());
new_cls_ = caller_.Owner();
new_cls_ = new_cls_.SuperClass();
- new_target_ = Function::null();
- while (!new_cls_.IsNull()) {
- // TODO(rmacnak): Should use Resolver::ResolveDynamicAnyArgs to handle
- // method-extractors and call-through-getters, but we're in a no
- // safepoint scope here.
- new_target_ = new_cls_.LookupDynamicFunction(name_);
- if (!new_target_.IsNull()) {
- break;
- }
- new_cls_ = new_cls_.SuperClass();
- }
+ new_target_ = Resolver::ResolveDynamicAnyArgs(zone_, new_cls_, name_,
+ /*allow_add=*/true);
}
args_desc_array_ = ic.arguments_descriptor();
ArgumentsDescriptor args_desc(args_desc_array_);
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 9683d81..26a5c3a 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -335,13 +335,15 @@
}
void ObjectStore::LazyInitCoreTypes() {
- if (non_nullable_list_rare_type_ == Type::null()) {
+ if (list_class_ == Type::null()) {
+ ASSERT(non_nullable_list_rare_type_ == Type::null());
ASSERT(non_nullable_map_rare_type_ == Type::null());
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
Class& cls = Class::Handle(zone, core_lib.LookupClass(Symbols::List()));
ASSERT(!cls.IsNull());
+ set_list_class(cls);
Type& type = Type::Handle(zone);
type ^= cls.RareType();
set_non_nullable_list_rare_type(type);
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 52c75ed..07ee7d6 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -82,6 +82,7 @@
RW(Type, string_type) \
RW(Type, legacy_string_type) \
RW(Type, non_nullable_string_type) \
+ CW(Class, list_class) /* maybe be null, lazily built */ \
CW(Type, non_nullable_list_rare_type) /* maybe be null, lazily built */ \
CW(Type, non_nullable_map_rare_type) /* maybe be null, lazily built */ \
FW(Type, non_nullable_future_rare_type) /* maybe be null, lazily built */ \
diff --git a/sdk/bin/dart2js_sdk.bat b/sdk/bin/dart2js_sdk.bat
index 8485cdc..0a9293c 100755
--- a/sdk/bin/dart2js_sdk.bat
+++ b/sdk/bin/dart2js_sdk.bat
@@ -47,7 +47,7 @@
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
- ^| find "> %~n1 [" 2^>nul`) do (
+ ^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
diff --git a/sdk/bin/dartanalyzer_sdk.bat b/sdk/bin/dartanalyzer_sdk.bat
index ab66885..57dd538 100644
--- a/sdk/bin/dartanalyzer_sdk.bat
+++ b/sdk/bin/dartanalyzer_sdk.bat
@@ -42,7 +42,7 @@
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
- ^| find "> %~n1 [" 2^>nul`) do (
+ ^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
diff --git a/sdk/bin/dartdevc.bat b/sdk/bin/dartdevc.bat
index fec39e4..6091a3a 100644
--- a/sdk/bin/dartdevc.bat
+++ b/sdk/bin/dartdevc.bat
@@ -56,7 +56,7 @@
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
- ^| find "> %~n1 [" 2^>nul`) do (
+ ^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
diff --git a/sdk/bin/dartdevc_sdk.bat b/sdk/bin/dartdevc_sdk.bat
index ce027a9..74b4c18 100644
--- a/sdk/bin/dartdevc_sdk.bat
+++ b/sdk/bin/dartdevc_sdk.bat
@@ -49,7 +49,7 @@
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
- ^| find "> %~n1 ["`) do (
+ ^| %SystemRoot%\System32\find.exe "> %~n1 ["`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
diff --git a/sdk/bin/dartfix.bat b/sdk/bin/dartfix.bat
index 4241694..b58475c 100644
--- a/sdk/bin/dartfix.bat
+++ b/sdk/bin/dartfix.bat
@@ -34,7 +34,7 @@
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
- ^| find "> %~n1 [" 2^>nul`) do (
+ ^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
diff --git a/sdk/bin/dartfmt_sdk.bat b/sdk/bin/dartfmt_sdk.bat
index 295b977..b4228d3 100644
--- a/sdk/bin/dartfmt_sdk.bat
+++ b/sdk/bin/dartfmt_sdk.bat
@@ -34,7 +34,7 @@
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
- ^| find "> %~n1 ["`) do (
+ ^| %SystemRoot%\System32\find.exe "> %~n1 ["`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
diff --git a/sdk/bin/pub_sdk.bat b/sdk/bin/pub_sdk.bat
index bde0e4a..2fe828b 100644
--- a/sdk/bin/pub_sdk.bat
+++ b/sdk/bin/pub_sdk.bat
@@ -43,7 +43,7 @@
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
- ^| find "> %~n1 [" 2^>nul`) do (
+ ^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
diff --git a/tools/VERSION b/tools/VERSION
index c3bec70..ecc7570 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 30
+PRERELEASE 31
PRERELEASE_PATCH 0
\ No newline at end of file