blob: e0b2de8a095ee936f84606a6dd2bd11257691f4c [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/kernel/factory.dart';
import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart';
import 'package:front_end/src/fasta/type_inference/type_inference_listener.dart';
import 'package:front_end/src/scanner/token.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 extends _ResolutionStorer<int, int, Node, int>
implements
TypeInferenceListener<int, int, Node, int>,
Factory<void, void, void, void> {
ResolutionStorer(Map<int, ResolutionData<DartType, int, Node, int>> data)
: super(data);
}
/// Implementation of [ResolutionStorer], with types parameterized to avoid
/// accidentally peeking into kernel internals.
///
/// TODO(paulberry): when the time is right, fuse this with [ResolutionStorer].
class _ResolutionStorer<Location, Declaration, Reference, PrefixInfo> {
final Map<Location,
ResolutionData<DartType, Declaration, Reference, PrefixInfo>> _data;
_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;
}
void asExpression(
ExpressionJudgment judgment,
Location location,
void expression,
Token asOperator,
void literalType,
DartType inferredType) {
_store(location, literalType: inferredType, inferredType: inferredType);
}
void assertInitializer(
InitializerJudgment judgment,
Location location,
Token assertKeyword,
Token leftParenthesis,
void condition,
Token comma,
void message,
Token rightParenthesis) {}
void assertStatement(
StatementJudgment judgment,
Location location,
Token assertKeyword,
Token leftParenthesis,
void condition,
Token comma,
void message,
Token rightParenthesis,
Token semicolon) {}
void awaitExpression(ExpressionJudgment judgment, Location location,
Token awaitKeyword, void expression, DartType inferredType) =>
genericExpression("awaitExpression", location, inferredType);
void block(StatementJudgment judgment, Location location, Token leftBracket,
List<void> statements, Token rightBracket) {}
void boolLiteral(ExpressionJudgment judgment, Location location,
Token literal, bool value, DartType inferredType) =>
genericExpression("boolLiteral", location, inferredType);
void breakStatement(
StatementJudgment judgment,
Location location,
Token breakKeyword,
void label,
Token semicolon,
covariant Object labelBinder) {}
void cascadeExpression(
ExpressionJudgment judgment, 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.
}
void catchStatement(
Catch judgment,
Location location,
Token onKeyword,
void type,
Token catchKeyword,
Token leftParenthesis,
Token exceptionParameter,
Token comma,
Token stackTraceParameter,
Token rightParenthesis,
void body,
DartType guardType,
covariant VariableDeclarationBinder exceptionBinder,
DartType exceptionType,
covariant VariableDeclarationBinder stackTraceBinder,
DartType stackTraceType) {
_store(location, literalType: guardType);
if (exceptionBinder != null) {
_store(exceptionBinder.fileOffset as Location,
literalType: exceptionType);
}
if (stackTraceBinder != null) {
_store(stackTraceBinder.fileOffset as Location,
literalType: stackTraceType);
}
}
void conditionalExpression(
ExpressionJudgment judgment,
Location location,
void condition,
Token question,
void thenExpression,
Token colon,
void elseExpression,
DartType inferredType) =>
genericExpression("conditionalExpression", location, inferredType);
void constructorInvocation(ExpressionJudgment judgment, Location location,
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);
}
void continueStatement(
StatementJudgment judgment,
Location location,
Token continueKeyword,
void label,
Token semicolon,
covariant Object labelBinder) {}
void continueSwitchStatement(
StatementJudgment judgment,
Location location,
Token continueKeyword,
void label,
Token semicolon,
covariant Object labelBinder) {}
void deferredCheck(ExpressionJudgment judgment, Location location,
DartType inferredType) =>
genericExpression("deferredCheck", location, inferredType);
void doStatement(
StatementJudgment judgment,
Location location,
Token doKeyword,
void body,
Token whileKeyword,
Token leftParenthesis,
void condition,
Token rightParenthesis,
Token semicolon) {}
void doubleLiteral(ExpressionJudgment judgment, Location location,
Token literal, double value, DartType inferredType) =>
genericExpression("doubleLiteral", location, inferredType);
void emptyStatement(Token semicolon) {}
void expressionStatement(StatementJudgment judgment, Location location,
void expression, Token semicolon) {}
void fieldInitializer(
InitializerJudgment judgment,
Location location,
Token thisKeyword,
Token period,
Token fieldName,
Token equals,
void expression,
Reference initializerField) {
_store(location, reference: initializerField);
}
void forInStatement(
StatementJudgment judgment,
Location location,
Token awaitKeyword,
Token forKeyword,
Token leftParenthesis,
Object loopVariable,
Token identifier,
Token inKeyword,
void iterator,
Token rightParenthesis,
void body,
covariant VariableDeclarationBinder loopVariableBinder,
DartType loopVariableType,
Location writeLocation,
DartType writeType,
Declaration writeVariable,
Reference writeTarget) {
if (loopVariableBinder != null) {
_store(loopVariableBinder.fileOffset as Location,
inferredType: loopVariableType);
} else {
if (writeVariable != null) {
_store(writeLocation,
declaration: writeVariable, inferredType: writeType);
} else {
_store(writeLocation,
reference: writeTarget,
isWriteReference: true,
writeContext: writeType);
}
}
}
void forStatement(
StatementJudgment judgment,
Location location,
Token forKeyword,
Token leftParenthesis,
void variableDeclarationList,
void initialization,
Token leftSeparator,
void condition,
Token rightSeparator,
void updaters,
Token rightParenthesis,
void body) {}
void functionDeclaration(
covariant VariableDeclarationBinder binder, FunctionType inferredType) {
_store(binder.fileOffset as Location, inferredType: inferredType);
}
Object binderForFunctionDeclaration(
StatementJudgment judgment, int fileOffset, String name) {
return new VariableDeclarationBinder(fileOffset);
}
void functionExpression(ExpressionJudgment judgment, Location location,
DartType inferredType) =>
genericExpression("functionExpression", location, inferredType);
void genericExpression(
String expressionType, Location location, DartType inferredType) {
_store(location, inferredType: inferredType);
}
void ifNull(ExpressionJudgment judgment, Location location, void leftOperand,
Token operator, void rightOperand, DartType inferredType) =>
genericExpression('ifNull', location, inferredType);
void ifStatement(
StatementJudgment judgment,
Location location,
Token ifKeyword,
Token leftParenthesis,
void condition,
Token rightParenthesis,
void thenStatement,
Token elseKeyword,
void elseStatement) {}
void intLiteral(ExpressionJudgment judgment, Location location, Token literal,
num value, DartType inferredType) =>
genericExpression("intLiteral", location, inferredType);
void invalidInitializer(InitializerJudgment judgment, Location location) {}
void labeledStatement(List<Object> labels, void statement) {}
void statementLabel(covariant void binder, Token label, Token colon) {}
void binderForStatementLabel(
StatementJudgment judgment, int fileOffset, String name) {}
void listLiteral(
ExpressionJudgment judgment,
Location location,
Token constKeyword,
Object typeArguments,
Token leftBracket,
void elements,
Token rightBracket,
DartType inferredType) =>
genericExpression("listLiteral", location, inferredType);
void logicalExpression(
ExpressionJudgment judgment,
Location location,
void leftOperand,
Token operator,
void rightOperand,
DartType inferredType) =>
genericExpression("logicalExpression", location, inferredType);
void mapLiteral(
ExpressionJudgment judgment,
Location location,
Token constKeyword,
Object typeArguments,
Token leftBracket,
List<Object> entries,
Token rightBracket,
DartType inferredType) =>
genericExpression("mapLiteral", location, inferredType);
void mapLiteralEntry(
Object judgment, int fileOffset, void key, Token separator, void value) {
// TODO(brianwilkerson) Implement this.
}
void namedFunctionExpression(ExpressionJudgment judgment,
covariant VariableDeclarationBinder binder, DartType inferredType) =>
genericExpression("namedFunctionExpression",
binder.fileOffset as Location, inferredType);
void not(ExpressionJudgment judgment, Location location, Token operator,
void operand, DartType inferredType) =>
genericExpression("not", location, inferredType);
void nullLiteral(ExpressionJudgment judgment, Location location,
Token literal, bool isSynthetic, DartType inferredType) {
if (isSynthetic) return null;
genericExpression("nullLiteral", location, inferredType);
}
void indexAssign(ExpressionJudgment judgment, Location location,
Reference writeMember, Reference combiner, DartType inferredType) {
_store(location,
reference: writeMember, inferredType: inferredType, combiner: combiner);
}
void isExpression(
ExpressionJudgment judgment,
Location location,
void expression,
Token isOperator,
void literalType,
DartType testedType,
DartType inferredType) {
_store(location, literalType: testedType, inferredType: inferredType);
}
void isNotExpression(
ExpressionJudgment judgment,
Location location,
void expression,
Token isOperator,
Token notOperator,
void literalType,
DartType type,
DartType inferredType) {
_store(location, literalType: type, inferredType: inferredType);
}
void methodInvocation(
ExpressionJudgment judgment,
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);
}
void methodInvocationCall(
ExpressionJudgment judgment,
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);
}
void propertyAssign(
ExpressionJudgment judgment,
Location location,
Reference writeMember,
DartType writeContext,
Reference combiner,
DartType inferredType) {
_store(location,
isWriteReference: true,
reference: writeMember,
writeContext: writeContext,
combiner: combiner,
inferredType: inferredType);
}
void propertySet(ExpressionJudgment judgment, Location location,
DartType inferredType) =>
genericExpression("propertySet", location, inferredType);
void propertyGet(ExpressionJudgment judgment, Location location,
Reference member, DartType inferredType) {
_store(location, reference: member, inferredType: inferredType);
}
void propertyGetCall(
ExpressionJudgment judgment, Location location, DartType inferredType) {
_store(location, isExplicitCall: true);
}
void redirectingInitializer(
InitializerJudgment judgment,
Location location,
Token thisKeyword,
Token period,
Token constructorName,
covariant Object argumentList,
Reference initializerTarget) {
_store(location, reference: initializerTarget);
}
void rethrow_(ExpressionJudgment judgment, Location location,
Token rethrowKeyword, DartType inferredType) =>
genericExpression('rethrow', location, inferredType);
void returnStatement(StatementJudgment judgment, Location location,
Token returnKeyword, void expression, Token semicolon) {}
void staticAssign(
ExpressionJudgment judgment,
Location location,
Reference writeMember,
DartType writeContext,
Reference combiner,
DartType inferredType) {
_store(location,
reference: writeMember,
isWriteReference: true,
writeContext: writeContext,
combiner: combiner,
inferredType: inferredType);
}
void staticGet(ExpressionJudgment judgment, Location location,
Reference expressionTarget, DartType inferredType) {
_store(location, reference: expressionTarget, inferredType: inferredType);
}
void staticInvocation(
ExpressionJudgment judgment,
Location location,
Reference expressionTarget,
List<DartType> expressionArgumentsTypes,
FunctionType calleeType,
Substitution substitution,
DartType inferredType) {
FunctionType invokeType = substitution == null
? calleeType
: substitution.substituteType(calleeType.withoutTypeParameters);
_store(location,
invokeType: invokeType,
argumentTypes: expressionArgumentsTypes,
reference: expressionTarget,
inferredType: inferredType);
}
void stringConcatenation(
ExpressionJudgment judgment, 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`.
}
void stringLiteral(ExpressionJudgment judgment, Location location,
Token literal, String value, DartType inferredType) =>
genericExpression("StringLiteral", location, inferredType);
void superInitializer(
InitializerJudgment judgment,
Location location,
Token superKeyword,
Token period,
Token constructorName,
covariant Object argumentList) {}
void switchCase(SwitchCaseJudgment judgment, List<Object> labels,
Token keyword, void expression, Token colon, List<void> statements) {}
void switchLabel(covariant void binder, Token label, Token colon) {}
void binderForSwitchLabel(
SwitchCaseJudgment judgment, int fileOffset, String name) {}
void switchStatement(
StatementJudgment judgment,
Location location,
Token switchKeyword,
Token leftParenthesis,
void expression,
Token rightParenthesis,
Token leftBracket,
void members,
Token rightBracket) {}
void symbolLiteral(
ExpressionJudgment judgment,
Location location,
Token poundSign,
List<Token> components,
String value,
DartType inferredType) =>
genericExpression("symbolLiteral", location, inferredType);
void thisExpression(ExpressionJudgment judgment, Location location,
Token thisKeyword, DartType inferredType) {}
void throw_(ExpressionJudgment judgment, Location location,
Token throwKeyword, void expression, DartType inferredType) =>
genericExpression('throw', location, inferredType);
void tryCatch(StatementJudgment judgment, Location location) {}
void tryFinally(
StatementJudgment judgment,
Location location,
Token tryKeyword,
void body,
void catchClauses,
Token finallyKeyword,
void finallyBlock) {}
void typeLiteral(ExpressionJudgment judgment, Location location,
Reference expressionType, DartType inferredType) {
_store(location, reference: expressionType, inferredType: inferredType);
}
void variableAssign(
ExpressionJudgment judgment,
Location location,
DartType writeContext,
Declaration writeVariable,
Reference combiner,
DartType inferredType) {
_store(location,
declaration: writeVariable,
isWriteReference: true,
writeContext: writeContext,
combiner: combiner,
inferredType: inferredType);
}
void variableDeclaration(covariant VariableDeclarationBinder binder,
DartType statementType, DartType inferredType) {
_store(binder.fileOffset as Location,
literalType: statementType, inferredType: inferredType);
}
Object binderForVariableDeclaration(
StatementJudgment judgment, int fileOffset, String name) {
return new VariableDeclarationBinder(fileOffset);
}
void variableGet(
ExpressionJudgment judgment,
Location location,
bool isInCascade,
covariant VariableDeclarationBinder variableBinder,
DartType inferredType) {
if (isInCascade) {
return;
}
_store(location,
declaration: variableBinder.fileOffset as Declaration,
inferredType: inferredType);
}
void whileStatement(
StatementJudgment judgment,
Location location,
Token whileKeyword,
Token leftParenthesis,
void condition,
Token rightParenthesis,
void body) {}
void yieldStatement(StatementJudgment judgment, Location location,
Token yieldKeyword, Token star, void expression, Token semicolon) {}
void storePrefixInfo(Location location, PrefixInfo prefixInfo) {
_store(location, prefixInfo: prefixInfo);
}
void storeClassReference(
Location location, Reference reference, DartType rawType) {
// TODO(paulberry): would it be better to use literalType?
_store(location, reference: reference, inferredType: rawType);
}
}
/// TODO(paulberry): eventually just use the element directly.
class VariableDeclarationBinder {
final int fileOffset;
VariableDeclarationBinder(this.fileOffset);
}
/// 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(', ')}>';
}
}