From 66fa0e2a491371b098323a0311a0e400ad1fad65 Mon Sep 17 00:00:00 2001 From: Mayank Patke Date: Thu, 13 Feb 2025 01:49:09 -0800 Subject: [PATCH] [dart2js] Clean up nullability adjustments in interface sufficiency test Now that https://github.com/dart-lang/sdk/issues/60076 has been addressed, we no longer need to widen the nullability ourselves. Change-Id: I4bc5a1767d9e2d98bcf0ca4c24171482e0f600ac Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/409162 Commit-Queue: Mayank Patke Reviewed-by: Stephen Adams --- pkg/compiler/lib/src/ssa/builder.dart | 14 +-- .../data/is_test_weakening_with_bounds.dart | 103 ++++++++++++++++++ 2 files changed, 106 insertions(+), 11 deletions(-) create mode 100644 pkg/compiler/test/codegen/data/is_test_weakening_with_bounds.dart diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart index 4c4e2ad1ec4b..8815be0c3225 100644 --- a/pkg/compiler/lib/src/ssa/builder.dart +++ b/pkg/compiler/lib/src/ssa/builder.dart @@ -7740,26 +7740,18 @@ class KernelSsaGraphBuilder extends ir.VisitorDefault final sufficiency = closedWorld.elementMap.typeEnvironment .computeTypeShapeCheckSufficiency( expressionStaticType: operandType, - // Add `?` in case operand is nullable: - checkTargetType: checkedType.withDeclaredNullability( - ir.Nullability.nullable, - ), + checkTargetType: checkedType, subtypeCheckMode: ir.SubtypeCheckMode.withNullabilities, ); // If `true` the caller only needs to check nullabillity and the actual // concrete class, no need to check [testedAgainstType] arguments. if (sufficiency == ir.TypeShapeCheckSufficiency.interfaceShape) { - return ir.InterfaceType( + return closedWorld.elementMap.coreTypes.rawType( checkedType.classNode, - (operandType is ir.InterfaceType && - operandType.nullability == ir.Nullability.nonNullable) + operandType.nullability == ir.Nullability.nonNullable ? ir.Nullability.nonNullable : checkedType.nullability, - [ - for (final parameter in checkedType.classNode.typeParameters) - parameter.defaultType, - ], ); } } diff --git a/pkg/compiler/test/codegen/data/is_test_weakening_with_bounds.dart b/pkg/compiler/test/codegen/data/is_test_weakening_with_bounds.dart new file mode 100644 index 000000000000..a122724c71db --- /dev/null +++ b/pkg/compiler/test/codegen/data/is_test_weakening_with_bounds.dart @@ -0,0 +1,103 @@ +// Copyright (c) 2025, 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. + +// `is` tests against some parameterized interface types are equivalent to a +// weaker test for just the interace. The weaker test is usually more efficient, +// sometimes being compiled to `instanceof`. + +class Base { + /*member: Base.test1:function(other) { + if (other instanceof A.D1) + return other.foo$0(); + return "other"; +}*/ + @pragma('dart2js:parameter:trust') + String test1(Base other) { + if (other is D1) return other.foo(); + return 'other'; + } + + /*member: Base.test1qn:function(other) { + if (other instanceof A.D1) + return other.foo$0(); + return "other"; +}*/ + @pragma('dart2js:parameter:trust') + String test1qn(Base? other) { + if (other is D1) return other.foo(); + return 'other'; + } + + /*member: Base.test1nq:function(other) { + if (other instanceof A.D1) + return other.method$0(); + return "other"; +}*/ + @pragma('dart2js:parameter:trust') + String? test1nq(Base other) { + if (other is D1?) return other.method(); // No promotion, so can't foo(). + return 'other'; + } + + /*member: Base.test1qq:function(other) { + var t1; + if (type$.nullable_D1_dynamic._is(other)) { + t1 = other.foo$0(); + return t1; + } + return "other"; +}*/ + @pragma('dart2js:parameter:trust') + String? test1qq(Base? other) { + if (other is D1?) return other?.foo(); + return 'other'; + } + + /*member: Base.test2:function(other) { + if (other instanceof A.D2) + return other.bar$0(); + return "other"; +}*/ + @pragma('dart2js:parameter:trust') + String test2(Base other) { + if (other is D2) return other.bar(); + return 'other'; + } + + @pragma('dart2js:never-inline') + /*member: Base.method:ignore*/ + String method() => 'Base.method'; +} + +class D1 extends Base { + @pragma('dart2js:never-inline') + /*member: D1.foo:ignore*/ + String foo() => 'D1<$T>.foo'; +} + +class D2 extends D1 { + @pragma('dart2js:never-inline') + /*member: D2.bar:ignore*/ + String bar() => 'D2.bar'; +} + +/*member: main:ignore*/ +main() { + final items = [Base(), D1(), D2()]; + + for (final item in items) { + print(item.test1(items.first)); + print(item.test1(item)); + + print(item.test1qn(items.first)); + print(item.test1qn(item)); + print(item.test1nq(items.first)); + print(item.test1nq(item)); + print(item.test1qq(items.first)); + print(item.test1qq(item)); + + print(item.test2(items.first)); + print(item.test2(item)); + } +}