Version 2.12.0-264.0.dev
Merge commit '64a8d2a8b8b85a6e3221ebbc80f36a7746045b4e' into 'dev'
diff --git a/DEPS b/DEPS
index 00cb7f7..5761840 100644
--- a/DEPS
+++ b/DEPS
@@ -111,7 +111,7 @@
"http_multi_server_rev" : "e8c8be7f15b4fb50757ff5bf29766721fbe24fe4",
"http_parser_rev": "5dd4d16693242049dfb43b5efa429fedbf932e98",
"http_retry_tag": "0.1.1",
- "http_rev": "3845753a54624b070828cb3eff7a6c2a4e046cfb",
+ "http_rev": "d5c678cd63c3e9c1d779a09acfa95b7e3af84665",
"http_throttle_tag" : "1.0.2",
"icu_rev" : "79326efe26e5440f530963704c3c0ff965b3a4ac",
"idl_parser_rev": "5fb1ebf49d235b5a70c9f49047e83b0654031eb7",
diff --git a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
index 52da455..50f73a3 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
@@ -95,6 +95,7 @@
Future<void> test_createChange_add() async {
await indexTestUnit('''
+/// Documentation for [new A]
class A {
A() {} // marker
factory A._() = A;
@@ -114,6 +115,7 @@
// validate change
refactoring.newName = 'newName';
return assertSuccessfulRefactoring('''
+/// Documentation for [new A.newName]
class A {
A.newName() {} // marker
factory A._() = A.newName;
@@ -129,6 +131,7 @@
Future<void> test_createChange_add_toSynthetic() async {
await indexTestUnit('''
+/// Documentation for [new A]
class A {
}
class B extends A {
@@ -146,6 +149,7 @@
// validate change
refactoring.newName = 'newName';
return assertSuccessfulRefactoring('''
+/// Documentation for [new A.newName]
class A {
A.newName();
}
@@ -160,6 +164,7 @@
Future<void> test_createChange_change() async {
await indexTestUnit('''
+/// Documentation for [A.test] and [new A.test]
class A {
A.test() {} // marker
factory A._() = A.test;
@@ -179,6 +184,7 @@
// validate change
refactoring.newName = 'newName';
return assertSuccessfulRefactoring('''
+/// Documentation for [A.newName] and [new A.newName]
class A {
A.newName() {} // marker
factory A._() = A.newName;
@@ -194,6 +200,7 @@
Future<void> test_createChange_remove() async {
await indexTestUnit('''
+/// Documentation for [A.test] and [new A.test]
class A {
A.test() {} // marker
factory A._() = A.test;
@@ -213,6 +220,7 @@
// validate change
refactoring.newName = '';
return assertSuccessfulRefactoring('''
+/// Documentation for [A] and [new A]
class A {
A() {} // marker
factory A._() = A;
diff --git a/pkg/analyzer/lib/src/dart/analysis/index.dart b/pkg/analyzer/lib/src/dart/analysis/index.dart
index c664f80..1df5522 100644
--- a/pkg/analyzer/lib/src/dart/analysis/index.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/index.dart
@@ -584,6 +584,28 @@
}
@override
+ visitCommentReference(CommentReference node) {
+ var identifier = node.identifier;
+ var element = identifier.staticElement;
+ if (element is ConstructorElement) {
+ if (identifier is PrefixedIdentifier) {
+ var offset = identifier.prefix.end;
+ var length = identifier.end - offset;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+ return;
+ } else {
+ var offset = identifier.end;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+ return;
+ }
+ }
+
+ return super.visitCommentReference(node);
+ }
+
+ @override
void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
SimpleIdentifier fieldName = node.fieldName;
if (fieldName != null) {
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
index 21fcfc4..1f5499e 100644
--- a/pkg/analyzer/test/src/dart/analysis/index_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -602,33 +602,39 @@
test_isReferencedBy_ConstructorElement() async {
await _indexTestUnit('''
+/// [new A.foo] 1
+/// [A.foo] 2
+/// [new A] 3
class A implements B {
A() {}
A.foo() {}
}
class B extends A {
- B() : super(); // 1
- B.foo() : super.foo(); // 2
- factory B.bar() = A.foo; // 3
+ B() : super(); // 4
+ B.foo() : super.foo(); // 5
+ factory B.bar() = A.foo; // 6
}
main() {
- new A(); // 4
- new A.foo(); // 5
+ new A(); // 7
+ new A.foo(); // 8
}
''');
var constA = findElement.unnamedConstructor('A');
var constA_foo = findElement.constructor('foo', of: 'A');
// A()
assertThat(constA)
- ..hasRelationCount(2)
- ..isReferencedAt('(); // 1', true, length: 0)
- ..isReferencedAt('(); // 4', true, length: 0);
+ ..hasRelationCount(3)
+ ..isReferencedAt('] 3', true, length: 0)
+ ..isReferencedAt('(); // 4', true, length: 0)
+ ..isReferencedAt('(); // 7', true, length: 0);
// A.foo()
assertThat(constA_foo)
- ..hasRelationCount(3)
- ..isReferencedAt('.foo(); // 2', true, length: 4)
- ..isReferencedAt('.foo; // 3', true, length: 4)
- ..isReferencedAt('.foo(); // 5', true, length: 4);
+ ..hasRelationCount(5)
+ ..isReferencedAt('.foo] 1', true, length: 4)
+ ..isReferencedAt('.foo] 2', true, length: 4)
+ ..isReferencedAt('.foo(); // 5', true, length: 4)
+ ..isReferencedAt('.foo; // 6', true, length: 4)
+ ..isReferencedAt('.foo(); // 8', true, length: 4);
}
test_isReferencedBy_ConstructorElement_classTypeAlias() async {
diff --git a/pkg/dart2native/bin/dart2native.dart b/pkg/dart2native/bin/dart2native.dart
index 7f407416..ed18daf 100644
--- a/pkg/dart2native/bin/dart2native.dart
+++ b/pkg/dart2native/bin/dart2native.dart
@@ -66,6 +66,8 @@
defaultsTo: '', valueHelp: 'feature', hide: true, help: '''
Comma separated list of experimental features.
''')
+ ..addFlag('sound-null-safety',
+ help: 'Respect the nullability of types at runtime.', defaultsTo: null)
..addFlag('verbose',
abbr: 'v', negatable: false, help: 'Show verbose output.')
..addOption(
@@ -116,6 +118,7 @@
defines: parsedArgs['define'],
enableExperiment: parsedArgs['enable-experiment'],
enableAsserts: parsedArgs['enable-asserts'],
+ soundNullSafety: parsedArgs['sound-null-safety'],
verbose: parsedArgs['verbose'],
verbosity: parsedArgs['verbosity'],
extraOptions: parsedArgs['extra-gen-snapshot-options']);
diff --git a/pkg/dart2native/lib/generate.dart b/pkg/dart2native/lib/generate.dart
index 6bc3abd..3df6176 100644
--- a/pkg/dart2native/lib/generate.dart
+++ b/pkg/dart2native/lib/generate.dart
@@ -26,6 +26,7 @@
List<String> defines,
String enableExperiment = '',
bool enableAsserts = false,
+ bool soundNullSafety,
bool verbose = false,
String verbosity = 'all',
List<String> extraOptions = const [],
@@ -61,7 +62,9 @@
enableExperiment: enableExperiment,
extraGenKernelOptions: [
'--invocation-modes=compile',
- '--verbosity=$verbosity'
+ '--verbosity=$verbosity',
+ if (soundNullSafety != null)
+ '--${soundNullSafety ? '' : 'no-'}sound-null-safety',
]);
if (kernelResult.exitCode != 0) {
// We pipe both stdout and stderr to stderr because the CFE doesn't print
diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart
index 021db07..affa10d 100644
--- a/pkg/dartdev/lib/src/commands/compile.dart
+++ b/pkg/dartdev/lib/src/commands/compile.dart
@@ -258,6 +258,9 @@
'''Get package locations from the specified file instead of .packages.
<path> can be relative or absolute.
For example: dart compile $commandName --packages=/tmp/pkgs main.dart''')
+ ..addFlag('sound-null-safety',
+ help: 'Respect the nullability of types at runtime.',
+ defaultsTo: null)
..addOption('save-debugging-info', abbr: 'S', valueHelp: 'path', help: '''
Remove debugging information from the output and save it separately to the specified file.
<path> can be relative or absolute.''');
@@ -294,6 +297,7 @@
packages: argResults['packages'],
enableAsserts: argResults['enable-asserts'],
enableExperiment: argResults.enabledExperiments.join(','),
+ soundNullSafety: argResults['sound-null-safety'],
debugFile: argResults['save-debugging-info'],
verbose: verbose,
verbosity: argResults['verbosity'],
diff --git a/pkg/dartdev/test/commands/compile_test.dart b/pkg/dartdev/test/commands/compile_test.dart
index 61ebc76..458fb39 100644
--- a/pkg/dartdev/test/commands/compile_test.dart
+++ b/pkg/dartdev/test/commands/compile_test.dart
@@ -310,6 +310,74 @@
reason: 'File not found: $outFile');
});
+ test('Compile and run exe with --sound-null-safety', () {
+ final p = project(mainSrc: '''void main() {
+ print((<int?>[] is List<int>) ? 'oh no' : 'sound');
+ }''');
+ final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+ final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
+
+ var result = p.runSync(
+ [
+ 'compile',
+ 'exe',
+ '--sound-null-safety',
+ '-o',
+ outFile,
+ inFile,
+ ],
+ );
+
+ expect(result.stderr, isEmpty);
+ expect(result.stdout, contains(soundNullSafetyMessage));
+ expect(result.exitCode, 0);
+ expect(File(outFile).existsSync(), true,
+ reason: 'File not found: $outFile');
+
+ result = Process.runSync(
+ outFile,
+ [],
+ );
+
+ expect(result.stdout, contains('sound'));
+ expect(result.stderr, isEmpty);
+ expect(result.exitCode, 0);
+ });
+
+ test('Compile and run exe with --no-sound-null-safety', () {
+ final p = project(mainSrc: '''void main() {
+ print((<int?>[] is List<int>) ? 'unsound' : 'oh no');
+ }''');
+ final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+ final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
+
+ var result = p.runSync(
+ [
+ 'compile',
+ 'exe',
+ '--no-sound-null-safety',
+ '-o',
+ outFile,
+ inFile,
+ ],
+ );
+
+ expect(result.stderr, isEmpty);
+ expect(result.stdout, contains(unsoundNullSafetyMessage));
+ expect(result.exitCode, 0);
+ expect(File(outFile).existsSync(), true,
+ reason: 'File not found: $outFile');
+
+ result = Process.runSync(
+ outFile,
+ [],
+ );
+
+ expect(result.stdout, contains('unsound'));
+ expect(result.stderr, isEmpty);
+ expect(result.exitCode, 0);
+ });
+
test('Compile exe without info', () {
final p = project(mainSrc: '''void main() {}''');
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
index 25d68b1..c75bd34 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
@@ -65,12 +65,16 @@
/// with legacy types.
DartType demoteTypeInLibrary(DartType type, Library library) {
if (library.isNonNullableByDefault) {
- return type.accept(const _DemotionNullabilityNormalization(
- demoteTypeVariables: true, forNonNullableByDefault: true)) ??
+ return type.accept1(
+ const _DemotionNullabilityNormalization(
+ demoteTypeVariables: true, forNonNullableByDefault: true),
+ Variance.covariant) ??
type;
} else {
- return type.accept(const _DemotionNullabilityNormalization(
- demoteTypeVariables: true, forNonNullableByDefault: false)) ??
+ return type.accept1(
+ const _DemotionNullabilityNormalization(
+ demoteTypeVariables: true, forNonNullableByDefault: false),
+ Variance.covariant) ??
type;
}
}
@@ -85,8 +89,10 @@
if (library.isNonNullableByDefault) {
return type;
} else {
- return type.accept(const _DemotionNullabilityNormalization(
- demoteTypeVariables: false, forNonNullableByDefault: false)) ??
+ return type.accept1(
+ const _DemotionNullabilityNormalization(
+ demoteTypeVariables: false, forNonNullableByDefault: false),
+ Variance.covariant) ??
type;
}
}
@@ -119,7 +125,7 @@
}
@override
- DartType visitTypeParameterType(TypeParameterType node) {
+ DartType visitTypeParameterType(TypeParameterType node, int variance) {
Nullability newNullability = visitNullability(node);
if (demoteTypeVariables && node.promotedBound != null) {
return new TypeParameterType(
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
index f07e42a..d65acf4 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
@@ -53,17 +53,11 @@
final DartType topType;
final DartType bottomType;
- bool isLeastClosure;
-
- _TypeSchemaEliminationVisitor(
- this.isLeastClosure, this.topType, this.bottomType);
-
- void changeVariance() {
- isLeastClosure = !isLeastClosure;
- }
+ _TypeSchemaEliminationVisitor(this.topType, this.bottomType);
@override
- DartType defaultDartType(DartType node) {
+ DartType defaultDartType(DartType node, int variance) {
+ bool isLeastClosure = variance == Variance.covariant;
if (node is UnknownType) {
return isLeastClosure ? bottomType : topType;
}
@@ -84,9 +78,9 @@
assert(bottomType == const NeverType(Nullability.nonNullable) ||
bottomType is NullType);
_TypeSchemaEliminationVisitor visitor =
- new _TypeSchemaEliminationVisitor(isLeastClosure, topType, bottomType);
- DartType result = schema.accept(visitor);
- assert(visitor.isLeastClosure == isLeastClosure);
+ new _TypeSchemaEliminationVisitor(topType, bottomType);
+ DartType result = schema.accept1(
+ visitor, isLeastClosure ? Variance.covariant : Variance.contravariant);
return result ?? schema;
}
}
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 9b60eea..f92c75c 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -878,6 +878,7 @@
discover
discovered
discovery
+discrepancy
disk
dispatch
dispatches
@@ -1604,6 +1605,7 @@
inversion
invert
inverted
+inverter
investigate
invisible
invocation
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index 3862cf5..dcbb5d9 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -4,6 +4,8 @@
// @dart = 2.9
+import 'package:kernel/src/replacement_visitor.dart';
+
import '../ast.dart'
show
BottomType,
@@ -501,195 +503,172 @@
DartType convertSuperBoundedToRegularBounded(
Library clientLibrary, TypeEnvironment typeEnvironment, DartType type,
{int variance = Variance.covariant}) {
- bool flipTop;
- bool flipBottom;
- DartType topType;
- DartType bottomType;
- bool isTop;
- bool isBottom;
- if (clientLibrary.isNonNullableByDefault) {
- flipTop = variance != Variance.contravariant;
- flipBottom = variance == Variance.contravariant;
- topType = typeEnvironment.coreTypes.objectNullableRawType;
- bottomType = const NeverType(Nullability.nonNullable);
- isTop = typeEnvironment.coreTypes.isTop(type);
- isBottom = typeEnvironment.coreTypes.isBottom(type);
- } else {
- flipTop = variance == Variance.covariant;
- flipBottom = variance != Variance.covariant;
- topType = const DynamicType();
- bottomType = const NullType();
- isTop = type is DynamicType ||
- type is VoidType ||
- type is InterfaceType &&
- type.classNode == typeEnvironment.coreTypes.objectClass;
- isBottom = type is NullType || type is BottomType;
+ return type.accept1(
+ new _SuperBoundedTypeInverter(typeEnvironment,
+ isNonNullableByDefault: clientLibrary.isNonNullableByDefault),
+ variance);
+}
+
+class _SuperBoundedTypeInverter extends ReplacementVisitor {
+ final TypeEnvironment typeEnvironment;
+ final bool isNonNullableByDefault;
+
+ _SuperBoundedTypeInverter(this.typeEnvironment, {this.isNonNullableByDefault})
+ : assert(typeEnvironment != null),
+ assert(isNonNullableByDefault != null);
+
+ bool flipTop(int variance) {
+ return isNonNullableByDefault
+ ? variance != Variance.contravariant
+ : variance == Variance.covariant;
}
- if (isTop && flipTop) {
- return bottomType;
- } else if (isBottom && flipBottom) {
- return topType;
- } else if (type is InterfaceType &&
- type.classNode.typeParameters.isNotEmpty) {
- assert(type.classNode.typeParameters.length == type.typeArguments.length);
+ bool flipBottom(int variance) {
+ return isNonNullableByDefault
+ ? variance == Variance.contravariant
+ : variance != Variance.covariant;
+ }
- List<DartType> convertedTypeArguments = null;
- for (int i = 0; i < type.typeArguments.length; ++i) {
- DartType convertedTypeArgument = convertSuperBoundedToRegularBounded(
- clientLibrary, typeEnvironment, type.typeArguments[i],
- variance: variance);
- if (convertedTypeArgument != null) {
- convertedTypeArguments ??= new List<DartType>.of(type.typeArguments);
- convertedTypeArguments[i] = convertedTypeArgument;
- }
+ DartType get topType {
+ return isNonNullableByDefault
+ ? typeEnvironment.coreTypes.objectNullableRawType
+ : const DynamicType();
+ }
+
+ DartType get bottomType {
+ return isNonNullableByDefault
+ ? const NeverType(Nullability.nonNullable)
+ : const NullType();
+ }
+
+ bool isTop(DartType node) {
+ if (isNonNullableByDefault) {
+ return typeEnvironment.coreTypes.isTop(node);
+ } else {
+ return node is DynamicType ||
+ node is VoidType ||
+ node is InterfaceType &&
+ node.classNode == typeEnvironment.coreTypes.objectClass;
}
- if (convertedTypeArguments == null) return null;
- return new InterfaceType(
- type.classNode, type.nullability, convertedTypeArguments);
- } else if (type is TypedefType &&
- type.typedefNode.typeParameters.isNotEmpty) {
- assert(type.typedefNode.typeParameters.length == type.typeArguments.length);
+ }
- List<DartType> convertedTypeArguments = null;
- for (int i = 0; i < type.typeArguments.length; i++) {
+ bool isBottom(DartType node) {
+ if (isNonNullableByDefault) {
+ return typeEnvironment.coreTypes.isBottom(node);
+ } else {
+ return node is NullType || node is BottomType;
+ }
+ }
+
+ @override
+ DartType visitDynamicType(DynamicType node, int variance) {
+ // dynamic is always a top type.
+ assert(isTop(node));
+ if (flipTop(variance)) {
+ return bottomType;
+ } else {
+ return null;
+ }
+ }
+
+ @override
+ DartType visitVoidType(VoidType node, int variance) {
+ // void is always a top type.
+ assert(isTop(node));
+ if (flipTop(variance)) {
+ return bottomType;
+ } else {
+ return null;
+ }
+ }
+
+ @override
+ DartType visitInterfaceType(InterfaceType node, int variance) {
+ // Check for Object-based top types.
+ if (isTop(node) && flipTop(variance)) {
+ return bottomType;
+ } else {
+ return super.visitInterfaceType(node, variance);
+ }
+ }
+
+ @override
+ DartType visitFutureOrType(FutureOrType node, int variance) {
+ // Check FutureOr-based top types.
+ if (isTop(node) && flipTop(variance)) {
+ return bottomType;
+ } else {
+ return super.visitFutureOrType(node, variance);
+ }
+ }
+
+ @override
+ DartType visitNullType(NullType node, int variance) {
+ // Null isn't a bottom type in NNBD.
+ if (isBottom(node) && flipBottom(variance)) {
+ return topType;
+ } else {
+ return null;
+ }
+ }
+
+ @override
+ DartType visitNeverType(NeverType node, int variance) {
+ // Depending on the variance, Never may not be a bottom type.
+ if (isBottom(node) && flipBottom(variance)) {
+ return topType;
+ } else {
+ return null;
+ }
+ }
+
+ @override
+ DartType visitTypeParameterType(TypeParameterType node, int variance) {
+ // Types such as X extends Never are bottom types.
+ if (isBottom(node) && flipBottom(variance)) {
+ return topType;
+ } else {
+ return null;
+ }
+ }
+
+ @override
+ DartType visitBottomType(BottomType node, int variance) {
+ // Bottom is always a bottom type.
+ assert(isBottom(node));
+ if (flipBottom(variance)) {
+ return topType;
+ } else {
+ return null;
+ }
+ }
+
+ // TypedefTypes receive special treatment because the variance of their
+ // arguments' positions depend on the opt-in status of the library.
+ // TODO(dmitryas): Remove the method when the discrepancy between the NNBD
+ // modes is resolved.
+ @override
+ DartType visitTypedefType(TypedefType node, int variance) {
+ Nullability newNullability = visitNullability(node);
+ List<DartType> newTypeArguments = null;
+ for (int i = 0; i < node.typeArguments.length; i++) {
// The implementation of instantiate-to-bound in legacy mode ignored the
// variance of type parameters of the typedef. This behavior is preserved
// here in passing the 'variance' parameter unchanged in for legacy
// libraries.
- DartType convertedTypeArgument = convertSuperBoundedToRegularBounded(
- clientLibrary, typeEnvironment, type.typeArguments[i],
- variance: clientLibrary.isNonNullableByDefault
+ DartType newTypeArgument = node.typeArguments[i].accept1(
+ this,
+ isNonNullableByDefault
? Variance.combine(
- variance, type.typedefNode.typeParameters[i].variance)
+ variance, node.typedefNode.typeParameters[i].variance)
: variance);
- if (convertedTypeArgument != null) {
- convertedTypeArguments ??= new List<DartType>.of(type.typeArguments);
- convertedTypeArguments[i] = convertedTypeArgument;
+ if (newTypeArgument != null) {
+ newTypeArguments ??= new List<DartType>.of(node.typeArguments);
+ newTypeArguments[i] = newTypeArgument;
}
}
- if (convertedTypeArguments == null) return null;
- return new TypedefType(
- type.typedefNode, type.nullability, convertedTypeArguments);
- } else if (type is FunctionType) {
- if (clientLibrary.isNonNullableByDefault && type.typedefType != null) {
- return convertSuperBoundedToRegularBounded(
- clientLibrary, typeEnvironment, type.typedefType,
- variance: variance);
- }
-
- DartType convertedReturnType = convertSuperBoundedToRegularBounded(
- clientLibrary, typeEnvironment, type.returnType,
- variance: variance);
-
- List<DartType> convertedPositionalParameters = null;
- for (int i = 0; i < type.positionalParameters.length; i++) {
- DartType convertedPositionalParameter =
- convertSuperBoundedToRegularBounded(
- clientLibrary, typeEnvironment, type.positionalParameters[i],
- variance: Variance.combine(variance, Variance.contravariant));
- if (convertedPositionalParameter != null) {
- convertedPositionalParameters ??=
- new List<DartType>.of(type.positionalParameters);
- convertedPositionalParameters[i] = convertedPositionalParameter;
- }
- }
-
- List<NamedType> convertedNamedParameters = null;
- for (int i = 0; i < type.namedParameters.length; i++) {
- NamedType convertedNamedParameter = new NamedType(
- type.namedParameters[i].name,
- convertSuperBoundedToRegularBounded(
- clientLibrary, typeEnvironment, type.namedParameters[i].type,
- variance: Variance.combine(variance, Variance.contravariant)),
- isRequired: type.namedParameters[i].isRequired);
- if (convertedNamedParameter != null) {
- convertedNamedParameters ??=
- new List<NamedType>.of(type.namedParameters);
- convertedNamedParameters[i] = convertedNamedParameter;
- }
- }
-
- List<TypeParameter> convertedTypeParameters = null;
- if (clientLibrary.isNonNullableByDefault &&
- type.typeParameters.isNotEmpty) {
- for (int i = 0; i < type.typeParameters.length; ++i) {
- DartType convertedBound = convertSuperBoundedToRegularBounded(
- clientLibrary, typeEnvironment, type.typeParameters[i].bound,
- variance: Variance.combine(variance, Variance.invariant));
- if (convertedBound != null) {
- if (convertedTypeParameters == null) {
- convertedTypeParameters = <TypeParameter>[];
- for (TypeParameter parameter in type.typeParameters) {
- convertedTypeParameters.add(new TypeParameter(parameter.name));
- }
- }
- convertedTypeParameters[i].bound = convertedBound;
- }
- }
-
- Map<TypeParameter, DartType> substitutionMap =
- <TypeParameter, DartType>{};
- for (int i = 0; i < type.typeParameters.length; ++i) {
- substitutionMap[type.typeParameters[i]] =
- new TypeParameterType.forAlphaRenaming(
- type.typeParameters[i], convertedTypeParameters[i]);
- }
- for (TypeParameter parameter in convertedTypeParameters) {
- parameter.bound = substitute(parameter.bound, substitutionMap);
- }
- List<DartType> defaultTypes = calculateBounds(convertedTypeParameters,
- typeEnvironment.coreTypes.objectClass, clientLibrary);
- for (int i = 0; i < convertedTypeParameters.length; ++i) {
- convertedTypeParameters[i].defaultType = defaultTypes[i];
- }
-
- if (convertedReturnType != null) {
- convertedReturnType = substitute(convertedReturnType, substitutionMap);
- }
- if (convertedPositionalParameters != null) {
- for (int i = 0; i < convertedPositionalParameters.length; ++i) {
- convertedPositionalParameters[i] =
- substitute(convertedPositionalParameters[i], substitutionMap);
- }
- }
- if (convertedNamedParameters != null) {
- for (int i = 0; i < convertedNamedParameters.length; ++i) {
- convertedNamedParameters[i] = new NamedType(
- convertedNamedParameters[i].name,
- substitute(convertedNamedParameters[i].type, substitutionMap),
- isRequired: convertedNamedParameters[i].isRequired);
- }
- }
- }
-
- if (convertedReturnType == null &&
- convertedPositionalParameters == null &&
- convertedNamedParameters == null &&
- convertedTypeParameters == null) {
- return null;
- }
-
- convertedReturnType ??= type.returnType;
- convertedPositionalParameters ??= type.positionalParameters;
- convertedNamedParameters ??= type.namedParameters;
- convertedTypeParameters ??= type.typeParameters;
-
- return new FunctionType(
- convertedPositionalParameters, convertedReturnType, type.nullability,
- namedParameters: convertedNamedParameters,
- typeParameters: type.typeParameters,
- requiredParameterCount: type.requiredParameterCount,
- typedefType: type.typedefType);
- } else if (type is FutureOrType) {
- DartType convertedTypeArgument = convertSuperBoundedToRegularBounded(
- clientLibrary, typeEnvironment, type.typeArgument,
- variance: variance);
- if (convertedTypeArgument == null) return null;
- return new FutureOrType(convertedTypeArgument, type.declaredNullability);
+ return createTypedef(node, newNullability, newTypeArguments);
}
-
- return null;
}
int computeVariance(TypeParameter typeParameter, DartType type,
diff --git a/pkg/kernel/lib/src/legacy_erasure.dart b/pkg/kernel/lib/src/legacy_erasure.dart
index 3a386bd..7a36398 100644
--- a/pkg/kernel/lib/src/legacy_erasure.dart
+++ b/pkg/kernel/lib/src/legacy_erasure.dart
@@ -21,7 +21,7 @@
///
/// Returns `null` if the type wasn't changed.
DartType rawLegacyErasure(DartType type) {
- return type.accept(const _LegacyErasure());
+ return type.accept1(const _LegacyErasure(), Variance.covariant);
}
/// Returns legacy erasure of [supertype], that is, the type in which all nnbd
@@ -34,7 +34,8 @@
List<DartType> newTypeArguments;
for (int i = 0; i < supertype.typeArguments.length; i++) {
DartType typeArgument = supertype.typeArguments[i];
- DartType newTypeArgument = typeArgument.accept(const _LegacyErasure());
+ DartType newTypeArgument =
+ typeArgument.accept1(const _LegacyErasure(), Variance.covariant);
if (newTypeArgument != null) {
newTypeArguments ??= supertype.typeArguments.toList(growable: false);
newTypeArguments[i] = newTypeArgument;
@@ -69,7 +70,7 @@
}
@override
- DartType visitNeverType(NeverType node) => const NullType();
+ DartType visitNeverType(NeverType node, int variance) => const NullType();
}
/// Returns `true` if a member declared in [declaringClass] inherited or
diff --git a/pkg/kernel/lib/src/norm.dart b/pkg/kernel/lib/src/norm.dart
index 1b92f42..aa49ef7 100644
--- a/pkg/kernel/lib/src/norm.dart
+++ b/pkg/kernel/lib/src/norm.dart
@@ -12,7 +12,7 @@
/// Returns normalization of [type].
DartType norm(CoreTypes coreTypes, DartType type) {
- return type.accept(new _Norm(coreTypes)) ?? type;
+ return type.accept1(new _Norm(coreTypes), Variance.covariant) ?? type;
}
/// Returns normalization of [supertype].
@@ -21,7 +21,8 @@
_Norm normVisitor = new _Norm(coreTypes);
List<DartType> typeArguments = null;
for (int i = 0; i < supertype.typeArguments.length; ++i) {
- DartType typeArgument = supertype.typeArguments[i].accept(normVisitor);
+ DartType typeArgument =
+ supertype.typeArguments[i].accept1(normVisitor, Variance.covariant);
if (typeArgument != null) {
typeArguments ??= supertype.typeArguments.toList();
typeArguments[i] = typeArgument;
@@ -42,16 +43,16 @@
_Norm(this.coreTypes);
@override
- DartType visitInterfaceType(InterfaceType node) {
+ DartType visitInterfaceType(InterfaceType node, int variance) {
return super
- .visitInterfaceType(node)
+ .visitInterfaceType(node, variance)
?.withDeclaredNullability(node.nullability);
}
@override
- DartType visitFutureOrType(FutureOrType node) {
+ DartType visitFutureOrType(FutureOrType node, int variance) {
DartType typeArgument = node.typeArgument;
- typeArgument = typeArgument.accept(this) ?? typeArgument;
+ typeArgument = typeArgument.accept1(this, variance) ?? typeArgument;
if (coreTypes.isTop(typeArgument)) {
assert(typeArgument.nullability == Nullability.nullable ||
typeArgument.nullability == Nullability.legacy);
@@ -90,20 +91,20 @@
}
@override
- DartType visitTypeParameterType(TypeParameterType node) {
+ DartType visitTypeParameterType(TypeParameterType node, int variance) {
if (node.promotedBound == null) {
DartType bound = node.parameter.bound;
if (normalizesToNever(bound)) {
DartType result = new NeverType(Nullability.nonNullable)
.withDeclaredNullability(node.nullability);
- return result.accept(this) ?? result;
+ return result.accept1(this, variance) ?? result;
}
assert(!coreTypes.isBottom(bound));
// If the bound isn't Never, the type is already normalized.
return null;
} else {
DartType bound = node.promotedBound;
- bound = bound.accept(this) ?? bound;
+ bound = bound.accept1(this, variance) ?? bound;
if (bound is NeverType && bound.nullability == Nullability.nonNullable) {
return bound;
} else if (coreTypes.isTop(bound)) {
@@ -133,7 +134,7 @@
}
@override
- DartType visitNeverType(NeverType node) {
+ DartType visitNeverType(NeverType node, int variance) {
if (node.nullability == Nullability.nullable) return const NullType();
return null;
}
diff --git a/pkg/kernel/lib/src/replacement_visitor.dart b/pkg/kernel/lib/src/replacement_visitor.dart
index e260919..b7cbd3b 100644
--- a/pkg/kernel/lib/src/replacement_visitor.dart
+++ b/pkg/kernel/lib/src/replacement_visitor.dart
@@ -9,15 +9,13 @@
/// Helper visitor that clones a type if a nested type is replaced, and
/// otherwise returns `null`.
-class ReplacementVisitor implements DartTypeVisitor<DartType> {
+class ReplacementVisitor implements DartTypeVisitor1<DartType, int> {
const ReplacementVisitor();
- void changeVariance() {}
-
Nullability visitNullability(DartType node) => null;
@override
- DartType visitFunctionType(FunctionType node) {
+ DartType visitFunctionType(FunctionType node, int variance) {
Nullability newNullability = visitNullability(node);
List<TypeParameter> newTypeParameters;
@@ -27,8 +25,10 @@
// cyclic typedefs. Currently
// instantiate_to_bound/non_simple_class_parametrized_typedef_cycle
// fails with this.
- DartType newBound = typeParameter.bound?.accept(this);
- DartType newDefaultType = typeParameter.defaultType?.accept(this);
+ DartType newBound = typeParameter.bound
+ ?.accept1(this, Variance.combine(variance, Variance.invariant));
+ DartType newDefaultType = typeParameter.defaultType
+ ?.accept1(this, Variance.combine(variance, Variance.invariant));
if (newBound != null || newDefaultType != null) {
newTypeParameters ??= node.typeParameters.toList(growable: false);
newTypeParameters[i] = new TypeParameter(
@@ -54,20 +54,20 @@
}
}
- DartType visitType(DartType type) {
+ DartType visitType(DartType type, int variance) {
if (type == null) return null;
- DartType result = type.accept(this);
+ DartType result = type.accept1(this, variance);
if (substitution != null) {
result = substitution.substituteType(result ?? type);
}
return result;
}
- DartType newReturnType = visitType(node.returnType);
- changeVariance();
+ DartType newReturnType = visitType(node.returnType, variance);
List<DartType> newPositionalParameters = null;
for (int i = 0; i < node.positionalParameters.length; i++) {
- DartType newType = visitType(node.positionalParameters[i]);
+ DartType newType = visitType(node.positionalParameters[i],
+ Variance.combine(variance, Variance.contravariant));
if (newType != null) {
newPositionalParameters ??=
node.positionalParameters.toList(growable: false);
@@ -76,7 +76,8 @@
}
List<NamedType> newNamedParameters = null;
for (int i = 0; i < node.namedParameters.length; i++) {
- DartType newType = visitType(node.namedParameters[i].type);
+ DartType newType = visitType(node.namedParameters[i].type,
+ Variance.combine(variance, Variance.contravariant));
NamedType newNamedType =
createNamedType(node.namedParameters[i], newType);
if (newNamedType != null) {
@@ -84,8 +85,7 @@
newNamedParameters[i] = newNamedType;
}
}
- changeVariance();
- DartType newTypedefType = visitType(node.typedefType);
+ DartType newTypedefType = visitType(node.typedefType, variance);
return createFunctionType(
node,
@@ -133,11 +133,11 @@
}
@override
- DartType visitInterfaceType(InterfaceType node) {
+ DartType visitInterfaceType(InterfaceType node, int variance) {
Nullability newNullability = visitNullability(node);
List<DartType> newTypeArguments = null;
for (int i = 0; i < node.typeArguments.length; i++) {
- DartType substitution = node.typeArguments[i].accept(this);
+ DartType substitution = node.typeArguments[i].accept1(this, variance);
if (substitution != null) {
newTypeArguments ??= node.typeArguments.toList(growable: false);
newTypeArguments[i] = substitution;
@@ -160,9 +160,9 @@
}
@override
- DartType visitFutureOrType(FutureOrType node) {
+ DartType visitFutureOrType(FutureOrType node, int variance) {
Nullability newNullability = visitNullability(node);
- DartType newTypeArgument = node.typeArgument.accept(this);
+ DartType newTypeArgument = node.typeArgument.accept1(this, variance);
return createFutureOrType(node, newNullability, newTypeArgument);
}
@@ -178,10 +178,10 @@
}
@override
- DartType visitDynamicType(DynamicType node) => null;
+ DartType visitDynamicType(DynamicType node, int variance) => null;
@override
- DartType visitNeverType(NeverType node) {
+ DartType visitNeverType(NeverType node, int variance) {
Nullability newNullability = visitNullability(node);
return createNeverType(node, newNullability);
}
@@ -196,22 +196,22 @@
}
@override
- DartType visitNullType(NullType node) => null;
+ DartType visitNullType(NullType node, int variance) => null;
@override
- DartType visitInvalidType(InvalidType node) => null;
+ DartType visitInvalidType(InvalidType node, int variance) => null;
@override
- DartType visitBottomType(BottomType node) => null;
+ DartType visitBottomType(BottomType node, int variance) => null;
@override
- DartType visitVoidType(VoidType node) => null;
+ DartType visitVoidType(VoidType node, int variance) => null;
@override
- DartType visitTypeParameterType(TypeParameterType node) {
+ DartType visitTypeParameterType(TypeParameterType node, int variance) {
Nullability newNullability = visitNullability(node);
if (node.promotedBound != null) {
- DartType newPromotedBound = node.promotedBound.accept(this);
+ DartType newPromotedBound = node.promotedBound.accept1(this, variance);
return createPromotedTypeParameterType(
node, newNullability, newPromotedBound);
}
@@ -242,11 +242,14 @@
}
@override
- DartType visitTypedefType(TypedefType node) {
+ DartType visitTypedefType(TypedefType node, int variance) {
Nullability newNullability = visitNullability(node);
List<DartType> newTypeArguments = null;
for (int i = 0; i < node.typeArguments.length; i++) {
- DartType substitution = node.typeArguments[i].accept(this);
+ DartType substitution = node.typeArguments[i].accept1(
+ this,
+ Variance.combine(
+ variance, node.typedefNode.typeParameters[i].variance));
if (substitution != null) {
newTypeArguments ??= node.typeArguments.toList(growable: false);
newTypeArguments[i] = substitution;
@@ -269,5 +272,5 @@
}
@override
- DartType defaultDartType(DartType node) => null;
+ DartType defaultDartType(DartType node, int variance) => null;
}
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index 03707fb..96d0aef 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -1001,7 +1001,6 @@
final DartType topFunctionType;
final Set<TypeParameter> eliminationTargets;
bool isLeastClosure;
- bool isCovariant = true;
bool Function(DartType type, bool Function(DartType type) recursor)
unhandledTypeHandler; // Can be null.
@@ -1018,37 +1017,32 @@
/// Returns a subtype of [type] for all values of [eliminationTargets].
DartType eliminateToLeast(DartType type) {
- isCovariant = true;
isLeastClosure = true;
- return type.accept(this) ?? type;
+ return type.accept1(this, Variance.covariant) ?? type;
}
/// Returns a supertype of [type] for all values of [eliminationTargets].
DartType eliminateToGreatest(DartType type) {
- isCovariant = true;
isLeastClosure = false;
- return type.accept(this) ?? type;
+ return type.accept1(this, Variance.covariant) ?? type;
}
- DartType get typeParameterReplacement {
+ DartType getTypeParameterReplacement(int variance) {
+ bool isCovariant = variance == Variance.covariant;
return isLeastClosure && isCovariant || (!isLeastClosure && !isCovariant)
? bottomType
: topType;
}
- DartType get functionReplacement {
+ DartType getFunctionReplacement(int variance) {
+ bool isCovariant = variance == Variance.covariant;
return isLeastClosure && isCovariant || (!isLeastClosure && !isCovariant)
? bottomType
: topFunctionType;
}
@override
- void changeVariance() {
- isCovariant = !isCovariant;
- }
-
- @override
- DartType visitFunctionType(FunctionType node) {
+ DartType visitFunctionType(FunctionType node, int variance) {
// - if `S` is
// `T Function<X0 extends B0, ...., Xk extends Bk>(T0 x0, ...., Tn xn,
// [Tn+1 xn+1, ..., Tm xm])`
@@ -1061,19 +1055,19 @@
for (TypeParameter typeParameter in node.typeParameters) {
if (containsTypeVariable(typeParameter.bound, eliminationTargets,
unhandledTypeHandler: unhandledTypeHandler)) {
- return functionReplacement;
+ return getFunctionReplacement(variance);
}
}
}
- return super.visitFunctionType(node);
+ return super.visitFunctionType(node, variance);
}
@override
- DartType visitTypeParameterType(TypeParameterType node) {
+ DartType visitTypeParameterType(TypeParameterType node, int variance) {
if (eliminationTargets.contains(node.parameter)) {
- return typeParameterReplacement;
+ return getTypeParameterReplacement(variance);
}
- return super.visitTypeParameterType(node);
+ return super.visitTypeParameterType(node, variance);
}
}
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 103983e..a90d4de 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -266,8 +266,8 @@
return unit.IssueLoad();
}
-DEFINE_NATIVE_ENTRY(Internal_inquireIs64Bit, 0, 0) {
-#if defined(ARCH_IS_64_BIT)
+DEFINE_NATIVE_ENTRY(Internal_has63BitSmis, 0, 0) {
+#if defined(ARCH_IS_64_BIT) && !defined(DART_COMPRESSED_POINTERS)
return Bool::True().ptr();
#else
return Bool::False().ptr();
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 6750bf9..000452a 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -337,7 +337,7 @@
V(Internal_collectAllGarbage, 0) \
V(Internal_makeListFixedLength, 1) \
V(Internal_makeFixedListUnmodifiable, 1) \
- V(Internal_inquireIs64Bit, 0) \
+ V(Internal_has63BitSmis, 0) \
V(Internal_extractTypeArguments, 2) \
V(Internal_prependTypeArguments, 4) \
V(Internal_boundsCheckForPartialInstantiation, 2) \
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm64.cc b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
index 80d2290..8b3fbd2 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
@@ -1356,7 +1356,7 @@
__ fcmpd(V0, V0);
__ b(normal_ir_body, VS);
- __ fcvtzds(R0, V0);
+ __ fcvtzdsx(R0, V0);
// Overflow is signaled with minint.
// Check for overflow and that it fits into Smi.
__ CompareImmediate(R0, 0xC000000000000000);
@@ -1380,7 +1380,7 @@
// Convert double value to signed 64-bit int in R0 and back to a
// double value in V1.
- __ fcvtzds(R0, V0);
+ __ fcvtzdsx(R0, V0);
__ scvtfdx(V1, R0);
// Tag the int as a Smi, making sure that it fits; this checks for
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index 86a8b3d..dec46f3 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -1213,12 +1213,18 @@
const Register crn = ConcreteRegister(rn);
EmitFPIntCvtOp(SCVTFD, static_cast<Register>(vd), crn, kFourBytes);
}
- void fcvtzds(Register rd, VRegister vn) {
+ void fcvtzdsx(Register rd, VRegister vn) {
ASSERT(rd != R31);
ASSERT(rd != CSP);
const Register crd = ConcreteRegister(rd);
EmitFPIntCvtOp(FCVTZDS, crd, static_cast<Register>(vn));
}
+ void fcvtzdsw(Register rd, VRegister vn) {
+ ASSERT(rd != R31);
+ ASSERT(rd != CSP);
+ const Register crd = ConcreteRegister(rd);
+ EmitFPIntCvtOp(FCVTZDS, crd, static_cast<Register>(vn), kFourBytes);
+ }
void fmovdd(VRegister vd, VRegister vn) { EmitFPOneSourceOp(FMOVDD, vd, vn); }
void fabsd(VRegister vd, VRegister vn) { EmitFPOneSourceOp(FABSD, vd, vn); }
void fnegd(VRegister vd, VRegister vn) { EmitFPOneSourceOp(FNEGD, vd, vn); }
diff --git a/runtime/vm/compiler/assembler/assembler_arm64_test.cc b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
index c6d8847..29ed087 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
@@ -3089,17 +3089,73 @@
EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(DoubleReturn, test->entry()));
}
-ASSEMBLER_TEST_GENERATE(Fcvtzds, assembler) {
+ASSEMBLER_TEST_GENERATE(Fcvtzdsx, assembler) {
__ LoadDImmediate(V0, 42.0);
- __ fcvtzds(R0, V0);
+ __ fcvtzdsx(R0, V0);
__ ret();
}
-ASSEMBLER_TEST_RUN(Fcvtzds, test) {
+ASSEMBLER_TEST_RUN(Fcvtzdsx, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
+ASSEMBLER_TEST_GENERATE(Fcvtzdsw, assembler) {
+ __ LoadDImmediate(V0, 42.0);
+ __ fcvtzdsw(R0, V0);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsw, test) {
+ typedef int64_t (*Int64Return)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
+ASSEMBLER_TEST_GENERATE(Fcvtzdsx_overflow, assembler) {
+ __ LoadDImmediate(V0, 1e20);
+ __ fcvtzdsx(R0, V0);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsx_overflow, test) {
+ typedef int64_t (*Int64Return)() DART_UNUSED;
+ EXPECT_EQ(kMaxInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
+ASSEMBLER_TEST_GENERATE(Fcvtzdsx_overflow_negative, assembler) {
+ __ LoadDImmediate(V0, -1e20);
+ __ fcvtzdsx(R0, V0);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsx_overflow_negative, test) {
+ typedef int64_t (*Int64Return)() DART_UNUSED;
+ EXPECT_EQ(kMinInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
+ASSEMBLER_TEST_GENERATE(Fcvtzdsw_overflow, assembler) {
+ __ LoadDImmediate(V0, 1e10);
+ __ fcvtzdsw(R0, V0);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsw_overflow, test) {
+ typedef int64_t (*Int64Return)() DART_UNUSED;
+ EXPECT_EQ(kMaxInt32, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
+ASSEMBLER_TEST_GENERATE(Fcvtzdsw_overflow_negative, assembler) {
+ __ LoadDImmediate(V0, -1e10);
+ __ fcvtzdsw(R0, V0);
+ __ sxtw(R0, R0);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsw_overflow_negative, test) {
+ typedef int64_t (*Int64Return)() DART_UNUSED;
+ EXPECT_EQ(kMinInt32, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
ASSEMBLER_TEST_GENERATE(Scvtfdx, assembler) {
__ LoadImmediate(R0, 42);
__ scvtfdx(V0, R0);
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 26ea233..0d89c3f 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -5140,7 +5140,7 @@
__ fcmpd(VTMP, VTMP);
__ b(&do_call, VS);
- __ fcvtzds(result, VTMP);
+ __ fcvtzdsx(result, VTMP);
// Overflow is signaled with minint.
// Check for overflow and that it fits into Smi.
@@ -5188,7 +5188,7 @@
__ fcmpd(value, value);
__ b(deopt, VS);
- __ fcvtzds(result, value);
+ __ fcvtzdsx(result, value);
// Check for overflow and that it fits into Smi.
__ CompareImmediate(result, 0xC000000000000000);
__ b(deopt, MI);
diff --git a/runtime/vm/instructions_arm64.cc b/runtime/vm/instructions_arm64.cc
index 210fca3..e7a0d24 100644
--- a/runtime/vm/instructions_arm64.cc
+++ b/runtime/vm/instructions_arm64.cc
@@ -20,8 +20,8 @@
: object_pool_(ObjectPool::Handle(code.GetObjectPool())),
target_code_pool_index_(-1) {
ASSERT(code.ContainsInstructionAt(pc));
- // Last instruction: blr ip0.
- ASSERT(*(reinterpret_cast<uint32_t*>(pc) - 1) == 0xd63f0200);
+ // Last instruction: blr lr.
+ ASSERT(*(reinterpret_cast<uint32_t*>(pc) - 1) == 0xd63f03c0);
Register reg;
InstructionPattern::DecodeLoadWordFromPool(pc - 2 * Instr::kInstrSize, ®,
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index 1c78f20..e5eb2d0 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -3360,13 +3360,21 @@
set_vregisterd(vd, 1, 0);
} else if (instr->Bits(16, 5) == 24) {
// Format(instr, "fcvtzds'sf 'rd, 'vn");
+ const intptr_t max = instr->Bit(31) == 1 ? INT64_MAX : INT32_MAX;
+ const intptr_t min = instr->Bit(31) == 1 ? INT64_MIN : INT32_MIN;
const double vn_val = bit_cast<double, int64_t>(get_vregisterd(vn, 0));
- if (vn_val >= static_cast<double>(INT64_MAX)) {
- set_register(instr, rd, INT64_MAX, instr->RdMode());
- } else if (vn_val <= static_cast<double>(INT64_MIN)) {
- set_register(instr, rd, INT64_MIN, instr->RdMode());
+ int64_t result;
+ if (vn_val >= static_cast<double>(max)) {
+ result = max;
+ } else if (vn_val <= static_cast<double>(min)) {
+ result = min;
} else {
- set_register(instr, rd, static_cast<int64_t>(vn_val), instr->RdMode());
+ result = static_cast<int64_t>(vn_val);
+ }
+ if (instr->Bit(31) == 1) {
+ set_register(instr, rd, result, instr->RdMode());
+ } else {
+ set_register(instr, rd, result & 0xffffffffll, instr->RdMode());
}
} else {
UnimplementedInstruction(instr);
diff --git a/sdk/lib/_internal/vm/lib/compact_hash.dart b/sdk/lib/_internal/vm/lib/compact_hash.dart
index 39c353f..b491dd6 100644
--- a/sdk/lib/_internal/vm/lib/compact_hash.dart
+++ b/sdk/lib/_internal/vm/lib/compact_hash.dart
@@ -109,7 +109,7 @@
// as unsigned words.
static int _indexSizeToHashMask(int indexSize) {
int indexBits = indexSize.bitLength - 2;
- return internal.is64Bit
+ return internal.has63BitSmis
? (1 << (32 - indexBits)) - 1
: (1 << (30 - indexBits)) - 1;
}
diff --git a/sdk/lib/_internal/vm/lib/core_patch.dart b/sdk/lib/_internal/vm/lib/core_patch.dart
index 34b26f3..6ffdce8 100644
--- a/sdk/lib/_internal/vm/lib/core_patch.dart
+++ b/sdk/lib/_internal/vm/lib/core_patch.dart
@@ -24,7 +24,7 @@
POWERS_OF_TEN,
SubListIterable,
UnmodifiableListBase,
- is64Bit,
+ has63BitSmis,
makeFixedListUnmodifiable,
makeListFixedLength,
patch,
diff --git a/sdk/lib/_internal/vm/lib/integers_patch.dart b/sdk/lib/_internal/vm/lib/integers_patch.dart
index 4831353..fa9cf80 100644
--- a/sdk/lib/_internal/vm/lib/integers_patch.dart
+++ b/sdk/lib/_internal/vm/lib/integers_patch.dart
@@ -31,7 +31,7 @@
return null; // Empty.
}
}
- var smiLimit = is64Bit ? 18 : 9;
+ var smiLimit = has63BitSmis ? 18 : 9;
if ((last - ix) >= smiLimit) {
return null; // May not fit into a Smi.
}
@@ -133,7 +133,7 @@
static int _parseRadix(String source, int radix, int start, int end, int sign,
bool allowU64, onError) {
- int tableIndex = (radix - 2) * 4 + (is64Bit ? 2 : 0);
+ int tableIndex = (radix - 2) * 4 + (has63BitSmis ? 2 : 0);
int blockSize = _PARSE_LIMITS[tableIndex];
int length = end - start;
if (length <= blockSize) {
@@ -180,7 +180,7 @@
// Although the unsigned overflow limits do not depend on the
// platform, the multiplier and block size, which are used to
// compute it, do.
- int X = is64Bit ? 1 : 0;
+ int X = has63BitSmis ? 1 : 0;
if (allowU64 &&
!(result >= _int64UnsignedOverflowLimits[X] &&
(result > _int64UnsignedOverflowLimits[X] ||
diff --git a/sdk/lib/_internal/vm/lib/internal_patch.dart b/sdk/lib/_internal/vm/lib/internal_patch.dart
index f1d22c9..c434ec9 100644
--- a/sdk/lib/_internal/vm/lib/internal_patch.dart
+++ b/sdk/lib/_internal/vm/lib/internal_patch.dart
@@ -102,9 +102,9 @@
}
}
-final bool is64Bit = _inquireIs64Bit();
+final bool has63BitSmis = _has63BitSmis();
-bool _inquireIs64Bit() native "Internal_inquireIs64Bit";
+bool _has63BitSmis() native "Internal_has63BitSmis";
@pragma("vm:recognized", "other")
@pragma("vm:entry-point", "call")
diff --git a/tools/VERSION b/tools/VERSION
index dacee7e..b8d079b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 12
PATCH 0
-PRERELEASE 263
+PRERELEASE 264
PRERELEASE_PATCH 0
\ No newline at end of file