[ddc] Avoid null check on forwarding field setters

Overriding fields can change the type to remove nullability and
can also be final so they override the getters only.

For DDC that means there is an inherited setter that could still be nullable and a forwarding setter that should allow null even though
the type of the overriding field is non-nullable. With enhanced null
safety asserts enabled in weak mode there should be no failure when
setting the inherited field to null.

Fixes: https://github.com/dart-lang/sdk/issues/50569
Change-Id: Ie6af0d1e265a5f3b15469311fa1f7e2a184d95ca
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/272480
Reviewed-by: Leaf Petersen <leafp@google.com>
Commit-Queue: Nicholas Shahan <nshahan@google.com>
Reviewed-by: Mark Zhou <markzipan@google.com>
This commit is contained in:
Nicholas Shahan 2022-11-29 21:49:15 +00:00 committed by Commit Queue
parent a9c11acd25
commit 2cbed01634
3 changed files with 22 additions and 1 deletions

View file

@ -2259,7 +2259,9 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
var body = <js_ast.Statement>[];
var value = _emitIdentifier('value');
if (_requiresExtraNullCheck(field.setterType, field.annotations)) {
// Avoid adding a null checks on forwarding field setters.
if (field.hasSetter &&
_requiresExtraNullCheck(field.setterType, field.annotations)) {
body.add(
_nullSafetyParameterCheck(value, field.location, field.name.text));
}

View file

@ -159,6 +159,9 @@ main() {
// Same class as above defined in and inherited from null safe library throw.
var nullSafeB = null_safe.B();
// Should not throw because the inherited setter does allow null even though
// the getter has an override and is non-nullable.
nullSafeB.nullableField = null;
Expect.throws(() {
nullSafeB.getterSetterPair = null;
}, asserted('i'));
@ -193,6 +196,10 @@ main() {
// Same class as above defined in null safe library throws.
var nullSafeD = null_safe.D();
// Should not throw because the inherited setters do allow null even though
// the getter has an override and is non-nullable.
nullSafeD.nullableField = null;
nullSafeD.nullableGetterSetterPair = null;
Expect.throws(() {
nullSafeD.field = null;
}, asserted('field'));

View file

@ -28,7 +28,10 @@ class A {
int get getterSetterPair => 0;
set getterSetterPair(int i) => null;
set setterOnly(String s) => null;
int? get nullableGetterSetterPair => 0;
set nullableGetterSetterPair(int? i) => null;
int field = 0;
int? nullableField = 0;
static bool staticField = false;
static int get staticGetterSetterPair => 0;
static set staticGetterSetterPair(int i) => null;
@ -44,6 +47,9 @@ class B extends A {
int get getterSetterPair => 999;
@override
int get field => 999;
// Getter override makes the type non-nullable.
@override
int get nullableField => 999;
}
/// Overrides the setters.
@ -60,4 +66,10 @@ class C extends A {
class D extends A {
@override
int field = 10;
// Field override is final (getter only) and makes type non-nullable.
@override
final int nullableField = 999;
// Getter has override to be non-nullable but nullable setter is inherited.
@override
int get nullableGetterSetterPair => 999;
}