[dart2js] Fix as-check type registration.
We would expect failing as checks to throw in all modes (unless --omit-as-casts is provided). However, the new test program fails in production mode. This is because we are not registering the type usage of the function's type parameter. This leads us to drop the as check completely later on. We should be doing subtype checks with nullability if we want to consider an as test omitted. Golem patch results: https://golem.corp.goog/Comparison?repository=dart#targetA%3Ddart2js%3BmachineTypeA%3Dlinux-x64%3BrevisionA%3D107840%3BpatchA%3Dnatebiggs--dart2js--Fix-as-check-type-registration.-7%3BtargetB%3Ddart2js%3BmachineTypeB%3Dlinux-x64%3BrevisionB%3D107839%3BpatchB%3DNone Fixed: https://github.com/dart-lang/sdk/issues/54419 Change-Id: If93f78a939a690f05f5398c1a5ca971df1fc9243 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/343821 Reviewed-by: Mayank Patke <fishythefish@google.com> Reviewed-by: Stephen Adams <sra@google.com> Commit-Queue: Nate Biggs <natebiggs@google.com>
This commit is contained in:
@@ -222,8 +222,8 @@ class ImpactBuilder extends StaticTypeVisitor implements ImpactRegistry {
|
||||
void handleAsExpression(ir.AsExpression node, ir.DartType operandType,
|
||||
{bool? isCalculatedTypeSubtype}) {
|
||||
if (isCalculatedTypeSubtype ??
|
||||
typeEnvironment.isSubtypeOf(operandType, node.type,
|
||||
ir.SubtypeCheckMode.ignoringNullabilities)) {
|
||||
typeEnvironment.isSubtypeOf(
|
||||
operandType, node.type, ir.SubtypeCheckMode.withNullabilities)) {
|
||||
// Skip unneeded casts.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1320,7 +1320,7 @@ abstract class StaticTypeVisitor extends StaticTypeBase {
|
||||
// Check if the calculated operandType is a subtype of the type specified
|
||||
// in the `as` expression.
|
||||
final isCalculatedTypeSubtype = typeEnvironment.isSubtypeOf(
|
||||
operandType, node.type, ir.SubtypeCheckMode.ignoringNullabilities);
|
||||
operandType, node.type, ir.SubtypeCheckMode.withNullabilities);
|
||||
if (!isCalculatedTypeSubtype &&
|
||||
operand is ir.VariableGet &&
|
||||
!_invalidatedVariables.contains(operand.variable)) {
|
||||
|
||||
@@ -56,12 +56,10 @@ class Class1<T> {
|
||||
}
|
||||
|
||||
var local2 =
|
||||
/*prod.hasThis*/
|
||||
/*spec.fields=[S,this],free=[S,this],hasThis*/
|
||||
/*fields=[S,this],free=[S,this],hasThis*/
|
||||
(o) {
|
||||
return
|
||||
/*prod.hasThis*/
|
||||
/*spec.fields=[S,this],free=[S,this],hasThis*/
|
||||
/*fields=[S,this],free=[S,this],hasThis*/
|
||||
() => Map<T, S>();
|
||||
};
|
||||
return local2(local<double>());
|
||||
|
||||
@@ -9,8 +9,7 @@ class A<T> {
|
||||
/*member: A.method:hasThis*/
|
||||
@pragma('dart2js:noInline')
|
||||
method() {
|
||||
/*spec.fields=[this],free=[this],hasThis*/
|
||||
/*prod.hasThis*/
|
||||
/*fields=[this],free=[this],hasThis*/
|
||||
dynamic local() => <T>[];
|
||||
return local;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import 'package:expect/expect.dart';
|
||||
|
||||
@pragma('dart2js:noInline')
|
||||
method<T>() {
|
||||
/*spec.fields=[T],free=[T]*/
|
||||
/*fields=[T],free=[T]*/
|
||||
dynamic local() => <T>[];
|
||||
return local;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ class A<T> {
|
||||
/*member: A.method:hasThis*/
|
||||
@pragma('dart2js:noInline')
|
||||
method() {
|
||||
/*spec.fields=[this],free=[this],hasThis*/
|
||||
/*prod.hasThis*/
|
||||
/*fields=[this],free=[this],hasThis*/
|
||||
dynamic local() => <T, int>{};
|
||||
return local;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import 'package:expect/expect.dart';
|
||||
|
||||
@pragma('dart2js:noInline')
|
||||
method<T>() {
|
||||
/*spec.fields=[T],free=[T]*/
|
||||
/*fields=[T],free=[T]*/
|
||||
dynamic local() => <T, int>{};
|
||||
return local;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
return t1;
|
||||
}*/
|
||||
/*prod.member: test1:function() {
|
||||
var t1 = [];
|
||||
var t1 = A._setArrayType([], type$.JSArray_int);
|
||||
t1.push(1);
|
||||
return t1;
|
||||
}*/
|
||||
|
||||
@@ -18,12 +18,18 @@ foo() {
|
||||
main() {
|
||||
runTest() async {
|
||||
await compile(TEST_ONE, entry: 'foo', check: (String generated) {
|
||||
Expect.isTrue(generated.contains('print([1, 2]);'),
|
||||
"Code pattern 'print([1, 2]);' not found in\n$generated");
|
||||
Expect.isTrue(generated.contains('print([3]);'),
|
||||
"Code pattern 'print([3]);' not found in\n$generated");
|
||||
Expect.isTrue(generated.contains('print([4, 5]);'),
|
||||
"Code pattern 'print([4, 5]);' not found in\n$generated");
|
||||
Expect.isTrue(
|
||||
generated.contains('A.print(A._setArrayType([1, 2], t1));'),
|
||||
"Code pattern 'A.print(A._setArrayType([1, 2], t1));' "
|
||||
"not found in\n$generated");
|
||||
Expect.isTrue(
|
||||
generated.contains('A.print(A._setArrayType([3], t1));'),
|
||||
"Code pattern 'A.print(A._setArrayType([3], t1));' "
|
||||
"not found in\n$generated");
|
||||
Expect.isTrue(
|
||||
generated.contains('A.print(A._setArrayType([4, 5], t1));'),
|
||||
"Code pattern 'A.print(A._setArrayType([4, 5], t1));' "
|
||||
"not found in\n$generated");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import 'package:compiler/src/util/testing.dart';
|
||||
|
||||
/*spec.class: Class:explicit=[Class.T*],implicit=[Class.T],needsArgs,test*/
|
||||
/*prod.class: Class:needsArgs*/
|
||||
/*prod.class: Class:implicit=[Class.T],needsArgs,test*/
|
||||
class Class<T> {
|
||||
method() {
|
||||
var list = <T>[];
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import 'package:compiler/src/util/testing.dart';
|
||||
|
||||
/*spec.class: Class:explicit=[Class.T*],implicit=[Class.T],needsArgs,test*/
|
||||
/*prod.class: Class:implicit=[Class.T],needsArgs,test*/
|
||||
class Class<T> {
|
||||
method() {
|
||||
var list = <T>[];
|
||||
|
||||
@@ -9,7 +9,7 @@ import 'package:compiler/src/util/testing.dart';
|
||||
/*class: A:implicit=[List<A<C*>*>,List<A<C2*>*>]*/
|
||||
class A<T> {}
|
||||
|
||||
/*spec.class: A1:implicit=[A1]*/
|
||||
/*class: A1:implicit=[A1]*/
|
||||
class A1 implements A<C1> {}
|
||||
|
||||
/*class: B:explicit=[B.T*],needsArgs,test*/
|
||||
|
||||
@@ -9,20 +9,19 @@ import 'package:compiler/src/util/testing.dart';
|
||||
// Test derived from language_2/generic_methods_dynamic_test/05
|
||||
|
||||
/*spec.class: global#JSArray:deps=[ArrayIterator,List],explicit=[JSArray,JSArray.E,JSArray<ArrayIterator.E>],implicit=[JSArray.E],needsArgs,test*/
|
||||
/*prod.class: global#JSArray:deps=[List],needsArgs*/
|
||||
/*prod.class: global#JSArray:deps=[List],implicit=[JSArray.E],needsArgs,test*/
|
||||
|
||||
/*spec.class: global#List:deps=[C.bar,JSArray.markFixedList],explicit=[List<B*>*,List<Object>,List<Object?>,List<String>?,List<markFixedList.T>],needsArgs,test*/
|
||||
/*prod.class: global#List:deps=[C.bar],explicit=[List<B*>*],needsArgs*/
|
||||
/*prod.class: global#List:deps=[C.bar],explicit=[List<B*>*],needsArgs,test*/
|
||||
|
||||
class A {}
|
||||
|
||||
/*spec.class: B:explicit=[List<B*>*],implicit=[B]*/
|
||||
/*prod.class: B:explicit=[List<B*>*]*/
|
||||
/*class: B:explicit=[List<B*>*],implicit=[B]*/
|
||||
class B {}
|
||||
|
||||
class C {
|
||||
/*spec.member: C.bar:explicit=[Iterable<bar.T*>*],implicit=[bar.T],needsArgs,selectors=[Selector(call, bar, arity=1, types=1)],test*/
|
||||
/*prod.member: C.bar:needsArgs,selectors=[Selector(call, bar, arity=1, types=1)]*/
|
||||
/*prod.member: C.bar:implicit=[bar.T],needsArgs,selectors=[Selector(call, bar, arity=1, types=1)],test*/
|
||||
List<T> bar<T>(Iterable<T> t) => <T>[t.first];
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
import 'package:compiler/src/util/testing.dart';
|
||||
|
||||
/*spec.class: global#JSArray:deps=[ArrayIterator,List],explicit=[JSArray,JSArray.E,JSArray<ArrayIterator.E>],implicit=[JSArray.E],needsArgs,test*/
|
||||
/*prod.class: global#JSArray:deps=[List],needsArgs*/
|
||||
/*prod.class: global#JSArray:deps=[List],implicit=[JSArray.E],needsArgs,test*/
|
||||
|
||||
@pragma('dart2js:noInline')
|
||||
/*spec.member: method:implicit=[method.T],needsArgs,test*/
|
||||
/*prod.member: method:needsArgs*/
|
||||
/*member: method:implicit=[method.T],needsArgs,test*/
|
||||
method<T>() {
|
||||
return /*spec.*/ () => <T>[];
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import 'package:compiler/src/util/testing.dart';
|
||||
|
||||
/*spec.class: global#LinkedHashMap:deps=[Map],explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],needsArgs,test*/
|
||||
/*prod.class: global#LinkedHashMap:deps=[Map],needsArgs*/
|
||||
/*prod.class: global#LinkedHashMap:deps=[Map],implicit=[LinkedHashMap.K,LinkedHashMap.V],needsArgs*/
|
||||
|
||||
@pragma('dart2js:noInline')
|
||||
/*spec.member: method:implicit=[method.T],needsArgs,test*/
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
// @dart = 2.7
|
||||
|
||||
/*prod.class: global#Map:*/
|
||||
/*prod.class: global#Map:needsArgs*/
|
||||
/*spec.class: global#Map:explicit=[Map,Map<Object?,Object?>],needsArgs,test*/
|
||||
|
||||
/*prod.class: global#LinkedHashMap:deps=[Map]*/
|
||||
/*prod.class: global#LinkedHashMap:deps=[Map],implicit=[LinkedHashMap.K,LinkedHashMap.V],needsArgs*/
|
||||
/*spec.class: global#LinkedHashMap:deps=[Map],explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],needsArgs,test*/
|
||||
|
||||
/*prod.class: global#JsLinkedHashMap:deps=[LinkedHashMap]*/
|
||||
/*prod.class: global#JsLinkedHashMap:deps=[LinkedHashMap],needsArgs*/
|
||||
/*spec.class: global#JsLinkedHashMap:deps=[LinkedHashMap],explicit=[JsLinkedHashMap,JsLinkedHashMap.K,JsLinkedHashMap.V,void Function(JsLinkedHashMap.K,JsLinkedHashMap.V)],implicit=[JsLinkedHashMap.K],needsArgs,test*/
|
||||
|
||||
/*prod.class: global#double:*/
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/*prod.class: global#Map:deps=[Class],needsArgs*/
|
||||
/*spec.class: global#Map:deps=[Class],explicit=[Map,Map<Object?,Object?>],needsArgs,test*/
|
||||
|
||||
/*prod.class: global#LinkedHashMap:deps=[Map],implicit=[LinkedHashMap.K],needsArgs*/
|
||||
/*prod.class: global#LinkedHashMap:deps=[Map],implicit=[LinkedHashMap.K,LinkedHashMap.V],needsArgs*/
|
||||
/*spec.class: global#LinkedHashMap:deps=[Map],explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],needsArgs,test*/
|
||||
|
||||
/*prod.class: global#JsLinkedHashMap:deps=[LinkedHashMap],implicit=[JsLinkedHashMap.K],needsArgs*/
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
// Ensure we don't omit as checks based on a subtype check ignoring nullability.
|
||||
|
||||
void foo<T>(T? x) {
|
||||
print(x as T);
|
||||
}
|
||||
|
||||
void main() {
|
||||
if (hasSoundNullSafety) {
|
||||
Expect.throws(() => foo<int>(null));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user