mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 14:32:24 +00:00
Implement AstBuilder integration for method/function invocations.
This is tricky because there isn't a clean correspondence between analyzer's AST (which reflects user syntax) and kernel representation. For example: f(args); could be a call to a static function f, a method f in the current class, or an invocation of a function-typed object stored in a variable called f. ResolutionStorer operates on the kernel representation, so it sees the difference, but ResolutionApplier operates on the analyzer AST, so it does not. So we go to some extra work to make sure a type is stored for f, regardless of whether f is a function, method, or a variable. This requires some re-ordering logic in ResolutionStorer, since the inferred type of f is not known until after the args have been visited. The implementation is not complete; currently the type that we store in the first two cases is `dynamic` because the type inference mechanism doesn't preserve enough information to allow us to determine the correct type; this will be remidied in a future CL. A similar situation occurs for: x.m(args); which could be a call to a method m in the object x, or an invocation of a function-typed object returned by the getter m in the object x. R=scheglov@google.com Review-Url: https://codereview.chromium.org/2984013002 .
This commit is contained in:
parent
ebd3ed5ade
commit
c057f091c2
6 changed files with 88 additions and 16 deletions
|
@ -88,6 +88,7 @@ class AnalyzerDietListener extends DietListener {
|
|||
// the body builder to do type inference, and then copy the inferred types
|
||||
// over to the analyzer AST.
|
||||
parserCallback();
|
||||
resolutionStorer.finished();
|
||||
// The inferred types and the body builder are no longer needed.
|
||||
_bodyBuilder = null;
|
||||
_kernelTypes = null;
|
||||
|
|
|
@ -38,10 +38,11 @@ class ResolutionApplier extends GeneralizingAstVisitor {
|
|||
@override
|
||||
void visitMethodInvocation(MethodInvocation node) {
|
||||
node.target?.accept(this);
|
||||
node.methodName.staticType = _getTypeFor(node.methodName);
|
||||
// TODO(paulberry): store resolution of node.methodName.
|
||||
// TODO(paulberry): store resolution of node.typeArguments.
|
||||
node.argumentList.accept(this);
|
||||
node.staticType = _getTypeFor(node.methodName);
|
||||
node.staticType = _getTypeFor(node.argumentList);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -17,13 +17,13 @@ class InstrumentedResolutionStorer extends ResolutionStorer {
|
|||
: super(types);
|
||||
|
||||
@override
|
||||
void _recordType(DartType type, int offset) {
|
||||
int _recordType(DartType type, int offset) {
|
||||
if (_debug) {
|
||||
print('Recording type $type for offset $offset');
|
||||
}
|
||||
assert(_types.length == _typeOffsets.length);
|
||||
_typeOffsets.add(offset);
|
||||
super._recordType(type, offset);
|
||||
return super._recordType(type, offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,16 @@ class InstrumentedResolutionStorer extends ResolutionStorer {
|
|||
class ResolutionStorer extends TypeInferenceListener {
|
||||
final List<DartType> _types;
|
||||
|
||||
/// Indices into [_types] which need to be filled in later.
|
||||
final _deferredTypeSlots = <int>[];
|
||||
|
||||
ResolutionStorer(this._types);
|
||||
|
||||
/// Verifies that all deferred work has been completed.
|
||||
void finished() {
|
||||
assert(_deferredTypeSlots.isEmpty);
|
||||
}
|
||||
|
||||
@override
|
||||
bool genericExpressionEnter(
|
||||
String expressionType, Expression expression, DartType typeContext) {
|
||||
|
@ -48,13 +56,76 @@ class ResolutionStorer extends TypeInferenceListener {
|
|||
super.genericExpressionExit(expressionType, expression, inferredType);
|
||||
}
|
||||
|
||||
@override
|
||||
void methodInvocationBeforeArgs(Expression expression, bool isImplicitCall) {
|
||||
if (!isImplicitCall) {
|
||||
// We are visiting a method invocation like: a.f(args). We have visited a
|
||||
// but we haven't visited the args yet.
|
||||
//
|
||||
// The analyzer AST will expect a type for f at this point. (It can't
|
||||
// wait until later, because for all it knows, a.f might be a property
|
||||
// access, in which case the appropriate time for the type is now). But
|
||||
// the type isn't known yet (because it may depend on type inference based
|
||||
// on arguments).
|
||||
//
|
||||
// So we add a `null` to our list of types; we'll update it with the
|
||||
// actual type later.
|
||||
_deferredTypeSlots.add(_recordType(null, expression.fileOffset));
|
||||
}
|
||||
super.methodInvocationBeforeArgs(expression, isImplicitCall);
|
||||
}
|
||||
|
||||
@override
|
||||
void methodInvocationExit(Expression expression, Arguments arguments,
|
||||
bool isImplicitCall, DartType inferredType) {
|
||||
if (!isImplicitCall) {
|
||||
// TODO(paulberry): get the actual callee function type from the inference
|
||||
// engine
|
||||
var calleeType = const DynamicType();
|
||||
_types[_deferredTypeSlots.removeLast()] = calleeType;
|
||||
}
|
||||
_recordType(inferredType, arguments.fileOffset);
|
||||
super.genericExpressionExit("methodInvocation", expression, inferredType);
|
||||
}
|
||||
|
||||
@override
|
||||
bool staticInvocationEnter(
|
||||
StaticInvocation expression, DartType typeContext) {
|
||||
// We are visiting a static invocation like: f(args), and we haven't visited
|
||||
// args yet.
|
||||
//
|
||||
// The analyzer AST will expect a type for f at this point. (It can't wait
|
||||
// until later, because for all it knows, f is a method on `this`, and
|
||||
// methods need a type for f at this point--see comments in
|
||||
// [methodInvocationBeforeArgs]). But the type isn't known yet (because it
|
||||
// may depend on type inference based on arguments).
|
||||
//
|
||||
// So we add a `null` to our list of types; we'll update it with the actual
|
||||
// type later.
|
||||
_deferredTypeSlots.add(_recordType(null, expression.fileOffset));
|
||||
return super.staticInvocationEnter(expression, typeContext);
|
||||
}
|
||||
|
||||
@override
|
||||
void staticInvocationExit(
|
||||
StaticInvocation expression, DartType inferredType) {
|
||||
// TODO(paulberry): get the actual callee function type from the inference
|
||||
// engine
|
||||
var calleeType = const DynamicType();
|
||||
_types[_deferredTypeSlots.removeLast()] = calleeType;
|
||||
_recordType(inferredType, expression.arguments.fileOffset);
|
||||
super.genericExpressionExit("staticInvocation", expression, inferredType);
|
||||
}
|
||||
|
||||
@override
|
||||
void variableDeclarationEnter(VariableDeclaration statement) {
|
||||
_recordType(statement.type, statement.fileOffset);
|
||||
super.variableDeclarationEnter(statement);
|
||||
}
|
||||
|
||||
void _recordType(DartType type, int offset) {
|
||||
int _recordType(DartType type, int offset) {
|
||||
int slot = _types.length;
|
||||
_types.add(type);
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -261,7 +261,10 @@ class TypeInferenceListener
|
|||
bool methodInvocationEnter(Expression expression, DartType typeContext) =>
|
||||
genericExpressionEnter("methodInvocation", expression, typeContext);
|
||||
|
||||
void methodInvocationExit(Expression expression, DartType inferredType) =>
|
||||
void methodInvocationBeforeArgs(Expression expression, bool isImplicitCall) {}
|
||||
|
||||
void methodInvocationExit(Expression expression, Arguments arguments,
|
||||
bool isImplicitCall, DartType inferredType) =>
|
||||
genericExpressionExit("methodInvocation", expression, inferredType);
|
||||
|
||||
bool notEnter(Not expression, DartType typeContext) =>
|
||||
|
|
|
@ -847,6 +847,7 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
|||
listener.methodInvocationEnter(expression, typeContext) || typeNeeded;
|
||||
// First infer the receiver so we can look up the method that was invoked.
|
||||
var receiverType = inferExpression(receiver, null, true);
|
||||
listener.methodInvocationBeforeArgs(expression, isImplicitCall);
|
||||
if (strongMode) {
|
||||
receiverVariable?.type = receiverType;
|
||||
}
|
||||
|
@ -882,7 +883,8 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
|||
isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
|
||||
receiverType: receiverType,
|
||||
forceArgumentInference: forceArgumentInference);
|
||||
listener.methodInvocationExit(expression, inferredType);
|
||||
listener.methodInvocationExit(
|
||||
expression, arguments, isImplicitCall, inferredType);
|
||||
return inferredType;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
# generating analyzer ASTs and connecting up type inference information.
|
||||
DeltaBlue: Crash
|
||||
accessors: Crash
|
||||
argument: Crash
|
||||
arithmetic: Crash
|
||||
bad_store: Crash
|
||||
call: Crash
|
||||
|
@ -22,17 +21,12 @@ external: Crash
|
|||
fallthrough: Crash
|
||||
fibonacci: Crash
|
||||
for_in_scope: Crash
|
||||
function_in_field: Crash
|
||||
function_type_is_check: Crash
|
||||
functions: Crash
|
||||
implicit_scope_test: Crash
|
||||
implicit_this: Crash
|
||||
inference/abstract_class_instantiation: Crash
|
||||
inference/assign_local: Crash
|
||||
inference/block_bodied_lambdas_async_all_returns_are_futures: Crash
|
||||
inference/block_bodied_lambdas_async_all_returns_are_values: Crash
|
||||
inference/block_bodied_lambdas_async_mix_of_values_and_futures: Crash
|
||||
inference/block_bodied_lambdas_async_star: Crash
|
||||
inference/block_bodied_lambdas_basic: Crash
|
||||
inference/block_bodied_lambdas_basic_void: Crash
|
||||
inference/block_bodied_lambdas_downwards_incompatible_with_upwards_inference: Crash
|
||||
|
@ -44,7 +38,6 @@ inference/block_bodied_lambdas_lub: Crash
|
|||
inference/block_bodied_lambdas_nested_lambdas: Crash
|
||||
inference/block_bodied_lambdas_no_return: Crash
|
||||
inference/block_bodied_lambdas_returns: Crash
|
||||
inference/block_bodied_lambdas_sync_star: Crash
|
||||
inference/block_bodied_lambdas_void_context: Crash
|
||||
inference/call_corner_cases: Crash
|
||||
inference/conditional_lub: Crash
|
||||
|
@ -212,6 +205,8 @@ inference/infer_local_function_return_type: Crash
|
|||
inference/infer_method_missing_params: Crash
|
||||
inference/infer_parameter_type_setter_from_field: Crash
|
||||
inference/infer_parameter_type_setter_from_setter: Fail
|
||||
inference/infer_prefix_expression: Crash
|
||||
inference/infer_prefix_expression_custom: Crash
|
||||
inference/infer_rethrow: Crash
|
||||
inference/infer_return_of_statement_lambda: Crash
|
||||
inference/infer_setter_cross_to_getter: Fail
|
||||
|
@ -251,6 +246,8 @@ inference/inferred_type_custom_binary_op: Crash
|
|||
inference/inferred_type_custom_binary_op_via_interface: Crash
|
||||
inference/inferred_type_custom_index_op: Crash
|
||||
inference/inferred_type_custom_index_op_via_interface: Crash
|
||||
inference/inferred_type_custom_unary_op: Crash
|
||||
inference/inferred_type_custom_unary_op_via_interface: Crash
|
||||
inference/inferred_type_extract_method_tear_off: Crash
|
||||
inference/inferred_type_extract_method_tear_off_via_interface: Crash
|
||||
inference/inferred_type_is_enum: Crash
|
||||
|
@ -304,7 +301,6 @@ inference/top_level_return_and_yield: Crash
|
|||
inference/try_catch: Crash
|
||||
inference/try_catch_finally: Crash
|
||||
inference/try_catch_promotion: Crash
|
||||
inference/try_finally: Crash
|
||||
inference/type_cast: Crash
|
||||
inference/type_promotion_ignores_local_functions: Crash
|
||||
inference/type_promotion_not_and_not: Crash
|
||||
|
@ -347,7 +343,6 @@ inference_new/property_get_toplevel: Crash
|
|||
inference_new/strongly_connected_component: Crash
|
||||
inference_new/unsafe_block_closure_inference_function_call_explicit_dynamic_param_via_expr2: Crash
|
||||
inference_new/unsafe_block_closure_inference_function_call_explicit_type_param_via_expr2: Crash
|
||||
inference_new/void_return_type_subtypes_dynamic: Crash
|
||||
invocations: Crash
|
||||
micro: Crash
|
||||
named_parameters: Crash
|
||||
|
@ -363,7 +358,6 @@ rasta/breaking_bad: Crash
|
|||
rasta/cascades: Crash
|
||||
rasta/class_hierarchy: Crash
|
||||
rasta/class_member: Crash
|
||||
rasta/constant_get_and_invoke: Crash
|
||||
rasta/deferred_load: Crash
|
||||
rasta/duplicated_mixin: Crash
|
||||
rasta/for_loop: Crash
|
||||
|
|
Loading…
Reference in a new issue