mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 14:59:41 +00:00
[CFE] Expression compilation: Use static type for extension types
This - combiend with sending the scriptUri and offset - allows us to expression evaluate stuff on extension types. Change-Id: I0db6c1f52ad3db4ce1a1a2a721e8f3e70033f9ec Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/339900 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Jens Johansen <jensj@google.com>
This commit is contained in:
parent
85cb56dd20
commit
f5743b9f44
|
@ -25,6 +25,8 @@ import 'package:kernel/canonical_name.dart'
|
|||
show CanonicalNameError, CanonicalNameSdkError;
|
||||
import 'package:kernel/class_hierarchy.dart'
|
||||
show ClassHierarchy, ClosedWorldClassHierarchy;
|
||||
import 'package:kernel/dart_scope_calculator.dart'
|
||||
show DartScope, DartScopeBuilder2;
|
||||
import 'package:kernel/kernel.dart'
|
||||
show
|
||||
Class,
|
||||
|
@ -32,12 +34,14 @@ import 'package:kernel/kernel.dart'
|
|||
DartType,
|
||||
Expression,
|
||||
Extension,
|
||||
ExtensionType,
|
||||
FunctionNode,
|
||||
Library,
|
||||
LibraryDependency,
|
||||
LibraryPart,
|
||||
Name,
|
||||
NamedNode,
|
||||
Node,
|
||||
NonNullableByDefaultCompiledMode,
|
||||
Procedure,
|
||||
ProcedureKind,
|
||||
|
@ -47,7 +51,9 @@ import 'package:kernel/kernel.dart'
|
|||
Supertype,
|
||||
TreeNode,
|
||||
TypeParameter,
|
||||
VariableDeclaration;
|
||||
VariableDeclaration,
|
||||
VisitorDefault,
|
||||
VisitorVoidMixin;
|
||||
import 'package:kernel/kernel.dart' as kernel show Combinator;
|
||||
import 'package:kernel/target/changed_structure_notifier.dart'
|
||||
show ChangedStructureNotifier;
|
||||
|
@ -1789,22 +1795,52 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
|
|||
@override
|
||||
Future<Procedure?> compileExpression(
|
||||
String expression,
|
||||
Map<String, DartType> definitions,
|
||||
Map<String, DartType> inputDefinitions,
|
||||
List<TypeParameter> typeDefinitions,
|
||||
String syntheticProcedureName,
|
||||
Uri libraryUri, {
|
||||
String? className,
|
||||
String? methodName,
|
||||
int offset = -1,
|
||||
int offset = TreeNode.noOffset,
|
||||
String? scriptUri,
|
||||
bool isStatic = false,
|
||||
}) async {
|
||||
IncrementalKernelTarget? lastGoodKernelTarget = this._lastGoodKernelTarget;
|
||||
assert(_dillLoadedData != null && lastGoodKernelTarget != null);
|
||||
Map<String, DartType> usedDefinitions =
|
||||
new Map<String, DartType>.of(inputDefinitions);
|
||||
|
||||
return await context.runInContext((_) async {
|
||||
LibraryBuilder libraryBuilder =
|
||||
lastGoodKernelTarget!.loader.readAsEntryPoint(libraryUri);
|
||||
|
||||
if (scriptUri != null && offset != TreeNode.noOffset) {
|
||||
Uri? scriptUriAsUri = Uri.tryParse(scriptUri);
|
||||
if (scriptUriAsUri != null) {
|
||||
Library library = libraryBuilder.library;
|
||||
Class? cls;
|
||||
if (className != null) {
|
||||
for (Class c in library.classes) {
|
||||
if (c.name == className) {
|
||||
cls = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
DartScope foundScope = DartScopeBuilder2.findScopeFromOffsetAndClass(
|
||||
library, scriptUriAsUri, cls, offset);
|
||||
// For now, if any definition is (or contains) an Extension Type,
|
||||
// we'll overwrite the given (runtime?) definitions so we know about
|
||||
// the extension type.
|
||||
for (MapEntry<String, DartType> def
|
||||
in foundScope.definitions.entries) {
|
||||
if (_ExtensionTypeFinder.isOrContainsExtensionType(def.value)) {
|
||||
usedDefinitions[def.key] = def.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ticker.logMs("Loaded library $libraryUri");
|
||||
|
||||
Class? cls;
|
||||
|
@ -1854,7 +1890,7 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
|
|||
}
|
||||
}
|
||||
int index = 0;
|
||||
for (String name in definitions.keys) {
|
||||
for (String name in usedDefinitions.keys) {
|
||||
index++;
|
||||
if (!(isLegalIdentifier(name) ||
|
||||
(extension != null &&
|
||||
|
@ -1961,9 +1997,9 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
|
|||
// https://github.com/dart-lang/sdk/issues/44158
|
||||
FunctionNode parameters = new FunctionNode(null,
|
||||
typeParameters: typeDefinitions,
|
||||
positionalParameters: definitions.keys
|
||||
.map<VariableDeclaration>((name) =>
|
||||
new VariableDeclarationImpl(name, type: definitions[name])
|
||||
positionalParameters: usedDefinitions.entries
|
||||
.map<VariableDeclaration>((MapEntry<String, DartType> def) =>
|
||||
new VariableDeclarationImpl(def.key, type: def.value)
|
||||
..fileOffset = cls?.fileOffset ??
|
||||
extension?.fileOffset ??
|
||||
libraryBuilder.library.fileOffset)
|
||||
|
@ -2219,6 +2255,28 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
class _ExtensionTypeFinder extends VisitorDefault<void> with VisitorVoidMixin {
|
||||
static bool isOrContainsExtensionType(DartType type) {
|
||||
if (type is ExtensionType) return true;
|
||||
_ExtensionTypeFinder finder = new _ExtensionTypeFinder();
|
||||
type.accept(finder);
|
||||
return finder._foundExtensionType;
|
||||
}
|
||||
|
||||
@override
|
||||
void visitExtensionType(ExtensionType node) {
|
||||
_foundExtensionType = true;
|
||||
}
|
||||
|
||||
@override
|
||||
void defaultNode(Node node) {
|
||||
if (_foundExtensionType) return;
|
||||
node.visitChildren(this);
|
||||
}
|
||||
|
||||
bool _foundExtensionType = false;
|
||||
}
|
||||
|
||||
/// Translate a parts "partUri" to an actual uri with handling of invalid uris.
|
||||
///
|
||||
/// ```
|
||||
|
|
|
@ -40,6 +40,7 @@ import "package:kernel/ast.dart"
|
|||
Library,
|
||||
Member,
|
||||
Procedure,
|
||||
TreeNode,
|
||||
TypeParameter;
|
||||
import 'package:kernel/target/targets.dart' show TargetFlags;
|
||||
import 'package:kernel/text/ast_to_text.dart' show Printer;
|
||||
|
@ -152,6 +153,10 @@ class TestCase {
|
|||
|
||||
final String? methodName;
|
||||
|
||||
final int? offset;
|
||||
|
||||
final String? scriptUri;
|
||||
|
||||
String expression;
|
||||
|
||||
List<CompilationResult> results = [];
|
||||
|
@ -169,6 +174,8 @@ class TestCase {
|
|||
this.library,
|
||||
this.className,
|
||||
this.methodName,
|
||||
this.offset,
|
||||
this.scriptUri,
|
||||
this.expression);
|
||||
|
||||
@override
|
||||
|
@ -266,6 +273,8 @@ class ReadTest extends Step<TestDescription, List<TestCase>, Context> {
|
|||
Uri? library;
|
||||
String? className;
|
||||
String? methodName;
|
||||
int? offset;
|
||||
String? scriptUri;
|
||||
String? expression;
|
||||
|
||||
dynamic maps = loadYamlNode(contents, sourceUrl: uri);
|
||||
|
@ -310,6 +319,11 @@ class ReadTest extends Step<TestDescription, List<TestCase>, Context> {
|
|||
isStaticMethod = value;
|
||||
} else if (key == "expression") {
|
||||
expression = value;
|
||||
} else if (key == "offset") {
|
||||
offset = value;
|
||||
} else if (key == "scriptUri") {
|
||||
Uri uri = entryPoint.resolveUri(Uri.parse(value as String));
|
||||
scriptUri = uri.toString();
|
||||
} else {
|
||||
throw new UnsupportedError("Unknown key: ${key}");
|
||||
}
|
||||
|
@ -332,6 +346,8 @@ class ReadTest extends Step<TestDescription, List<TestCase>, Context> {
|
|||
library,
|
||||
className,
|
||||
methodName,
|
||||
offset,
|
||||
scriptUri,
|
||||
expression);
|
||||
tests.add(test);
|
||||
}
|
||||
|
@ -386,6 +402,8 @@ class CompileExpression extends Step<List<TestCase>, List<TestCase>, Context> {
|
|||
className: test.className,
|
||||
methodName: test.methodName,
|
||||
isStatic: test.isStaticMethod,
|
||||
scriptUri: test.scriptUri,
|
||||
offset: test.offset ?? TreeNode.noOffset,
|
||||
);
|
||||
List<DiagnosticMessage> errors = context.takeErrors();
|
||||
test.results.add(new CompilationResult(compiledProcedure, errors));
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# Copyright (c) 2023, 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.
|
||||
|
||||
sources: |
|
||||
//@dart=3.3
|
||||
|
||||
void main() {
|
||||
Foo f = new Foo(42);
|
||||
print(f);
|
||||
print(f.value);
|
||||
f.printValue();
|
||||
f.printThis();
|
||||
}
|
||||
|
||||
extension type Foo(int value) {
|
||||
void printValue() {
|
||||
print("This foos value is '$value'");
|
||||
}
|
||||
void printThis() {
|
||||
print("This foos this value is '$this'");
|
||||
}
|
||||
}
|
||||
|
||||
definitions: ["f"]
|
||||
# int
|
||||
definition_types: ["dart:core", "int", "1", "0"]
|
||||
type_definitions: []
|
||||
type_bounds: []
|
||||
type_defaults: []
|
||||
method: "main"
|
||||
static: true
|
||||
offset: 64 # at the start of the 'print(f.value);' line.
|
||||
scriptUri: main.dart
|
||||
expression: |
|
||||
f.value
|
|
@ -0,0 +1,4 @@
|
|||
Errors: {
|
||||
}
|
||||
static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(#lib1::Foo /* = dart.core::int */ f) → dynamic
|
||||
return f as{Unchecked} dart.core::int;
|
|
@ -0,0 +1,51 @@
|
|||
# Copyright (c) 2023, 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.
|
||||
|
||||
sources:
|
||||
foo.dart: |
|
||||
//@dart=3.3
|
||||
part 'bar.dart';
|
||||
|
||||
void foo() {
|
||||
Foo x = new Foo(42);
|
||||
print(x);
|
||||
print(x.value);
|
||||
x.printFoo();
|
||||
}
|
||||
|
||||
extension type Foo(int value) {
|
||||
void printFoo() {
|
||||
print("This foos value is '$value'");
|
||||
}
|
||||
}
|
||||
bar.dart: |
|
||||
//@dart=3.3
|
||||
part of 'foo.dart';
|
||||
|
||||
void bar() {
|
||||
Bar x = new Bar('');
|
||||
print(x);
|
||||
print(x.value);
|
||||
x.printBar();
|
||||
}
|
||||
|
||||
extension type Bar(String value) {
|
||||
void printBar() {
|
||||
print("This bars value is '$value'");
|
||||
}
|
||||
}
|
||||
|
||||
definitions: ["x"]
|
||||
# String
|
||||
definition_types: ["dart:core", "String", "1", "0"]
|
||||
type_definitions: []
|
||||
type_bounds: []
|
||||
type_defaults: []
|
||||
entry_point: "foo.dart" # the main library
|
||||
method: "main"
|
||||
static: true
|
||||
offset: 83 # at the start of the 'print(x.value);' line. In both files!
|
||||
scriptUri: bar.dart
|
||||
expression: |
|
||||
x.printBar()
|
|
@ -0,0 +1,4 @@
|
|||
Errors: {
|
||||
}
|
||||
static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(#lib1::Bar /* = dart.core::String */ x) → dynamic
|
||||
return #lib1::Bar|printBar(x);
|
|
@ -0,0 +1,51 @@
|
|||
# Copyright (c) 2023, 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.
|
||||
|
||||
sources:
|
||||
foo.dart: |
|
||||
//@dart=3.3
|
||||
part 'bar.dart';
|
||||
|
||||
void foo() {
|
||||
Foo x = new Foo(42);
|
||||
print(x);
|
||||
print(x.value);
|
||||
x.printFoo();
|
||||
}
|
||||
|
||||
extension type Foo(int value) {
|
||||
void printFoo() {
|
||||
print("This foos value is '$value'");
|
||||
}
|
||||
}
|
||||
bar.dart: |
|
||||
//@dart=3.3
|
||||
part of 'foo.dart';
|
||||
|
||||
void bar() {
|
||||
Bar x = new Bar('');
|
||||
print(x);
|
||||
print(x.value);
|
||||
x.printBar();
|
||||
}
|
||||
|
||||
extension type Bar(String value) {
|
||||
void printBar() {
|
||||
print("This bars value is '$value'");
|
||||
}
|
||||
}
|
||||
|
||||
definitions: ["x"]
|
||||
# int
|
||||
definition_types: ["dart:core", "int", "1", "0"]
|
||||
type_definitions: []
|
||||
type_bounds: []
|
||||
type_defaults: []
|
||||
entry_point: "foo.dart" # the main library
|
||||
method: "main"
|
||||
static: true
|
||||
offset: 83 # at the start of the 'print(x.value);' line. In both files!
|
||||
scriptUri: foo.dart
|
||||
expression: |
|
||||
x.printFoo()
|
|
@ -0,0 +1,4 @@
|
|||
Errors: {
|
||||
}
|
||||
static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(#lib1::Foo /* = dart.core::int */ x) → dynamic
|
||||
return #lib1::Foo|printFoo(x);
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright (c) 2023, 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.
|
||||
|
||||
sources: |
|
||||
//@dart=3.3
|
||||
|
||||
void main() {
|
||||
Foo f = new Foo(42);
|
||||
List<Foo> foos = [f];
|
||||
foos.first.printValue();
|
||||
}
|
||||
|
||||
extension type Foo(int value) {
|
||||
void printValue() {
|
||||
print("This foos value is '$value'");
|
||||
}
|
||||
}
|
||||
|
||||
definitions: ["f", "foos"]
|
||||
# int, List<int>
|
||||
definition_types: ["dart:core", "int", "1", "0", "dart:core", "List", "1", "1", "dart:core", "int", "1", "0"]
|
||||
type_definitions: []
|
||||
type_bounds: []
|
||||
type_defaults: []
|
||||
method: "main"
|
||||
static: true
|
||||
offset: 76 # at the start of the 'foos.first.printValue();' line.
|
||||
scriptUri: main.dart
|
||||
expression: |
|
||||
foos.first.value
|
|
@ -0,0 +1,4 @@
|
|||
Errors: {
|
||||
}
|
||||
static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(#lib1::Foo /* = dart.core::int */ f, dart.core::List<#lib1::Foo /* = dart.core::int */> foos) → dynamic
|
||||
return foos.{dart.core::Iterable::first}{#lib1::Foo% /* = dart.core::int */} as{Unchecked} dart.core::int;
|
Loading…
Reference in a new issue