blob: ebdd2cce5980f8a1de0778d262b49f331ce00506 [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:analyzer/src/fasta/resolution_applier.dart';
import 'package:front_end/src/fasta/type_inference/type_inference_listener.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/type_algebra.dart';
class ResolutionData<Type, Declaration, Reference, PrefixInfo> {
final List<Type> argumentTypes;
final Reference combiner;
final Declaration declaration;
final Type inferredType;
final Type invokeType;
final bool isExplicitCall;
final bool isImplicitCall;
final bool isWriteReference;
final Type literalType;
final PrefixInfo prefixInfo;
final Reference reference;
final Type writeContext;
ResolutionData(
{this.argumentTypes,
this.combiner,
this.declaration,
this.inferredType,
this.invokeType,
this.isExplicitCall = false,
this.isImplicitCall = false,
this.isWriteReference = false,
this.literalType,
this.prefixInfo,
this.reference,
this.writeContext});
}
/// Type inference listener that records inferred types for later use by
/// [ResolutionApplier].
class ResolutionStorer<Location, Declaration, Reference, PrefixInfo>
extends TypeInferenceListener<Location, Declaration, Reference,
PrefixInfo> {
final Map<Location,
ResolutionData<DartType, Declaration, Reference, PrefixInfo>> _data;
final _stack = <Function>[];
ResolutionStorer(this._data);
void _store(Location location,
{List<DartType> argumentTypes,
Reference combiner,
Declaration declaration,
DartType inferredType,
DartType invokeType,
bool isExplicitCall = false,
bool isImplicitCall = false,
bool isWriteReference = false,
DartType literalType,
PrefixInfo prefixInfo,
Reference reference,
bool replace = false,
DartType writeContext}) {
if (!replace && _data.containsKey(location)) {
throw new StateError('Data already stored for offset $location');
}
_data[location] = new ResolutionData(
argumentTypes: argumentTypes,
combiner: combiner,
declaration: declaration,
inferredType: inferredType,
invokeType: invokeType,
isExplicitCall: isExplicitCall,
isImplicitCall: isImplicitCall,
isWriteReference: isWriteReference,
literalType: literalType,
prefixInfo: prefixInfo,
reference: reference,
writeContext: writeContext);
}
void _unstore(Location location) {
_data.remove(location) == null;
}
@override
void asExpressionExit(Location location, DartType inferredType) {
_store(location, literalType: inferredType, inferredType: inferredType);
}
@override
void cascadeExpressionExit(Location location, DartType inferredType) {
// Overridden so that the type of the expression will not be recorded. We
// don't need to record the type because the type is always the same as the
// type of the target, and we don't have the appropriate offset so we can't
// correctly apply the type even if we recorded it.
}
@override
void catchStatementEnter(
Location location,
DartType guardType,
Location exceptionLocation,
DartType exceptionType,
Location stackTraceLocation,
DartType stackTraceType) {
_store(location, literalType: guardType);
if (exceptionLocation != null) {
_store(exceptionLocation, literalType: exceptionType);
}
if (stackTraceLocation != null) {
_store(stackTraceLocation, literalType: stackTraceType);
}
}
@override
void constructorInvocationEnter(Location location, DartType typeContext) {
_push((Reference expressionTarget, DartType inferredType) {
// A class reference may have already been stored at this location by
// storeClassReference. We want to replace it with a constructor
// reference.
_unstore(location);
_store(location, inferredType: inferredType, reference: expressionTarget);
});
}
@override
void constructorInvocationExit(
Location location, Reference expressionTarget, DartType inferredType) {
_pop()(expressionTarget, inferredType);
}
@override
void fieldInitializerEnter(Location location, Reference initializerField) {
_store(location, reference: initializerField);
}
void finished() {
assert(_stack.isEmpty);
}
@override
void forInStatementEnter(
Location location,
Location variableLocation,
Location writeLocation,
DartType writeType,
Declaration writeVariable,
Reference writeTarget) {
_push((DartType variableType) {
if (variableLocation != null) {
_store(variableLocation, inferredType: variableType);
} else {
if (writeVariable != null) {
_store(writeLocation,
declaration: writeVariable, inferredType: writeType);
} else {
_store(writeLocation,
reference: writeTarget,
isWriteReference: true,
writeContext: writeType);
}
}
});
}
@override
void forInStatementExit(
Location location, bool variablePresent, DartType variableType) {
_pop()(variableType);
}
@override
void genericExpressionEnter(
String expressionType, Location location, DartType typeContext) {
super.genericExpressionEnter(expressionType, location, typeContext);
}
@override
void genericExpressionExit(
String expressionType, Location location, DartType inferredType) {
_store(location, inferredType: inferredType);
super.genericExpressionExit(expressionType, location, inferredType);
}
@override
void functionDeclarationExit(Location location, FunctionType inferredType) {
_store(location, inferredType: inferredType);
}
@override
void nullLiteralExit(
Location location, bool isSynthetic, DartType inferredType) {
if (isSynthetic) return null;
super.nullLiteralExit(location, isSynthetic, inferredType);
}
@override
void indexAssignExit(Location location, Reference writeMember,
Reference combiner, DartType inferredType) {
_store(location,
reference: writeMember, inferredType: inferredType, combiner: combiner);
}
@override
void isExpressionExit(
Location location, DartType testedType, DartType inferredType) {
_store(location, literalType: testedType, inferredType: inferredType);
}
void isNotExpressionExit(
Location location, DartType type, DartType inferredType) {
_store(location, literalType: type, inferredType: inferredType);
}
@override
void methodInvocationExit(
Location resultOffset,
List<DartType> argumentsTypes,
bool isImplicitCall,
Reference interfaceMember,
FunctionType calleeType,
Substitution substitution,
DartType inferredType) {
FunctionType invokeType = substitution == null
? calleeType
: substitution.substituteType(calleeType.withoutTypeParameters);
_store(resultOffset,
inferredType: inferredType,
argumentTypes: argumentsTypes,
invokeType: invokeType,
isImplicitCall: isImplicitCall,
reference: interfaceMember);
super.genericExpressionExit("methodInvocation", resultOffset, inferredType);
}
@override
void methodInvocationExitCall(
Location resultOffset,
List<DartType> argumentsTypes,
bool isImplicitCall,
FunctionType calleeType,
Substitution substitution,
DartType inferredType) {
FunctionType invokeType = substitution == null
? calleeType
: substitution.substituteType(calleeType.withoutTypeParameters);
_store(resultOffset,
inferredType: inferredType,
argumentTypes: argumentsTypes,
invokeType: invokeType,
isImplicitCall: isImplicitCall);
super.genericExpressionExit("methodInvocation", resultOffset, inferredType);
}
@override
void propertyAssignExit(Location location, Reference writeMember,
DartType writeContext, Reference combiner, DartType inferredType) {
_store(location,
isWriteReference: true,
reference: writeMember,
writeContext: writeContext,
combiner: combiner,
inferredType: inferredType);
}
@override
void propertyGetExit(
Location location, Reference member, DartType inferredType) {
_store(location, reference: member, inferredType: inferredType);
}
@override
void propertyGetExitCall(Location location, DartType inferredType) {
_store(location, isExplicitCall: true);
}
@override
void redirectingInitializerEnter(
Location location, Reference initializerTarget) {
_store(location, reference: initializerTarget);
}
@override
void staticAssignEnter(Location location, DartType typeContext) {
_push((Reference writeMember, DartType writeContext, Reference combiner,
DartType inferredType) {
_store(location,
reference: writeMember,
isWriteReference: true,
writeContext: writeContext,
combiner: combiner,
inferredType: inferredType);
});
}
@override
void staticAssignExit(Location location, Reference writeMember,
DartType writeContext, Reference combiner, DartType inferredType) {
_pop()(writeMember, writeContext, combiner, inferredType);
}
@override
void staticGetEnter(Location location, DartType typeContext) {
_push(
(Location location, Reference expressionTarget, DartType inferredType) {
_store(location, reference: expressionTarget, inferredType: inferredType);
});
}
@override
void staticGetExit(
Location location, Reference expressionTarget, DartType inferredType) {
_pop()(location, expressionTarget, inferredType);
}
@override
void staticInvocationEnter(Location location,
Location expressionArgumentsLocation, DartType typeContext) {
_push((Reference expressionTarget,
List<DartType> expressionArgumentsTypes,
FunctionType calleeType,
Substitution substitution,
DartType inferredType) {
FunctionType invokeType = substitution == null
? calleeType
: substitution.substituteType(calleeType.withoutTypeParameters);
_store(expressionArgumentsLocation,
invokeType: invokeType,
argumentTypes: expressionArgumentsTypes,
reference: expressionTarget,
inferredType: inferredType);
});
}
@override
void staticInvocationExit(
Location location,
Reference expressionTarget,
List<DartType> expressionArgumentsTypes,
FunctionType calleeType,
Substitution substitution,
DartType inferredType) {
_pop()(expressionTarget, expressionArgumentsTypes, calleeType, substitution,
inferredType);
}
@override
void stringConcatenationExit(Location location, DartType inferredType) {
// We don't need the type - we already know that it is String.
// Moreover, the file offset for StringConcatenation is `-1`.
}
@override
void thisExpressionExit(Location location, DartType inferredType) {}
@override
void typeLiteralEnter(Location location, DartType typeContext) {
_push((Reference expressionType, DartType inferredType) {
_store(location, reference: expressionType, inferredType: inferredType);
});
}
void typeLiteralExit(
Location location, Reference expressionType, DartType inferredType) {
_pop()(expressionType, inferredType);
}
@override
void variableAssignExit(Location location, DartType writeContext,
Declaration writeVariable, Reference combiner, DartType inferredType) {
_store(location,
declaration: writeVariable,
isWriteReference: true,
writeContext: writeContext,
combiner: combiner,
inferredType: inferredType);
}
@override
void variableDeclarationExit(
Location location, DartType statementType, DartType inferredType) {
_store(location, literalType: statementType, inferredType: inferredType);
}
@override
void variableGetExit(Location location, bool isInCascade,
Declaration expressionVariable, DartType inferredType) {
if (isInCascade) {
return;
}
_store(location,
declaration: expressionVariable, inferredType: inferredType);
}
void _push(Function f) {
_stack.add(f);
}
Function _pop() {
return _stack.removeLast();
}
@override
void storePrefixInfo(Location location, PrefixInfo prefixInfo) {
_store(location, prefixInfo: prefixInfo);
}
@override
void storeClassReference(
Location location, Reference reference, DartType rawType) {
// TODO(paulberry): would it be better to use literalType?
_store(location, reference: reference, inferredType: rawType);
}
}
/// A [DartType] wrapper around invocation type arguments.
class TypeArgumentsDartType implements DartType {
final List<DartType> types;
TypeArgumentsDartType(this.types);
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
@override
String toString() {
return '<${types.join(', ')}>';
}
}