[record_use] Static getters and setters
Closes: https://github.com/dart-lang/native/issues/2906 TEST=pkg/compiler/test/record_use/record_use_test.dart TEST=pkg/dart2wasm/test/record_use_test.dart TEST=pkg/vm/test/transformations/record_use_test.dart Change-Id: I8c3591e9896b90ca9b26b96506834556a221d47d Cq-Include-Trybots: luci.dart.try:dart2wasm-asserts-linux-chrome-try,dart2wasm-asserts-minified-linux-d8-try,dart2wasm-linux-chrome-try,dart2wasm-linux-d8-try,dart2wasm-linux-firefox-try,dart2wasm-linux-jscm-chrome-try,dart2wasm-linux-optimized-jsc-try,pkg-linux-debug-try,pkg-linux-release-arm64-try,pkg-linux-release-try,pkg-mac-release-arm64-try,pkg-mac-release-try,pkg-win-release-arm64-try,pkg-win-release-try,dart2js-canary-linux-try,dart2js-hostasserts-linux-d8-try,dart2js-linux-chrome-try,dart2js-linux-firefox-try,dart2js-mac-chrome-try,dart2js-mac-safari-try,dart2js-minified-csp-linux-chrome-try,dart2js-minified-linux-d8-try,dart2js-unit-linux-x64-release-try,dart2js-win-chrome-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/483580 Reviewed-by: Michael Goderbauer <goderbauer@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Nate Biggs <natebiggs@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
committed by
Commit Queue
parent
f125fd9d08
commit
8457c9dc3b
@@ -2377,8 +2377,22 @@ class SsaCodeGenerator implements HVisitor<void>, HBlockInformationVisitor {
|
||||
staticUse = StaticUse.constructorInvoke(element, callStructure);
|
||||
} else if (element.isGetter) {
|
||||
staticUse = StaticUse.staticGet(element);
|
||||
if (_shouldRecordMethodUses(element)) {
|
||||
recordedMethodUses = _recordMethodUses(
|
||||
element,
|
||||
node.inputs,
|
||||
node.sourceInformation!,
|
||||
);
|
||||
}
|
||||
} else if (element.isSetter) {
|
||||
staticUse = StaticUse.staticSet(element);
|
||||
if (_shouldRecordMethodUses(element)) {
|
||||
recordedMethodUses = _recordMethodUses(
|
||||
element,
|
||||
node.inputs,
|
||||
node.sourceInformation!,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
assert(element.isFunction);
|
||||
CallStructure callStructure = CallStructure.unnamed(
|
||||
|
||||
@@ -148,13 +148,13 @@ void _validateRecordUseDeclaration(
|
||||
);
|
||||
}
|
||||
|
||||
final bool onNonStaticMethod =
|
||||
node is! Procedure || !node.isStatic || node.kind != ProcedureKind.Method;
|
||||
final bool onStaticMethod =
|
||||
node is Procedure && node.isStatic && node.kind != ProcedureKind.Factory;
|
||||
|
||||
final bool onClassWithoutConstConstructor =
|
||||
node is! Class ||
|
||||
!node.constructors.any((constructor) => constructor.isConst);
|
||||
if (onNonStaticMethod && onClassWithoutConstConstructor) {
|
||||
if (!onStaticMethod && onClassWithoutConstConstructor) {
|
||||
errorReporter.report(
|
||||
diag.recordUseCannotBePlacedHere.withLocation(
|
||||
fileUri,
|
||||
|
||||
@@ -36,6 +36,36 @@ class CallRecorder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Will record a static get if it is annotated with `@RecordUse`.
|
||||
void recordStaticGet(ast.StaticGet node) {
|
||||
final target = node.target;
|
||||
if (target is ast.Procedure && isBeingRecorded(target)) {
|
||||
_addToUsage(
|
||||
target,
|
||||
CallWithArguments(
|
||||
positionalArguments: [],
|
||||
namedArguments: {},
|
||||
loadingUnits: [_loadingUnitLookup(node)],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Will record a static set if it is annotated with `@RecordUse`.
|
||||
void recordStaticSet(ast.StaticSet node) {
|
||||
final target = node.target;
|
||||
if (target is ast.Procedure && isBeingRecorded(target)) {
|
||||
_addToUsage(
|
||||
target,
|
||||
CallWithArguments(
|
||||
positionalArguments: [_evaluateLiteral(node.value)],
|
||||
namedArguments: {},
|
||||
loadingUnits: [_loadingUnitLookup(node)],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Will record a tear-off if the target is annotated with `@RecordUse`.
|
||||
void recordConstantExpression(ast.ConstantExpression node) {
|
||||
final constant = node.constant;
|
||||
|
||||
@@ -94,6 +94,24 @@ class _RecordUseVisitor extends ast.RecursiveVisitor {
|
||||
super.visitStaticInvocation(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitStaticGet(ast.StaticGet node) {
|
||||
if (_isAnnotation(node)) return;
|
||||
|
||||
staticCallRecorder.recordStaticGet(node);
|
||||
|
||||
super.visitStaticGet(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitStaticSet(ast.StaticSet node) {
|
||||
if (_isAnnotation(node)) return;
|
||||
|
||||
staticCallRecorder.recordStaticSet(node);
|
||||
|
||||
super.visitStaticSet(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitConstantExpression(ast.ConstantExpression node) {
|
||||
if (_isAnnotation(node)) return;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// 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.
|
||||
|
||||
import 'package:meta/meta.dart' show RecordUse;
|
||||
|
||||
class SomeClass {
|
||||
@RecordUse()
|
||||
static int get someStaticGetter => 42;
|
||||
|
||||
@RecordUse()
|
||||
static set someStaticSetter(int value) {}
|
||||
}
|
||||
|
||||
@RecordUse()
|
||||
int get someTopLevelGetter => 42;
|
||||
|
||||
@RecordUse()
|
||||
set someTopLevelSetter(int value) {}
|
||||
|
||||
void main() {
|
||||
print(SomeClass.someStaticGetter);
|
||||
SomeClass.someStaticSetter = 123;
|
||||
print(someTopLevelGetter);
|
||||
someTopLevelSetter = 456;
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
library #lib;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:meta/meta.dart" as meta;
|
||||
|
||||
import "package:meta/meta.dart" show RecordUse;
|
||||
|
||||
abstract class SomeClass extends core::Object {
|
||||
|
||||
[@vm.inferred-return-type.metadata=dart.core::_Smi (value: 42)]
|
||||
[@vm.unboxing-info.metadata=()->i]
|
||||
@#C1
|
||||
static get someStaticGetter() → core::int
|
||||
return 42;
|
||||
|
||||
[@vm.unboxing-info.metadata=(i)->b]
|
||||
@#C1
|
||||
static set someStaticSetter([@vm.inferred-arg-type.metadata=dart.core::_Smi (value: 123)] core::int value) → void {}
|
||||
}
|
||||
|
||||
[@vm.inferred-return-type.metadata=dart.core::_Smi (value: 42)]
|
||||
[@vm.unboxing-info.metadata=()->i]
|
||||
@#C1
|
||||
static get someTopLevelGetter() → core::int
|
||||
return 42;
|
||||
|
||||
[@vm.unboxing-info.metadata=(i)->b]
|
||||
@#C1
|
||||
static set someTopLevelSetter([@vm.inferred-arg-type.metadata=dart.core::_Smi (value: 456)] core::int value) → void {}
|
||||
|
||||
[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)]
|
||||
static method main() → void {
|
||||
core::print([@vm.inferred-type.metadata=dart.core::_Smi (value: 42)] self::SomeClass::someStaticGetter);
|
||||
self::SomeClass::someStaticSetter = 123;
|
||||
core::print([@vm.inferred-type.metadata=dart.core::_Smi (value: 42)] self::someTopLevelGetter);
|
||||
self::someTopLevelSetter = 456;
|
||||
}
|
||||
constants {
|
||||
#C1 = meta::RecordUse {}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
{
|
||||
"constants": [
|
||||
{
|
||||
"type": "int",
|
||||
"value": 123
|
||||
},
|
||||
{
|
||||
"type": "int",
|
||||
"value": 456
|
||||
}
|
||||
],
|
||||
"definitions": [
|
||||
{
|
||||
"path": [
|
||||
{
|
||||
"kind": "class",
|
||||
"name": "SomeClass"
|
||||
},
|
||||
{
|
||||
"disambiguators": [
|
||||
"static"
|
||||
],
|
||||
"kind": "getter",
|
||||
"name": "someStaticGetter"
|
||||
}
|
||||
],
|
||||
"uri": "package:record_use_test/static_getters_setters.dart"
|
||||
},
|
||||
{
|
||||
"path": [
|
||||
{
|
||||
"kind": "class",
|
||||
"name": "SomeClass"
|
||||
},
|
||||
{
|
||||
"disambiguators": [
|
||||
"static"
|
||||
],
|
||||
"kind": "setter",
|
||||
"name": "someStaticSetter"
|
||||
}
|
||||
],
|
||||
"uri": "package:record_use_test/static_getters_setters.dart"
|
||||
},
|
||||
{
|
||||
"path": [
|
||||
{
|
||||
"disambiguators": [
|
||||
"static"
|
||||
],
|
||||
"kind": "getter",
|
||||
"name": "someTopLevelGetter"
|
||||
}
|
||||
],
|
||||
"uri": "package:record_use_test/static_getters_setters.dart"
|
||||
},
|
||||
{
|
||||
"path": [
|
||||
{
|
||||
"disambiguators": [
|
||||
"static"
|
||||
],
|
||||
"kind": "setter",
|
||||
"name": "someTopLevelSetter"
|
||||
}
|
||||
],
|
||||
"uri": "package:record_use_test/static_getters_setters.dart"
|
||||
}
|
||||
],
|
||||
"loading_units": [
|
||||
{
|
||||
"name": "1"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"comment": "Recorded usages of objects tagged with a `RecordUse` annotation.",
|
||||
"version": "0.4.0"
|
||||
},
|
||||
"uses": {
|
||||
"static_calls": [
|
||||
{
|
||||
"definition_index": 0,
|
||||
"uses": [
|
||||
{
|
||||
"loading_unit_indices": [
|
||||
0
|
||||
],
|
||||
"type": "with_arguments"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"definition_index": 1,
|
||||
"uses": [
|
||||
{
|
||||
"loading_unit_indices": [
|
||||
0
|
||||
],
|
||||
"positional": [
|
||||
0
|
||||
],
|
||||
"type": "with_arguments"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"definition_index": 2,
|
||||
"uses": [
|
||||
{
|
||||
"loading_unit_indices": [
|
||||
0
|
||||
],
|
||||
"type": "with_arguments"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"definition_index": 3,
|
||||
"uses": [
|
||||
{
|
||||
"loading_unit_indices": [
|
||||
0
|
||||
],
|
||||
"positional": [
|
||||
1
|
||||
],
|
||||
"type": "with_arguments"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user