[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:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
69e9d32e87
commit
d441e28656
@@ -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() {}
|
||||
+8
@@ -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() {}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user