From d441e28656418da265ae19c46fdb2bf66a3e85e1 Mon Sep 17 00:00:00 2001 From: Jens Johansen Date: Thu, 28 May 2026 05:15:07 -0700 Subject: [PATCH] [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 Reviewed-by: Martin Kustermann Commit-Queue: Jens Johansen --- .../testcases/general/issue_63440.dart | 16 ++++++++++ .../general/issue_63440.dart.strong.expect | 20 +++++++++++++ .../issue_63440.dart.strong.modular.expect | 20 +++++++++++++ .../issue_63440.dart.strong.outline.expect | 20 +++++++++++++ ...issue_63440.dart.strong.transformed.expect | 18 ++++++++++++ .../issue_63440.dart.textual_outline.expect | 8 +++++ ...63440.dart.textual_outline_modelled.expect | 8 +++++ .../general/issue_63440_prime_1.dart | 16 ++++++++++ .../issue_63440_prime_1.dart.strong.expect | 29 +++++++++++++++++++ ...e_63440_prime_1.dart.strong.modular.expect | 29 +++++++++++++++++++ ...e_63440_prime_1.dart.strong.outline.expect | 28 ++++++++++++++++++ ...440_prime_1.dart.strong.transformed.expect | 26 +++++++++++++++++ ..._63440_prime_1.dart.textual_outline.expect | 8 +++++ ...ime_1.dart.textual_outline_modelled.expect | 8 +++++ pkg/front_end/testcases/none/issue_63440.dart | 16 ++++++++++ .../none/issue_63440.dart.strong.expect | 20 +++++++++++++ .../issue_63440.dart.strong.modular.expect | 20 +++++++++++++ .../issue_63440.dart.strong.outline.expect | 20 +++++++++++++ ...issue_63440.dart.strong.transformed.expect | 20 +++++++++++++ .../issue_63440.dart.textual_outline.expect | 8 +++++ ...63440.dart.textual_outline_modelled.expect | 8 +++++ pkg/front_end/testcases/strong.status | 3 ++ .../mixin_full_resolution.dart | 25 +++++++++------- 23 files changed, 384 insertions(+), 10 deletions(-) create mode 100644 pkg/front_end/testcases/general/issue_63440.dart create mode 100644 pkg/front_end/testcases/general/issue_63440.dart.strong.expect create mode 100644 pkg/front_end/testcases/general/issue_63440.dart.strong.modular.expect create mode 100644 pkg/front_end/testcases/general/issue_63440.dart.strong.outline.expect create mode 100644 pkg/front_end/testcases/general/issue_63440.dart.strong.transformed.expect create mode 100644 pkg/front_end/testcases/general/issue_63440.dart.textual_outline.expect create mode 100644 pkg/front_end/testcases/general/issue_63440.dart.textual_outline_modelled.expect create mode 100644 pkg/front_end/testcases/general/issue_63440_prime_1.dart create mode 100644 pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.expect create mode 100644 pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.modular.expect create mode 100644 pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.outline.expect create mode 100644 pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.transformed.expect create mode 100644 pkg/front_end/testcases/general/issue_63440_prime_1.dart.textual_outline.expect create mode 100644 pkg/front_end/testcases/general/issue_63440_prime_1.dart.textual_outline_modelled.expect create mode 100644 pkg/front_end/testcases/none/issue_63440.dart create mode 100644 pkg/front_end/testcases/none/issue_63440.dart.strong.expect create mode 100644 pkg/front_end/testcases/none/issue_63440.dart.strong.modular.expect create mode 100644 pkg/front_end/testcases/none/issue_63440.dart.strong.outline.expect create mode 100644 pkg/front_end/testcases/none/issue_63440.dart.strong.transformed.expect create mode 100644 pkg/front_end/testcases/none/issue_63440.dart.textual_outline.expect create mode 100644 pkg/front_end/testcases/none/issue_63440.dart.textual_outline_modelled.expect diff --git a/pkg/front_end/testcases/general/issue_63440.dart b/pkg/front_end/testcases/general/issue_63440.dart new file mode 100644 index 00000000000..67a556c9af0 --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440.dart @@ -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; +} \ No newline at end of file diff --git a/pkg/front_end/testcases/general/issue_63440.dart.strong.expect b/pkg/front_end/testcases/general/issue_63440.dart.strong.expect new file mode 100644 index 00000000000..5f25a9ef1b5 --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440.dart.strong.expect @@ -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; +} diff --git a/pkg/front_end/testcases/general/issue_63440.dart.strong.modular.expect b/pkg/front_end/testcases/general/issue_63440.dart.strong.modular.expect new file mode 100644 index 00000000000..5f25a9ef1b5 --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440.dart.strong.modular.expect @@ -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; +} diff --git a/pkg/front_end/testcases/general/issue_63440.dart.strong.outline.expect b/pkg/front_end/testcases/general/issue_63440.dart.strong.outline.expect new file mode 100644 index 00000000000..5a4f2dc56e4 --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440.dart.strong.outline.expect @@ -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 + ; diff --git a/pkg/front_end/testcases/general/issue_63440.dart.strong.transformed.expect b/pkg/front_end/testcases/general/issue_63440.dart.strong.transformed.expect new file mode 100644 index 00000000000..117041e60d5 --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440.dart.strong.transformed.expect @@ -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; +} diff --git a/pkg/front_end/testcases/general/issue_63440.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue_63440.dart.textual_outline.expect new file mode 100644 index 00000000000..25f37f488c8 --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440.dart.textual_outline.expect @@ -0,0 +1,8 @@ +mixin M { + final c = 1; + void set c(int _) {} +} + +class MA = Object with M; + +void hello() {} diff --git a/pkg/front_end/testcases/general/issue_63440.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue_63440.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..530858a2ab7 --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440.dart.textual_outline_modelled.expect @@ -0,0 +1,8 @@ +class MA = Object with M; + +mixin M { + final c = 1; + void set c(int _) {} +} + +void hello() {} diff --git a/pkg/front_end/testcases/general/issue_63440_prime_1.dart b/pkg/front_end/testcases/general/issue_63440_prime_1.dart new file mode 100644 index 00000000000..8bbfe299280 --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440_prime_1.dart @@ -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; +} \ No newline at end of file diff --git a/pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.expect b/pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.expect new file mode 100644 index 00000000000..bea06e9e0d4 --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.expect @@ -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; +} diff --git a/pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.modular.expect b/pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.modular.expect new file mode 100644 index 00000000000..bea06e9e0d4 --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.modular.expect @@ -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; +} diff --git a/pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.outline.expect b/pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.outline.expect new file mode 100644 index 00000000000..f93a51e24fb --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.outline.expect @@ -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 + ; diff --git a/pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.transformed.expect b/pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.transformed.expect new file mode 100644 index 00000000000..19fb9191a5c --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440_prime_1.dart.strong.transformed.expect @@ -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; +} diff --git a/pkg/front_end/testcases/general/issue_63440_prime_1.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue_63440_prime_1.dart.textual_outline.expect new file mode 100644 index 00000000000..6cfaaca6eb1 --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440_prime_1.dart.textual_outline.expect @@ -0,0 +1,8 @@ +mixin M { + late final int c; + void set c(int _) {} +} + +class MA = Object with M; + +void hello() {} diff --git a/pkg/front_end/testcases/general/issue_63440_prime_1.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue_63440_prime_1.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..73b72ddc03c --- /dev/null +++ b/pkg/front_end/testcases/general/issue_63440_prime_1.dart.textual_outline_modelled.expect @@ -0,0 +1,8 @@ +class MA = Object with M; + +mixin M { + late final int c; + void set c(int _) {} +} + +void hello() {} diff --git a/pkg/front_end/testcases/none/issue_63440.dart b/pkg/front_end/testcases/none/issue_63440.dart new file mode 100644 index 00000000000..9050c33691b --- /dev/null +++ b/pkg/front_end/testcases/none/issue_63440.dart @@ -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; +} \ No newline at end of file diff --git a/pkg/front_end/testcases/none/issue_63440.dart.strong.expect b/pkg/front_end/testcases/none/issue_63440.dart.strong.expect new file mode 100644 index 00000000000..5f25a9ef1b5 --- /dev/null +++ b/pkg/front_end/testcases/none/issue_63440.dart.strong.expect @@ -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; +} diff --git a/pkg/front_end/testcases/none/issue_63440.dart.strong.modular.expect b/pkg/front_end/testcases/none/issue_63440.dart.strong.modular.expect new file mode 100644 index 00000000000..5f25a9ef1b5 --- /dev/null +++ b/pkg/front_end/testcases/none/issue_63440.dart.strong.modular.expect @@ -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; +} diff --git a/pkg/front_end/testcases/none/issue_63440.dart.strong.outline.expect b/pkg/front_end/testcases/none/issue_63440.dart.strong.outline.expect new file mode 100644 index 00000000000..5a4f2dc56e4 --- /dev/null +++ b/pkg/front_end/testcases/none/issue_63440.dart.strong.outline.expect @@ -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 + ; diff --git a/pkg/front_end/testcases/none/issue_63440.dart.strong.transformed.expect b/pkg/front_end/testcases/none/issue_63440.dart.strong.transformed.expect new file mode 100644 index 00000000000..5f25a9ef1b5 --- /dev/null +++ b/pkg/front_end/testcases/none/issue_63440.dart.strong.transformed.expect @@ -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; +} diff --git a/pkg/front_end/testcases/none/issue_63440.dart.textual_outline.expect b/pkg/front_end/testcases/none/issue_63440.dart.textual_outline.expect new file mode 100644 index 00000000000..25f37f488c8 --- /dev/null +++ b/pkg/front_end/testcases/none/issue_63440.dart.textual_outline.expect @@ -0,0 +1,8 @@ +mixin M { + final c = 1; + void set c(int _) {} +} + +class MA = Object with M; + +void hello() {} diff --git a/pkg/front_end/testcases/none/issue_63440.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/none/issue_63440.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..530858a2ab7 --- /dev/null +++ b/pkg/front_end/testcases/none/issue_63440.dart.textual_outline_modelled.expect @@ -0,0 +1,8 @@ +class MA = Object with M; + +mixin M { + final c = 1; + void set c(int _) {} +} + +void hello() {} diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status index f1377469307..9aab2473241 100644 --- a/pkg/front_end/testcases/strong.status +++ b/pkg/front_end/testcases/strong.status @@ -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 diff --git a/pkg/vm/lib/modular/transformations/mixin_full_resolution.dart b/pkg/vm/lib/modular/transformations/mixin_full_resolution.dart index 1503f46dce5..c736449d361 100644 --- a/pkg/vm/lib/modular/transformations/mixin_full_resolution.dart +++ b/pkg/vm/lib/modular/transformations/mixin_full_resolution.dart @@ -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);