[vm,aot] Fix parameter type checks in the implicit setters of covariant-by-class fields

Implicit setters of covariant fields (both covariant by declaration and
covariant by class aka generic-covariant-impl) need to perform a type
check of their argument.

It means that inferred type of the field cannot be used as inferred
type of parameter of such setter. This change removes such uses of
an inferred type of the field, which restores parameter type check
which was previously incorrectly optimized out.

TEST=runtime/tests/vm/dart/regress_63419_test.dart
Fixes https://github.com/dart-lang/sdk/issues/63419

Change-Id: Ie313dbaab51dff15d60ce4390e7e41bdc66ad59d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/509020
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov
2026-06-03 11:32:28 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 021068bb3d
commit 6b9aecbe5f
3 changed files with 48 additions and 2 deletions
@@ -194,7 +194,7 @@ class UnboxingInfoManager {
// Arguments of implicit setters for covariant fields
// cannot be unboxed based on the field type as setter
// performs a type check before value is assigned to the field.
if (member.isCovariantByDeclaration) {
if (member.isCovariantByDeclaration || member.isCovariantByClass) {
unboxingInfo.argsInfo.length = 0;
} else {
_applyToArg(member, unboxingInfo, 0, inferredType);
@@ -0,0 +1,45 @@
// Copyright (c) 2026, 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.
// Regression test for https://github.com/dart-lang/sdk/issues/63419.
// VMOptions=--compiler-passes=-Inlining
import 'package:expect/expect.dart';
abstract interface class Box1<T> {
T get x;
void set x(T value);
}
class StringBox implements Box1<String> {
@pragma("vm:never-inline")
String x = 'yay';
}
abstract interface class Box2<T> {
T get x;
void set x(T value);
}
class IntBox implements Box2<int> {
@pragma("vm:never-inline")
int x = 0;
}
void main() {
final Box1<Object> box1 = StringBox();
box1.x = 'xyz';
Expect.equals('xyz', box1.x);
Expect.throws(() {
box1.x = 123;
});
final Box2<Object> box2 = IntBox();
box2.x = 123;
Expect.equals(123, box2.x);
Expect.throws(() {
box2.x = 'abc';
});
}
@@ -308,7 +308,8 @@ ScopeBuildingResult* ScopeBuilder::BuildScopes() {
AbstractType::ZoneHandle(Z, function.ParameterTypeAt(pos)),
LocalVariable::kNoKernelOffset, /*is_late=*/false,
/*inferred_type_md=*/nullptr,
/*inferred_arg_type_md=*/field.is_covariant()
/*inferred_arg_type_md=*/
(field.is_covariant() || field.is_generic_covariant_impl())
? nullptr
: &inferred_field_type);
} else {