[CFE/VM] Fix mixin deleting procedure-setter because of final field

Fixes https://github.com/dart-lang/sdk/issues/63440
Tested: Tests added.
Change-Id: I0bdfd71c48ecae6094557fa4f46b8fc4b50afa73
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/506980
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
This commit is contained in:
Jens Johansen
2026-05-28 05:15:07 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 69e9d32e87
commit d441e28656
23 changed files with 384 additions and 10 deletions
@@ -0,0 +1,16 @@
// 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.
// This has historically crashed with target vm.
mixin M {
final c = 1;
void set c(int _) {}
}
class MA = Object with M;
void hello() {
MA().c = 42;
}
@@ -0,0 +1,20 @@
library;
import self as self;
import "dart:core" as core;
abstract class M extends core::Object /*isMixinDeclaration*/ {
final field core::int c = 1;
set c(wildcard core::int _#wc0#formal) → void {}
}
class MA = core::Object with self::M {
synthetic constructor •() → self::MA
: super core::Object::•()
;
synthetic mixin-super-stub get c() → core::int
return super.{self::M::c};
synthetic mixin-super-stub set c(core::int _#wc0#formal) → void
return super.{self::M::c} = _#wc0#formal;
}
static method hello() → void {
new self::MA::•().{self::MA::c} = 42;
}
@@ -0,0 +1,20 @@
library;
import self as self;
import "dart:core" as core;
abstract class M extends core::Object /*isMixinDeclaration*/ {
final field core::int c = 1;
set c(wildcard core::int _#wc0#formal) → void {}
}
class MA = core::Object with self::M {
synthetic constructor •() → self::MA
: super core::Object::•()
;
synthetic mixin-super-stub get c() → core::int
return super.{self::M::c};
synthetic mixin-super-stub set c(core::int _#wc0#formal) → void
return super.{self::M::c} = _#wc0#formal;
}
static method hello() → void {
new self::MA::•().{self::MA::c} = 42;
}
@@ -0,0 +1,20 @@
library;
import self as self;
import "dart:core" as core;
abstract class M extends core::Object /*isMixinDeclaration*/ {
final field core::int c;
set c(wildcard core::int _#wc0#formal) → void
;
}
class MA = core::Object with self::M {
synthetic constructor •() → self::MA
: super core::Object::•()
;
synthetic mixin-super-stub get c() → core::int
return super.{self::M::c};
synthetic mixin-super-stub set c(core::int _#wc0#formal) → void
return super.{self::M::c} = _#wc0#formal;
}
static method hello() → void
;
@@ -0,0 +1,18 @@
library;
import self as self;
import "dart:core" as core;
abstract class M extends core::Object /*isMixinDeclaration*/ {
final field core::int c = 1;
set c(wildcard core::int _#wc0#formal) → void {}
}
class MA extends core::Object implements self::M /*isEliminatedMixin*/ {
final field core::int c = 1;
synthetic constructor •() → self::MA
: super core::Object::•()
;
set c(core::int _#wc0#formal) → void {}
}
static method hello() → void {
new self::MA::•().{self::MA::c} = 42;
}
@@ -0,0 +1,8 @@
mixin M {
final c = 1;
void set c(int _) {}
}
class MA = Object with M;
void hello() {}
@@ -0,0 +1,8 @@
class MA = Object with M;
mixin M {
final c = 1;
void set c(int _) {}
}
void hello() {}
@@ -0,0 +1,16 @@
// 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.
// This has historically crashed with target vm.
mixin M {
late final int c;
void set c(int _) {}
}
class MA = Object with M;
void hello() {
MA().c = 42;
}
@@ -0,0 +1,29 @@
library;
//
// Problems in library:
//
// pkg/front_end/testcases/general/issue_63440_prime_1.dart:9:12: Error: Conflicts with the implicit setter of the field 'c'.
// void set c(int _) {}
// ^
// pkg/front_end/testcases/general/issue_63440_prime_1.dart:8:18: Context: Field 'c' with the implicit setter.
// late final int c;
// ^
//
import self as self;
import "dart:core" as core;
abstract class M extends core::Object /*isMixinDeclaration*/ {
late final [setter] field core::int c;
}
class MA = core::Object with self::M {
synthetic constructor •() → self::MA
: super core::Object::•()
;
synthetic mixin-super-stub get c() → core::int
return super.{self::M::c};
synthetic mixin-super-stub set c(core::int value) → void
return super.{self::M::c} = value;
}
static method hello() → void {
new self::MA::•().{self::MA::c} = 42;
}
@@ -0,0 +1,29 @@
library;
//
// Problems in library:
//
// pkg/front_end/testcases/general/issue_63440_prime_1.dart:9:12: Error: Conflicts with the implicit setter of the field 'c'.
// void set c(int _) {}
// ^
// pkg/front_end/testcases/general/issue_63440_prime_1.dart:8:18: Context: Field 'c' with the implicit setter.
// late final int c;
// ^
//
import self as self;
import "dart:core" as core;
abstract class M extends core::Object /*isMixinDeclaration*/ {
late final [setter] field core::int c;
}
class MA = core::Object with self::M {
synthetic constructor •() → self::MA
: super core::Object::•()
;
synthetic mixin-super-stub get c() → core::int
return super.{self::M::c};
synthetic mixin-super-stub set c(core::int value) → void
return super.{self::M::c} = value;
}
static method hello() → void {
new self::MA::•().{self::MA::c} = 42;
}
@@ -0,0 +1,28 @@
library;
//
// Problems in library:
//
// pkg/front_end/testcases/general/issue_63440_prime_1.dart:9:12: Error: Conflicts with the implicit setter of the field 'c'.
// void set c(int _) {}
// ^
// pkg/front_end/testcases/general/issue_63440_prime_1.dart:8:18: Context: Field 'c' with the implicit setter.
// late final int c;
// ^
//
import self as self;
import "dart:core" as core;
abstract class M extends core::Object /*isMixinDeclaration*/ {
late final [setter] field core::int c;
}
class MA = core::Object with self::M {
synthetic constructor •() → self::MA
: super core::Object::•()
;
synthetic mixin-super-stub get c() → core::int
return super.{self::M::c};
synthetic mixin-super-stub set c(core::int value) → void
return super.{self::M::c} = value;
}
static method hello() → void
;
@@ -0,0 +1,26 @@
library;
//
// Problems in library:
//
// pkg/front_end/testcases/general/issue_63440_prime_1.dart:9:12: Error: Conflicts with the implicit setter of the field 'c'.
// void set c(int _) {}
// ^
// pkg/front_end/testcases/general/issue_63440_prime_1.dart:8:18: Context: Field 'c' with the implicit setter.
// late final int c;
// ^
//
import self as self;
import "dart:core" as core;
abstract class M extends core::Object /*isMixinDeclaration*/ {
late final [setter] field core::int c;
}
class MA extends core::Object implements self::M /*isEliminatedMixin*/ {
late final [setter] field core::int c;
synthetic constructor •() → self::MA
: super core::Object::•()
;
}
static method hello() → void {
new self::MA::•().{self::MA::c} = 42;
}
@@ -0,0 +1,8 @@
mixin M {
late final int c;
void set c(int _) {}
}
class MA = Object with M;
void hello() {}
@@ -0,0 +1,8 @@
class MA = Object with M;
mixin M {
late final int c;
void set c(int _) {}
}
void hello() {}
@@ -0,0 +1,16 @@
// 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.
// This has historically crashed with target vm, but not target none.
mixin M {
final c = 1;
void set c(int _) {}
}
class MA = Object with M;
void hello() {
MA().c = 42;
}
@@ -0,0 +1,20 @@
library;
import self as self;
import "dart:core" as core;
abstract class M extends core::Object /*isMixinDeclaration*/ {
final field core::int c = 1;
set c(wildcard core::int _#wc0#formal) → void {}
}
class MA = core::Object with self::M {
synthetic constructor •() → self::MA
: super core::Object::•()
;
synthetic mixin-super-stub get c() → core::int
return super.{self::M::c};
synthetic mixin-super-stub set c(core::int _#wc0#formal) → void
return super.{self::M::c} = _#wc0#formal;
}
static method hello() → void {
new self::MA::•().{self::MA::c} = 42;
}
@@ -0,0 +1,20 @@
library;
import self as self;
import "dart:core" as core;
abstract class M extends core::Object /*isMixinDeclaration*/ {
final field core::int c = 1;
set c(wildcard core::int _#wc0#formal) → void {}
}
class MA = core::Object with self::M {
synthetic constructor •() → self::MA
: super core::Object::•()
;
synthetic mixin-super-stub get c() → core::int
return super.{self::M::c};
synthetic mixin-super-stub set c(core::int _#wc0#formal) → void
return super.{self::M::c} = _#wc0#formal;
}
static method hello() → void {
new self::MA::•().{self::MA::c} = 42;
}
@@ -0,0 +1,20 @@
library;
import self as self;
import "dart:core" as core;
abstract class M extends core::Object /*isMixinDeclaration*/ {
final field core::int c;
set c(wildcard core::int _#wc0#formal) → void
;
}
class MA = core::Object with self::M {
synthetic constructor •() → self::MA
: super core::Object::•()
;
synthetic mixin-super-stub get c() → core::int
return super.{self::M::c};
synthetic mixin-super-stub set c(core::int _#wc0#formal) → void
return super.{self::M::c} = _#wc0#formal;
}
static method hello() → void
;
@@ -0,0 +1,20 @@
library;
import self as self;
import "dart:core" as core;
abstract class M extends core::Object /*isMixinDeclaration*/ {
final field core::int c = 1;
set c(wildcard core::int _#wc0#formal) → void {}
}
class MA = core::Object with self::M {
synthetic constructor •() → self::MA
: super core::Object::•()
;
synthetic mixin-super-stub get c() → core::int
return super.{self::M::c};
synthetic mixin-super-stub set c(core::int _#wc0#formal) → void
return super.{self::M::c} = _#wc0#formal;
}
static method hello() → void {
new self::MA::•().{self::MA::c} = 42;
}
@@ -0,0 +1,8 @@
mixin M {
final c = 1;
void set c(int _) {}
}
class MA = Object with M;
void hello() {}
@@ -0,0 +1,8 @@
class MA = Object with M;
mixin M {
final c = 1;
void set c(int _) {}
}
void hello() {}
+3
View File
@@ -121,6 +121,9 @@ nnbd/platform_definite_assignment/main: SemiFuzzFailure
nnbd/platform_nonnullable_fields/main: SemiFuzzFailure
nnbd/platform_optional_parameters/main: SemiFuzzFailure
# Unclear exactly what is going on here - but target none isn't super important.
none/issue_63440: SemiFuzzFailure
# UNSORTED ONES:
constructor_tearoffs/explicit_instantiation: SemiFuzzFailure
enhanced_parts/deferred_siblings: SemiFuzzFailure
@@ -157,14 +157,16 @@ class MixinFullResolution {
Reference? getterReference = indexedClass?.lookupGetterReference(
field.name,
);
Reference? setterReference = indexedClass?.lookupSetterReference(
field.name,
);
// We only use any given setter reference if it belongs to the field.
Reference? setterReference = field.hasSetter
? indexedClass?.lookupSetterReference(field.name)
: null;
if (getterReference == null) {
getterReference = nonSetters[field.name]?.reference;
getterReference?.canonicalName?.unbind();
}
if (setterReference == null) {
if (setterReference == null && field.hasSetter) {
setterReference = setters[field.name]?.reference;
setterReference?.canonicalName?.unbind();
}
@@ -174,12 +176,15 @@ class MixinFullResolution {
getterReference,
setterReference,
);
Procedure? setter = setters[field.name];
if (setter != null) {
setters.remove(field.name);
Variable parameter = setter.function.positionalParameters.first;
clone.isCovariantByDeclaration = parameter.isCovariantByDeclaration;
clone.isCovariantByClass = parameter.isCovariantByClass;
if (field.hasSetter) {
// Only remove a setter with this name if it belongs to the field.
Procedure? setter = setters[field.name];
if (setter != null) {
setters.remove(field.name);
Variable parameter = setter.function.positionalParameters.first;
clone.isCovariantByDeclaration = parameter.isCovariantByDeclaration;
clone.isCovariantByClass = parameter.isCovariantByClass;
}
}
nonSetters.remove(field.name);
class_.addField(clone);