Skip to content

Commit 1f845d1

Browse files
jensjohaCommit Queue
authored andcommitted
[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 <[email protected]> Commit-Queue: Jens Johansen <[email protected]> Reviewed-by: Nicholas Shahan <[email protected]>
1 parent d084999 commit 1f845d1

File tree

35 files changed

+844
-39
lines changed

35 files changed

+844
-39
lines changed

pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,8 +1066,10 @@ void runAgnosticSharedTestsShard1(
10661066
breakpointId: 'innerScopeBP',
10671067
expression: 'notInScope',
10681068
expectedError:
1069-
"Error: The getter 'notInScope' isn't defined for the"
1070-
" type 'C'.",
1069+
"DartError: NoSuchMethodError: 'notInScope'\n"
1070+
'method not found\n'
1071+
"Receiver: Instance of 'C'\n"
1072+
'Arguments: []\n',
10711073
);
10721074
});
10731075

@@ -1076,8 +1078,10 @@ void runAgnosticSharedTestsShard1(
10761078
breakpointId: 'innerScopeBP',
10771079
expression: 'innerNotInScope',
10781080
expectedError:
1079-
"Error: The getter 'innerNotInScope' isn't defined for the"
1080-
" type 'C'.",
1081+
"DartError: NoSuchMethodError: 'innerNotInScope'\n"
1082+
'method not found\n'
1083+
"Receiver: Instance of 'C'\n"
1084+
'Arguments: []\n',
10811085
);
10821086
});
10831087
});
@@ -1105,7 +1109,11 @@ void runAgnosticSharedTestsShard1(
11051109
await driver.checkInFrame(
11061110
breakpointId: 'parseIntPlusOneBP',
11071111
expression: 'typo',
1108-
expectedError: "Error: The getter 'typo' isn't defined",
1112+
expectedError:
1113+
"DartError: NoSuchMethodError: 'typo'\n"
1114+
'method not found\n'
1115+
'Receiver: "1234"\n'
1116+
'Arguments: []\n',
11091117
);
11101118
});
11111119

@@ -1183,7 +1191,11 @@ void runAgnosticSharedTestsShard1(
11831191
await driver.checkInFrame(
11841192
breakpointId: 'methodBP',
11851193
expression: 'typo',
1186-
expectedError: "The getter 'typo' isn't defined for the type 'C'",
1194+
expectedError:
1195+
"DartError: NoSuchMethodError: 'typo'\n"
1196+
'method not found\n'
1197+
"Receiver: Instance of 'C'\n"
1198+
'Arguments: []\n',
11871199
);
11881200
});
11891201

@@ -1510,7 +1522,11 @@ void runAgnosticSharedTestsShard2(
15101522
await driver.checkInFrame(
15111523
breakpointId: 'constructorBP',
15121524
expression: 'typo',
1513-
expectedError: "The getter 'typo' isn't defined for the type 'C'",
1525+
expectedError:
1526+
"DartError: NoSuchMethodError: 'typo'\n"
1527+
'method not found\n'
1528+
"Receiver: Instance of 'C'\n"
1529+
'Arguments: []\n',
15141530
);
15151531
});
15161532

@@ -1645,7 +1661,11 @@ void runAgnosticSharedTestsShard2(
16451661
await driver.checkInFrame(
16461662
breakpointId: 'asyncTestBP1',
16471663
expression: 'typo',
1648-
expectedError: "The getter 'typo' isn't defined for the type 'D'",
1664+
expectedError:
1665+
"DartError: NoSuchMethodError: 'typo'\n"
1666+
'method not found\n'
1667+
"Receiver: Instance of 'D'\n"
1668+
'Arguments: []\n',
16491669
);
16501670
});
16511671

pkg/front_end/lib/src/base/incremental_compiler.dart

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:_fe_analyzer_shared/src/scanner/abstract_scanner.dart'
1010
show ScannerConfiguration;
1111
import 'package:front_end/src/base/name_space.dart';
1212
import 'package:front_end/src/type_inference/inference_results.dart';
13+
import 'package:front_end/src/type_inference/object_access_target.dart';
1314
import 'package:kernel/binary/ast_from_binary.dart'
1415
show
1516
BinaryBuilderWithMetadata,
@@ -20,7 +21,7 @@ import 'package:kernel/binary/ast_from_binary.dart'
2021
import 'package:kernel/canonical_name.dart'
2122
show CanonicalNameError, CanonicalNameSdkError;
2223
import 'package:kernel/class_hierarchy.dart'
23-
show ClassHierarchy, ClosedWorldClassHierarchy;
24+
show ClassHierarchy, ClassHierarchySubtypes, ClosedWorldClassHierarchy;
2425
import 'package:kernel/dart_scope_calculator.dart'
2526
show DartScope, DartScopeBuilder2;
2627
import 'package:kernel/kernel.dart'
@@ -35,6 +36,7 @@ import 'package:kernel/kernel.dart'
3536
ExtensionType,
3637
ExtensionTypeDeclaration,
3738
FunctionNode,
39+
InterfaceType,
3840
Library,
3941
LibraryDependency,
4042
LibraryPart,
@@ -50,10 +52,11 @@ import 'package:kernel/kernel.dart'
5052
TreeNode,
5153
TypeParameter,
5254
VariableDeclaration,
55+
VariableGet,
56+
VariableSet,
5357
VisitorDefault,
5458
VisitorVoidMixin,
55-
VariableGet,
56-
VariableSet;
59+
Member;
5760
import 'package:kernel/kernel.dart' as kernel show Combinator;
5861
import 'package:kernel/reference_from_index.dart';
5962
import 'package:kernel/target/changed_structure_notifier.dart'
@@ -92,7 +95,7 @@ import '../source/source_library_builder.dart'
9295
import '../source/source_loader.dart';
9396
import '../type_inference/inference_helper.dart' show InferenceHelper;
9497
import '../type_inference/inference_visitor.dart'
95-
show ExpressionEvaluationHelper;
98+
show ExpressionEvaluationHelper, OverwrittenInterfaceMember;
9699
import '../util/error_reporter_file_copier.dart' show saveAsGzip;
97100
import '../util/experiment_environment_getter.dart'
98101
show enableIncrementalCompilerBenchmarking, getExperimentEnvironment;
@@ -1953,8 +1956,10 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
19531956
new Name(syntheticProcedureName), ProcedureKind.Method, parameters,
19541957
isStatic: isStatic, fileUri: debugLibrary.fileUri);
19551958

1959+
ClassHierarchy hierarchy = lastGoodKernelTarget.loader.hierarchy;
1960+
19561961
ExpressionEvaluationHelper expressionEvaluationHelper =
1957-
new ExpressionEvaluationHelperImpl(extraKnownVariables);
1962+
new ExpressionEvaluationHelperImpl(extraKnownVariables, hierarchy);
19581963

19591964
Expression compiledExpression = await lastGoodKernelTarget.loader
19601965
.buildExpression(
@@ -2188,8 +2193,10 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
21882193
// Coverage-ignore(suite): Not run.
21892194
class ExpressionEvaluationHelperImpl implements ExpressionEvaluationHelper {
21902195
final Set<VariableDeclarationImpl> knownButUnavailable = {};
2196+
final ClassHierarchy hierarchy;
21912197

2192-
ExpressionEvaluationHelperImpl(List<VariableDeclarationImpl> extraKnown) {
2198+
ExpressionEvaluationHelperImpl(
2199+
List<VariableDeclarationImpl> extraKnown, this.hierarchy) {
21932200
for (VariableDeclarationImpl variable in extraKnown) {
21942201
if (variable.isConst) {
21952202
// We allow const variables - these are inlined (we check
@@ -2232,6 +2239,47 @@ class ExpressionEvaluationHelperImpl implements ExpressionEvaluationHelper {
22322239
includeExpression: false,
22332240
));
22342241
}
2242+
2243+
@override
2244+
OverwrittenInterfaceMember? overwriteFindInterfaceMember({
2245+
required ObjectAccessTarget target,
2246+
required DartType receiverType,
2247+
required Name name,
2248+
}) {
2249+
// On a missing target, rewrite to a dynamic target instead.
2250+
if (target.kind == ObjectAccessTargetKind.missing) {
2251+
// On a private name, try to find a descendant of receiverType
2252+
// that has the name.
2253+
ClassHierarchy hierarchy = this.hierarchy;
2254+
if (name.isPrivate &&
2255+
receiverType is InterfaceType &&
2256+
hierarchy is ClosedWorldClassHierarchy) {
2257+
// Find all libraries that contains a subtype of this type with a
2258+
// textually matching name.
2259+
ClassHierarchySubtypes subtypeInformation =
2260+
hierarchy.computeSubtypesInformation();
2261+
Set<Library> foundMatchInLibrary = {};
2262+
for (Class cls
2263+
in subtypeInformation.getSubtypesOf(receiverType.classNode)) {
2264+
for (Member member in cls.members) {
2265+
if (member.name.text == name.text) {
2266+
foundMatchInLibrary.add(cls.enclosingLibrary);
2267+
break;
2268+
}
2269+
}
2270+
}
2271+
// If we only found one such library we overwrite the name so the VM
2272+
// will mangle the names right and find the wanted target.
2273+
if (foundMatchInLibrary.length == 1 &&
2274+
name.library != foundMatchInLibrary.first) {
2275+
name = new Name(name.text, foundMatchInLibrary.first);
2276+
}
2277+
}
2278+
return new OverwrittenInterfaceMember(
2279+
target: const ObjectAccessTarget.dynamic(), name: name);
2280+
}
2281+
return null;
2282+
}
22352283
}
22362284

22372285
// Coverage-ignore(suite): Not run.

pkg/front_end/lib/src/type_inference/inference_visitor.dart

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ import 'shared_type_analyzer.dart';
7272
import 'stack_values.dart';
7373
import 'type_constraint_gatherer.dart';
7474
import 'type_inference_engine.dart';
75-
import 'type_inferrer.dart' show TypeInferrerImpl;
7675
import 'type_schema.dart' show UnknownType, isKnown;
7776

7877
abstract class InferenceVisitor {
@@ -174,18 +173,13 @@ class InferenceVisitorImpl extends InferenceVisitorBase
174173
// variable was declared outside the try statement or local function.
175174
bool _inTryOrLocalFunction = false;
176175

177-
/// Helper used to issue correct error messages and avoid access to
178-
/// unavailable variables upon expression evaluation.
179-
final ExpressionEvaluationHelper? expressionEvaluationHelper;
180-
181176
InferenceVisitorImpl(
182-
TypeInferrerImpl inferrer,
183-
InferenceHelper helper,
177+
super.inferrer,
178+
super.helper,
184179
this._constructorBuilder,
185180
this.operations,
186181
this.typeAnalyzerOptions,
187-
this.expressionEvaluationHelper)
188-
: super(inferrer, helper);
182+
super.expressionEvaluationHelper);
189183

190184
@override
191185
int get stackHeight => _rewriteStack.length;
@@ -7292,6 +7286,16 @@ class InferenceVisitorImpl extends InferenceVisitorBase
72927286
leftType, binaryName, fileOffset,
72937287
includeExtensionMethods: true, isSetter: false);
72947288

7289+
if (expressionEvaluationHelper != null) {
7290+
// Coverage-ignore-block(suite): Not run.
7291+
OverwrittenInterfaceMember? overWritten =
7292+
expressionEvaluationHelper?.overwriteFindInterfaceMember(
7293+
target: binaryTarget, name: binaryName, receiverType: leftType);
7294+
if (overWritten != null) {
7295+
binaryTarget = overWritten.target;
7296+
}
7297+
}
7298+
72957299
MethodContravarianceCheckKind binaryCheckKind =
72967300
preCheckInvocationContravariance(leftType, binaryTarget,
72977301
isThisReceiver: false);
@@ -7462,6 +7466,18 @@ class InferenceVisitorImpl extends InferenceVisitorBase
74627466
expressionType, unaryName, fileOffset,
74637467
includeExtensionMethods: true, isSetter: false);
74647468

7469+
if (expressionEvaluationHelper != null) {
7470+
// Coverage-ignore-block(suite): Not run.
7471+
OverwrittenInterfaceMember? overWritten =
7472+
expressionEvaluationHelper?.overwriteFindInterfaceMember(
7473+
target: unaryTarget,
7474+
name: unaryName,
7475+
receiverType: expressionType);
7476+
if (overWritten != null) {
7477+
unaryTarget = overWritten.target;
7478+
}
7479+
}
7480+
74657481
MethodContravarianceCheckKind unaryCheckKind =
74667482
preCheckInvocationContravariance(expressionType, unaryTarget,
74677483
isThisReceiver: false);
@@ -7589,6 +7605,17 @@ class InferenceVisitorImpl extends InferenceVisitorBase
75897605
Expression readIndex,
75907606
DartType indexType,
75917607
MethodContravarianceCheckKind readCheckKind) {
7608+
if (expressionEvaluationHelper != null) {
7609+
// Coverage-ignore-block(suite): Not run.
7610+
OverwrittenInterfaceMember? overWritten =
7611+
expressionEvaluationHelper?.overwriteFindInterfaceMember(
7612+
target: readTarget,
7613+
name: indexGetName,
7614+
receiverType: receiverType);
7615+
if (overWritten != null) {
7616+
readTarget = overWritten.target;
7617+
}
7618+
}
75927619
Expression read;
75937620
DartType readType = readTarget.getReturnType(this);
75947621
switch (readTarget.kind) {
@@ -7731,6 +7758,17 @@ class InferenceVisitorImpl extends InferenceVisitorBase
77317758
DartType indexType,
77327759
Expression value,
77337760
DartType valueType) {
7761+
if (expressionEvaluationHelper != null) {
7762+
// Coverage-ignore-block(suite): Not run.
7763+
OverwrittenInterfaceMember? overWritten =
7764+
expressionEvaluationHelper?.overwriteFindInterfaceMember(
7765+
target: writeTarget,
7766+
name: indexSetName,
7767+
receiverType: receiverType);
7768+
if (overWritten != null) {
7769+
writeTarget = overWritten.target;
7770+
}
7771+
}
77347772
Expression write;
77357773
switch (writeTarget.kind) {
77367774
case ObjectAccessTargetKind.missing:
@@ -7902,6 +7940,18 @@ class InferenceVisitorImpl extends InferenceVisitorBase
79027940
Expression value,
79037941
{required DartType valueType,
79047942
required bool forEffect}) {
7943+
if (expressionEvaluationHelper != null) {
7944+
// Coverage-ignore-block(suite): Not run.
7945+
OverwrittenInterfaceMember? overWritten =
7946+
expressionEvaluationHelper?.overwriteFindInterfaceMember(
7947+
target: writeTarget,
7948+
name: propertyName,
7949+
receiverType: receiverType);
7950+
if (overWritten != null) {
7951+
writeTarget = overWritten.target;
7952+
propertyName = overWritten.name;
7953+
}
7954+
}
79057955
Expression write;
79067956
DartType writeType = valueType;
79077957
switch (writeTarget.kind) {
@@ -12824,4 +12874,18 @@ abstract class ExpressionEvaluationHelper {
1282412874

1282512875
ExpressionInferenceResult? visitVariableSet(
1282612876
VariableSet node, DartType typeContext, InferenceHelper helper);
12877+
12878+
OverwrittenInterfaceMember? overwriteFindInterfaceMember({
12879+
required ObjectAccessTarget target,
12880+
required DartType receiverType,
12881+
required Name name,
12882+
});
12883+
}
12884+
12885+
// Coverage-ignore(suite): Not run.
12886+
class OverwrittenInterfaceMember {
12887+
final ObjectAccessTarget target;
12888+
final Name name;
12889+
12890+
OverwrittenInterfaceMember({required this.target, required this.name});
1282712891
}

pkg/front_end/lib/src/type_inference/inference_visitor_base.dart

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,12 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
141141

142142
final InferenceHelper _helper;
143143

144-
InferenceVisitorBase(this._inferrer, this._helper);
144+
/// Helper used to issue correct error messages and avoid access to
145+
/// unavailable variables upon expression evaluation.
146+
final ExpressionEvaluationHelper? expressionEvaluationHelper;
147+
148+
InferenceVisitorBase(
149+
this._inferrer, this._helper, this.expressionEvaluationHelper);
145150

146151
AssignedVariables<TreeNode, VariableDeclaration> get assignedVariables =>
147152
_inferrer.assignedVariables;
@@ -3797,6 +3802,17 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
37973802
isSetter: false,
37983803
);
37993804

3805+
if (expressionEvaluationHelper != null) {
3806+
// Coverage-ignore-block(suite): Not run.
3807+
OverwrittenInterfaceMember? overWritten =
3808+
expressionEvaluationHelper?.overwriteFindInterfaceMember(
3809+
target: target, name: name, receiverType: receiverType);
3810+
if (overWritten != null) {
3811+
target = overWritten.target;
3812+
name = overWritten.name;
3813+
}
3814+
}
3815+
38003816
switch (target.kind) {
38013817
case ObjectAccessTargetKind.instanceMember:
38023818
case ObjectAccessTargetKind.objectMember:
@@ -4840,6 +4856,20 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
48404856
includeExtensionMethods: true,
48414857
isSetter: false,
48424858
);
4859+
4860+
if (expressionEvaluationHelper != null) {
4861+
// Coverage-ignore-block(suite): Not run.
4862+
OverwrittenInterfaceMember? overWritten =
4863+
expressionEvaluationHelper?.overwriteFindInterfaceMember(
4864+
target: readTarget,
4865+
name: propertyName,
4866+
receiverType: receiverType);
4867+
if (overWritten != null) {
4868+
readTarget = overWritten.target;
4869+
propertyName = overWritten.name;
4870+
}
4871+
}
4872+
48434873
// Coverage-ignore(suite): Not run.
48444874
readType ??= readTarget.getGetterType(this);
48454875

0 commit comments

Comments
 (0)