Files
sdk/pkg/compiler/test/codegen/data/is_test_weakening.dart
T
Stephen Adams e962350dd6 [dart2js] Simply is-test when type parameters not needed
Sometimes the type expression of a is-test can be widened to one that
does not use type variables:

```dart
void addAll(Iterable<E> items) {
  if (items is List<E>) {
    ... items[i] ...  // code specialized to lists
  }
  ...
}
```

Changing `is List<E>` to `is List` is more efficient, but not possible
at the source level since the explicit type parameter is needed for
type promotion.

This change uses a predicate provided by the Kernel package to widen
an interface type when generating the CFG instructions for the
is-test. This can lead to knock-on optimizations like compiling `is X`
to `instanceof`.



Bug: #54998
Change-Id: I956b9d9b8a31ae40aee86e31def475baa9ab5cfe
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/408124
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
2025-02-06 16:54:50 -08:00

104 lines
2.6 KiB
Dart

// 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<T> {
/*member: Base.test1:function(other) {
if (other instanceof A.D1)
return other.foo$0();
return "other";
}*/
@pragma('dart2js:parameter:trust')
String test1(Base<T> other) {
if (other is D1<T>) 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<T>? other) {
if (other is D1<T>) 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<T> other) {
if (other is D1<T>?) 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<T>? other) {
if (other is D1<T>?) 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<T> other) {
if (other is D2<T>) return other.bar();
return 'other';
}
@pragma('dart2js:never-inline')
/*member: Base.method:ignore*/
String method() => 'Base.method';
}
class D1<T> extends Base<T> {
@pragma('dart2js:never-inline')
/*member: D1.foo:ignore*/
String foo() => 'D1<$T>.foo';
}
class D2<T> extends D1<T> {
@pragma('dart2js:never-inline')
/*member: D2.bar:ignore*/
String bar() => 'D2.bar';
}
/*member: main:ignore*/
main() {
final items = [Base<int>(), D1<int>(), D2<int>()];
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));
}
}