Version 2.13.0-150.0.dev
Merge commit 'd59c8bc4fdfa3335210117e776e099fd15eb69bc' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 5c095eda..beda8cf 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
"constraint, update this by running tools/generate_package_config.dart."
],
"configVersion": 2,
- "generated": "2021-03-17T11:06:05.181429",
+ "generated": "2021-03-18T10:46:33.455990",
"generator": "tools/generate_package_config.dart",
"packages": [
{
diff --git a/DEPS b/DEPS
index 50bd12c..ffe4f75 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
# co19 is a cipd package. Use update.sh in tests/co19[_2] to update these
# hashes. It requires access to the dart-build-access group, which EngProd
# has.
- "co19_rev": "8cf837f5abf0a30ed91ebf480df58e5c0480947e",
+ "co19_rev": "1abf208ef6428aac8fee6f3175d65b1c59cd15c8",
"co19_2_rev": "cf6eed0535e45413672bb5bb6e65df9f59846372",
# The internal benchmarks to use. See go/dart-benchmarks-internal
diff --git a/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart b/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart
index 6494ac3..4baea51 100644
--- a/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart
@@ -619,7 +619,7 @@
print('--annotations diff [${uri.pathSegments.last}]-------------');
AnnotatedCode? annotatedCode = code[uri];
print(new AnnotatedCode(annotatedCode?.annotatedCode ?? "",
- annotatedCode?.sourceCode ?? "", annotations[uri]!)
+ annotatedCode?.sourceCode ?? "", annotations[uri] ?? const [])
.toText());
print('----------------------------------------------------------');
}
diff --git a/pkg/compiler/lib/src/kernel/transformations/list_factory_specializer.dart b/pkg/compiler/lib/src/kernel/transformations/list_factory_specializer.dart
index 5c10d5f..b14d9e2 100644
--- a/pkg/compiler/lib/src/kernel/transformations/list_factory_specializer.dart
+++ b/pkg/compiler/lib/src/kernel/transformations/list_factory_specializer.dart
@@ -283,7 +283,7 @@
type: closureParameter.type)
..fileOffset = closureParameter.fileOffset;
this.argument = argument;
- variables[closureParameter] = parameter;
+ setVariableClone(closureParameter, parameter);
}
Statement run() {
@@ -340,17 +340,8 @@
}
@override
- visitVariableGet(VariableGet node) {
- // Unmapped variables are from an outer scope.
- var mapped = variables[node.variable] ?? node.variable;
- return VariableGet(mapped, visitOptionalType(node.promotedType))
- ..fileOffset = node.fileOffset;
- }
-
- @override
- visitVariableSet(VariableSet node) {
- // Unmapped variables are from an outer scope.
- var mapped = variables[node.variable] ?? node.variable;
- return VariableSet(mapped, clone(node.value))..fileOffset = node.fileOffset;
+ VariableDeclaration getVariableClone(VariableDeclaration variable) {
+ VariableDeclaration clone = super.getVariableClone(variable);
+ return clone ?? variable;
}
}
diff --git a/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart
new file mode 100644
index 0000000..a2fd1da
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart
@@ -0,0 +1,8 @@
+// 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.
+
+main() {
+ int localFunction(int i) => i * 2;
+ new List<int>.generate(10, (i) => localFunction(i));
+}
diff --git a/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.strong.expect b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.strong.expect
new file mode 100644
index 0000000..fa4652c
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.strong.expect
@@ -0,0 +1,9 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+ function localFunction(core::int i) → core::int
+ return i.{core::num::*}(2){(core::num) → core::int};
+ core::List::generate<core::int>(10, (core::int i) → core::int => localFunction(i){(core::int) → core::int});
+}
diff --git a/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.strong.transformed.expect
new file mode 100644
index 0000000..e8cb15b
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.strong.transformed.expect
@@ -0,0 +1,16 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_interceptors" as _in;
+
+static method main() → dynamic {
+ function localFunction(core::int i) → core::int
+ return i.{core::num::*}(2){(core::num) → core::int};
+ block {
+ final _in::JSArray<core::int> _list = _in::JSArray::allocateGrowable<core::int>(10);
+ for (core::int* i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+ core::int i = i;
+ _list.{_in::JSArray::[]=}{Invariant,BoundsSafe}(i, localFunction(i){(core::int) → core::int});
+ }
+ } =>_list;
+}
diff --git a/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.textual_outline.expect b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.textual_outline.expect
new file mode 100644
index 0000000..bae895a
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.textual_outline.expect
@@ -0,0 +1 @@
+main() {}
diff --git a/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..bae895a
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.textual_outline_modelled.expect
@@ -0,0 +1 @@
+main() {}
diff --git a/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.weak.expect b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.weak.expect
new file mode 100644
index 0000000..fa4652c
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.weak.expect
@@ -0,0 +1,9 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+ function localFunction(core::int i) → core::int
+ return i.{core::num::*}(2){(core::num) → core::int};
+ core::List::generate<core::int>(10, (core::int i) → core::int => localFunction(i){(core::int) → core::int});
+}
diff --git a/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.weak.outline.expect b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.weak.outline.expect
new file mode 100644
index 0000000..e2cba6b
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.weak.outline.expect
@@ -0,0 +1,5 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.weak.transformed.expect
new file mode 100644
index 0000000..e8cb15b
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/list_generate_local_function_invocation.dart.weak.transformed.expect
@@ -0,0 +1,16 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_interceptors" as _in;
+
+static method main() → dynamic {
+ function localFunction(core::int i) → core::int
+ return i.{core::num::*}(2){(core::num) → core::int};
+ block {
+ final _in::JSArray<core::int> _list = _in::JSArray::allocateGrowable<core::int>(10);
+ for (core::int* i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+ core::int i = i;
+ _list.{_in::JSArray::[]=}{Invariant,BoundsSafe}(i, localFunction(i){(core::int) → core::int});
+ }
+ } =>_list;
+}
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
index 58634b4..7610147 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
@@ -20,7 +20,7 @@
;
@#C12
get a0() → ffi::Array<ffi::Uint8>
- return new ffi::Array::_<ffi::Array<ffi::Uint8>>( block {
+ return new ffi::Array::_<ffi::Uint8>( block {
core::Object #typedDataBase = this.{ffi::Struct::_addressOf};
core::int #offset = (#C14).{core::List::[]}(ffi::_abi());
} =>#typedDataBase is ffi::Pointer<dynamic> ?{core::Object} ffi::_fromAddress<ffi::Uint8>(#typedDataBase.{ffi::Pointer::address}.{core::num::+}(#offset)) : let typ::TypedData #typedData = _in::unsafeCast<typ::TypedData>(#typedDataBase) in #typedData.{typ::TypedData::buffer}.{typ::ByteBuffer::asUint8List}(#typedData.{typ::TypedData::offsetInBytes}.{core::num::+}(#offset), (#C8).{core::List::[]}(ffi::_abi())), #C3, #C15);
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
index 5ea5b51..2b04c25 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
@@ -20,7 +20,7 @@
;
@#C12
get a0() → ffi::Array<ffi::Uint8>
- return new ffi::Array::_<ffi::Array<ffi::Uint8>>( block {
+ return new ffi::Array::_<ffi::Uint8>( block {
core::Object #typedDataBase = this.{ffi::Struct::_addressOf};
core::int #offset = (#C14).{core::List::[]}(ffi::_abi());
} =>#typedDataBase is ffi::Pointer<dynamic> ?{core::Object} ffi::_fromAddress<ffi::Uint8>(#typedDataBase.{ffi::Pointer::address}.{core::num::+}(#offset)) : let typ::TypedData #typedData = _in::unsafeCast<typ::TypedData>(#typedDataBase) in #typedData.{typ::TypedData::buffer}.{typ::ByteBuffer::asUint8List}(#typedData.{typ::TypedData::offsetInBytes}.{core::num::+}(#offset), (#C8).{core::List::[]}(ffi::_abi())), #C3, #C15);
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
index c6d3600..7f11381 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
@@ -20,7 +20,7 @@
;
@#C13
get a0() → ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>>
- return new ffi::Array::_<ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>>>( block {
+ return new ffi::Array::_<ffi::Array<ffi::Array<ffi::Uint8>>>( block {
core::Object #typedDataBase = this.{ffi::Struct::_addressOf};
core::int #offset = (#C15).{core::List::[]}(ffi::_abi());
} =>#typedDataBase is ffi::Pointer<dynamic> ?{core::Object} ffi::_fromAddress<ffi::Array<ffi::Array<ffi::Uint8>>>(#typedDataBase.{ffi::Pointer::address}.{core::num::+}(#offset)) : let typ::TypedData #typedData = _in::unsafeCast<typ::TypedData>(#typedDataBase) in #typedData.{typ::TypedData::buffer}.{typ::ByteBuffer::asUint8List}(#typedData.{typ::TypedData::offsetInBytes}.{core::num::+}(#offset), (#C8).{core::List::[]}(ffi::_abi())), #C12, #C16);
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
index d65caa1..18b2371 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
@@ -20,7 +20,7 @@
;
@#C13
get a0() → ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>>
- return new ffi::Array::_<ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>>>( block {
+ return new ffi::Array::_<ffi::Array<ffi::Array<ffi::Uint8>>>( block {
core::Object #typedDataBase = this.{ffi::Struct::_addressOf};
core::int #offset = (#C15).{core::List::[]}(ffi::_abi());
} =>#typedDataBase is ffi::Pointer<dynamic> ?{core::Object} ffi::_fromAddress<ffi::Array<ffi::Array<ffi::Uint8>>>(#typedDataBase.{ffi::Pointer::address}.{core::num::+}(#offset)) : let typ::TypedData #typedData = _in::unsafeCast<typ::TypedData>(#typedDataBase) in #typedData.{typ::TypedData::buffer}.{typ::ByteBuffer::asUint8List}(#typedData.{typ::TypedData::offsetInBytes}.{core::num::+}(#offset), (#C8).{core::List::[]}(ffi::_abi())), #C12, #C16);
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index a04b607..930ff79 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -13,7 +13,7 @@
/// This class does not clone members. For that, use the
/// [CloneVisitorWithMembers] and setup references properly.
class CloneVisitorNotMembers implements TreeVisitor<TreeNode> {
- final Map<VariableDeclaration, VariableDeclaration> variables =
+ final Map<VariableDeclaration, VariableDeclaration> _variables =
<VariableDeclaration, VariableDeclaration>{};
final Map<LabeledStatement, LabeledStatement> labels =
<LabeledStatement, LabeledStatement>{};
@@ -43,6 +43,20 @@
return map;
}
+ /// Returns the clone of [variable] or `null` if no clone has been created
+ /// for variable.
+ VariableDeclaration? getVariableClone(VariableDeclaration variable) {
+ return _variables[variable];
+ }
+
+ /// Registers [clone] as the clone for [variable].
+ ///
+ /// Returns the [clone].
+ VariableDeclaration setVariableClone(
+ VariableDeclaration variable, VariableDeclaration clone) {
+ return _variables[variable] = clone;
+ }
+
TreeNode visitLibrary(Library node) {
throw 'Cloning of libraries is not implemented';
}
@@ -140,11 +154,11 @@
visitVariableGet(VariableGet node) {
return new VariableGet(
- variables[node.variable]!, visitOptionalType(node.promotedType));
+ getVariableClone(node.variable)!, visitOptionalType(node.promotedType));
}
visitVariableSet(VariableSet node) {
- return new VariableSet(variables[node.variable]!, clone(node.value));
+ return new VariableSet(getVariableClone(node.variable)!, clone(node.value));
}
visitPropertyGet(PropertyGet node) {
@@ -454,14 +468,16 @@
}
visitVariableDeclaration(VariableDeclaration node) {
- return variables[node] = new VariableDeclaration(node.name,
- initializer: cloneOptional(node.initializer),
- type: visitType(node.type))
- ..annotations = cloneAnnotations && !node.annotations.isEmpty
- ? node.annotations.map(clone).toList()
- : const <Expression>[]
- ..flags = node.flags
- ..fileEqualsOffset = _cloneFileOffset(node.fileEqualsOffset);
+ return setVariableClone(
+ node,
+ new VariableDeclaration(node.name,
+ initializer: cloneOptional(node.initializer),
+ type: visitType(node.type))
+ ..annotations = cloneAnnotations && !node.annotations.isEmpty
+ ? node.annotations.map(clone).toList()
+ : const <Expression>[]
+ ..flags = node.flags
+ ..fileEqualsOffset = _cloneFileOffset(node.fileEqualsOffset));
}
visitFunctionDeclaration(FunctionDeclaration node) {
@@ -701,7 +717,7 @@
@override
TreeNode visitLocalFunctionInvocation(LocalFunctionInvocation node) {
return new LocalFunctionInvocation(
- variables[node.variable]!, clone(node.arguments),
+ getVariableClone(node.variable)!, clone(node.arguments),
functionType: visitType(node.functionType) as FunctionType);
}
diff --git a/pkg/kernel/lib/kernel.dart b/pkg/kernel/lib/kernel.dart
index cae6df9..9433890 100644
--- a/pkg/kernel/lib/kernel.dart
+++ b/pkg/kernel/lib/kernel.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.9
-
/// Conventions for paths:
///
/// - Use the [Uri] class for paths that may have the `file`, `dart` or
@@ -23,18 +21,19 @@
export 'ast.dart';
-Component loadComponentFromBinary(String path, [Component component]) {
+Component loadComponentFromBinary(String path, [Component? component]) {
List<int> bytes = new File(path).readAsBytesSync();
return loadComponentFromBytes(bytes, component);
}
-Component loadComponentFromBytes(List<int> bytes, [Component component]) {
+Component loadComponentFromBytes(List<int> bytes, [Component? component]) {
component ??= new Component();
new BinaryBuilder(bytes).readComponent(component);
return component;
}
-Component loadComponentSourceFromBytes(List<int> bytes, [Component component]) {
+Component loadComponentSourceFromBytes(List<int> bytes,
+ [Component? component]) {
component ??= new Component();
new BinaryBuilder(bytes).readComponentSource(component);
return component;
@@ -68,7 +67,7 @@
return sink.builder.toBytes();
}
-void writeLibraryToText(Library library, {String path}) {
+void writeLibraryToText(Library library, {String? path}) {
StringBuffer buffer = new StringBuffer();
new Printer(buffer).writeLibraryFile(library);
if (path == null) {
@@ -79,7 +78,7 @@
}
void writeComponentToText(Component component,
- {String path, bool showOffsets: false, bool showMetadata: false}) {
+ {String? path, bool showOffsets: false, bool showMetadata: false}) {
StringBuffer buffer = new StringBuffer();
new Printer(buffer, showOffsets: showOffsets, showMetadata: showMetadata)
.writeComponentFile(component);
diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart
index 27f5eba..2f4eba5 100644
--- a/pkg/kernel/lib/target/targets.dart
+++ b/pkg/kernel/lib/target/targets.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.9
-
library kernel.target.targets;
import '../ast.dart';
@@ -66,8 +64,8 @@
'none': (TargetFlags flags) => new NoneTarget(flags),
};
-Target getTarget(String name, TargetFlags flags) {
- _TargetBuilder builder = targets[name];
+Target? getTarget(String name, TargetFlags flags) {
+ _TargetBuilder? builder = targets[name];
if (builder == null) return null;
return builder(flags);
}
@@ -241,8 +239,8 @@
CoreTypes coreTypes,
List<Library> libraries,
DiagnosticReporter diagnosticReporter,
- {void logger(String msg),
- ChangedStructureNotifier changedStructureNotifier}) {}
+ {void Function(String msg)? logger,
+ ChangedStructureNotifier? changedStructureNotifier}) {}
/// Perform target-specific modular transformations on the given libraries.
void performModularTransformationsOnLibraries(
@@ -265,7 +263,7 @@
/// procedure.
void performTransformationsOnProcedure(
CoreTypes coreTypes, ClassHierarchy hierarchy, Procedure procedure,
- {void logger(String msg)}) {}
+ {void Function(String msg)? logger}) {}
/// Whether a platform library may define a restricted type, such as `bool`,
/// `int`, `double`, `num`, and `String`.
@@ -327,9 +325,14 @@
///
/// This is determined by the [enabledLateLowerings] mask.
bool isLateFieldLoweringEnabled(
- {bool hasInitializer, bool isFinal, bool isStatic}) {
+ {required bool hasInitializer,
+ required bool isFinal,
+ required bool isStatic}) {
+ // ignore: unnecessary_null_comparison
assert(hasInitializer != null);
+ // ignore: unnecessary_null_comparison
assert(isFinal != null);
+ // ignore: unnecessary_null_comparison
assert(isStatic != null);
int mask = LateLowering.getFieldLowering(
hasInitializer: hasInitializer, isFinal: isFinal, isStatic: isStatic);
@@ -341,9 +344,14 @@
///
/// This is determined by the [enabledLateLowerings] mask.
bool isLateLocalLoweringEnabled(
- {bool hasInitializer, bool isFinal, bool isPotentiallyNullable}) {
+ {required bool hasInitializer,
+ required bool isFinal,
+ required bool isPotentiallyNullable}) {
+ // ignore: unnecessary_null_comparison
assert(hasInitializer != null);
+ // ignore: unnecessary_null_comparison
assert(isFinal != null);
+ // ignore: unnecessary_null_comparison
assert(isPotentiallyNullable != null);
int mask = LateLowering.getLocalLowering(
hasInitializer: hasInitializer,
@@ -399,15 +407,15 @@
String toString() => 'Target($name)';
- Class concreteListLiteralClass(CoreTypes coreTypes) => null;
- Class concreteConstListLiteralClass(CoreTypes coreTypes) => null;
+ Class? concreteListLiteralClass(CoreTypes coreTypes) => null;
+ Class? concreteConstListLiteralClass(CoreTypes coreTypes) => null;
- Class concreteMapLiteralClass(CoreTypes coreTypes) => null;
- Class concreteConstMapLiteralClass(CoreTypes coreTypes) => null;
+ Class? concreteMapLiteralClass(CoreTypes coreTypes) => null;
+ Class? concreteConstMapLiteralClass(CoreTypes coreTypes) => null;
- Class concreteIntLiteralClass(CoreTypes coreTypes, int value) => null;
- Class concreteDoubleLiteralClass(CoreTypes coreTypes, double value) => null;
- Class concreteStringLiteralClass(CoreTypes coreTypes, String value) => null;
+ Class? concreteIntLiteralClass(CoreTypes coreTypes, int value) => null;
+ Class? concreteDoubleLiteralClass(CoreTypes coreTypes, double value) => null;
+ Class? concreteStringLiteralClass(CoreTypes coreTypes, String value) => null;
ConstantsBackend constantsBackend(CoreTypes coreTypes);
}
@@ -416,7 +424,7 @@
@override
final bool supportsUnevaluatedConstants;
- const NoneConstantsBackend({this.supportsUnevaluatedConstants});
+ const NoneConstantsBackend({required this.supportsUnevaluatedConstants});
}
class NoneTarget extends Target {
@@ -456,8 +464,8 @@
Map<String, String> environmentDefines,
DiagnosticReporter diagnosticReporter,
ReferenceFromIndex referenceFromIndex,
- {void logger(String msg),
- ChangedStructureNotifier changedStructureNotifier}) {}
+ {void Function(String msg)? logger,
+ ChangedStructureNotifier? changedStructureNotifier}) {}
@override
Expression instantiateInvocation(CoreTypes coreTypes, Expression receiver,
@@ -509,9 +517,14 @@
static const int all = (1 << 16) - 1;
static int getLocalLowering(
- {bool hasInitializer, bool isFinal, bool isPotentiallyNullable}) {
+ {required bool hasInitializer,
+ required bool isFinal,
+ required bool isPotentiallyNullable}) {
+ // ignore: unnecessary_null_comparison
assert(hasInitializer != null);
+ // ignore: unnecessary_null_comparison
assert(isFinal != null);
+ // ignore: unnecessary_null_comparison
assert(isPotentiallyNullable != null);
if (hasInitializer) {
if (isFinal) {
@@ -545,9 +558,14 @@
}
static int getFieldLowering(
- {bool hasInitializer, bool isFinal, bool isStatic}) {
+ {required bool hasInitializer,
+ required bool isFinal,
+ required bool isStatic}) {
+ // ignore: unnecessary_null_comparison
assert(hasInitializer != null);
+ // ignore: unnecessary_null_comparison
assert(isFinal != null);
+ // ignore: unnecessary_null_comparison
assert(isStatic != null);
if (hasInitializer) {
if (isFinal) {
diff --git a/pkg/kernel/lib/text/text_serialization_verifier.dart b/pkg/kernel/lib/text/text_serialization_verifier.dart
index 0298ad7..dab2bc7 100644
--- a/pkg/kernel/lib/text/text_serialization_verifier.dart
+++ b/pkg/kernel/lib/text/text_serialization_verifier.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.9
-
import 'dart:convert' show json;
import '../ast.dart';
@@ -14,7 +12,7 @@
import '../text/text_serializer.dart';
-const Uri noUri = null;
+const Uri? noUri = null;
const int noOffset = -1;
@@ -28,12 +26,12 @@
/// round-trip serialization failed on or to the closest parent with location.
final TreeNode context;
- RoundTripStatus(this.node, {TreeNode context})
+ RoundTripStatus(this.node, {required TreeNode context})
: context = node is TreeNode && node.location != null ? node : context;
- Uri get uri => context?.location?.file;
+ Uri? get uri => context.location?.file;
- int get offset => context?.fileOffset;
+ int get offset => context.fileOffset;
bool get isSuccess;
@@ -42,11 +40,11 @@
String get nameForDebugging;
int compareTo(RoundTripStatus other) {
- if (node is TreeNode && other.node is TreeNode) {
- TreeNode thisNode = this.node;
- TreeNode otherNode = other.node;
- Uri thisUri = thisNode.location?.file;
- Uri otherUri = otherNode.location?.file;
+ Node thisNode = this.node;
+ Node otherNode = other.node;
+ if (thisNode is TreeNode && otherNode is TreeNode) {
+ Uri? thisUri = thisNode.location?.file;
+ Uri? otherUri = otherNode.location?.file;
int thisOffset = thisNode.fileOffset;
int otherOffset = otherNode.fileOffset;
@@ -58,16 +56,20 @@
} else if (otherUri == null) {
compareUri = -1;
} else {
+ // ignore: unnecessary_null_comparison
assert(thisUri != null && otherUri != null);
compareUri = thisUri.toString().compareTo(otherUri.toString());
}
if (compareUri != 0) return compareUri;
int compareOffset;
+ // ignore: unnecessary_null_comparison
if (thisOffset == null && otherOffset == null) {
compareOffset = 0;
+ // ignore: unnecessary_null_comparison
} else if (thisOffset == null) {
compareOffset = 1;
+ // ignore: unnecessary_null_comparison
} else if (otherOffset == null) {
compareOffset = -1;
} else {
@@ -99,12 +101,12 @@
sb.writeln("Status: ${nameForDebugging}");
sb.writeln("Node type: ${node.runtimeType}");
sb.writeln("Node: ${json.encode(node.leakingDebugToString())}");
- if (node is TreeNode) {
- TreeNode treeNode = node;
+ Node treeNode = node;
+ if (treeNode is TreeNode) {
if (treeNode.parent != null) {
sb.writeln("Parent type: ${treeNode.parent.runtimeType}");
sb.writeln(
- "Parent: ${json.encode(treeNode.parent.leakingDebugToString())}");
+ "Parent: ${json.encode(treeNode.parent!.leakingDebugToString())}");
}
}
}
@@ -119,7 +121,7 @@
class RoundTripSuccess extends RoundTripStatus {
final String serialized;
- RoundTripSuccess(Node node, this.serialized, {TreeNode context})
+ RoundTripSuccess(Node node, this.serialized, {required TreeNode context})
: super(node, context: context);
@override
@@ -139,7 +141,7 @@
final String message;
RoundTripInitialSerializationFailure(Node node, this.message,
- {TreeNode context})
+ {required TreeNode context})
: super(node, context: context);
@override
@@ -158,7 +160,8 @@
class RoundTripDeserializationFailure extends RoundTripStatus {
final String message;
- RoundTripDeserializationFailure(Node node, this.message, {TreeNode context})
+ RoundTripDeserializationFailure(Node node, this.message,
+ {required TreeNode context})
: super(node, context: context);
@override
@@ -179,7 +182,7 @@
final String serialized;
RoundTripSecondSerializationFailure(Node node, this.initial, this.serialized,
- {TreeNode context})
+ {required TreeNode context})
: super(node, context: context);
@override
@@ -206,7 +209,7 @@
final CanonicalName root;
- TextSerializationVerifier({CanonicalName root})
+ TextSerializationVerifier({CanonicalName? root})
: root = root ?? new CanonicalName.root() {
initializeSerializers();
}
@@ -220,7 +223,7 @@
makeRoundTrip<Library>(node, librarySerializer);
}
- T readNode<T extends TreeNode>(
+ T? readNode<T extends TreeNode>(
T node, String input, TextSerializer<T> serializer) {
TextIterator stream = new TextIterator(input, 0);
stream.moveNext();
@@ -240,6 +243,7 @@
node, "unexpected trailing text",
context: node));
}
+ // ignore: unnecessary_null_comparison
if (result == null) {
_status.add(new RoundTripDeserializationFailure(
node, "Deserialization of the following returned null: '${input}'",
@@ -270,7 +274,7 @@
}
// Do the round trip.
- T deserialized = readNode(node, initial, serializer);
+ T? deserialized = readNode(node, initial, serializer);
if (_failures.length != failureCount) {
return;
}
diff --git a/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart b/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart
index 2eeb952..2d301ed 100644
--- a/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart
+++ b/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart
@@ -2,12 +2,8 @@
// 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.
-// @dart = 2.9
-
library kernel.transformations.track_widget_constructor_locations;
-import 'package:meta/meta.dart';
-
import '../ast.dart';
import '../target/changed_structure_notifier.dart';
@@ -36,7 +32,7 @@
.any((NamedExpression argument) => argument.name == argumentName);
}
-VariableDeclaration _getNamedParameter(
+VariableDeclaration? _getNamedParameter(
FunctionNode function,
String parameterName,
) {
@@ -128,7 +124,7 @@
///
/// Used to flow the location passed in as an argument to the factory to the
/// actual constructor call within the factory.
- Procedure _currentFactory;
+ Procedure? _currentFactory;
WidgetCreatorTracker _tracker;
@@ -136,12 +132,12 @@
///
/// The transformation of the call sites is affected by the NNBD opt-in status
/// of the library.
- Library _currentLibrary;
+ Library? _currentLibrary;
_WidgetCallSiteTransformer(
- {@required Class widgetClass,
- @required Class locationClass,
- @required WidgetCreatorTracker tracker})
+ {required Class widgetClass,
+ required Class locationClass,
+ required WidgetCreatorTracker tracker})
: _widgetClass = widgetClass,
_locationClass = locationClass,
_tracker = tracker;
@@ -158,8 +154,8 @@
/// without re-parsing the source code.
ConstructorInvocation _constructLocation(
Location location, {
- String name,
- ListLiteral parameterLocations,
+ String? name,
+ ListLiteral? parameterLocations,
bool showFile: true,
}) {
final List<NamedExpression> arguments = <NamedExpression>[
@@ -192,7 +188,8 @@
_currentFactory = null;
return node;
}
- return defaultTreeNode(node);
+ node.transformChildren(this);
+ return node;
}
bool _isSubclassOfWidget(Class clazz) {
@@ -206,12 +203,12 @@
if (!target.isFactory) {
return node;
}
- final Class constructedClass = target.enclosingClass;
+ final Class constructedClass = target.enclosingClass!;
if (!_isSubclassOfWidget(constructedClass)) {
return node;
}
- _addLocationArgument(node, target.function, constructedClass,
+ _addLocationArgument(node, target.function!, constructedClass,
isConst: node.isConst);
return node;
}
@@ -237,7 +234,7 @@
return node;
}
- _addLocationArgument(node, constructor.function, constructedClass,
+ _addLocationArgument(node, constructor.function!, constructedClass,
isConst: node.isConst);
return node;
}
@@ -249,13 +246,13 @@
// argument to the factory constructor rather than the location
if (_currentFactory != null &&
_tracker._isSubclassOf(
- constructedClass, _currentFactory.enclosingClass) &&
+ constructedClass, _currentFactory!.enclosingClass!) &&
// If the constructor invocation is constant we cannot refer to the
// location parameter of the surrounding factory since it isn't a
// constant expression.
!isConst) {
- final VariableDeclaration creationLocationParameter = _getNamedParameter(
- _currentFactory.function,
+ final VariableDeclaration? creationLocationParameter = _getNamedParameter(
+ _currentFactory!.function!,
_creationLocationParameterName,
);
if (creationLocationParameter != null) {
@@ -264,7 +261,7 @@
}
final Arguments arguments = node.arguments;
- final Location location = node.location;
+ final Location location = node.location!;
final List<ConstructorInvocation> parameterLocations =
<ConstructorInvocation>[];
final List<VariableDeclaration> parameters = function.positionalParameters;
@@ -272,14 +269,14 @@
final Expression expression = arguments.positional[i];
final VariableDeclaration parameter = parameters[i];
parameterLocations.add(_constructLocation(
- expression.location,
+ expression.location!,
name: parameter.name,
showFile: false,
));
}
for (NamedExpression expression in arguments.named) {
parameterLocations.add(_constructLocation(
- expression.location,
+ expression.location!,
name: expression.name,
showFile: false,
));
@@ -289,7 +286,7 @@
parameterLocations: new ListLiteral(
parameterLocations,
typeArgument:
- new InterfaceType(_locationClass, _currentLibrary.nonNullable),
+ new InterfaceType(_locationClass, _currentLibrary!.nonNullable),
isConst: true,
),
);
@@ -299,7 +296,7 @@
assert(
_currentLibrary == null,
"Attempting to enter library '${library.fileUri}' "
- "without having exited library '${_currentLibrary.fileUri}'.");
+ "without having exited library '${_currentLibrary!.fileUri}'.");
_currentLibrary = library;
}
@@ -317,24 +314,30 @@
/// on the base widget class and flowed through the constructors using a named
/// parameter.
class WidgetCreatorTracker {
- Class _widgetClass;
- Class _locationClass;
+ bool _foundClasses = false;
+ late Class _widgetClass;
+ late Class _locationClass;
/// Marker interface indicating that a private _location field is
/// available.
- Class _hasCreationLocationClass;
+ late Class _hasCreationLocationClass;
void _resolveFlutterClasses(Iterable<Library> libraries) {
// If the Widget or Debug location classes have been updated we need to get
// the latest version
+ bool foundWidgetClass = false;
+ bool foundHasCreationLocationClass = false;
+ bool foundLocationClass = false;
for (Library library in libraries) {
final Uri importUri = library.importUri;
+ // ignore: unnecessary_null_comparison
if (importUri != null && importUri.scheme == 'package') {
if (importUri.path == 'flutter/src/widgets/framework.dart' ||
importUri.path == 'flutter_web/src/widgets/framework.dart') {
for (Class class_ in library.classes) {
if (class_.name == 'Widget') {
_widgetClass = class_;
+ foundWidgetClass = true;
}
}
} else {
@@ -344,14 +347,18 @@
for (Class class_ in library.classes) {
if (class_.name == '_HasCreationLocation') {
_hasCreationLocationClass = class_;
+ foundHasCreationLocationClass = true;
} else if (class_.name == '_Location') {
_locationClass = class_;
+ foundLocationClass = true;
}
}
}
}
}
}
+ _foundClasses =
+ foundWidgetClass && foundHasCreationLocationClass && foundLocationClass;
}
/// Modify [clazz] to add a field named [_locationFieldName] that is the
@@ -360,9 +367,9 @@
/// This method should only be called for classes that implement but do not
/// extend [Widget].
void _transformClassImplementingWidget(
- Class clazz, ChangedStructureNotifier changedStructureNotifier) {
+ Class clazz, ChangedStructureNotifier? changedStructureNotifier) {
if (clazz.fields
- .any((Field field) => field.name.text == _locationFieldName)) {
+ .any((Field field) => field.name!.text == _locationFieldName)) {
// This class has already been transformed. Skip
return;
}
@@ -383,7 +390,7 @@
isFinal: true,
getterReference: clazz.reference.canonicalName
?.getChildFromFieldWithName(fieldName)
- ?.reference);
+ .reference);
clazz.addField(locationField);
final Set<Constructor> _handledConstructors =
@@ -394,7 +401,7 @@
return;
}
assert(!_hasNamedParameter(
- constructor.function,
+ constructor.function!,
_creationLocationParameterName,
));
final VariableDeclaration variable = new VariableDeclaration(
@@ -402,7 +409,7 @@
type: new InterfaceType(
_locationClass, clazz.enclosingLibrary.nullable),
initializer: new NullLiteral());
- if (!_maybeAddNamedParameter(constructor.function, variable)) {
+ if (!_maybeAddNamedParameter(constructor.function!, variable)) {
return;
}
@@ -417,7 +424,7 @@
}
_maybeAddCreationLocationArgument(
initializer.arguments,
- initializer.target.function,
+ initializer.target.function!,
new VariableGet(variable),
_locationClass,
);
@@ -462,14 +469,14 @@
/// compilation where the class hierarchy is kept between compiles and thus
/// has to be kept up to date.
void transform(Component module, List<Library> libraries,
- ChangedStructureNotifier changedStructureNotifier) {
+ ChangedStructureNotifier? changedStructureNotifier) {
if (libraries.isEmpty) {
return;
}
_resolveFlutterClasses(module.libraries);
- if (_widgetClass == null) {
+ if (!_foundClasses) {
// This application doesn't actually use the package:flutter library.
return;
}
@@ -508,7 +515,7 @@
bool _isSubclassOf(Class a, Class b) {
// TODO(askesc): Cache results.
// TODO(askesc): Test for subtype rather than subclass.
- Class current = a;
+ Class? current = a;
while (current != null) {
if (current == b) return true;
current = current.superclass;
@@ -520,7 +527,7 @@
Set<Library> librariesToBeTransformed,
Set<Class> transformedClasses,
Class clazz,
- ChangedStructureNotifier changedStructureNotifier) {
+ ChangedStructureNotifier? changedStructureNotifier) {
if (!_isSubclassOfWidget(clazz) ||
!librariesToBeTransformed.contains(clazz.enclosingLibrary) ||
!transformedClasses.add(clazz)) {
@@ -533,7 +540,7 @@
_transformWidgetConstructors(
librariesToBeTransformed,
transformedClasses,
- clazz.superclass,
+ clazz.superclass!,
changedStructureNotifier,
);
}
@@ -541,7 +548,7 @@
for (Procedure procedure in clazz.procedures) {
if (procedure.isFactory) {
_maybeAddNamedParameter(
- procedure.function,
+ procedure.function!,
new VariableDeclaration(_creationLocationParameterName,
type: new InterfaceType(
_locationClass, clazz.enclosingLibrary.nullable),
@@ -552,7 +559,7 @@
// Handle the widget class and classes that implement but do not extend the
// widget class.
- if (!_isSubclassOfWidget(clazz.superclass)) {
+ if (!_isSubclassOfWidget(clazz.superclass!)) {
_transformClassImplementingWidget(clazz, changedStructureNotifier);
return;
}
@@ -571,12 +578,12 @@
_locationClass, clazz.enclosingLibrary.nullable),
initializer: new NullLiteral());
if (_hasNamedParameter(
- constructor.function, _creationLocationParameterName)) {
+ constructor.function!, _creationLocationParameterName)) {
// Constructor was already rewritten.
// TODO(jacobr): is this case actually hit?
return;
}
- if (!_maybeAddNamedParameter(constructor.function, variable)) {
+ if (!_maybeAddNamedParameter(constructor.function!, variable)) {
return;
}
for (Initializer initializer in constructor.initializers) {
@@ -590,7 +597,7 @@
_maybeAddCreationLocationArgument(
initializer.arguments,
- initializer.target.function,
+ initializer.target.function!,
new VariableGet(variable),
_locationClass,
);
@@ -598,7 +605,7 @@
_isSubclassOfWidget(initializer.target.enclosingClass)) {
_maybeAddCreationLocationArgument(
initializer.arguments,
- initializer.target.function,
+ initializer.target.function!,
new VariableGet(variable),
_locationClass,
);
diff --git a/pkg/kernel/pubspec.yaml b/pkg/kernel/pubspec.yaml
index 09b5348..72c0820 100644
--- a/pkg/kernel/pubspec.yaml
+++ b/pkg/kernel/pubspec.yaml
@@ -8,8 +8,6 @@
environment:
sdk: '>=2.12.0 <3.0.0'
dependencies:
- meta:
- path: ../meta
dev_dependencies:
args: '>=0.13.4 <2.0.0'
expect:
diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart
index 4569be7..2de1c0b 100644
--- a/pkg/vm/lib/transformations/ffi_definitions.dart
+++ b/pkg/vm/lib/transformations/ffi_definitions.dart
@@ -1029,7 +1029,7 @@
ConstantExpression(IntConstant(length)),
transformer.intListConstantExpression(nestedDimensions)
], types: [
- dartType
+ typeArgument
]))
..fileOffset = fileOffset);
}
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index 673bc1f..14d1b20 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -361,6 +361,7 @@
scope_->InsertParameterAt(pos++, parsed_function_->receiver_var());
// Create all positional and named parameters.
+ current_function_async_marker_ = FunctionNodeHelper::kSync;
AddPositionalAndNamedParameters(
pos, kTypeCheckEverythingNotCheckedInNonDynamicallyInvokedMethod,
attrs);
@@ -706,15 +707,15 @@
return;
case kSuperPropertyGet:
HandleLoadReceiver();
- helper_.ReadPosition(); // read position.
- helper_.SkipName(); // read name.
+ helper_.ReadPosition(); // read position.
+ helper_.SkipName(); // read name.
helper_.SkipInterfaceMemberNameReference(); // read target_reference.
return;
case kSuperPropertySet:
HandleLoadReceiver();
- helper_.ReadPosition(); // read position.
- helper_.SkipName(); // read name.
- VisitExpression(); // read value.
+ helper_.ReadPosition(); // read position.
+ helper_.SkipName(); // read name.
+ VisitExpression(); // read value.
helper_.SkipInterfaceMemberNameReference(); // read target_reference.
return;
case kStaticGet:
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index f9612e6..df878fa 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -731,11 +731,12 @@
extension PointerArray<T extends NativeType> on Array<Pointer<T>> {
@patch
- Pointer<T> operator [](int index) => _loadPointer(this, _intPtrSize * index);
+ Pointer<T> operator [](int index) =>
+ _loadPointer(_typedDataBase, _intPtrSize * index);
@patch
void operator []=(int index, Pointer<T> value) =>
- _storePointer(this, _intPtrSize * index, value);
+ _storePointer(_typedDataBase, _intPtrSize * index, value);
}
extension ArrayArray<T extends NativeType> on Array<Array<T>> {
diff --git a/sdk/lib/core/errors.dart b/sdk/lib/core/errors.dart
index 4157688..683267d 100644
--- a/sdk/lib/core/errors.dart
+++ b/sdk/lib/core/errors.dart
@@ -520,7 +520,7 @@
/// The operation was not allowed by the current state of the object.
///
-/// Should be used when this particular object is currenty in a state
+/// Should be used when this particular object is currently in a state
/// which doesn't support the requested operation, but other similar
/// objects might, or the object might change its state to one which
/// supports the operation.
diff --git a/sdk/lib/core/int.dart b/sdk/lib/core/int.dart
index 92d494b..a799e46 100644
--- a/sdk/lib/core/int.dart
+++ b/sdk/lib/core/int.dart
@@ -111,7 +111,7 @@
///
/// The least significant [shiftAmount] bits are dropped,
/// the remaining bits (if any) are shifted down,
- /// and zero-bits are shifted in as the new most signficant bits.
+ /// and zero-bits are shifted in as the new most significant bits.
///
/// The [shiftAmount] must be non-negative.
int operator >>>(int shiftAmount);
diff --git a/sdk/lib/core/string_buffer.dart b/sdk/lib/core/string_buffer.dart
index b15cb77..9f5a615 100644
--- a/sdk/lib/core/string_buffer.dart
+++ b/sdk/lib/core/string_buffer.dart
@@ -24,7 +24,7 @@
/// operation.
bool get isNotEmpty => !isEmpty;
- /// Adds the string representatoon of [object] to the buffer.
+ /// Adds the string representation of [object] to the buffer.
external void write(Object? object);
/// Adds the string representation of [charCode] to the buffer.
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index 701c37e..7d22b20 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -331,7 +331,7 @@
/// The authority is formatted from the [userInfo], [host] and [port]
/// parts.
///
- /// The valie is the empty string if there is no authority component.
+ /// The value is the empty string if there is no authority component.
String get authority;
/// The user info part of the authority component.
@@ -414,7 +414,7 @@
/// specified for FORM post in the [HTML 4.01 specification section
/// 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
///
- /// Each key and value in the reulting map has been decoded. If there is no
+ /// Each key and value in the resulting map has been decoded. If there is no
/// query the map is empty.
///
/// Keys are mapped to lists of their values. If a key occurs only once,
diff --git a/tests/ffi/regress_45198_test.dart b/tests/ffi/regress_45198_test.dart
new file mode 100644
index 0000000..3247d27
--- /dev/null
+++ b/tests/ffi/regress_45198_test.dart
@@ -0,0 +1,29 @@
+// 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 "dart:ffi";
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+class Struct8BytesInlineArrayInt extends Struct {
+ @Array(2)
+ external Array<Pointer<Int8>> a0;
+}
+
+void main() {
+ final arrayPointer = calloc<Struct8BytesInlineArrayInt>();
+
+ final pointer = Pointer<Int8>.fromAddress(0xdeadbeef);
+
+ final array = arrayPointer.ref.a0;
+ print(arrayPointer);
+ print(array);
+ Expect.type<Array<Pointer<Int8>>>(array);
+ Expect.equals(nullptr, array[0]);
+ array[0] = pointer;
+ Expect.equals(pointer, array[0]);
+
+ calloc.free(arrayPointer);
+}
diff --git a/tests/ffi_2/regress_45198_test.dart b/tests/ffi_2/regress_45198_test.dart
new file mode 100644
index 0000000..48c1204
--- /dev/null
+++ b/tests/ffi_2/regress_45198_test.dart
@@ -0,0 +1,29 @@
+// 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 "dart:ffi";
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+class Struct8BytesInlineArrayInt extends Struct {
+ @Array(2)
+ Array<Pointer<Int8>> a0;
+}
+
+void main() {
+ final arrayPointer = calloc<Struct8BytesInlineArrayInt>();
+
+ final pointer = Pointer<Int8>.fromAddress(0xdeadbeef);
+
+ final array = arrayPointer.ref.a0;
+ print(arrayPointer);
+ print(array);
+ Expect.type<Array<Pointer<Int8>>>(array);
+ Expect.equals(nullptr, array[0]);
+ array[0] = pointer;
+ Expect.equals(pointer, array[0]);
+
+ calloc.free(arrayPointer);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 2965fb3..cb8bd38 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 149
+PRERELEASE 150
PRERELEASE_PATCH 0
\ No newline at end of file