From 1f845d1eb7e8da739412ab6ad72283e95c185fa9 Mon Sep 17 00:00:00 2001 From: Jens Johansen Date: Tue, 26 Aug 2025 00:27:19 -0700 Subject: [PATCH] [CFE] Expression evaluation: Use dynamic get etc and fixup names to access private stuff when possible For expression evaluation we want to be "more than dart" in that if for instance we can see (in the debugger) that a List contains `B`s (even if it's typed as containing `A`s) we'd like to be able to access things on `B` (without manually having to cast to either `B` or `dynamic`). Furthermore - when we in the debugger can see that it's a `B`, and that `B` has, say, a field `_privateField` or a method `_privateMethod` we'd like to be able to access that even if `B` is in another library. This CL - for expression evaluation - makes dynamic accesses and calls where we would normally issue a "missing getter" (etc) error, and tries to create a `Name` so private access is possible. Change-Id: I887318a50413e9a5f11ec685b27719edd312dca0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/446260 Reviewed-by: Alexander Markov Commit-Queue: Jens Johansen Reviewed-by: Nicholas Shahan --- .../expression_compiler_e2e_shared.dart | 36 ++++++-- .../lib/src/base/incremental_compiler.dart | 60 ++++++++++++-- .../src/type_inference/inference_visitor.dart | 82 +++++++++++++++++-- .../inference_visitor_base.dart | 32 +++++++- pkg/front_end/test/expression_suite.dart | 18 +++- .../test/spell_checking_list_code.txt | 2 + .../beyond_dart_semantics_01.expression.yaml | 46 +++++++++++ ...d_dart_semantics_01.expression.yaml.expect | 4 + .../beyond_dart_semantics_02.expression.yaml | 48 +++++++++++ ...d_dart_semantics_02.expression.yaml.expect | 4 + .../beyond_dart_semantics_03.expression.yaml | 55 +++++++++++++ ...d_dart_semantics_03.expression.yaml.expect | 4 + ...nd_dart_semantics_03_prime.expression.yaml | 63 ++++++++++++++ ..._semantics_03_prime.expression.yaml.expect | 4 + .../beyond_dart_semantics_04.expression.yaml | 55 +++++++++++++ ...d_dart_semantics_04.expression.yaml.expect | 4 + .../beyond_dart_semantics_05.expression.yaml | 52 ++++++++++++ ...d_dart_semantics_05.expression.yaml.expect | 4 + .../beyond_dart_semantics_06.expression.yaml | 52 ++++++++++++ ...d_dart_semantics_06.expression.yaml.expect | 4 + .../beyond_dart_semantics_07.expression.yaml | 52 ++++++++++++ ...d_dart_semantics_07.expression.yaml.expect | 4 + .../beyond_dart_semantics_08.expression.yaml | 52 ++++++++++++ ...d_dart_semantics_08.expression.yaml.expect | 4 + .../beyond_dart_semantics_09.expression.yaml | 52 ++++++++++++ ...d_dart_semantics_09.expression.yaml.expect | 4 + .../beyond_dart_semantics_10.expression.yaml | 52 ++++++++++++ ...d_dart_semantics_10.expression.yaml.expect | 4 + .../extension_usage_from_dill.yaml | 4 - ...from_dill.yaml.world.1.expression.2.expect | 2 +- ...from_dill.yaml.world.1.expression.3.expect | 2 +- ...from_dill.yaml.world.2.expression.2.expect | 2 +- ...from_dill.yaml.world.2.expression.3.expect | 2 +- pkg/kernel/lib/text/ast_to_text.dart | 10 ++- pkg/vm_service/test/eval_test_common.dart | 8 +- 35 files changed, 844 insertions(+), 39 deletions(-) create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_01.expression.yaml create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_01.expression.yaml.expect create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_02.expression.yaml create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_02.expression.yaml.expect create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_03.expression.yaml create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_03.expression.yaml.expect create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_03_prime.expression.yaml create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_03_prime.expression.yaml.expect create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_04.expression.yaml create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_04.expression.yaml.expect create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_05.expression.yaml create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_05.expression.yaml.expect create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_06.expression.yaml create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_06.expression.yaml.expect create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_07.expression.yaml create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_07.expression.yaml.expect create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_08.expression.yaml create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_08.expression.yaml.expect create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_09.expression.yaml create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_09.expression.yaml.expect create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_10.expression.yaml create mode 100644 pkg/front_end/testcases/expression/beyond_dart_semantics_10.expression.yaml.expect diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart index 0c2ef265ab3..acccc9609a9 100644 --- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart +++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart @@ -1066,8 +1066,10 @@ void runAgnosticSharedTestsShard1( breakpointId: 'innerScopeBP', expression: 'notInScope', expectedError: - "Error: The getter 'notInScope' isn't defined for the" - " type 'C'.", + "DartError: NoSuchMethodError: 'notInScope'\n" + 'method not found\n' + "Receiver: Instance of 'C'\n" + 'Arguments: []\n', ); }); @@ -1076,8 +1078,10 @@ void runAgnosticSharedTestsShard1( breakpointId: 'innerScopeBP', expression: 'innerNotInScope', expectedError: - "Error: The getter 'innerNotInScope' isn't defined for the" - " type 'C'.", + "DartError: NoSuchMethodError: 'innerNotInScope'\n" + 'method not found\n' + "Receiver: Instance of 'C'\n" + 'Arguments: []\n', ); }); }); @@ -1105,7 +1109,11 @@ void runAgnosticSharedTestsShard1( await driver.checkInFrame( breakpointId: 'parseIntPlusOneBP', expression: 'typo', - expectedError: "Error: The getter 'typo' isn't defined", + expectedError: + "DartError: NoSuchMethodError: 'typo'\n" + 'method not found\n' + 'Receiver: "1234"\n' + 'Arguments: []\n', ); }); @@ -1183,7 +1191,11 @@ void runAgnosticSharedTestsShard1( await driver.checkInFrame( breakpointId: 'methodBP', expression: 'typo', - expectedError: "The getter 'typo' isn't defined for the type 'C'", + expectedError: + "DartError: NoSuchMethodError: 'typo'\n" + 'method not found\n' + "Receiver: Instance of 'C'\n" + 'Arguments: []\n', ); }); @@ -1510,7 +1522,11 @@ void runAgnosticSharedTestsShard2( await driver.checkInFrame( breakpointId: 'constructorBP', expression: 'typo', - expectedError: "The getter 'typo' isn't defined for the type 'C'", + expectedError: + "DartError: NoSuchMethodError: 'typo'\n" + 'method not found\n' + "Receiver: Instance of 'C'\n" + 'Arguments: []\n', ); }); @@ -1645,7 +1661,11 @@ void runAgnosticSharedTestsShard2( await driver.checkInFrame( breakpointId: 'asyncTestBP1', expression: 'typo', - expectedError: "The getter 'typo' isn't defined for the type 'D'", + expectedError: + "DartError: NoSuchMethodError: 'typo'\n" + 'method not found\n' + "Receiver: Instance of 'D'\n" + 'Arguments: []\n', ); }); diff --git a/pkg/front_end/lib/src/base/incremental_compiler.dart b/pkg/front_end/lib/src/base/incremental_compiler.dart index 9e08bd4ee8a..ea1f138221b 100644 --- a/pkg/front_end/lib/src/base/incremental_compiler.dart +++ b/pkg/front_end/lib/src/base/incremental_compiler.dart @@ -10,6 +10,7 @@ import 'package:_fe_analyzer_shared/src/scanner/abstract_scanner.dart' show ScannerConfiguration; import 'package:front_end/src/base/name_space.dart'; import 'package:front_end/src/type_inference/inference_results.dart'; +import 'package:front_end/src/type_inference/object_access_target.dart'; import 'package:kernel/binary/ast_from_binary.dart' show BinaryBuilderWithMetadata, @@ -20,7 +21,7 @@ import 'package:kernel/binary/ast_from_binary.dart' import 'package:kernel/canonical_name.dart' show CanonicalNameError, CanonicalNameSdkError; import 'package:kernel/class_hierarchy.dart' - show ClassHierarchy, ClosedWorldClassHierarchy; + show ClassHierarchy, ClassHierarchySubtypes, ClosedWorldClassHierarchy; import 'package:kernel/dart_scope_calculator.dart' show DartScope, DartScopeBuilder2; import 'package:kernel/kernel.dart' @@ -35,6 +36,7 @@ import 'package:kernel/kernel.dart' ExtensionType, ExtensionTypeDeclaration, FunctionNode, + InterfaceType, Library, LibraryDependency, LibraryPart, @@ -50,10 +52,11 @@ import 'package:kernel/kernel.dart' TreeNode, TypeParameter, VariableDeclaration, + VariableGet, + VariableSet, VisitorDefault, VisitorVoidMixin, - VariableGet, - VariableSet; + Member; import 'package:kernel/kernel.dart' as kernel show Combinator; import 'package:kernel/reference_from_index.dart'; import 'package:kernel/target/changed_structure_notifier.dart' @@ -92,7 +95,7 @@ import '../source/source_library_builder.dart' import '../source/source_loader.dart'; import '../type_inference/inference_helper.dart' show InferenceHelper; import '../type_inference/inference_visitor.dart' - show ExpressionEvaluationHelper; + show ExpressionEvaluationHelper, OverwrittenInterfaceMember; import '../util/error_reporter_file_copier.dart' show saveAsGzip; import '../util/experiment_environment_getter.dart' show enableIncrementalCompilerBenchmarking, getExperimentEnvironment; @@ -1953,8 +1956,10 @@ class IncrementalCompiler implements IncrementalKernelGenerator { new Name(syntheticProcedureName), ProcedureKind.Method, parameters, isStatic: isStatic, fileUri: debugLibrary.fileUri); + ClassHierarchy hierarchy = lastGoodKernelTarget.loader.hierarchy; + ExpressionEvaluationHelper expressionEvaluationHelper = - new ExpressionEvaluationHelperImpl(extraKnownVariables); + new ExpressionEvaluationHelperImpl(extraKnownVariables, hierarchy); Expression compiledExpression = await lastGoodKernelTarget.loader .buildExpression( @@ -2188,8 +2193,10 @@ class IncrementalCompiler implements IncrementalKernelGenerator { // Coverage-ignore(suite): Not run. class ExpressionEvaluationHelperImpl implements ExpressionEvaluationHelper { final Set knownButUnavailable = {}; + final ClassHierarchy hierarchy; - ExpressionEvaluationHelperImpl(List extraKnown) { + ExpressionEvaluationHelperImpl( + List extraKnown, this.hierarchy) { for (VariableDeclarationImpl variable in extraKnown) { if (variable.isConst) { // We allow const variables - these are inlined (we check @@ -2232,6 +2239,47 @@ class ExpressionEvaluationHelperImpl implements ExpressionEvaluationHelper { includeExpression: false, )); } + + @override + OverwrittenInterfaceMember? overwriteFindInterfaceMember({ + required ObjectAccessTarget target, + required DartType receiverType, + required Name name, + }) { + // On a missing target, rewrite to a dynamic target instead. + if (target.kind == ObjectAccessTargetKind.missing) { + // On a private name, try to find a descendant of receiverType + // that has the name. + ClassHierarchy hierarchy = this.hierarchy; + if (name.isPrivate && + receiverType is InterfaceType && + hierarchy is ClosedWorldClassHierarchy) { + // Find all libraries that contains a subtype of this type with a + // textually matching name. + ClassHierarchySubtypes subtypeInformation = + hierarchy.computeSubtypesInformation(); + Set foundMatchInLibrary = {}; + for (Class cls + in subtypeInformation.getSubtypesOf(receiverType.classNode)) { + for (Member member in cls.members) { + if (member.name.text == name.text) { + foundMatchInLibrary.add(cls.enclosingLibrary); + break; + } + } + } + // If we only found one such library we overwrite the name so the VM + // will mangle the names right and find the wanted target. + if (foundMatchInLibrary.length == 1 && + name.library != foundMatchInLibrary.first) { + name = new Name(name.text, foundMatchInLibrary.first); + } + } + return new OverwrittenInterfaceMember( + target: const ObjectAccessTarget.dynamic(), name: name); + } + return null; + } } // Coverage-ignore(suite): Not run. diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/type_inference/inference_visitor.dart index 4ff4f4293d0..57eec271d85 100644 --- a/pkg/front_end/lib/src/type_inference/inference_visitor.dart +++ b/pkg/front_end/lib/src/type_inference/inference_visitor.dart @@ -72,7 +72,6 @@ import 'shared_type_analyzer.dart'; import 'stack_values.dart'; import 'type_constraint_gatherer.dart'; import 'type_inference_engine.dart'; -import 'type_inferrer.dart' show TypeInferrerImpl; import 'type_schema.dart' show UnknownType, isKnown; abstract class InferenceVisitor { @@ -174,18 +173,13 @@ class InferenceVisitorImpl extends InferenceVisitorBase // variable was declared outside the try statement or local function. bool _inTryOrLocalFunction = false; - /// Helper used to issue correct error messages and avoid access to - /// unavailable variables upon expression evaluation. - final ExpressionEvaluationHelper? expressionEvaluationHelper; - InferenceVisitorImpl( - TypeInferrerImpl inferrer, - InferenceHelper helper, + super.inferrer, + super.helper, this._constructorBuilder, this.operations, this.typeAnalyzerOptions, - this.expressionEvaluationHelper) - : super(inferrer, helper); + super.expressionEvaluationHelper); @override int get stackHeight => _rewriteStack.length; @@ -7292,6 +7286,16 @@ class InferenceVisitorImpl extends InferenceVisitorBase leftType, binaryName, fileOffset, includeExtensionMethods: true, isSetter: false); + if (expressionEvaluationHelper != null) { + // Coverage-ignore-block(suite): Not run. + OverwrittenInterfaceMember? overWritten = + expressionEvaluationHelper?.overwriteFindInterfaceMember( + target: binaryTarget, name: binaryName, receiverType: leftType); + if (overWritten != null) { + binaryTarget = overWritten.target; + } + } + MethodContravarianceCheckKind binaryCheckKind = preCheckInvocationContravariance(leftType, binaryTarget, isThisReceiver: false); @@ -7462,6 +7466,18 @@ class InferenceVisitorImpl extends InferenceVisitorBase expressionType, unaryName, fileOffset, includeExtensionMethods: true, isSetter: false); + if (expressionEvaluationHelper != null) { + // Coverage-ignore-block(suite): Not run. + OverwrittenInterfaceMember? overWritten = + expressionEvaluationHelper?.overwriteFindInterfaceMember( + target: unaryTarget, + name: unaryName, + receiverType: expressionType); + if (overWritten != null) { + unaryTarget = overWritten.target; + } + } + MethodContravarianceCheckKind unaryCheckKind = preCheckInvocationContravariance(expressionType, unaryTarget, isThisReceiver: false); @@ -7589,6 +7605,17 @@ class InferenceVisitorImpl extends InferenceVisitorBase Expression readIndex, DartType indexType, MethodContravarianceCheckKind readCheckKind) { + if (expressionEvaluationHelper != null) { + // Coverage-ignore-block(suite): Not run. + OverwrittenInterfaceMember? overWritten = + expressionEvaluationHelper?.overwriteFindInterfaceMember( + target: readTarget, + name: indexGetName, + receiverType: receiverType); + if (overWritten != null) { + readTarget = overWritten.target; + } + } Expression read; DartType readType = readTarget.getReturnType(this); switch (readTarget.kind) { @@ -7731,6 +7758,17 @@ class InferenceVisitorImpl extends InferenceVisitorBase DartType indexType, Expression value, DartType valueType) { + if (expressionEvaluationHelper != null) { + // Coverage-ignore-block(suite): Not run. + OverwrittenInterfaceMember? overWritten = + expressionEvaluationHelper?.overwriteFindInterfaceMember( + target: writeTarget, + name: indexSetName, + receiverType: receiverType); + if (overWritten != null) { + writeTarget = overWritten.target; + } + } Expression write; switch (writeTarget.kind) { case ObjectAccessTargetKind.missing: @@ -7902,6 +7940,18 @@ class InferenceVisitorImpl extends InferenceVisitorBase Expression value, {required DartType valueType, required bool forEffect}) { + if (expressionEvaluationHelper != null) { + // Coverage-ignore-block(suite): Not run. + OverwrittenInterfaceMember? overWritten = + expressionEvaluationHelper?.overwriteFindInterfaceMember( + target: writeTarget, + name: propertyName, + receiverType: receiverType); + if (overWritten != null) { + writeTarget = overWritten.target; + propertyName = overWritten.name; + } + } Expression write; DartType writeType = valueType; switch (writeTarget.kind) { @@ -12824,4 +12874,18 @@ abstract class ExpressionEvaluationHelper { ExpressionInferenceResult? visitVariableSet( VariableSet node, DartType typeContext, InferenceHelper helper); + + OverwrittenInterfaceMember? overwriteFindInterfaceMember({ + required ObjectAccessTarget target, + required DartType receiverType, + required Name name, + }); +} + +// Coverage-ignore(suite): Not run. +class OverwrittenInterfaceMember { + final ObjectAccessTarget target; + final Name name; + + OverwrittenInterfaceMember({required this.target, required this.name}); } diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart index a38339ab7f5..9ac647f2af0 100644 --- a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart +++ b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart @@ -141,7 +141,12 @@ abstract class InferenceVisitorBase implements InferenceVisitor { final InferenceHelper _helper; - InferenceVisitorBase(this._inferrer, this._helper); + /// Helper used to issue correct error messages and avoid access to + /// unavailable variables upon expression evaluation. + final ExpressionEvaluationHelper? expressionEvaluationHelper; + + InferenceVisitorBase( + this._inferrer, this._helper, this.expressionEvaluationHelper); AssignedVariables get assignedVariables => _inferrer.assignedVariables; @@ -3797,6 +3802,17 @@ abstract class InferenceVisitorBase implements InferenceVisitor { isSetter: false, ); + if (expressionEvaluationHelper != null) { + // Coverage-ignore-block(suite): Not run. + OverwrittenInterfaceMember? overWritten = + expressionEvaluationHelper?.overwriteFindInterfaceMember( + target: target, name: name, receiverType: receiverType); + if (overWritten != null) { + target = overWritten.target; + name = overWritten.name; + } + } + switch (target.kind) { case ObjectAccessTargetKind.instanceMember: case ObjectAccessTargetKind.objectMember: @@ -4840,6 +4856,20 @@ abstract class InferenceVisitorBase implements InferenceVisitor { includeExtensionMethods: true, isSetter: false, ); + + if (expressionEvaluationHelper != null) { + // Coverage-ignore-block(suite): Not run. + OverwrittenInterfaceMember? overWritten = + expressionEvaluationHelper?.overwriteFindInterfaceMember( + target: readTarget, + name: propertyName, + receiverType: receiverType); + if (overWritten != null) { + readTarget = overWritten.target; + propertyName = overWritten.name; + } + } + // Coverage-ignore(suite): Not run. readType ??= readTarget.getGetterType(this); diff --git a/pkg/front_end/test/expression_suite.dart b/pkg/front_end/test/expression_suite.dart index 1c2dd99fbc6..56817cebe3e 100644 --- a/pkg/front_end/test/expression_suite.dart +++ b/pkg/front_end/test/expression_suite.dart @@ -26,6 +26,7 @@ import 'package:front_end/src/compute_platform_binaries_location.dart' show computePlatformBinariesLocation; import 'package:front_end/src/kernel/utils.dart' show serializeComponent, serializeProcedure; +import 'package:front_end/src/source/source_loader.dart'; import 'package:front_end/src/testing/compiler_common.dart'; import "package:kernel/ast.dart" show @@ -95,10 +96,12 @@ class Context extends ChainContext { } class CompilationResult { + Library? compiledInLibrary; Procedure? compiledProcedure; List errors; - CompilationResult(this.compiledProcedure, this.errors); + CompilationResult( + this.compiledInLibrary, this.compiledProcedure, this.errors); String printResult(Uri entryPoint, Context context) { StringBuffer buffer = new StringBuffer(); @@ -119,8 +122,8 @@ class CompilationResult { if (compiledProcedure == null) { buffer.write(""); } else { - Printer printer = new Printer(buffer); - printer.visitProcedure(compiledProcedure!); + Printer printer = new Printer(buffer, showLibraryForNames: true); + printer.writeProcedureInLibrary(compiledProcedure!, compiledInLibrary!); printer.writeConstantTable(new Component()); } Uri base = entryPoint.resolve("."); @@ -434,6 +437,12 @@ class CompileExpression extends Step, List, Context> { } } + SourceLoader loader = compiler.kernelTargetForTesting!.loader; + Library? libraryLookup = (loader.lookupCompilationUnit(test.library) ?? + loader.lookupCompilationUnitByFileUri(test.library)) + ?.libraryBuilder + .library; + Procedure? compiledProcedure = await compiler.compileExpression( test.expression, definitions, @@ -447,7 +456,8 @@ class CompileExpression extends Step, List, Context> { offset: test.offset ?? TreeNode.noOffset, ); List errors = context.takeErrors(); - test.results.add(new CompilationResult(compiledProcedure, errors)); + test.results + .add(new CompilationResult(libraryLookup, compiledProcedure, errors)); if (compiledProcedure != null) { // Confirm we can serialize generated procedure. compilerResult.component.computeCanonicalNames(); diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt index ef7a8602571..594aaf3f2e4 100644 --- a/pkg/front_end/test/spell_checking_list_code.txt +++ b/pkg/front_end/test/spell_checking_list_code.txt @@ -1090,6 +1090,7 @@ man manage managed manages +mangle mangled manifest manipulating @@ -1909,6 +1910,7 @@ testers tex textualize textualized +textually tfa th thereby diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_01.expression.yaml b/pkg/front_end/testcases/expression/beyond_dart_semantics_01.expression.yaml new file mode 100644 index 00000000000..30d68fc5ac8 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_01.expression.yaml @@ -0,0 +1,46 @@ +# 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. + +# Definition, offset, method etc extracted by starting the VM with +# `-DDFE_VERBOSE=true`, e.g. +# ``` +# out/ReleaseX64/dart -DDFE_VERBOSE=true --enable-vm-service \ +# --disable-service-auth-codes --pause_isolates_on_start inputFile.dart +# ``` +# and then issuing the expression compilation. +# +# A list of "A"s has a "B" in it. Given that it's a List we can't access +# B-members in Dart - but expression evaluation should be able to. + +sources: | + import "dart:developer"; + + abstract class A {} + class B extends A { + final int value; + B(this.value); + } + + void foo (List list) { + debugger(); + for(var element in list) { + print(element); + } + } + + void main() { + foo([new B(42)]); + } + +definitions: ["list"] +definition_types: ["dart:core", "_GrowableList", "1", "1", "org-dartlang-test:///a/b/c/main.dart", "A", "1", "0"] +type_definitions: [] +type_bounds: [] +type_defaults: [] +method: "foo" +static: true +offset: 133 +scriptUri: main.dart +expression: | + list.first.value diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_01.expression.yaml.expect b/pkg/front_end/testcases/expression/beyond_dart_semantics_01.expression.yaml.expect new file mode 100644 index 00000000000..6e8784a56b5 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_01.expression.yaml.expect @@ -0,0 +1,4 @@ +Errors: { +} +static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dart.core::_GrowableList<#lib1::A> list) → dynamic + return list.{dart.core::_GrowableList::first}{#lib1::A}{dynamic}.value; diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_02.expression.yaml b/pkg/front_end/testcases/expression/beyond_dart_semantics_02.expression.yaml new file mode 100644 index 00000000000..cd6c48fc553 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_02.expression.yaml @@ -0,0 +1,48 @@ +# 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. + +# Definition, offset, method etc extracted by starting the VM with +# `-DDFE_VERBOSE=true`, e.g. +# ``` +# out/ReleaseX64/dart -DDFE_VERBOSE=true --enable-vm-service \ +# --disable-service-auth-codes --pause_isolates_on_start inputFile.dart +# ``` +# and then issuing the expression compilation. +# +# A list of "A"s has a "B" in it. Given that it's a List we can't access +# B-members in Dart - but expression evaluation should be able to. +# Accessing a private name is a different story though - but here - with it +# being in the same library - it should be fine. + +sources: | + import "dart:developer"; + + abstract class A {} + class B extends A { + final int _value; + B(this._value); + } + + void foo (List list) { + debugger(); + for(var element in list) { + print(element); + } + } + + void main() { + foo([new B(42)]); + } + +definitions: ["list"] +definition_types: ["dart:core", "_GrowableList", "1", "1", "org-dartlang-test:///a/b/c/main.dart", "A", "1", "0"] +type_definitions: [] +type_bounds: [] +type_defaults: [] +method: "foo" +static: true +offset: 135 +scriptUri: main.dart +expression: | + list.first._value diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_02.expression.yaml.expect b/pkg/front_end/testcases/expression/beyond_dart_semantics_02.expression.yaml.expect new file mode 100644 index 00000000000..f894a0f72ac --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_02.expression.yaml.expect @@ -0,0 +1,4 @@ +Errors: { +} +static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dart.core::_GrowableList<#lib1::A> list) → dynamic + return list.{dart.core::_GrowableList::first}{#lib1::A}{dynamic}._value; diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_03.expression.yaml b/pkg/front_end/testcases/expression/beyond_dart_semantics_03.expression.yaml new file mode 100644 index 00000000000..7a08b340abe --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_03.expression.yaml @@ -0,0 +1,55 @@ +# 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. + +# Definition, offset, method etc extracted by starting the VM with +# `-DDFE_VERBOSE=true`, e.g. +# ``` +# out/ReleaseX64/dart -DDFE_VERBOSE=true --enable-vm-service \ +# --disable-service-auth-codes --pause_isolates_on_start inputFile.dart +# ``` +# and then issuing the expression compilation. +# +# A list of "A"s has a "B" in it. Given that it's a List we can't access +# B-members in Dart - but expression evaluation should be able to. +# Accessing a private name is a different story though - but here - where there +# is a single library that has a subclass of A (i.e. B) with a matching name +# we should be able to use that. + +sources: + main.dart: | + library main; + import "dart:developer"; + import "lib.dart"; + + abstract class A {} + + void foo (List list) { + debugger(); + for(var element in list) { + print(element); + } + } + + void main() { + foo([new B(42)]); + } + lib.dart: | + library lib; + import "main.dart"; + class B extends A { + final int _value; + B(this._value); + } + +definitions: ["list"] +definition_types: ["dart:core", "_GrowableList", "1", "1", "org-dartlang-test:///a/b/c/main.dart", "A", "1", "0"] +type_definitions: [] +type_bounds: [] +type_defaults: [] +method: "foo" +static: true +offset: 94 +scriptUri: main.dart +expression: | + list.first._value diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_03.expression.yaml.expect b/pkg/front_end/testcases/expression/beyond_dart_semantics_03.expression.yaml.expect new file mode 100644 index 00000000000..1da3716a9df --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_03.expression.yaml.expect @@ -0,0 +1,4 @@ +Errors: { +} +static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dart.core::_GrowableList list) → dynamic + return list.{dart.core::_GrowableList::first}{main::A}{dynamic}.lib::_value; diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_03_prime.expression.yaml b/pkg/front_end/testcases/expression/beyond_dart_semantics_03_prime.expression.yaml new file mode 100644 index 00000000000..39a7242bf87 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_03_prime.expression.yaml @@ -0,0 +1,63 @@ +# 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. + +# Definition, offset, method etc extracted by starting the VM with +# `-DDFE_VERBOSE=true`, e.g. +# ``` +# out/ReleaseX64/dart -DDFE_VERBOSE=true --enable-vm-service \ +# --disable-service-auth-codes --pause_isolates_on_start inputFile.dart +# ``` +# and then issuing the expression compilation. +# +# A list of "A"s has a "B" in it. Given that it's a List we can't access +# B-members in Dart - but expression evaluation should be able to. +# Accessing a private name is a different story though - but here - where there +# are move than one library that has a subclass of A (both B and C) with a +# matching name we can't pick one. + +sources: + main.dart: | + library main; + import "dart:developer"; + import "lib1.dart"; + import "lib2.dart"; + + abstract class A {} + + void foo (List list) { + debugger(); + for(var element in list) { + print(element); + } + } + + void main() { + foo([new B(42)]); + } + lib1.dart: | + library lib1; + import "main.dart"; + class B extends A { + final int _value; + B(this._value); + } + lib2.dart: | + library lib2; + import "main.dart"; + class C extends A { + final int _value; + C(this._value); + } + +definitions: ["list"] +definition_types: ["dart:core", "_GrowableList", "1", "1", "org-dartlang-test:///a/b/c/main.dart", "A", "1", "0"] +type_definitions: [] +type_bounds: [] +type_defaults: [] +method: "foo" +static: true +offset: 94 +scriptUri: main.dart +expression: | + list.first._value diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_03_prime.expression.yaml.expect b/pkg/front_end/testcases/expression/beyond_dart_semantics_03_prime.expression.yaml.expect new file mode 100644 index 00000000000..b50d3c244e2 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_03_prime.expression.yaml.expect @@ -0,0 +1,4 @@ +Errors: { +} +static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dart.core::_GrowableList list) → dynamic + return list.{dart.core::_GrowableList::first}{main::A}{dynamic}._value; diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_04.expression.yaml b/pkg/front_end/testcases/expression/beyond_dart_semantics_04.expression.yaml new file mode 100644 index 00000000000..4f5ab6ec92d --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_04.expression.yaml @@ -0,0 +1,55 @@ +# 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. + +# Definition, offset, method etc extracted by starting the VM with +# `-DDFE_VERBOSE=true`, e.g. +# ``` +# out/ReleaseX64/dart -DDFE_VERBOSE=true --enable-vm-service \ +# --disable-service-auth-codes --pause_isolates_on_start inputFile.dart +# ``` +# and then issuing the expression compilation. +# +# A list of "A"s has a "B" in it. Given that it's a List we can't access +# B-members in Dart - but expression evaluation should be able to. +# Accessing a private name is a different story though - but here - where there +# is a single library that has a subclass of A (i.e. B) with a matching name +# we should be able to use that. + +sources: + main.dart: | + library main; + import "dart:developer"; + import "lib.dart"; + + abstract class A {} + + void foo (List list) { + debugger(); + for(var element in list) { + print(element); + } + } + + void main() { + foo([new B(42)]); + } + lib.dart: | + library lib; + import "main.dart"; + class B extends A { + int _value; + B(this._value); + } + +definitions: ["list"] +definition_types: ["dart:core", "_GrowableList", "1", "1", "org-dartlang-test:///a/b/c/main.dart", "A", "1", "0"] +type_definitions: [] +type_bounds: [] +type_defaults: [] +method: "foo" +static: true +offset: 94 +scriptUri: main.dart +expression: | + list.first._value = 41 diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_04.expression.yaml.expect b/pkg/front_end/testcases/expression/beyond_dart_semantics_04.expression.yaml.expect new file mode 100644 index 00000000000..dc393b65290 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_04.expression.yaml.expect @@ -0,0 +1,4 @@ +Errors: { +} +static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dart.core::_GrowableList list) → dynamic + return list.{dart.core::_GrowableList::first}{main::A}.{dynamic}lib::_value = 41; diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_05.expression.yaml b/pkg/front_end/testcases/expression/beyond_dart_semantics_05.expression.yaml new file mode 100644 index 00000000000..86ba8cb307a --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_05.expression.yaml @@ -0,0 +1,52 @@ +# 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. + +# Definition, offset, method etc extracted by starting the VM with +# `-DDFE_VERBOSE=true`, e.g. +# ``` +# out/ReleaseX64/dart -DDFE_VERBOSE=true --enable-vm-service \ +# --disable-service-auth-codes --pause_isolates_on_start inputFile.dart +# ``` +# and then issuing the expression compilation. +# +# A list of "A"s has a "B" in it. Given that it's a List we can't access +# B-members in Dart - but expression evaluation should be able to. +# Here a method call. + +sources: + main.dart: | + library main; + import "dart:developer"; + import "lib.dart"; + + abstract class A {} + + void foo (List list) { + debugger(); + for(var element in list) { + print(element); + } + } + + void main() { + foo([new B()]); + } + lib.dart: | + library lib; + import "main.dart"; + class B extends A { + String hello() => "hello"; + } + +definitions: ["list"] +definition_types: ["dart:core", "_GrowableList", "1", "1", "org-dartlang-test:///a/b/c/main.dart", "A", "1", "0"] +type_definitions: [] +type_bounds: [] +type_defaults: [] +method: "foo" +static: true +offset: 94 +scriptUri: main.dart +expression: | + list.first.hello() diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_05.expression.yaml.expect b/pkg/front_end/testcases/expression/beyond_dart_semantics_05.expression.yaml.expect new file mode 100644 index 00000000000..81d5f443de9 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_05.expression.yaml.expect @@ -0,0 +1,4 @@ +Errors: { +} +static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dart.core::_GrowableList list) → dynamic + return list.{dart.core::_GrowableList::first}{main::A}{dynamic}.hello(); diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_06.expression.yaml b/pkg/front_end/testcases/expression/beyond_dart_semantics_06.expression.yaml new file mode 100644 index 00000000000..dfa96448aca --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_06.expression.yaml @@ -0,0 +1,52 @@ +# 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. + +# Definition, offset, method etc extracted by starting the VM with +# `-DDFE_VERBOSE=true`, e.g. +# ``` +# out/ReleaseX64/dart -DDFE_VERBOSE=true --enable-vm-service \ +# --disable-service-auth-codes --pause_isolates_on_start inputFile.dart +# ``` +# and then issuing the expression compilation. +# +# A list of "A"s has a "B" in it. Given that it's a List we can't access +# B-members in Dart - but expression evaluation should be able to. +# Here a private method call. + +sources: + main.dart: | + library main; + import "dart:developer"; + import "lib.dart"; + + abstract class A {} + + void foo (List list) { + debugger(); + for(var element in list) { + print(element); + } + } + + void main() { + foo([new B()]); + } + lib.dart: | + library lib; + import "main.dart"; + class B extends A { + String _hello() => "hello"; + } + +definitions: ["list"] +definition_types: ["dart:core", "_GrowableList", "1", "1", "org-dartlang-test:///a/b/c/main.dart", "A", "1", "0"] +type_definitions: [] +type_bounds: [] +type_defaults: [] +method: "foo" +static: true +offset: 94 +scriptUri: main.dart +expression: | + list.first._hello() diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_06.expression.yaml.expect b/pkg/front_end/testcases/expression/beyond_dart_semantics_06.expression.yaml.expect new file mode 100644 index 00000000000..795381c2443 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_06.expression.yaml.expect @@ -0,0 +1,4 @@ +Errors: { +} +static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dart.core::_GrowableList list) → dynamic + return list.{dart.core::_GrowableList::first}{main::A}{dynamic}.lib::_hello(); diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_07.expression.yaml b/pkg/front_end/testcases/expression/beyond_dart_semantics_07.expression.yaml new file mode 100644 index 00000000000..ffcfecf3852 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_07.expression.yaml @@ -0,0 +1,52 @@ +# 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. + +# Definition, offset, method etc extracted by starting the VM with +# `-DDFE_VERBOSE=true`, e.g. +# ``` +# out/ReleaseX64/dart -DDFE_VERBOSE=true --enable-vm-service \ +# --disable-service-auth-codes --pause_isolates_on_start inputFile.dart +# ``` +# and then issuing the expression compilation. +# +# A list of "A"s has a "B" in it. Given that it's a List we can't access +# B-members in Dart - but expression evaluation should be able to. +# Here an index get. + +sources: + main.dart: | + library main; + import "dart:developer"; + import "lib.dart"; + + abstract class A {} + + void foo (List list) { + debugger(); + for(var element in list) { + print(element); + } + } + + void main() { + foo([new B()]); + } + lib.dart: | + library lib; + import "main.dart"; + class B extends A { + int operator [](int index) => 42; + } + +definitions: ["list"] +definition_types: ["dart:core", "_GrowableList", "1", "1", "org-dartlang-test:///a/b/c/main.dart", "A", "1", "0"] +type_definitions: [] +type_bounds: [] +type_defaults: [] +method: "foo" +static: true +offset: 94 +scriptUri: main.dart +expression: | + list.first[1] diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_07.expression.yaml.expect b/pkg/front_end/testcases/expression/beyond_dart_semantics_07.expression.yaml.expect new file mode 100644 index 00000000000..28ceb3d7d93 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_07.expression.yaml.expect @@ -0,0 +1,4 @@ +Errors: { +} +static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dart.core::_GrowableList list) → dynamic + return list.{dart.core::_GrowableList::first}{main::A}{dynamic}.[](1); diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_08.expression.yaml b/pkg/front_end/testcases/expression/beyond_dart_semantics_08.expression.yaml new file mode 100644 index 00000000000..36207f523c3 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_08.expression.yaml @@ -0,0 +1,52 @@ +# 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. + +# Definition, offset, method etc extracted by starting the VM with +# `-DDFE_VERBOSE=true`, e.g. +# ``` +# out/ReleaseX64/dart -DDFE_VERBOSE=true --enable-vm-service \ +# --disable-service-auth-codes --pause_isolates_on_start inputFile.dart +# ``` +# and then issuing the expression compilation. +# +# A list of "A"s has a "B" in it. Given that it's a List we can't access +# B-members in Dart - but expression evaluation should be able to. +# Here an index set. + +sources: + main.dart: | + library main; + import "dart:developer"; + import "lib.dart"; + + abstract class A {} + + void foo (List list) { + debugger(); + for(var element in list) { + print(element); + } + } + + void main() { + foo([new B()]); + } + lib.dart: | + library lib; + import "main.dart"; + class B extends A { + void operator []=(int index, int value) {} + } + +definitions: ["list"] +definition_types: ["dart:core", "_GrowableList", "1", "1", "org-dartlang-test:///a/b/c/main.dart", "A", "1", "0"] +type_definitions: [] +type_bounds: [] +type_defaults: [] +method: "foo" +static: true +offset: 94 +scriptUri: main.dart +expression: | + list.first[1] = 42 diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_08.expression.yaml.expect b/pkg/front_end/testcases/expression/beyond_dart_semantics_08.expression.yaml.expect new file mode 100644 index 00000000000..133eff746c0 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_08.expression.yaml.expect @@ -0,0 +1,4 @@ +Errors: { +} +static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dart.core::_GrowableList list) → dynamic + return let final main::A #t1 = list.{dart.core::_GrowableList::first}{main::A} in let final dart.core::int #t2 = 1 in let final dart.core::int #t3 = 42 in let final void #t4 = #t1{dynamic}.[]=(#t2, #t3) in #t3; diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_09.expression.yaml b/pkg/front_end/testcases/expression/beyond_dart_semantics_09.expression.yaml new file mode 100644 index 00000000000..274b35cb47c --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_09.expression.yaml @@ -0,0 +1,52 @@ +# 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. + +# Definition, offset, method etc extracted by starting the VM with +# `-DDFE_VERBOSE=true`, e.g. +# ``` +# out/ReleaseX64/dart -DDFE_VERBOSE=true --enable-vm-service \ +# --disable-service-auth-codes --pause_isolates_on_start inputFile.dart +# ``` +# and then issuing the expression compilation. +# +# A list of "A"s has a "B" in it. Given that it's a List we can't access +# B-members in Dart - but expression evaluation should be able to. +# Here an unary expression. + +sources: + main.dart: | + library main; + import "dart:developer"; + import "lib.dart"; + + abstract class A {} + + void foo (List list) { + debugger(); + for(var element in list) { + print(element); + } + } + + void main() { + foo([new B()]); + } + lib.dart: | + library lib; + import "main.dart"; + class B extends A { + int operator -() => 42; + } + +definitions: ["list"] +definition_types: ["dart:core", "_GrowableList", "1", "1", "org-dartlang-test:///a/b/c/main.dart", "A", "1", "0"] +type_definitions: [] +type_bounds: [] +type_defaults: [] +method: "foo" +static: true +offset: 94 +scriptUri: main.dart +expression: | + -list.first diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_09.expression.yaml.expect b/pkg/front_end/testcases/expression/beyond_dart_semantics_09.expression.yaml.expect new file mode 100644 index 00000000000..6c4e44c26e7 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_09.expression.yaml.expect @@ -0,0 +1,4 @@ +Errors: { +} +static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dart.core::_GrowableList list) → dynamic + return list.{dart.core::_GrowableList::first}{main::A}{dynamic}.unary-(); diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_10.expression.yaml b/pkg/front_end/testcases/expression/beyond_dart_semantics_10.expression.yaml new file mode 100644 index 00000000000..6f4f2093b3b --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_10.expression.yaml @@ -0,0 +1,52 @@ +# 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. + +# Definition, offset, method etc extracted by starting the VM with +# `-DDFE_VERBOSE=true`, e.g. +# ``` +# out/ReleaseX64/dart -DDFE_VERBOSE=true --enable-vm-service \ +# --disable-service-auth-codes --pause_isolates_on_start inputFile.dart +# ``` +# and then issuing the expression compilation. +# +# A list of "A"s has a "B" in it. Given that it's a List we can't access +# B-members in Dart - but expression evaluation should be able to. +# Here a binary expression. + +sources: + main.dart: | + library main; + import "dart:developer"; + import "lib.dart"; + + abstract class A {} + + void foo (List list) { + debugger(); + for(var element in list) { + print(element); + } + } + + void main() { + foo([new B()]); + } + lib.dart: | + library lib; + import "main.dart"; + class B extends A { + int operator +(int i) => 40 + i; + } + +definitions: ["list"] +definition_types: ["dart:core", "_GrowableList", "1", "1", "org-dartlang-test:///a/b/c/main.dart", "A", "1", "0"] +type_definitions: [] +type_bounds: [] +type_defaults: [] +method: "foo" +static: true +offset: 94 +scriptUri: main.dart +expression: | + list.first + 2 diff --git a/pkg/front_end/testcases/expression/beyond_dart_semantics_10.expression.yaml.expect b/pkg/front_end/testcases/expression/beyond_dart_semantics_10.expression.yaml.expect new file mode 100644 index 00000000000..3a0e2d67dc2 --- /dev/null +++ b/pkg/front_end/testcases/expression/beyond_dart_semantics_10.expression.yaml.expect @@ -0,0 +1,4 @@ +Errors: { +} +static method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(dart.core::_GrowableList list) → dynamic + return list.{dart.core::_GrowableList::first}{main::A}{dynamic}.+(2); diff --git a/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml b/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml index d01429b0915..408a19f7006 100644 --- a/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml +++ b/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml @@ -41,10 +41,8 @@ worlds: expression: print("1234".parseInt()) - uri: lib2.dart expression: print("1234".parseInt()) - errors: true - uri: lib3.dart expression: print("1234".parseInt()) - errors: true - uri: main.dart expression: print("1234".parseInt()) - uri: main.dart @@ -86,10 +84,8 @@ worlds: expression: print("1234".parseInt()) - uri: lib2.dart expression: print("1234".parseInt()) - errors: true - uri: lib3.dart expression: print("1234".parseInt()) - errors: true - uri: main.dart expression: print("1234".parseInt()) - uri: main.dart diff --git a/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.1.expression.2.expect b/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.1.expression.2.expect index e0672a24c6f..43e93b0d61f 100644 --- a/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.1.expression.2.expect +++ b/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.1.expression.2.expect @@ -1,2 +1,2 @@ method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr() → dynamic - return dart.core::print(invalid-expression "org-dartlang-debug:synthetic_debug_expression:1:14: Error: The method 'parseInt' isn't defined for the type 'String'.\nTry correcting the name to the name of an existing method, or defining a method named 'parseInt'.\nprint(\"1234\".parseInt())\n ^^^^^^^^" in "1234"{}.parseInt()); + return dart.core::print("1234"{dynamic}.parseInt()); diff --git a/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.1.expression.3.expect b/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.1.expression.3.expect index e0672a24c6f..43e93b0d61f 100644 --- a/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.1.expression.3.expect +++ b/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.1.expression.3.expect @@ -1,2 +1,2 @@ method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr() → dynamic - return dart.core::print(invalid-expression "org-dartlang-debug:synthetic_debug_expression:1:14: Error: The method 'parseInt' isn't defined for the type 'String'.\nTry correcting the name to the name of an existing method, or defining a method named 'parseInt'.\nprint(\"1234\".parseInt())\n ^^^^^^^^" in "1234"{}.parseInt()); + return dart.core::print("1234"{dynamic}.parseInt()); diff --git a/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.2.expression.2.expect b/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.2.expression.2.expect index e0672a24c6f..43e93b0d61f 100644 --- a/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.2.expression.2.expect +++ b/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.2.expression.2.expect @@ -1,2 +1,2 @@ method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr() → dynamic - return dart.core::print(invalid-expression "org-dartlang-debug:synthetic_debug_expression:1:14: Error: The method 'parseInt' isn't defined for the type 'String'.\nTry correcting the name to the name of an existing method, or defining a method named 'parseInt'.\nprint(\"1234\".parseInt())\n ^^^^^^^^" in "1234"{}.parseInt()); + return dart.core::print("1234"{dynamic}.parseInt()); diff --git a/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.2.expression.3.expect b/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.2.expression.3.expect index e0672a24c6f..43e93b0d61f 100644 --- a/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.2.expression.3.expect +++ b/pkg/front_end/testcases/incremental/extension_usage_from_dill.yaml.world.2.expression.3.expect @@ -1,2 +1,2 @@ method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr() → dynamic - return dart.core::print(invalid-expression "org-dartlang-debug:synthetic_debug_expression:1:14: Error: The method 'parseInt' isn't defined for the type 'String'.\nTry correcting the name to the name of an existing method, or defining a method named 'parseInt'.\nprint(\"1234\".parseInt())\n ^^^^^^^^" in "1234"{}.parseInt()); + return dart.core::print("1234"{dynamic}.parseInt()); diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart index ce719c78be6..0207788a907 100644 --- a/pkg/kernel/lib/text/ast_to_text.dart +++ b/pkg/kernel/lib/text/ast_to_text.dart @@ -240,6 +240,7 @@ class Printer extends VisitorDefault with VisitorVoidMixin { int column = 0; bool showOffsets; bool showMetadata; + bool showLibraryForNames; Library? _currentLibrary; static final int SPACE = 0; @@ -251,6 +252,7 @@ class Printer extends VisitorDefault with VisitorVoidMixin { {NameSystem? syntheticNames, this.showOffsets = false, this.showMetadata = false, + this.showLibraryForNames = false, this.importTable, this.annotator, this.metadata}) @@ -431,6 +433,12 @@ class Printer extends VisitorDefault with VisitorVoidMixin { outerPrinter: this, importsToPrint: imports); } + void writeProcedureInLibrary(Procedure procedure, Library library) { + _currentLibrary = library; + visitProcedure(procedure); + _currentLibrary = null; + } + void printLibraryImportTable(LibraryImportTable imports) { for (Library library in imports.importedLibraries) { String importPath = imports.getImportPath(library); @@ -704,7 +712,7 @@ class Printer extends VisitorDefault with VisitorVoidMixin { } void writeName(Name name, {bool showLibrary = false}) { - if (showLibrary && + if ((showLibrary || showLibraryForNames) && name.isPrivate && name.libraryReference != _currentLibrary?.reference) { writeWord('${getLibraryReference(name.libraryReference!)}::${name.text}'); diff --git a/pkg/vm_service/test/eval_test_common.dart b/pkg/vm_service/test/eval_test_common.dart index 7b3b33af371..1b9321e7bb5 100644 --- a/pkg/vm_service/test/eval_test_common.dart +++ b/pkg/vm_service/test/eval_test_common.dart @@ -71,8 +71,12 @@ final evalTests = [ print(result); expect(result.valueAsString, '10005'); - await expectError( - () => service.evaluate(isolateId, instance.id!, 'this + frog'), + result = await service.evaluate(isolateId, instance.id!, 'this + frog'); + print(result); + expect(result, isA()); + expect( + result.message, + contains("Class 'int' has no instance getter 'frog'"), ); }, resumeIsolate,