[vm, dynamic_modules] Support extensions and extension types in dynamic interface annotator
TEST=pkg/vm/test/transformations/dynamic_interface_annotator_test.dart Bug: b/404399018 Change-Id: I9b4baafc0c75b62f4fe15cb1191f0e31669a8538 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/416340 Reviewed-by: Nate Biggs <natebiggs@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
committed by
Commit Queue
parent
55d57541cb
commit
2ac7957077
@@ -0,0 +1,16 @@
|
||||
# Copyright (c) 2025, 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.
|
||||
|
||||
callable:
|
||||
- library: 'shared/shared.dart'
|
||||
# TODO(sigmund): This should be included by default
|
||||
- library: 'dart:core'
|
||||
class: 'Object'
|
||||
- library: 'dart:core'
|
||||
class: 'int'
|
||||
- library: 'dart:core'
|
||||
class: 'String'
|
||||
- library: 'dart:core'
|
||||
class: 'pragma'
|
||||
member: '_'
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2025, 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 '../../common/testing.dart' as helper;
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
import 'shared/shared.dart'; // ignore: unused_import
|
||||
|
||||
/// A dynamic module is allowed to extend a class in the dynamic interface and
|
||||
/// override its members.
|
||||
void main() async {
|
||||
final result = (await helper.load('entry1.dart')) as String;
|
||||
Expect.equals('abcdef42', result);
|
||||
helper.done();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2025, 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 '../shared/shared.dart';
|
||||
|
||||
@pragma('dyn-module:entry-point')
|
||||
Object? dynamicModuleEntrypoint() =>
|
||||
'abc'.addSuffix('def') + MyExtensionType.foo(42).info.toString();
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2025, 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.
|
||||
|
||||
extension type MyExtensionType.foo(int _info) {
|
||||
int get info => _info;
|
||||
}
|
||||
|
||||
extension MyExtension on String {
|
||||
String addSuffix(String suffix) => this + suffix;
|
||||
}
|
||||
@@ -152,6 +152,16 @@ class _Annotator extends RecursiveVisitor {
|
||||
c.accept(this);
|
||||
}
|
||||
}
|
||||
for (final ext in node.extensions) {
|
||||
if (ext.name[0] != '_') {
|
||||
ext.accept(this);
|
||||
}
|
||||
}
|
||||
for (final extensionType in node.extensionTypeDeclarations) {
|
||||
if (extensionType.name[0] != '_') {
|
||||
extensionType.accept(this);
|
||||
}
|
||||
}
|
||||
for (final exportRef in node.additionalExports) {
|
||||
exportRef.node!.accept(this);
|
||||
}
|
||||
@@ -207,6 +217,34 @@ class _Annotator extends RecursiveVisitor {
|
||||
node.addAnnotation(ConstantExpression(pragma));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitExtension(Extension node) {
|
||||
for (final md in node.memberDescriptors) {
|
||||
final member = md.memberReference?.node;
|
||||
if (member != null) {
|
||||
annotateMember(member as Member);
|
||||
}
|
||||
final tearOff = md.tearOffReference?.node;
|
||||
if (tearOff != null) {
|
||||
annotateMember(tearOff as Member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitExtensionTypeDeclaration(ExtensionTypeDeclaration node) {
|
||||
for (final md in node.memberDescriptors) {
|
||||
final member = md.memberReference?.node;
|
||||
if (member != null) {
|
||||
annotateMember(member as Member);
|
||||
}
|
||||
final tearOff = md.tearOffReference?.node;
|
||||
if (tearOff != null) {
|
||||
annotateMember(tearOff as Member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _ImplicitExtendableAnnotator {
|
||||
|
||||
@@ -9,12 +9,14 @@ callable:
|
||||
member: sfield9
|
||||
- library: 'lib3.dart'
|
||||
class: ['A', 'B']
|
||||
- library: 'lib4.dart'
|
||||
- library: 'prefix/lib*'
|
||||
|
||||
extendable:
|
||||
- library: 'lib1.dart'
|
||||
class: ['A', 'O', 'Q', 'S', 'T', 'V']
|
||||
- library: 'lib2.dart'
|
||||
- library: 'lib4.dart'
|
||||
|
||||
can-be-overridden:
|
||||
- library: 'lib1.dart'
|
||||
@@ -22,3 +24,4 @@ can-be-overridden:
|
||||
- library: 'lib2.dart'
|
||||
class: 'D'
|
||||
member: 'build'
|
||||
- library: 'lib4.dart'
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2025, 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.
|
||||
|
||||
export 'lib5.dart';
|
||||
|
||||
extension type E3(int _info) {
|
||||
int get info => _info;
|
||||
}
|
||||
|
||||
extension type _E4(int _info) {
|
||||
int get info => _info;
|
||||
}
|
||||
|
||||
extension E5 on String {
|
||||
String addSuffix1(String suffix) => this + suffix;
|
||||
}
|
||||
|
||||
extension _E6 on String {
|
||||
String addSuffix2(String suffix) => this + suffix;
|
||||
}
|
||||
|
||||
extension on String {
|
||||
String addSuffix3(String suffix) => this + suffix;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "lib5.dart" as lib5;
|
||||
additionalExports = (lib5::E1,
|
||||
lib5::E2)
|
||||
|
||||
export "file:pkg/vm/testcases/transformations/dynamic_interface_annotator/lib5.dart";
|
||||
|
||||
extension E5 on core::String {
|
||||
method addSuffix1 = self::E5|addSuffix1;
|
||||
method tearoff addSuffix1 = self::E5|get#addSuffix1;
|
||||
}
|
||||
extension _E6 on core::String {
|
||||
method addSuffix2 = self::_E6|addSuffix2;
|
||||
method tearoff addSuffix2 = self::_E6|get#addSuffix2;
|
||||
}
|
||||
extension /* unnamed */ _extension#2 on core::String {
|
||||
method addSuffix3 = self::_extension#2|addSuffix3;
|
||||
method tearoff addSuffix3 = self::_extension#2|get#addSuffix3;
|
||||
}
|
||||
extension type E3(core::int _info) {
|
||||
abstract extension-type-member representation-field get _info() → core::int;
|
||||
get info = self::E3|get#info;
|
||||
constructor • = self::E3|constructor#;
|
||||
constructor tearoff • = self::E3|constructor#_#new#tearOff;
|
||||
}
|
||||
extension type _E4(core::int _info) {
|
||||
abstract extension-type-member representation-field get _info() → core::int;
|
||||
get info = self::_E4|get#info;
|
||||
constructor • = self::_E4|constructor#;
|
||||
constructor tearoff • = self::_E4|constructor#_#new#tearOff;
|
||||
}
|
||||
@#C3
|
||||
static extension-type-member method E3|constructor#(core::int _info) → self::E3% /* erasure=core::int, declared=! */ {
|
||||
lowered final self::E3% /* erasure=core::int, declared=! */ #this = _info;
|
||||
return #this;
|
||||
}
|
||||
@#C3
|
||||
static extension-type-member method E3|constructor#_#new#tearOff(core::int _info) → self::E3% /* erasure=core::int, declared=! */
|
||||
return self::E3|constructor#(_info);
|
||||
@#C3
|
||||
static extension-type-member method E3|get#info(lowered final self::E3% /* erasure=core::int, declared=! */ #this) → core::int
|
||||
return #this as{Unchecked} core::int;
|
||||
static extension-type-member method _E4|constructor#(core::int _info) → self::_E4% /* erasure=core::int, declared=! */ {
|
||||
lowered final self::_E4% /* erasure=core::int, declared=! */ #this = _info;
|
||||
return #this;
|
||||
}
|
||||
static extension-type-member method _E4|constructor#_#new#tearOff(core::int _info) → self::_E4% /* erasure=core::int, declared=! */
|
||||
return self::_E4|constructor#(_info);
|
||||
static extension-type-member method _E4|get#info(lowered final self::_E4% /* erasure=core::int, declared=! */ #this) → core::int
|
||||
return #this as{Unchecked} core::int;
|
||||
@#C3
|
||||
static extension-member method E5|addSuffix1(lowered final core::String #this, core::String suffix) → core::String
|
||||
return #this.{core::String::+}(suffix){(core::String) → core::String};
|
||||
@#C3
|
||||
static extension-member method E5|get#addSuffix1(lowered final core::String #this) → (core::String) → core::String
|
||||
return (core::String suffix) → core::String => self::E5|addSuffix1(#this, suffix);
|
||||
static extension-member method _E6|addSuffix2(lowered final core::String #this, core::String suffix) → core::String
|
||||
return #this.{core::String::+}(suffix){(core::String) → core::String};
|
||||
static extension-member method _E6|get#addSuffix2(lowered final core::String #this) → (core::String) → core::String
|
||||
return (core::String suffix) → core::String => self::_E6|addSuffix2(#this, suffix);
|
||||
static extension-member method _extension#2|addSuffix3(lowered final core::String #this, core::String suffix) → core::String
|
||||
return #this.{core::String::+}(suffix){(core::String) → core::String};
|
||||
static extension-member method _extension#2|get#addSuffix3(lowered final core::String #this) → (core::String) → core::String
|
||||
return (core::String suffix) → core::String => self::_extension#2|addSuffix3(#this, suffix);
|
||||
constants {
|
||||
#C1 = "dyn-module:callable"
|
||||
#C2 = null
|
||||
#C3 = core::pragma {name:#C1, options:#C2}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2025, 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.
|
||||
|
||||
extension type E1._(int _info) {
|
||||
int get info => _info;
|
||||
}
|
||||
|
||||
extension E2 on String {
|
||||
int get lastChar => codeUnitAt(length - 1);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
extension E2 on core::String {
|
||||
get lastChar = self::E2|get#lastChar;
|
||||
}
|
||||
extension type E1(core::int _info) {
|
||||
abstract extension-type-member representation-field get _info() → core::int;
|
||||
get info = self::E1|get#info;
|
||||
constructor _ = self::E1|constructor#_;
|
||||
constructor tearoff _ = self::E1|constructor#_#_#tearOff;
|
||||
}
|
||||
@#C3
|
||||
static extension-type-member method E1|constructor#_(core::int _info) → self::E1% /* erasure=core::int, declared=! */ {
|
||||
lowered final self::E1% /* erasure=core::int, declared=! */ #this = _info;
|
||||
return #this;
|
||||
}
|
||||
@#C3
|
||||
static extension-type-member method E1|constructor#_#_#tearOff(core::int _info) → self::E1% /* erasure=core::int, declared=! */
|
||||
return self::E1|constructor#_(_info);
|
||||
@#C3
|
||||
static extension-type-member method E1|get#info(lowered final self::E1% /* erasure=core::int, declared=! */ #this) → core::int
|
||||
return #this as{Unchecked} core::int;
|
||||
@#C3
|
||||
static extension-member method E2|get#lastChar(lowered final core::String #this) → core::int
|
||||
return #this.{core::String::codeUnitAt}(#this.{core::String::length}{core::int}.{core::num::-}(1){(core::num) → core::int}){(core::int) → core::int};
|
||||
constants {
|
||||
#C1 = "dyn-module:callable"
|
||||
#C2 = null
|
||||
#C3 = core::pragma {name:#C1, options:#C2}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
import 'lib1.dart';
|
||||
import 'lib2.dart';
|
||||
import 'lib3.dart';
|
||||
import 'lib4.dart';
|
||||
import 'prefix/lib1.dart';
|
||||
import 'prefix/lib2.dart';
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import self as self;
|
||||
import "file:pkg/vm/testcases/transformations/dynamic_interface_annotator/lib1.dart";
|
||||
import "file:pkg/vm/testcases/transformations/dynamic_interface_annotator/lib2.dart";
|
||||
import "file:pkg/vm/testcases/transformations/dynamic_interface_annotator/lib3.dart";
|
||||
import "file:pkg/vm/testcases/transformations/dynamic_interface_annotator/lib4.dart";
|
||||
import "file:pkg/vm/testcases/transformations/dynamic_interface_annotator/prefix/lib1.dart";
|
||||
import "file:pkg/vm/testcases/transformations/dynamic_interface_annotator/prefix/lib2.dart";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user