blob: c39447ea93e8a0e3f7b1dc726160ec2178d29794 [file] [log] [blame]
// Copyright (c) 2017, 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/fasta/type_inference/type_inference_listener.dart';
import 'package:kernel/ast.dart';
/// Type inference listener that records inferred types and file offsets for
/// later use by [ValidatingResolutionApplier].
class InstrumentedResolutionStorer extends ResolutionStorer {
/// Indicates whether debug messages should be printed.
static const bool _debug = false;
final List<int> _typeOffsets;
InstrumentedResolutionStorer(List<DartType> types, this._typeOffsets)
: super(types);
@override
int _recordType(DartType type, int offset) {
if (_debug) {
print('Recording type $type for offset $offset');
}
assert(_types.length == _typeOffsets.length);
_typeOffsets.add(offset);
return super._recordType(type, offset);
}
}
/// Type inference listener that records inferred types for later use by
/// [ResolutionApplier].
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) {
super.genericExpressionEnter(expressionType, expression, typeContext);
return true;
}
@override
void genericExpressionExit(
String expressionType, Expression expression, DartType inferredType) {
_recordType(inferredType, expression.fileOffset);
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);
}
int _recordType(DartType type, int offset) {
int slot = _types.length;
_types.add(type);
return slot;
}
}