| // 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(', ')}>'; |
| } |
| } |