[VM] [CFE]: Make VM send over type information for expression compilation

Missing:
* Function types.
* Type variables in bounds, like "method<T, S extends T>() {}" and
  "method<T extends Foo<T>>() {}"

This is in many ways a follow-up to
https://dart-review.googlesource.com/c/sdk/+/212286

TEST=service and (cfe) expression suite tests added.

Change-Id: I20472b59ed73e9845f073e176d73b2c213f9407a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/215760
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
This commit is contained in:
Jens Johansen 2022-01-28 07:49:21 +00:00 committed by Commit Bot
parent c49ccf09f1
commit adb1dc9380
42 changed files with 1350 additions and 54 deletions

View file

@ -0,0 +1,213 @@
// Copyright (c) 2022, 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:front_end/src/api_prototype/incremental_kernel_generator.dart'
show isLegalIdentifier;
import 'package:front_end/src/api_prototype/lowering_predicates.dart'
show isExtensionThisName;
import 'package:kernel/ast.dart'
show
Class,
DartType,
DynamicType,
InterfaceType,
Library,
Nullability,
TypeParameter;
import 'package:kernel/library_index.dart' show LibraryIndex;
Map<String, DartType>? createDefinitionsWithTypes(
Iterable<Library>? knownLibraries,
List<String> definitionTypes,
List<String> definitions) {
if (knownLibraries == null) {
return null;
}
List<ParsedType> definitionTypesParsed =
parseDefinitionTypes(definitionTypes);
if (definitionTypesParsed.length != definitions.length) {
return null;
}
Set<String> libraryUris = collectParsedTypeUris(definitionTypesParsed);
LibraryIndex libraryIndex =
new LibraryIndex.fromLibraries(knownLibraries, libraryUris);
Map<String, DartType> completeDefinitions = {};
for (int i = 0; i < definitions.length; i++) {
String name = definitions[i];
if (isLegalIdentifier(name) || (i == 0 && isExtensionThisName(name))) {
ParsedType type = definitionTypesParsed[i];
DartType dartType = type.createDartType(libraryIndex);
completeDefinitions[name] = dartType;
}
}
return completeDefinitions;
}
List<TypeParameter>? createTypeParametersWithBounds(
Iterable<Library>? knownLibraries,
List<String> typeBounds,
List<String> typeDefaults,
List<String> typeDefinitions) {
if (knownLibraries == null) {
return null;
}
List<ParsedType> typeBoundsParsed = parseDefinitionTypes(typeBounds);
if (typeBoundsParsed.length != typeDefinitions.length) {
return null;
}
List<ParsedType> typeDefaultsParsed = parseDefinitionTypes(typeDefaults);
if (typeDefaultsParsed.length != typeDefinitions.length) {
return null;
}
Set<String> libraryUris = collectParsedTypeUris(typeBoundsParsed)
..addAll(collectParsedTypeUris(typeDefaultsParsed));
LibraryIndex libraryIndex =
new LibraryIndex.fromLibraries(knownLibraries, libraryUris);
List<TypeParameter> typeParameters = [];
for (int i = 0; i < typeDefinitions.length; i++) {
String name = typeDefinitions[i];
if (!isLegalIdentifier(name)) continue;
ParsedType bound = typeBoundsParsed[i];
DartType dartTypeBound = bound.createDartType(libraryIndex);
ParsedType defaultType = typeDefaultsParsed[i];
DartType dartTypeDefaultType = defaultType.createDartType(libraryIndex);
typeParameters
.add(new TypeParameter(name, dartTypeBound, dartTypeDefaultType));
}
return typeParameters;
}
List<ParsedType> parseDefinitionTypes(List<String> definitionTypes) {
List<ParsedType> result = [];
int i = 0;
List<ParsedType> argumentReceivers = [];
while (i < definitionTypes.length) {
String uriOrNullString = definitionTypes[i];
if (uriOrNullString == "null") {
if (argumentReceivers.isEmpty) {
result.add(new ParsedType.nullType());
} else {
argumentReceivers
.removeLast()
.arguments!
.add(new ParsedType.nullType());
}
i++;
continue;
} else {
// We expect at least 4 elements: Uri, class name, nullability,
// number of type arguments.
if (i + 4 > definitionTypes.length) throw "invalid input";
String className = definitionTypes[i + 1];
int nullability = int.parse(definitionTypes[i + 2]);
int typeArgumentsCount = int.parse(definitionTypes[i + 3]);
ParsedType type = new ParsedType(uriOrNullString, className, nullability);
if (argumentReceivers.isEmpty) {
result.add(type);
} else {
argumentReceivers.removeLast().arguments!.add(type);
}
for (int j = 0; j < typeArgumentsCount; j++) {
argumentReceivers.add(type);
}
i += 4;
}
}
if (argumentReceivers.isNotEmpty) {
throw "Nesting error on input $definitionTypes";
}
return result;
}
class ParsedType {
final String? uri;
final String? className;
final int? nullability;
final List<ParsedType>? arguments;
bool get isNullType => uri == null;
ParsedType(this.uri, this.className, this.nullability) : arguments = [];
ParsedType.nullType()
: uri = null,
className = null,
nullability = null,
arguments = null;
@override
bool operator ==(Object other) {
if (other is! ParsedType) return false;
if (uri != other.uri) return false;
if (className != other.className) return false;
if (nullability != other.nullability) return false;
if (arguments?.length != other.arguments?.length) return false;
if (arguments != null) {
for (int i = 0; i < arguments!.length; i++) {
if (arguments![i] != other.arguments![i]) return false;
}
}
return true;
}
@override
int get hashCode {
if (isNullType) return 0;
int hash = 0x3fffffff & uri.hashCode;
hash = 0x3fffffff & (hash * 31 + (hash ^ className.hashCode));
hash = 0x3fffffff & (hash * 31 + (hash ^ nullability.hashCode));
for (ParsedType argument in arguments!) {
hash = 0x3fffffff & (hash * 31 + (hash ^ argument.hashCode));
}
return hash;
}
@override
String toString() {
if (isNullType) return "null-type";
return "$uri[$className] ($nullability) <$arguments>";
}
DartType createDartType(LibraryIndex libraryIndex) {
if (isNullType) return new DynamicType();
Class? classNode = libraryIndex.tryGetClass(uri!, className!);
if (classNode == null) return new DynamicType();
return new InterfaceType(
classNode,
_getDartNullability(),
arguments
?.map((e) => e.createDartType(libraryIndex))
.toList(growable: false));
}
Nullability _getDartNullability() {
if (isNullType) throw "No nullability on the null type";
if (nullability == 0) return Nullability.nullable;
if (nullability == 1) return Nullability.nonNullable;
if (nullability == 2) return Nullability.legacy;
throw "Unknown nullability";
}
}
Set<String> collectParsedTypeUris(List<ParsedType> parsedTypes) {
Set<String> result = {};
List<ParsedType> workList = new List.from(parsedTypes);
while (workList.isNotEmpty) {
ParsedType type = workList.removeLast();
if (type.isNullType) continue;
result.add(type.uri!);
workList.addAll(type.arguments!);
}
return result;
}

View file

@ -18,6 +18,9 @@ export '../api_prototype/compiler_options.dart'
export '../api_prototype/experimental_flags.dart'
show defaultExperimentalFlags, ExperimentalFlag;
export '../api_prototype/expression_compilation_tools.dart'
show createDefinitionsWithTypes, createTypeParametersWithBounds;
export '../api_prototype/file_system.dart'
show FileSystem, FileSystemEntity, FileSystemException;

View file

@ -0,0 +1,135 @@
// Copyright (c) 2022, 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:expect/minitest.dart';
import 'package:front_end/src/api_prototype/expression_compilation_tools.dart';
void main() {
// null value.
expect(parseDefinitionTypes(["null"]), [new ParsedType.nullType()]);
// String, kNonNullable
expect(
parseDefinitionTypes([
"dart:core",
"_OneByteString",
"1",
"0",
]),
[new ParsedType("dart:core", "_OneByteString", 1)]);
// List<something it can't represent which thus becomes an explicit
// dynamic/null>, kNonNullable.
expect(parseDefinitionTypes(["dart:core", "List", "1", "1", "null"]), [
new ParsedType("dart:core", "List", 1)
..arguments!.add(new ParsedType.nullType())
]);
// List<int>, kNonNullable
expect(
parseDefinitionTypes([
"dart:core",
"_GrowableList",
"1",
"1",
"dart:core",
"int",
"1",
"0",
]),
[
new ParsedType("dart:core", "_GrowableList", 1)
..arguments!.add(new ParsedType("dart:core", "int", 1))
]);
// Map<int, int>, kNonNullable
expect(
parseDefinitionTypes([
"dart:core",
"Map",
"1",
"2",
"dart:core",
"int",
"1",
"0",
"dart:core",
"int",
"1",
"0",
]),
[
new ParsedType("dart:core", "Map", 1)
..arguments!.add(new ParsedType("dart:core", "int", 1))
..arguments!.add(new ParsedType("dart:core", "int", 1))
]);
// [0] = String
// [1] = int
// [2] = List<String>
// [3] = Bar
// [4] = null
// [5] = HashMap<Map<int, List<int>>, List<String>>
expect(
parseDefinitionTypes([
// String, kNonNullable, no arguments
"dart:core", "_OneByteString", "1", "0",
// Int, kNonNullable, no arguments
"dart:core", "_Smi", "1", "0",
// List, kNonNullable, 1 argument
"dart:core", "_GrowableList", "1", "1",
// -> String, kNonNullable (i.e. the above is List<String>)
/**/ "dart:core", "String", "1", "0",
// "Bar", kNonNullable, no arguments
"file://wherever/t.dart", "Bar", "1", "0",
// null value
"null",
// HashMap, kNonNullable, 2 arguments
"dart:collection", "_InternalLinkedHashMap", "1", "2",
// -> Map, kNonNullable, 2 arguments
/**/ "dart:core", "Map", "1", "2",
// -> -> int, kNonNullable, no arguments
/*/**/*/ "dart:core", "int", "1", "0",
// -> -> List, kNonNullable, 1 argument
/*/**/*/ "dart:core", "List", "1", "1",
// -> -> -> int, kNonNullable, no arguments
/*/*/**/*/*/ "dart:core", "int", "1", "0",
// -> List, kNonNullable, 1 argument
"dart:core", "List", "1", "1",
// -> -> String, kNonNullable, no arguments
"dart:core", "String", "1", "0"
]),
<ParsedType>[
// String
new ParsedType("dart:core", "_OneByteString", 1),
// int
new ParsedType("dart:core", "_Smi", 1),
// List<String>
new ParsedType("dart:core", "_GrowableList", 1)
..arguments!.addAll([
new ParsedType("dart:core", "String", 1),
]),
// Bar
new ParsedType("file://wherever/t.dart", "Bar", 1),
// null value
new ParsedType.nullType(),
// HashMap<Map<int, List<int>>, List<String>>
new ParsedType("dart:collection", "_InternalLinkedHashMap", 1)
..arguments!.addAll([
new ParsedType("dart:core", "Map", 1)
..arguments!.addAll([
new ParsedType("dart:core", "int", 1),
new ParsedType("dart:core", "List", 1)
..arguments!.addAll([
new ParsedType("dart:core", "int", 1),
]),
]),
new ParsedType("dart:core", "List", 1)
..arguments!.addAll([
new ParsedType("dart:core", "String", 1),
]),
]),
]);
}

View file

@ -16,6 +16,12 @@ import "package:front_end/src/api_prototype/compiler_options.dart"
show CompilerOptions, DiagnosticMessage;
import 'package:front_end/src/api_prototype/experimental_flags.dart';
import 'package:front_end/src/api_prototype/expression_compilation_tools.dart'
show createDefinitionsWithTypes, createTypeParametersWithBounds;
import 'package:front_end/src/api_prototype/incremental_kernel_generator.dart'
show IncrementalCompilerResult;
import "package:front_end/src/api_prototype/memory_file_system.dart"
show MemoryFileSystem;
@ -34,7 +40,7 @@ import 'package:front_end/src/fasta/incremental_compiler.dart'
show IncrementalCompiler;
import "package:kernel/ast.dart"
show Procedure, Component, DynamicType, DartType, TypeParameter;
show Component, DartType, DynamicType, Procedure, TypeParameter;
import 'package:kernel/target/targets.dart' show TargetFlags;
@ -132,8 +138,14 @@ class TestCase {
final List<String> definitions;
final List<String> definitionTypes;
final List<String> typeDefinitions;
final List<String> typeBounds;
final List<String> typeDefaults;
final bool isStaticMethod;
final Uri? library;
@ -151,7 +163,10 @@ class TestCase {
this.entryPoint,
this.import,
this.definitions,
this.definitionTypes,
this.typeDefinitions,
this.typeBounds,
this.typeDefaults,
this.isStaticMethod,
this.library,
this.className,
@ -164,7 +179,10 @@ class TestCase {
"$entryPoint, "
"$import, "
"$definitions, "
"$definitionTypes, "
"$typeDefinitions,"
"$typeBounds,"
"$typeDefaults,"
"$library, "
"$className, "
"static = $isStaticMethod)";
@ -259,7 +277,10 @@ class ReadTest extends Step<TestDescription, List<TestCase>, Context> {
Uri? entryPoint;
Uri? import;
List<String> definitions = <String>[];
List<String> definitionTypes = <String>[];
List<String> typeDefinitions = <String>[];
List<String> typeBounds = <String>[];
List<String> typeDefaults = <String>[];
bool isStaticMethod = false;
Uri? library;
String? className;
@ -289,9 +310,16 @@ class ReadTest extends Step<TestDescription, List<TestCase>, Context> {
methodName = value as String;
} else if (key == "definitions") {
definitions = (value as YamlList).map((x) => x as String).toList();
} else if (key == "definition_types") {
definitionTypes =
(value as YamlList).map((x) => x as String).toList();
} else if (key == "type_definitions") {
typeDefinitions =
(value as YamlList).map((x) => x as String).toList();
} else if (key == "type_bounds") {
typeBounds = (value as YamlList).map((x) => x as String).toList();
} else if (key == "type_defaults") {
typeDefaults = (value as YamlList).map((x) => x as String).toList();
} else if (key == "static") {
isStaticMethod = value;
} else if (key == "expression") {
@ -303,7 +331,10 @@ class ReadTest extends Step<TestDescription, List<TestCase>, Context> {
entryPoint,
import,
definitions,
definitionTypes,
typeDefinitions,
typeBounds,
typeDefaults,
isStaticMethod,
library,
className,
@ -328,15 +359,29 @@ class CompileExpression extends Step<List<TestCase>, List<TestCase>, Context> {
// Compile [test.expression], update [test.errors] with results.
// As a side effect - verify that generated procedure can be serialized.
Future<void> compileExpression(TestCase test, IncrementalCompiler compiler,
Component component, Context context) async {
Map<String, DartType> definitions = {};
for (String name in test.definitions) {
definitions[name] = new DynamicType();
IncrementalCompilerResult sourceCompilerResult, Context context) async {
Map<String, DartType>? definitions = createDefinitionsWithTypes(
sourceCompilerResult.classHierarchy?.knownLibraries,
test.definitionTypes,
test.definitions);
if (definitions == null) {
definitions = {};
for (String name in test.definitions) {
definitions[name] = new DynamicType();
}
}
List<TypeParameter> typeParams = [];
for (String name in test.typeDefinitions) {
typeParams
.add(new TypeParameter(name, new DynamicType(), new DynamicType()));
List<TypeParameter>? typeParams = createTypeParametersWithBounds(
sourceCompilerResult.classHierarchy?.knownLibraries,
test.typeBounds,
test.typeDefaults,
test.typeDefinitions);
if (typeParams == null) {
typeParams = [];
for (String name in test.typeDefinitions) {
typeParams
.add(new TypeParameter(name, new DynamicType(), new DynamicType()));
}
}
Procedure? compiledProcedure = await compiler.compileExpression(
@ -353,7 +398,7 @@ class CompileExpression extends Step<List<TestCase>, List<TestCase>, Context> {
test.results.add(new CompilationResult(compiledProcedure, errors));
if (compiledProcedure != null) {
// Confirm we can serialize generated procedure.
component.computeCanonicalNames();
sourceCompilerResult.component.computeCanonicalNames();
List<int> list = serializeProcedure(compiledProcedure);
assert(list.length > 0);
}
@ -371,8 +416,9 @@ class CompileExpression extends Step<List<TestCase>, List<TestCase>, Context> {
await new File.fromUri(test.import!).readAsBytes());
}
var sourceCompiler = new IncrementalCompiler(context.compilerContext);
var sourceCompilerResult =
IncrementalCompiler sourceCompiler =
new IncrementalCompiler(context.compilerContext);
IncrementalCompilerResult sourceCompilerResult =
await sourceCompiler.computeDelta(entryPoints: [test.entryPoint!]);
Component component = sourceCompilerResult.component;
var errors = context.takeErrors();
@ -387,11 +433,12 @@ class CompileExpression extends Step<List<TestCase>, List<TestCase>, Context> {
path: test.entryPoint!.path + ".dill");
Uint8List dillData = await serializeComponent(component);
context.fileSystem.entityForUri(dillFileUri).writeAsBytesSync(dillData);
await compileExpression(test, sourceCompiler, component, context);
await compileExpression(
test, sourceCompiler, sourceCompilerResult, context);
var dillCompiler =
IncrementalCompiler dillCompiler =
new IncrementalCompiler(context.compilerContext, dillFileUri);
var dillCompilerResult =
IncrementalCompilerResult dillCompilerResult =
await dillCompiler.computeDelta(entryPoints: [test.entryPoint!]);
component = dillCompilerResult.component;
component.computeCanonicalNames();
@ -400,7 +447,7 @@ class CompileExpression extends Step<List<TestCase>, List<TestCase>, Context> {
// Since it compiled successfully from source, the bootstrap-from-Dill
// should also succeed without errors.
assert(errors.isEmpty);
await compileExpression(test, dillCompiler, component, context);
await compileExpression(test, dillCompiler, dillCompilerResult, context);
}
return new Result.pass(tests);
}

View file

@ -398,6 +398,7 @@ micro
minimize
minimizer
minimizing
minitest
minst
mintty
minutes

View file

@ -0,0 +1,17 @@
# Copyright (c) 2022, 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.
entry_point: "main.dart"
definitions: ["x"]
# List<String>
definition_types: ["dart:core", "List", "1", "1", "dart:core", "String", "1", "0"]
type_definitions: [""]
type_bounds: []
type_defaults: []
position: "main.dart"
method: "hasList"
# x is List<String> with entries, so x.first is String, String has extension
# with method getFortyTwo.
expression: |
x.first.getFortyTwo()

View file

@ -0,0 +1,4 @@
Errors: {
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr< extends dynamic>(dart.core::List<dart.core::String> x) → dynamic
return main::Foo|getFortyTwo(x.{dart.core::Iterable::first}{dart.core::String*});

View file

@ -0,0 +1,16 @@
# Copyright (c) 2022, 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.
entry_point: "main.dart"
definitions: ["x", "y"]
# List<String>, int
definition_types: ["dart:core", "List", "1", "1", "dart:core", "String", "1", "0", "dart:core", "int", "1", "0"]
type_definitions: []
type_bounds: []
type_defaults: []
position: "main.dart"
method: "hasList"
# Because x has a type (List<String>) x.fold knows that element is a String.
expression: |
x.fold<int>(0, (previousValue, element) => previousValue + element.length)

View file

@ -0,0 +1,4 @@
Errors: {
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dart.core::List<dart.core::String> x, dart.core::int y) → dynamic
return x.{dart.core::Iterable::fold}<dart.core::int*>(0, (dart.core::int* previousValue, dart.core::String* element) → dart.core::int* => previousValue.{dart.core::num::+}(element.{dart.core::String::length}{dart.core::int*}){(dart.core::num*) →* dart.core::int*}){(dart.core::int*, (dart.core::int*, dart.core::String*) →* dart.core::int*) →* dart.core::int*};

View file

@ -100,3 +100,30 @@ class E<T> {
T _t;
T get t => _t;
}
void withBound<E extends String>(List<E> x) {
List<E> y = [];
List<String> z = [];
z.addAll(y);
}
void withBound2<E>() {
print(E);
}
void hasList() {
List<String> x = ["a", "b", "c"];
int xCombinedLength = x.fold<int>(
0, (previousValue, element) => previousValue + element.length);
print("xCombinedLength = $xCombinedLength");
}
void hasClosure() {
List<String> x() {
return ["hello"];
}
int xCombinedLength = x()
.fold<int>(0, (previousValue, element) => previousValue + element.length);
print("xCombinedLength = $xCombinedLength");
}

View file

@ -0,0 +1,15 @@
# Copyright (c) 2022, 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.
entry_point: "main.dart"
definitions: ["x"]
# _Closure --- note that this is not what the VM sends (anymore).
definition_types: ["dart:core", "_Closure", "1", "0"]
type_definitions: []
type_bounds: []
type_defaults: []
position: "main.dart"
method: "hasClosure"
expression: |
x().fold<int>(0, (previousValue, element) => previousValue + element.length)

View file

@ -0,0 +1,9 @@
Errors: {
org-dartlang-debug:synthetic_debug_expression:1:2: Error: Cannot invoke an instance of '_Closure' because it declares 'call' to be something other than a method.
- '_Closure' is from 'dart:core'.
Try changing 'call' to a method or explicitly invoke 'call'.
x().fold<int>(0, (previousValue, element) => previousValue + element.length)
^
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dart.core::_Closure x) → dynamic
return invalid-expression "org-dartlang-debug:synthetic_debug_expression:1:2: Error: Cannot invoke an instance of '_Closure' because it declares 'call' to be something other than a method.\n - '_Closure' is from 'dart:core'.\nTry changing 'call' to a method or explicitly invoke 'call'.\nx().fold<int>(0, (previousValue, element) => previousValue + element.length)\n ^"{dynamic}.fold<dart.core::int*>(0, (dynamic previousValue, dynamic element) → dynamic => previousValue{dynamic}.+(element{dynamic}.length));

View file

@ -0,0 +1,15 @@
# Copyright (c) 2022, 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.
entry_point: "main.dart"
definitions: ["x"]
# _Closure is send as null aka dynamic.
definition_types: ["null"]
type_definitions: []
type_bounds: []
type_defaults: []
position: "main.dart"
method: "hasClosure"
expression: |
x().fold<int>(0, (previousValue, element) => previousValue + element.length)

View file

@ -0,0 +1,4 @@
Errors: {
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dynamic x) → dynamic
return x{dynamic}.call(){dynamic}.fold<dart.core::int*>(0, (dynamic previousValue, dynamic element) → dynamic => previousValue{dynamic}.+(element{dynamic}.length));

View file

@ -0,0 +1,18 @@
# Copyright (c) 2022, 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.
entry_point: "main.dart"
definitions: ["x"]
# List<String>
definition_types: ["dart:core", "List", "1", "1", "dart:core", "String", "1", "0"]
type_definitions: ["E"]
# String
type_bounds: ["dart:core", "String", "1", "0"]
# String
type_defaults: ["dart:core", "String", "1", "0"]
position: "main.dart"
method: "withBound"
# Can add List<E> to List<String> as E extends String.
expression: |
() { List<E> y = []; x.addAll(y); }()

View file

@ -0,0 +1,7 @@
Errors: {
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<E extends dart.core::String>(dart.core::List<dart.core::String> x) → dynamic
return (() → Null {
dart.core::List<#lib1::debugExpr::E*>* y = dart.core::_GrowableList::•<#lib1::debugExpr::E*>(0);
x.{dart.core::List::addAll}(y){(dart.core::Iterable<dart.core::String*>*) →* void};
})(){() →* Null};

View file

@ -0,0 +1,18 @@
# Copyright (c) 2022, 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.
entry_point: "main.dart"
definitions: ["x"]
# List<String>
definition_types: ["dart:core", "List", "1", "1", "dart:core", "String", "1", "0"]
type_definitions: ["E"]
# String
type_bounds: ["dart:core", "String", "1", "0"]
# String
type_defaults: ["dart:core", "String", "1", "0"]
position: "main.dart"
method: "withBound"
# Can't add List<String> to List<E> :(
expression: |
() { List<E> y = []; y.addAll(x); }

View file

@ -0,0 +1,12 @@
Errors: {
org-dartlang-debug:synthetic_debug_expression:1:31: Error: The argument type 'List<String>' can't be assigned to the parameter type 'Iterable<E>'.
- 'List' is from 'dart:core'.
- 'Iterable' is from 'dart:core'.
() { List<E> y = []; y.addAll(x); }
^
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<E extends dart.core::String>(dart.core::List<dart.core::String> x) → dynamic
return () → Null {
dart.core::List<#lib1::debugExpr::E*>* y = dart.core::_GrowableList::•<#lib1::debugExpr::E*>(0);
y.{dart.core::List::addAll}(invalid-expression "org-dartlang-debug:synthetic_debug_expression:1:31: Error: The argument type 'List<String>' can't be assigned to the parameter type 'Iterable<E>'.\n - 'List' is from 'dart:core'.\n - 'Iterable' is from 'dart:core'.\n() { List<E> y = []; y.addAll(x); }\n ^" in x as{TypeError} Never){(dart.core::Iterable<#lib1::debugExpr::E*>*) →* void};
};

View file

@ -0,0 +1,16 @@
# Copyright (c) 2022, 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.
entry_point: "main.dart"
definitions: []
definition_types: []
type_definitions: ["E"]
# Object?
type_bounds: ["dart:core", "Object", "0", "0"]
# null (because dynamic).
type_defaults: ["null"]
position: "main.dart"
method: "withBound2"
expression: |
print(E)

View file

@ -0,0 +1,4 @@
Errors: {
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<E extends dart.core::Object? = dynamic>() → dynamic
return dart.core::print(#lib1::debugExpr::E*);

View file

@ -285,7 +285,10 @@ abstract class CompilerInterface {
Future<Null> compileExpression(
String expression,
List<String> definitions,
List<String> definitionTypes,
List<String> typeDefinitions,
List<String> typeBounds,
List<String> typeDefaults,
String libraryUri,
String klass,
String method,
@ -840,15 +843,27 @@ class FrontendCompiler implements CompilerInterface {
Future<Null> compileExpression(
String expression,
List<String> definitions,
List<String> definitionTypes,
List<String> typeDefinitions,
List<String> typeBounds,
List<String> typeDefaults,
String libraryUri,
String klass,
String method,
bool isStatic) async {
final String boundaryKey = Uuid().generateV4();
_outputStream.writeln('result $boundaryKey');
Procedure procedure = await _generator.compileExpression(expression,
definitions, typeDefinitions, libraryUri, klass, method, isStatic);
Procedure procedure = await _generator.compileExpression(
expression,
definitions,
definitionTypes,
typeDefinitions,
typeBounds,
typeDefaults,
libraryUri,
klass,
method,
isStatic);
if (procedure != null) {
Component component = createExpressionEvaluationComponent(procedure);
final IOSink sink = File(_kernelBinaryFilename).openWrite();
@ -1127,7 +1142,10 @@ class _CompileExpressionRequest {
// Note that FE will reject a compileExpression command by returning a null
// procedure when defs or typeDefs include an illegal identifier.
List<String> defs = <String>[];
List<String> defTypes = <String>[];
List<String> typeDefs = <String>[];
List<String> typeBounds = <String>[];
List<String> typeDefaults = <String>[];
String library;
String klass;
String method;
@ -1268,7 +1286,10 @@ StreamSubscription<String> listenAndCompile(CompilerInterface compiler,
compiler.compileExpression(
compileExpressionRequest.expression,
compileExpressionRequest.defs,
compileExpressionRequest.defTypes,
compileExpressionRequest.typeDefs,
compileExpressionRequest.typeBounds,
compileExpressionRequest.typeDefaults,
compileExpressionRequest.library,
compileExpressionRequest.klass,
compileExpressionRequest.method,

View file

@ -22,9 +22,14 @@ class LibraryIndex {
final Map<String, _ClassTable> _libraries = <String, _ClassTable>{};
/// Indexes the libraries with the URIs given in [libraryUris].
LibraryIndex(Component component, Iterable<String> libraryUris) {
LibraryIndex(Component component, Iterable<String> libraryUris)
: this.fromLibraries(component.libraries, libraryUris);
/// Indexes the libraries with the URIs given in [libraryUris].
LibraryIndex.fromLibraries(
Iterable<Library> libraries, Iterable<String> libraryUris) {
Set<String> libraryUriSet = libraryUris.toSet();
for (Library library in component.libraries) {
for (Library library in libraries) {
String uri = '${library.importUri}';
if (libraryUriSet.contains(uri)) {
_libraries[uri] = new _ClassTable(library);

View file

@ -500,16 +500,19 @@ Future _processExpressionCompilationRequest(request) async {
final dynamic dart_platform_kernel = request[3];
final String expression = request[4];
final List<String> definitions = request[5].cast<String>();
final List<String> typeDefinitions = request[6].cast<String>();
final String libraryUri = request[7];
final String? klass = request[8];
final String? method = request[9];
final bool isStatic = request[10];
final List<List<int>> dillData = request[11].cast<List<int>>();
final int blobLoadCount = request[12];
final bool enableAsserts = request[13];
final List<String> definitionTypes = request[6].cast<String>();
final List<String> typeDefinitions = request[7].cast<String>();
final List<String> typeBounds = request[8].cast<String>();
final List<String> typeDefaults = request[9].cast<String>();
final String libraryUri = request[10];
final String? klass = request[11];
final String? method = request[12];
final bool isStatic = request[13];
final List<List<int>> dillData = request[14].cast<List<int>>();
final int blobLoadCount = request[15];
final bool enableAsserts = request[16];
final List<String>? experimentalFlags =
request[14] != null ? request[14].cast<String>() : null;
request[17] != null ? request[17].cast<String>() : null;
IncrementalCompilerWrapper? compiler = isolateCompilers[isolateGroupId];
@ -623,7 +626,10 @@ Future _processExpressionCompilationRequest(request) async {
Procedure? procedure = await compiler.generator!.compileExpression(
expression,
definitions,
definitionTypes,
typeDefinitions,
typeBounds,
typeDefaults,
libraryUri,
klass,
method,

View file

@ -194,23 +194,43 @@ class IncrementalCompiler {
Future<Procedure?> compileExpression(
String expression,
List<String> definitions,
List<String> definitionTypes,
List<String> typeDefinitions,
List<String> typeBounds,
List<String> typeDefaults,
String libraryUri,
String? klass,
String? method,
bool isStatic) {
Map<String, DartType> completeDefinitions = {};
for (int i = 0; i < definitions.length; i++) {
String name = definitions[i];
if (isLegalIdentifier(name) || (i == 0 && isExtensionThisName(name))) {
completeDefinitions[name] = new DynamicType();
ClassHierarchy? classHierarchy =
(_lastKnownGood ?? _combinePendingDeltas(false)).classHierarchy;
Map<String, DartType>? completeDefinitions = createDefinitionsWithTypes(
classHierarchy?.knownLibraries, definitionTypes, definitions);
if (completeDefinitions == null) {
completeDefinitions = {};
// No class hierarchy or wasn't provided correct types.
// Revert to old behaviour of setting everything to dynamic.
for (int i = 0; i < definitions.length; i++) {
String name = definitions[i];
if (isLegalIdentifier(name) || (i == 0 && isExtensionThisName(name))) {
completeDefinitions[name] = new DynamicType();
}
}
}
List<TypeParameter> typeParameters = [];
for (String name in typeDefinitions) {
if (!isLegalIdentifier(name)) continue;
typeParameters.add(new TypeParameter(name, new DynamicType()));
List<TypeParameter>? typeParameters = createTypeParametersWithBounds(
classHierarchy?.knownLibraries,
typeBounds,
typeDefaults,
typeDefinitions);
if (typeParameters == null) {
// No class hierarchy or wasn't provided correct types.
// Revert to old behaviour of setting everything to dynamic.
typeParameters = [];
for (String name in typeDefinitions) {
if (!isLegalIdentifier(name)) continue;
typeParameters.add(new TypeParameter(name, new DynamicType()));
}
}
Uri library = Uri.parse(libraryUri);

View file

@ -115,14 +115,32 @@ main() {
await compiler.compile();
compiler.accept();
{
Procedure? procedure = await compiler.compileExpression('main',
<String>[], <String>[], main.uri.toString(), null, null, true);
Procedure? procedure = await compiler.compileExpression(
'main',
<String>[],
<String>[],
<String>[],
<String>[],
<String>[],
main.uri.toString(),
null,
null,
true);
expect(procedure, isNotNull);
expect(errorsReported, equals(0));
}
{
Procedure? procedure = await compiler.compileExpression('main1',
<String>[], <String>[], main.uri.toString(), null, null, true);
Procedure? procedure = await compiler.compileExpression(
'main1',
<String>[],
<String>[],
<String>[],
<String>[],
<String>[],
main.uri.toString(),
null,
null,
true);
expect(procedure, isNotNull);
expect(errorsReported, equals(1));
errorsReported = 0;
@ -1038,8 +1056,17 @@ main() {
}
compiler.accept();
{
Procedure? procedure = await compiler.compileExpression('a', <String>[],
<String>[], 'package:foo/bar.dart', 'A', null, true);
Procedure? procedure = await compiler.compileExpression(
'a',
<String>[],
<String>[],
<String>[],
<String>[],
<String>[],
'package:foo/bar.dart',
'A',
null,
true);
expect(procedure, isNotNull);
}
@ -1055,8 +1082,17 @@ main() {
}
await compiler.reject();
{
Procedure? procedure = await compiler.compileExpression('a', <String>[],
<String>[], 'package:foo/bar.dart', 'A', null, true);
Procedure? procedure = await compiler.compileExpression(
'a',
<String>[],
<String>[],
<String>[],
<String>[],
<String>[],
'package:foo/bar.dart',
'A',
null,
true);
expect(procedure, isNotNull);
}
});
@ -1106,7 +1142,16 @@ main() {
compiler.accept();
{
final Procedure procedure = (await compiler.compileExpression(
'a', <String>[], <String>[], barUri.toString(), 'A', null, true))!;
'a',
<String>[],
<String>[],
<String>[],
<String>[],
<String>[],
barUri.toString(),
'A',
null,
true))!;
// Verify that the expression only has links to the only bar we know
// about.
final LibraryReferenceCollector lrc = new LibraryReferenceCollector();
@ -1153,7 +1198,16 @@ main() {
}
{
final Procedure procedure = (await compiler.compileExpression(
'a', <String>[], <String>[], barUri.toString(), 'A', null, true))!;
'a',
<String>[],
<String>[],
<String>[],
<String>[],
<String>[],
barUri.toString(),
'A',
null,
true))!;
// Verify that the expression only has links to the original bar.
final LibraryReferenceCollector lrc = new LibraryReferenceCollector();
procedure.accept(lrc);

View file

@ -0,0 +1,32 @@
// Copyright (c) 2022, 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 'dart:developer';
import 'package:observatory/models.dart' show InstanceKind;
import 'package:observatory/service_io.dart';
import 'package:test/test.dart';
import 'service_test_common.dart';
import 'test_helper.dart';
void testFunction() {
List<String> x = ["a", "b", "c"];
int xCombinedLength = x.fold<int>(
0, (previousValue, element) => previousValue + element.length);
debugger();
print("xCombinedLength = $xCombinedLength");
}
var tests = <IsolateTest>[
hasStoppedAtBreakpoint,
(Isolate isolate) async {
Instance result = await isolate.evalFrame(0, '''x.fold<int>(
0, (previousValue, element) => previousValue + element.length)''')
as Instance;
expect(result.valueAsString, equals('3'));
expect(result.kind, equals(InstanceKind.int));
},
];
main(args) => runIsolateTests(args, tests, testeeConcurrent: testFunction);

View file

@ -0,0 +1,116 @@
// Copyright (c) 2022, 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 'dart:collection';
import 'dart:developer';
import 'package:observatory/models.dart' show InstanceKind;
import 'package:observatory/service_io.dart';
import 'package:test/test.dart';
import 'service_test_common.dart';
import 'test_helper.dart';
class A {}
class B extends A {}
class C extends Object with ListMixin<C> implements List<C> {
int length = 0;
C operator [](int index) => throw UnimplementedError();
void operator []=(int index, C value) {}
}
void testFunction4<T4 extends List<T4>>() {
debugger();
print("T4 = $T4");
}
void testFunction3<T3, S3 extends T3>() {
debugger();
print("T3 = $T3");
print("S3 = $S3");
}
void testFunction2<E extends String>(List<E> x) {
debugger();
print("x = $x");
}
void testFunction() {
testFunction2<String>(<String>["a", "b", "c"]);
testFunction3<A, B>();
testFunction4<C>();
}
void fooxx<E extends String>(List<E> y) {
List<E> x = new List<E>.from(["hello"]);
}
var tests = <IsolateTest>[
hasStoppedAtBreakpoint,
(Isolate isolate) async {
{
// Can add List<E extends String> to List<String> directly.
Instance result = await isolate.evalFrame(0, '''() {
List<E> y = new List<E>.from(["hello"]);
x.addAll(y);
return x.last;
}()''') as Instance;
expect(result.valueAsString, equals("hello"));
expect(result.kind, equals(InstanceKind.string));
}
{
// Can't add List<String> to List<E extends String> directly.
DartError result = await isolate.evalFrame(0, '''() {
List<E> y = [];
y.addAll(x);
return y.last;
}()''') as DartError;
expect(
result.message,
contains(
"The argument type '_GrowableList<String>' can't be assigned "
"to the parameter type 'Iterable<E>'"));
}
{
// Can add List<String> to List<E extends String> via cast.
Instance result = await isolate.evalFrame(0, '''() {
List<E> y = [];
y.addAll(x.cast());
return y.toString();
}()''') as Instance;
// Notice how "hello" was added a few evaluations back.
expect(result.valueAsString, equals("[a, b, c, hello]"));
expect(result.kind, equals(InstanceKind.string));
}
{
// Can create List<String> from List<E extends String>.
Instance result = await isolate.evalFrame(0, '''() {
List<E> y = new List<E>.from(x);
return y.toString();
}()''') as Instance;
// Notice how "hello" was added a few evaluations back.
expect(result.valueAsString, equals("[a, b, c, hello]"));
expect(result.kind, equals(InstanceKind.string));
}
},
resumeIsolate,
(Isolate isolate) async {
// This is just to make sure the VM doesn't crash.
Instance result =
await isolate.evalFrame(0, '''S3.toString()''') as Instance;
expect(result.valueAsString, equals("B"));
expect(result.kind, equals(InstanceKind.string));
},
resumeIsolate,
(Isolate isolate) async {
// This is just to make sure the VM doesn't crash.
Instance result =
await isolate.evalFrame(0, '''T4.toString()''') as Instance;
expect(result.valueAsString, equals("C"));
expect(result.kind, equals(InstanceKind.string));
},
];
main(args) => runIsolateTests(args, tests, testeeConcurrent: testFunction);

View file

@ -0,0 +1,38 @@
// Copyright (c) 2022, 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 'dart:developer';
import 'package:observatory/models.dart' show InstanceKind;
import 'package:observatory/service_io.dart';
import 'package:test/test.dart';
import 'service_test_common.dart';
import 'test_helper.dart';
extension on String {
String printAndReturnHello() {
String response = "Hello from String '$this'";
print(response);
return response;
}
}
void testFunction() {
String x = "hello";
String value = x.printAndReturnHello();
debugger();
print("value = $value");
}
var tests = <IsolateTest>[
hasStoppedAtBreakpoint,
(Isolate isolate) async {
Instance result =
await isolate.evalFrame(0, 'x.printAndReturnHello()') as Instance;
expect(result.valueAsString, equals("Hello from String 'hello'"));
expect(result.kind, equals(InstanceKind.string));
},
];
main(args) => runIsolateTests(args, tests, testeeConcurrent: testFunction);

View file

@ -95,6 +95,7 @@ evaluate_activation_in_method_class_test: SkipByDesign # Debugger is disabled in
evaluate_activation_test: SkipByDesign
evaluate_async_closure_test: SkipByDesign
evaluate_class_type_parameters_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_fold_on_list_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_function_type_parameters_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_in_async_activation_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_in_async_star_activation_test: SkipByDesign # Debugger is disabled in AOT mode.
@ -102,6 +103,8 @@ evaluate_in_extension_method_test: SkipByDesign # Debugger is disabled in AOT mo
evaluate_in_frame_rpc_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_in_frame_with_scope_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_in_sync_star_activation_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_type_arguments_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_type_with_extension_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_with_escaping_closure_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_with_scope_test: SkipByDesign # Debugger is disabled in AOT mode.
field_script_test: SkipByDesign # Debugger is disabled in AOT mode.

View file

@ -0,0 +1,32 @@
// Copyright (c) 2022, 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 'dart:developer';
import 'package:observatory_2/models.dart' show InstanceKind;
import 'package:observatory_2/service_io.dart';
import 'package:test/test.dart';
import 'service_test_common.dart';
import 'test_helper.dart';
void testFunction() {
List<String> x = ["a", "b", "c"];
int xCombinedLength = x.fold<int>(
0, (previousValue, element) => previousValue + element.length);
debugger();
print("xCombinedLength = $xCombinedLength");
}
var tests = <IsolateTest>[
hasStoppedAtBreakpoint,
(Isolate isolate) async {
Instance result = await isolate.evalFrame(0, '''x.fold<int>(
0, (previousValue, element) => previousValue + element.length)''')
as Instance;
expect(result.valueAsString, equals('3'));
expect(result.kind, equals(InstanceKind.int));
},
];
main(args) => runIsolateTests(args, tests, testeeConcurrent: testFunction);

View file

@ -0,0 +1,116 @@
// Copyright (c) 2022, 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 'dart:collection';
import 'dart:developer';
import 'package:observatory_2/models.dart' show InstanceKind;
import 'package:observatory_2/service_io.dart';
import 'package:test/test.dart';
import 'service_test_common.dart';
import 'test_helper.dart';
class A {}
class B extends A {}
class C extends Object with ListMixin<C> implements List<C> {
int length = 0;
C operator [](int index) => throw UnimplementedError();
void operator []=(int index, C value) {}
}
void testFunction4<T4 extends List<T4>>() {
debugger();
print("T4 = $T4");
}
void testFunction3<T3, S3 extends T3>() {
debugger();
print("T3 = $T3");
print("S3 = $S3");
}
void testFunction2<E extends String>(List<E> x) {
debugger();
print("x = $x");
}
void testFunction() {
testFunction2<String>(<String>["a", "b", "c"]);
testFunction3<A, B>();
testFunction4<C>();
}
void fooxx<E extends String>(List<E> y) {
List<E> x = new List<E>.from(["hello"]);
}
var tests = <IsolateTest>[
hasStoppedAtBreakpoint,
(Isolate isolate) async {
{
// Can add List<E extends String> to List<String> directly.
Instance result = await isolate.evalFrame(0, '''() {
List<E> y = new List<E>.from(["hello"]);
x.addAll(y);
return x.last;
}()''') as Instance;
expect(result.valueAsString, equals("hello"));
expect(result.kind, equals(InstanceKind.string));
}
{
// Can't add List<String> to List<E extends String> directly.
DartError result = await isolate.evalFrame(0, '''() {
List<E> y = [];
y.addAll(x);
return y.last;
}()''') as DartError;
expect(
result.message,
contains(
"The argument type '_GrowableList<String>' can't be assigned "
"to the parameter type 'Iterable<E>'"));
}
{
// Can add List<String> to List<E extends String> via cast.
Instance result = await isolate.evalFrame(0, '''() {
List<E> y = [];
y.addAll(x.cast());
return y.toString();
}()''') as Instance;
// Notice how "hello" was added a few evaluations back.
expect(result.valueAsString, equals("[a, b, c, hello]"));
expect(result.kind, equals(InstanceKind.string));
}
{
// Can create List<String> from List<E extends String>.
Instance result = await isolate.evalFrame(0, '''() {
List<E> y = new List<E>.from(x);
return y.toString();
}()''') as Instance;
// Notice how "hello" was added a few evaluations back.
expect(result.valueAsString, equals("[a, b, c, hello]"));
expect(result.kind, equals(InstanceKind.string));
}
},
resumeIsolate,
(Isolate isolate) async {
// This is just to make sure the VM doesn't crash.
Instance result =
await isolate.evalFrame(0, '''S3.toString()''') as Instance;
expect(result.valueAsString, equals("B"));
expect(result.kind, equals(InstanceKind.string));
},
resumeIsolate,
(Isolate isolate) async {
// This is just to make sure the VM doesn't crash.
Instance result =
await isolate.evalFrame(0, '''T4.toString()''') as Instance;
expect(result.valueAsString, equals("C"));
expect(result.kind, equals(InstanceKind.string));
},
];
main(args) => runIsolateTests(args, tests, testeeConcurrent: testFunction);

View file

@ -0,0 +1,38 @@
// Copyright (c) 2022, 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 'dart:developer';
import 'package:observatory_2/models.dart' show InstanceKind;
import 'package:observatory_2/service_io.dart';
import 'package:test/test.dart';
import 'service_test_common.dart';
import 'test_helper.dart';
extension on String {
String printAndReturnHello() {
String response = "Hello from String '$this'";
print(response);
return response;
}
}
void testFunction() {
String x = "hello";
String value = x.printAndReturnHello();
debugger();
print("value = $value");
}
var tests = <IsolateTest>[
hasStoppedAtBreakpoint,
(Isolate isolate) async {
Instance result =
await isolate.evalFrame(0, 'x.printAndReturnHello()') as Instance;
expect(result.valueAsString, equals("Hello from String 'hello'"));
expect(result.kind, equals(InstanceKind.string));
},
];
main(args) => runIsolateTests(args, tests, testeeConcurrent: testFunction);

View file

@ -95,6 +95,7 @@ evaluate_activation_in_method_class_test: SkipByDesign # Debugger is disabled in
evaluate_activation_test: SkipByDesign
evaluate_async_closure_test: SkipByDesign
evaluate_class_type_parameters_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_fold_on_list_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_function_type_parameters_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_in_async_activation_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_in_async_star_activation_test: SkipByDesign # Debugger is disabled in AOT mode.
@ -102,6 +103,8 @@ evaluate_in_extension_method_test: SkipByDesign # Debugger is disabled in AOT mo
evaluate_in_frame_rpc_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_in_frame_with_scope_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_in_sync_star_activation_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_type_arguments_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_type_with_extension_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_with_escaping_closure_test: SkipByDesign # Debugger is disabled in AOT mode.
evaluate_with_scope_test: SkipByDesign # Debugger is disabled in AOT mode.
field_script_test: SkipByDesign # Debugger is disabled in AOT mode.

View file

@ -208,6 +208,7 @@ TEST_CASE(EvalExpression) {
KernelIsolate::CompileExpressionToKernel(
/*platform_kernel=*/nullptr, /*platform_kernel_size=*/0,
expr_text.ToCString(), Array::empty_array(), Array::empty_array(),
Array::empty_array(), Array::empty_array(), Array::empty_array(),
String::Handle(lib_handle.url()).ToCString(), "A",
/* method= */ nullptr,
/* is_static= */ false);

View file

@ -1287,7 +1287,9 @@ ObjectPtr ActivationFrame::EvaluateCompiledExpression(
TypeArgumentsPtr ActivationFrame::BuildParameters(
const GrowableObjectArray& param_names,
const GrowableObjectArray& param_values,
const GrowableObjectArray& type_params_names) {
const GrowableObjectArray& type_params_names,
const GrowableObjectArray& type_params_bounds,
const GrowableObjectArray& type_params_defaults) {
GetDescIndices();
bool type_arguments_available = false;
String& name = String::Handle();
@ -1329,6 +1331,12 @@ TypeArgumentsPtr ActivationFrame::BuildParameters(
intptr_t num_vars = function().NumTypeArguments();
type_params_names.Grow(num_vars);
type_params_names.SetLength(num_vars);
type_params_bounds.Grow(num_vars);
type_params_bounds.SetLength(num_vars);
type_params_defaults.Grow(num_vars);
type_params_defaults.SetLength(num_vars);
AbstractType& bound = AbstractType::Handle();
AbstractType& defaultType = AbstractType::Handle();
TypeParameters& type_params = TypeParameters::Handle();
Function& current = Function::Handle(function().ptr());
intptr_t mapping_offset = num_vars;
@ -1341,12 +1349,16 @@ TypeArgumentsPtr ActivationFrame::BuildParameters(
mapping_offset -= size;
for (intptr_t j = 0; j < size; ++j) {
name = type_params.NameAt(j);
bound = type_params.BoundAt(j);
defaultType = type_params.DefaultAt(j);
// Write the names in backwards in terms of chain of functions.
// But keep the order of names within the same function. so they
// match up with the order of the types in 'type_arguments'.
// Index:0 1 2 3 ...
// |Names in Grandparent| |Names in Parent| ..|Names in Child|
type_params_names.SetAt(mapping_offset + j, name);
type_params_bounds.SetAt(mapping_offset + j, bound);
type_params_defaults.SetAt(mapping_offset + j, defaultType);
}
}
if (!type_arguments.IsNull()) {

View file

@ -392,7 +392,9 @@ class ActivationFrame : public ZoneAllocated {
TypeArgumentsPtr BuildParameters(
const GrowableObjectArray& param_names,
const GrowableObjectArray& param_values,
const GrowableObjectArray& type_params_names);
const GrowableObjectArray& type_params_names,
const GrowableObjectArray& type_params_bounds,
const GrowableObjectArray& type_params_defaults);
ObjectPtr EvaluateCompiledExpression(const ExternalTypedData& kernel_data,
const Array& arguments,

View file

@ -181,7 +181,10 @@ DART_EXPORT Dart_Handle Dart_EvaluateStaticExpr(Dart_Handle lib_handle,
/* platform_kernel= */ nullptr, /* platform_kernel_size= */ 0,
expr.ToCString(),
/* definitions= */ Array::empty_array(),
/* definition_types= */ Array::empty_array(),
/* type_defintions= */ Array::empty_array(),
/* type_bounds= */ Array::empty_array(),
/* type_defaults= */ Array::empty_array(),
String::Handle(lib.url()).ToCString(),
/* klass= */ nullptr,
/* method= */ nullptr,

View file

@ -476,7 +476,10 @@ class KernelCompilationRequest : public ValueObject {
intptr_t platform_kernel_size,
const char* expression,
const Array& definitions,
const Array& definition_types,
const Array& type_definitions,
const Array& type_bounds,
const Array& type_defaults,
char const* library_uri,
char const* klass,
char const* method,
@ -537,6 +540,22 @@ class KernelCompilationRequest : public ValueObject {
}
definitions_object.value.as_array.values = definitions_array;
Dart_CObject definition_types_object;
intptr_t num_definition_types = definition_types.Length();
definition_types_object.type = Dart_CObject_kArray;
definition_types_object.value.as_array.length = num_definition_types;
Dart_CObject** definition_types_array =
new Dart_CObject*[num_definition_types];
for (intptr_t i = 0; i < num_definition_types; ++i) {
definition_types_array[i] = new Dart_CObject;
definition_types_array[i]->type = Dart_CObject_kString;
definition_types_array[i]->value.as_string = const_cast<char*>(
String::CheckedHandle(thread->zone(), definition_types.At(i))
.ToCString());
}
definition_types_object.value.as_array.values = definition_types_array;
Dart_CObject type_definitions_object;
intptr_t num_type_definitions = type_definitions.Length();
type_definitions_object.type = Dart_CObject_kArray;
@ -553,6 +572,35 @@ class KernelCompilationRequest : public ValueObject {
}
type_definitions_object.value.as_array.values = type_definitions_array;
Dart_CObject type_bounds_object;
intptr_t num_type_bounds = type_bounds.Length();
type_bounds_object.type = Dart_CObject_kArray;
type_bounds_object.value.as_array.length = num_type_bounds;
Dart_CObject** type_bounds_array = new Dart_CObject*[num_type_bounds];
for (intptr_t i = 0; i < num_type_bounds; ++i) {
type_bounds_array[i] = new Dart_CObject;
type_bounds_array[i]->type = Dart_CObject_kString;
type_bounds_array[i]->value.as_string = const_cast<char*>(
String::CheckedHandle(thread->zone(), type_bounds.At(i)).ToCString());
}
type_bounds_object.value.as_array.values = type_bounds_array;
Dart_CObject type_defaults_object;
intptr_t num_type_defaults = type_defaults.Length();
type_defaults_object.type = Dart_CObject_kArray;
type_defaults_object.value.as_array.length = num_type_defaults;
Dart_CObject** type_defaults_array = new Dart_CObject*[num_type_defaults];
for (intptr_t i = 0; i < num_type_defaults; ++i) {
type_defaults_array[i] = new Dart_CObject;
type_defaults_array[i]->type = Dart_CObject_kString;
type_defaults_array[i]->value.as_string = const_cast<char*>(
String::CheckedHandle(thread->zone(), type_defaults.At(i))
.ToCString());
}
type_defaults_object.value.as_array.values = type_defaults_array;
Dart_CObject library_uri_object;
library_uri_object.type = Dart_CObject_kString;
library_uri_object.value.as_string = const_cast<char*>(library_uri);
@ -659,7 +707,10 @@ class KernelCompilationRequest : public ValueObject {
&dart_platform_kernel,
&expression_object,
&definitions_object,
&definition_types_object,
&type_definitions_object,
&type_bounds_object,
&type_defaults_object,
&library_uri_object,
&class_object,
&method_object,
@ -690,11 +741,26 @@ class KernelCompilationRequest : public ValueObject {
}
delete[] definitions_array;
for (intptr_t i = 0; i < num_definition_types; ++i) {
delete definition_types_array[i];
}
delete[] definition_types_array;
for (intptr_t i = 0; i < num_type_definitions; ++i) {
delete type_definitions_array[i];
}
delete[] type_definitions_array;
for (intptr_t i = 0; i < num_type_bounds; ++i) {
delete type_bounds_array[i];
}
delete[] type_bounds_array;
for (intptr_t i = 0; i < num_type_defaults; ++i) {
delete type_defaults_array[i];
}
delete[] type_defaults_array;
for (intptr_t i = 0; i < num_dills; ++i) {
delete dills_array[i];
}
@ -1142,7 +1208,10 @@ Dart_KernelCompilationResult KernelIsolate::CompileExpressionToKernel(
intptr_t platform_kernel_size,
const char* expression,
const Array& definitions,
const Array& definition_types,
const Array& type_definitions,
const Array& type_bounds,
const Array& type_defaults,
const char* library_url,
const char* klass,
const char* method,
@ -1160,7 +1229,8 @@ Dart_KernelCompilationResult KernelIsolate::CompileExpressionToKernel(
ASSERT(is_static || (klass != nullptr));
return request.SendAndWaitForResponse(
kernel_port, platform_kernel, platform_kernel_size, expression,
definitions, type_definitions, library_url, klass, method, is_static,
definitions, definition_types, type_definitions, type_bounds,
type_defaults, library_url, klass, method, is_static,
experimental_flags_);
}

View file

@ -73,7 +73,10 @@ class KernelIsolate : public AllStatic {
intptr_t platform_kernel_size,
const char* expression,
const Array& definitions,
const Array& definition_types,
const Array& type_definitions,
const Array& type_bounds,
const Array& type_defaults,
const char* library_url,
const char* klass,
const char* method,

View file

@ -2857,6 +2857,51 @@ static const MethodParameter* const build_expression_evaluation_scope_params[] =
NULL,
};
static void CollectStringifiedType(Zone* zone,
const AbstractType& type,
const GrowableObjectArray& output) {
Instance& instance = Instance::Handle(zone);
if (type.IsFunctionType()) {
// The closure class
// (IsolateGroup::Current()->object_store()->closure_class())
// is statically typed weird (the call method redirects to itself)
// and the type is therefore not useful for the CFE. We use null instead.
output.Add(instance);
return;
}
if (type.IsDynamicType()) {
// Dynamic is weird in that it seems to have a class with no name and a
// library called something like '7189777121420'. We use null instead.
output.Add(instance);
return;
}
if (type.IsTypeParameter() && type.IsAbstractType()) {
// Calling type_class on an abstract type parameter will crash the VM.
// We use null instead.
output.Add(instance);
return;
}
const Class& cls = Class::Handle(type.type_class());
const Library& lib = Library::Handle(zone, cls.library());
instance ^= lib.url();
output.Add(instance);
instance ^= cls.ScrubbedName();
output.Add(instance);
instance ^= Smi::New((intptr_t)type.nullability());
output.Add(instance);
const TypeArguments& srcArguments = TypeArguments::Handle(type.arguments());
instance ^= Smi::New(srcArguments.Length());
output.Add(instance);
for (int i = 0; i < srcArguments.Length(); i++) {
const AbstractType& src_type = AbstractType::Handle(srcArguments.TypeAt(i));
CollectStringifiedType(zone, src_type, output);
}
}
static void BuildExpressionEvaluationScope(Thread* thread, JSONStream* js) {
if (CheckDebuggerDisabled(thread, js)) {
return;
@ -2877,6 +2922,10 @@ static void BuildExpressionEvaluationScope(Thread* thread, JSONStream* js) {
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
const GrowableObjectArray& type_params_names =
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
const GrowableObjectArray& type_params_bounds =
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
const GrowableObjectArray& type_params_defaults =
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
String& klass_name = String::Handle(zone);
String& method_name = String::Handle(zone);
String& library_uri = String::Handle(zone);
@ -2896,7 +2945,8 @@ static void BuildExpressionEvaluationScope(Thread* thread, JSONStream* js) {
}
ActivationFrame* frame = stack->FrameAt(framePos);
frame->BuildParameters(param_names, param_values, type_params_names);
frame->BuildParameters(param_names, param_values, type_params_names,
type_params_bounds, type_params_defaults);
if (frame->function().is_static()) {
const Class& cls = Class::Handle(zone, frame->function().Owner());
@ -2976,6 +3026,28 @@ static void BuildExpressionEvaluationScope(Thread* thread, JSONStream* js) {
jsonParamNames.AddValue(param_name.ToCString());
}
}
{
const JSONArray jsonParamTypes(&report, "param_types");
Object& obj = Object::Handle();
Instance& instance = Instance::Handle();
const GrowableObjectArray& param_types =
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
AbstractType& type = AbstractType::Handle();
for (intptr_t i = 0; i < param_names.Length(); i++) {
obj = param_values.At(i);
if (obj.IsNull()) {
param_types.Add(obj);
} else if (obj.IsInstance()) {
instance ^= param_values.At(i);
type = instance.GetType(Heap::kNew);
CollectStringifiedType(zone, type, param_types);
}
}
for (intptr_t i = 0; i < param_types.Length(); i++) {
instance ^= param_types.At(i);
jsonParamTypes.AddValue(instance.ToCString());
}
}
{
JSONArray jsonTypeParamsNames(&report, "type_params_names");
@ -2985,6 +3057,36 @@ static void BuildExpressionEvaluationScope(Thread* thread, JSONStream* js) {
jsonTypeParamsNames.AddValue(type_param_name.ToCString());
}
}
{
const JSONArray jsonParamTypes(&report, "type_params_bounds");
const GrowableObjectArray& type_params_bounds_strings =
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
AbstractType& type = AbstractType::Handle();
for (intptr_t i = 0; i < type_params_bounds.Length(); i++) {
type ^= type_params_bounds.At(i);
CollectStringifiedType(zone, type, type_params_bounds_strings);
}
Instance& instance = Instance::Handle();
for (intptr_t i = 0; i < type_params_bounds_strings.Length(); i++) {
instance ^= type_params_bounds_strings.At(i);
jsonParamTypes.AddValue(instance.ToCString());
}
}
{
const JSONArray jsonParamTypes(&report, "type_params_defaults");
const GrowableObjectArray& type_params_defaults_strings =
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
AbstractType& type = AbstractType::Handle();
for (intptr_t i = 0; i < type_params_defaults.Length(); i++) {
type ^= type_params_defaults.At(i);
CollectStringifiedType(zone, type, type_params_defaults_strings);
}
Instance& instance = Instance::Handle();
for (intptr_t i = 0; i < type_params_defaults_strings.Length(); i++) {
instance ^= type_params_defaults_strings.At(i);
jsonParamTypes.AddValue(instance.ToCString());
}
}
report.AddProperty("libraryUri", library_uri.ToCString());
if (!klass_name.IsNull()) {
report.AddProperty("klass", klass_name.ToCString());
@ -3036,7 +3138,10 @@ static const MethodParameter* const compile_expression_params[] = {
RUNNABLE_ISOLATE_PARAMETER,
new StringParameter("expression", true),
new StringParameter("definitions", false),
new StringParameter("definitionTypes", false),
new StringParameter("typeDefinitions", false),
new StringParameter("typeBounds", false),
new StringParameter("typeDefaults", false),
new StringParameter("libraryUri", true),
new StringParameter("klass", false),
new BoolParameter("isStatic", false),
@ -3070,6 +3175,12 @@ static void CompileExpression(Thread* thread, JSONStream* js) {
PrintInvalidParamError(js, "definitions");
return;
}
const GrowableObjectArray& param_types =
GrowableObjectArray::Handle(thread->zone(), GrowableObjectArray::New());
if (!ParseCSVList(js->LookupParam("definitionTypes"), param_types)) {
PrintInvalidParamError(js, "definitionTypes");
return;
}
const GrowableObjectArray& type_params =
GrowableObjectArray::Handle(thread->zone(), GrowableObjectArray::New());
@ -3077,6 +3188,18 @@ static void CompileExpression(Thread* thread, JSONStream* js) {
PrintInvalidParamError(js, "typedDefinitions");
return;
}
const GrowableObjectArray& type_bounds =
GrowableObjectArray::Handle(thread->zone(), GrowableObjectArray::New());
if (!ParseCSVList(js->LookupParam("typeBounds"), type_bounds)) {
PrintInvalidParamError(js, "typeBounds");
return;
}
const GrowableObjectArray& type_defaults =
GrowableObjectArray::Handle(thread->zone(), GrowableObjectArray::New());
if (!ParseCSVList(js->LookupParam("typeDefaults"), type_defaults)) {
PrintInvalidParamError(js, "typeDefaults");
return;
}
const uint8_t* kernel_buffer = Service::dart_library_kernel();
const intptr_t kernel_buffer_len = Service::dart_library_kernel_length();
@ -3085,7 +3208,10 @@ static void CompileExpression(Thread* thread, JSONStream* js) {
KernelIsolate::CompileExpressionToKernel(
kernel_buffer, kernel_buffer_len, js->LookupParam("expression"),
Array::Handle(Array::MakeFixedLength(params)),
Array::Handle(Array::MakeFixedLength(param_types)),
Array::Handle(Array::MakeFixedLength(type_params)),
Array::Handle(Array::MakeFixedLength(type_bounds)),
Array::Handle(Array::MakeFixedLength(type_defaults)),
js->LookupParam("libraryUri"), js->LookupParam("klass"),
js->LookupParam("method"), is_static);
@ -3145,6 +3271,10 @@ static void EvaluateCompiledExpression(Thread* thread, JSONStream* js) {
}
const GrowableObjectArray& type_params_names =
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
const GrowableObjectArray& type_params_bounds =
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
const GrowableObjectArray& type_params_defaults =
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
const ExternalTypedData& kernel_data = ExternalTypedData::Handle(
zone, DecodeKernelBuffer(js->LookupParam("kernelBytes")));
@ -3160,7 +3290,8 @@ static void EvaluateCompiledExpression(Thread* thread, JSONStream* js) {
ActivationFrame* frame = stack->FrameAt(frame_pos);
TypeArguments& type_arguments = TypeArguments::Handle(
zone,
frame->BuildParameters(param_names, param_values, type_params_names));
frame->BuildParameters(param_names, param_values, type_params_names,
type_params_bounds, type_params_defaults));
const Object& result = Object::Handle(
zone,

View file

@ -648,7 +648,9 @@ Dart_Handle TestCase::EvaluateExpression(const Library& lib,
KernelIsolate::CompileExpressionToKernel(
/* platform_kernel= */ nullptr, /* platform_kernel_size= */ 0,
expr.ToCString(), param_names, Array::empty_array(),
String::Handle(lib.url()).ToCString(), /* klass= */ nullptr,
Array::empty_array(), Array::empty_array(), Array::empty_array(),
String::Handle(lib.url()).ToCString(),
/* klass= */ nullptr,
/* method= */ nullptr,
/* is_static= */ true);
if (compilation_result.status != Dart_KernelCompilationStatus_Ok) {

View file

@ -124,7 +124,10 @@ class _Evaluator {
'isolateId': _message.params['isolateId']!,
'expression': _message.params['expression']!,
'definitions': buildScopeResponseResult['param_names']!,
'definitionTypes': buildScopeResponseResult['param_types']!,
'typeDefinitions': buildScopeResponseResult['type_params_names']!,
'typeBounds': buildScopeResponseResult['type_params_bounds']!,
'typeDefaults': buildScopeResponseResult['type_params_defaults']!,
'libraryUri': buildScopeResponseResult['libraryUri']!,
'isStatic': buildScopeResponseResult['isStatic']!,
};