Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(494)

Unified Diff: pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart

Issue 2890803002: Perform type inference directly within kernel shadow infer() methods. (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 645f9fa0d900cc58886e5b8264165a2b0e8ac2dc..dc8e854e9057faf4fa4158e5197924e53b806d82 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -8,33 +8,58 @@ import 'package:front_end/src/fasta/type_inference/type_inference_engine.dart';
import 'package:front_end/src/fasta/type_inference/type_inference_listener.dart';
import 'package:front_end/src/fasta/type_inference/type_promotion.dart';
import 'package:front_end/src/fasta/type_inference/type_schema.dart';
-import 'package:front_end/src/fasta/type_inference/type_schema_elimination.dart';
import 'package:front_end/src/fasta/type_inference/type_schema_environment.dart';
import 'package:kernel/ast.dart'
show
BottomType,
Class,
- Constructor,
DartType,
DynamicType,
Expression,
Field,
- FunctionNode,
FunctionType,
InterfaceType,
Member,
Name,
Procedure,
- ReturnStatement,
Statement,
- TypeParameter,
TypeParameterType,
- VariableDeclaration,
- VoidType;
+ VariableDeclaration;
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/type_algebra.dart';
+/// Keeps track of information about the innermost function or closure being
+/// inferred.
+class ClosureContext {
+ final bool isAsync;
+
+ final bool isGenerator;
+
+ final DartType returnContext;
+
+ DartType _inferredReturnType;
+
+ ClosureContext(this.isAsync, this.isGenerator, this.returnContext);
+
+ /// Gets the return type that was inferred for the current closure, or `null`
+ /// if there were no `return` statements.
+ get inferredReturnType {
+ return _inferredReturnType;
+ }
+
+ /// Updates the inferred return type based on the presence of a return
+ /// statement returning the given [type].
+ void updateInferredReturnType(TypeInferrerImpl inferrer, DartType type) {
+ if (_inferredReturnType == null) {
+ _inferredReturnType = type;
+ } else {
+ _inferredReturnType = inferrer.typeSchemaEnvironment
+ .getLeastUpperBound(_inferredReturnType, type);
+ }
+ }
+}
+
/// Keeps track of the local state for the type inference that occurs during
/// compilation of a single method body or top level initializer.
///
@@ -90,7 +115,7 @@ abstract class TypeInferrerImpl extends TypeInferrer {
/// Context information for the current closure, or `null` if we are not
/// inside a closure.
- _ClosureContext _closureContext;
+ ClosureContext closureContext;
TypeInferrerImpl(TypeInferenceEngineImpl engine, this.uri, this.listener)
: coreTypes = engine.coreTypes,
@@ -103,656 +128,7 @@ abstract class TypeInferrerImpl extends TypeInferrer {
/// inference.
TypePromoter<Expression, VariableDeclaration> get typePromoter;
- /// Gets the initializer for the given [field], or `null` if there is no
- /// initializer.
- Expression getFieldInitializer(KernelField field);
-
- /// Performs the core type inference algorithm for type cast expressions.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- DartType inferAsExpression(DartType typeContext, bool typeNeeded,
- Expression operand, DartType type) {
- typeNeeded = listener.asExpressionEnter(typeContext) || typeNeeded;
- inferExpression(operand, null, false);
- var inferredType = typeNeeded ? type : null;
- listener.asExpressionExit(inferredType);
- return inferredType;
- }
-
- /// Performs the core type inference algorithm for boolean literals.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- DartType inferBoolLiteral(DartType typeContext, bool typeNeeded) {
- typeNeeded = listener.boolLiteralEnter(typeContext) || typeNeeded;
- var inferredType = typeNeeded ? coreTypes.boolClass.rawType : null;
- listener.boolLiteralExit(inferredType);
- return inferredType;
- }
-
- /// Performs the core type inference algorithm for conditional expressions.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- ///
- /// [condition], [then], and [otherwise] are the subexpressions. The inferred
- /// type is reported via [setStaticType].
- DartType inferConditionalExpression(
- DartType typeContext,
- bool typeNeeded,
- Expression condition,
- Expression then,
- Expression otherwise,
- void setStaticType(DartType type)) {
- typeNeeded = listener.conditionalExpressionEnter(typeContext) || typeNeeded;
- inferExpression(condition, coreTypes.boolClass.rawType, false);
- // TODO(paulberry): is it correct to pass the context down?
- DartType thenType = inferExpression(then, typeContext, true);
- DartType otherwiseType = inferExpression(otherwise, typeContext, true);
- // TODO(paulberry): the spec proposal says we should only use LUB if the
- // typeContext is `null`. If typeContext is non-null, we should use the
- // greatest closure of the context with respect to `?`
- DartType type =
- typeSchemaEnvironment.getLeastUpperBound(thenType, otherwiseType);
- setStaticType(type);
- var inferredType = typeNeeded ? type : null;
- listener.conditionalExpressionExit(inferredType);
- return inferredType;
- }
-
- /// Performs the core type inference algorithm for constructor invocations.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- ///
- /// [offset] is the location of the constructor invocation in the source file.
- /// [target] is the constructor that is being called. [explicitTypeArguments]
- /// is the set of type arguments explicitly provided, or `null` if no type
- /// arguments were provided. [forEachArgument] is a callback which can be
- /// used to iterate through all constructor arguments (both named and
- /// positional). [setInferredTypeArguments] is a callback which can be used
- /// to record the inferred type arguments.
- DartType inferConstructorInvocation(
- DartType typeContext,
- bool typeNeeded,
- int offset,
- Constructor target,
- List<DartType> explicitTypeArguments,
- void forEachArgument(void callback(String name, Expression expression)),
- void setInferredTypeArguments(List<DartType> types)) {
- typeNeeded = listener.constructorInvocationEnter(typeContext) || typeNeeded;
- var inferredType = _inferInvocation(
- typeContext,
- typeNeeded,
- offset,
- target.function.functionType,
- target.enclosingClass.thisType,
- explicitTypeArguments,
- forEachArgument,
- setInferredTypeArguments);
- listener.constructorInvocationExit(inferredType);
- return inferredType;
- }
-
- /// Modifies a type as appropriate when inferring a declared variable's type.
- DartType inferDeclarationType(DartType initializerType) {
- if (initializerType is BottomType ||
- (initializerType is InterfaceType &&
- initializerType.classNode == coreTypes.nullClass)) {
- // If the initializer type is Null or bottom, the inferred type is
- // dynamic.
- // TODO(paulberry): this rule is inherited from analyzer behavior but is
- // not spec'ed anywhere.
- return const DynamicType();
- }
- return initializerType;
- }
-
- /// Performs the core type inference algorithm for double literals.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- DartType inferDoubleLiteral(DartType typeContext, bool typeNeeded) {
- typeNeeded = listener.doubleLiteralEnter(typeContext) || typeNeeded;
- var inferredType = typeNeeded ? coreTypes.doubleClass.rawType : null;
- listener.doubleLiteralExit(inferredType);
- return inferredType;
- }
-
- /// Performs type inference on the given [expression].
- ///
- /// [typeContext] is the expected type of the expression, based on surrounding
- /// code. [typeNeeded] indicates whether it is necessary to compute the
- /// actual type of the expression. If [typeNeeded] is `true`, the actual type
- /// of the expression is returned; otherwise `null` is returned.
- ///
- /// Derived classes should override this method with logic that dispatches on
- /// the expression type and calls the appropriate specialized "infer" method.
- DartType inferExpression(
- Expression expression, DartType typeContext, bool typeNeeded);
-
- /// Performs the core type inference algorithm for expression statements.
- void inferExpressionStatement(Expression expression) {
- inferExpression(expression, null, false);
- }
-
- /// Performs type inference on the given [field]'s initializer expression.
- ///
- /// Derived classes should provide an implementation that calls
- /// [inferExpression] for the given [field]'s initializer expression.
- DartType inferFieldInitializer(
- KernelField field, DartType type, bool typeNeeded);
-
- /// Performs the core type inference algorithm for local function
- /// declarations.
- ///
- /// [body] is the body of the function.
- void inferFunctionDeclaration(Statement body) {
- var oldClosureContext = _closureContext;
- _closureContext = null;
- inferStatement(body);
- _closureContext = oldClosureContext;
- }
-
- /// Performs the core type inference algorithm for function expressions.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- ///
- /// [body] is the body of the expression. [isExpressionFunction] indicates
- /// whether the function expression was declared using "=>" syntax. [isAsync]
- /// and [isGenerator] together indicate whether the function is marked as
- /// "async", "async*", or "sync*". [offset] is the character offset of the
- /// function expression.
- ///
- /// [setReturnType] is a callback that will be used to store the return type
- /// of the function expression. [getFunctionType] is a callback that will be
- /// used to query the function expression for its full expression type.
- DartType inferFunctionExpression(
- DartType typeContext,
- bool typeNeeded,
- FunctionNode function,
- bool isAsync,
- bool isGenerator,
- int offset,
- void setReturnType(DartType type),
- DartType getFunctionType()) {
- typeNeeded = listener.functionExpressionEnter(typeContext) || typeNeeded;
- // TODO(paulberry): do we also need to visit default parameter values?
-
- // Let `<T0, ..., Tn>` be the set of type parameters of the closure (with
- // `n`=0 if there are no type parameters).
- List<TypeParameter> typeParameters = function.typeParameters;
-
- // Let `(P0 x0, ..., Pm xm)` be the set of formal parameters of the closure
- // (including required, positional optional, and named optional parameters).
- // If any type `Pi` is missing, denote it as `_`.
- List<VariableDeclaration> formals = function.positionalParameters.toList()
- ..addAll(function.namedParameters);
-
- // Let `B` denote the closure body. If `B` is an expression function body
- // (`=> e`), treat it as equivalent to a block function body containing a
- // single `return` statement (`{ return e; }`).
-
- // Attempt to match `K` as a function type compatible with the closure (that
- // is, one having n type parameters and a compatible set of formal
- // parameters). If there is a successful match, let `<S0, ..., Sn>` be the
- // set of matched type parameters and `(Q0, ..., Qm)` be the set of matched
- // formal parameter types, and let `N` be the return type.
- Substitution substitution;
- List<DartType> formalTypesFromContext =
- new List<DartType>.filled(formals.length, null);
- DartType returnContext;
- if (strongMode && typeContext is FunctionType) {
- for (int i = 0; i < formals.length; i++) {
- if (i < function.positionalParameters.length) {
- formalTypesFromContext[i] =
- _getPositionalParameterType(typeContext, i);
- } else {
- formalTypesFromContext[i] =
- _getNamedParameterType(typeContext, formals[i].name);
- }
- }
- returnContext = typeContext.returnType;
-
- // Let `[T/S]` denote the type substitution where each `Si` is replaced with
- // the corresponding `Ti`.
- var substitutionMap = <TypeParameter, DartType>{};
- for (int i = 0; i < typeContext.typeParameters.length; i++) {
- substitutionMap[typeContext.typeParameters[i]] =
- i < typeParameters.length
- ? new TypeParameterType(typeParameters[i])
- : const DynamicType();
- }
- substitution = Substitution.fromMap(substitutionMap);
- } else {
- // If the match is not successful because `K` is `_`, let all `Si`, all
- // `Qi`, and `N` all be `_`.
-
- // If the match is not successful for any other reason, this will result in
- // a type error, so the implementation is free to choose the best error
- // recovery path.
- substitution = Substitution.empty;
- }
-
- // Define `Ri` as follows: if `Pi` is not `_`, let `Ri` be `Pi`.
- // Otherwise, if `Qi` is not `_`, let `Ri` be the greatest closure of
- // `Qi[T/S]` with respect to `?`. Otherwise, let `Ri` be `dynamic`.
- for (int i = 0; i < formals.length; i++) {
- KernelVariableDeclaration formal = formals[i];
- if (KernelVariableDeclaration.isImplicitlyTyped(formal)) {
- if (formalTypesFromContext[i] != null) {
- var inferredType = greatestClosure(coreTypes,
- substitution.substituteType(formalTypesFromContext[i]));
- instrumentation?.record(Uri.parse(uri), formal.fileOffset, 'type',
- new InstrumentationValueForType(inferredType));
- formal.type = inferredType;
- }
- }
- }
-
- // Let `N’` be `N[T/S]`, adjusted accordingly if the closure is declared
- // with `async`, `async*`, or `sync*`.
- if (returnContext != null) {
- returnContext = substitution.substituteType(returnContext);
- }
- if (isGenerator) {
- if (isAsync) {
- returnContext =
- _getTypeArgumentOf(returnContext, coreTypes.streamClass);
- } else {
- returnContext =
- _getTypeArgumentOf(returnContext, coreTypes.iterableClass);
- }
- } else if (isAsync) {
- // TODO(paulberry): do we have to handle FutureOr<> here?
- returnContext = _getTypeArgumentOf(returnContext, coreTypes.futureClass);
- }
-
- // Apply type inference to `B` in return context `N’`, with any references
- // to `xi` in `B` having type `Pi`. This produces `B’`.
- bool isExpressionFunction = function.body is ReturnStatement;
- bool needToSetReturnType = isExpressionFunction || strongMode;
- _ClosureContext oldClosureContext = _closureContext;
- _closureContext = new _ClosureContext(isAsync, isGenerator, returnContext);
- inferStatement(function.body);
-
- // If the closure is declared with `async*` or `sync*`, let `M` be the least
- // upper bound of the types of the `yield` expressions in `B’`, or `void` if
- // `B’` contains no `yield` expressions. Otherwise, let `M` be the least
- // upper bound of the types of the `return` expressions in `B’`, or `void`
- // if `B’` contains no `return` expressions.
- DartType inferredReturnType;
- if (needToSetReturnType || typeNeeded) {
- inferredReturnType = inferReturnType(
- _closureContext.inferredReturnType, isExpressionFunction);
- if (!isExpressionFunction &&
- returnContext != null &&
- !typeSchemaEnvironment.isSubtypeOf(
- inferredReturnType, returnContext)) {
- // For block-bodied functions, if the inferred return type isn't a
- // subtype of the context, we use the context. TODO(paulberry): this is
- // inherited from analyzer; it's not part of the spec. See also
- // dartbug.com/29606.
- inferredReturnType = greatestClosure(coreTypes, returnContext);
- }
-
- // Let `M’` be `M`, adjusted accordingly if the closure is declared with
- // `async`, `async*`, or `sync*`.
- if (isGenerator) {
- if (isAsync) {
- inferredReturnType =
- _wrapType(inferredReturnType, coreTypes.streamClass);
- } else {
- inferredReturnType =
- _wrapType(inferredReturnType, coreTypes.iterableClass);
- }
- } else if (isAsync) {
- inferredReturnType =
- _wrapType(inferredReturnType, coreTypes.futureClass);
- }
- }
-
- // Then the result of inference is `<T0, ..., Tn>(R0 x0, ..., Rn xn) B` with
- // type `<T0, ..., Tn>(R0, ..., Rn) -> M’` (with some of the `Ri` and `xi`
- // denoted as optional or named parameters, if appropriate).
- if (needToSetReturnType) {
- instrumentation?.record(Uri.parse(uri), offset, 'returnType',
- new InstrumentationValueForType(inferredReturnType));
- setReturnType(inferredReturnType);
- }
- _closureContext = oldClosureContext;
- var inferredType = typeNeeded ? getFunctionType() : null;
- listener.functionExpressionExit(inferredType);
- return inferredType;
- }
-
- /// Performs the core type inference algorithm for if statements.
- void inferIfStatement(
- Expression condition, Statement then, Statement otherwise) {
- inferExpression(condition, coreTypes.boolClass.rawType, false);
- inferStatement(then);
- if (otherwise != null) inferStatement(otherwise);
- }
-
- /// Performs the core type inference algorithm for integer literals.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- DartType inferIntLiteral(DartType typeContext, bool typeNeeded) {
- typeNeeded = listener.intLiteralEnter(typeContext) || typeNeeded;
- var inferredType = typeNeeded ? coreTypes.intClass.rawType : null;
- listener.intLiteralExit(inferredType);
- return inferredType;
- }
-
- /// Performs the core type inference algorithm for an "is" expression.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- ///
- /// [operand] is the expression appearing to the left of "is".
- DartType inferIsExpression(
- DartType typeContext, bool typeNeeded, Expression operand) {
- typeNeeded = listener.isExpressionEnter(typeContext) || typeNeeded;
- inferExpression(operand, null, false);
- var inferredType = typeNeeded ? coreTypes.boolClass.rawType : null;
- listener.isExpressionExit(inferredType);
- return inferredType;
- }
-
- /// Performs the core type inference algorithm for list literals.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- DartType inferListLiteral(
- DartType typeContext,
- bool typeNeeded,
- int offset,
- DartType declaredTypeArgument,
- Iterable<Expression> expressions,
- void setTypeArgument(DartType typeArgument)) {
- typeNeeded = listener.listLiteralEnter(typeContext) || typeNeeded;
- var listClass = coreTypes.listClass;
- var listType = listClass.thisType;
- List<DartType> inferredTypes;
- DartType inferredTypeArgument;
- List<DartType> formalTypes;
- List<DartType> actualTypes;
- bool inferenceNeeded = declaredTypeArgument == null && strongMode;
- if (inferenceNeeded) {
- inferredTypes = [const UnknownType()];
- typeSchemaEnvironment.inferGenericFunctionOrType(listType,
- listClass.typeParameters, null, null, typeContext, inferredTypes);
- inferredTypeArgument = inferredTypes[0];
- formalTypes = [];
- actualTypes = [];
- } else {
- inferredTypeArgument = declaredTypeArgument ?? const DynamicType();
- }
- for (var expression in expressions) {
- var expressionType =
- inferExpression(expression, inferredTypeArgument, inferenceNeeded);
- if (inferenceNeeded) {
- formalTypes.add(listType.typeArguments[0]);
- actualTypes.add(expressionType);
- }
- }
- if (inferenceNeeded) {
- typeSchemaEnvironment.inferGenericFunctionOrType(
- listType,
- listClass.typeParameters,
- formalTypes,
- actualTypes,
- typeContext,
- inferredTypes);
- inferredTypeArgument = inferredTypes[0];
- instrumentation?.record(Uri.parse(uri), offset, 'typeArgs',
- new InstrumentationValueForTypeArgs([inferredTypeArgument]));
- setTypeArgument(inferredTypeArgument);
- }
- var inferredType = typeNeeded
- ? new InterfaceType(listClass, [inferredTypeArgument])
- : null;
- listener.listLiteralExit(inferredType);
- return inferredType;
- }
-
- /// Performs the core type inference algorithm for method invocations.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- ///
- /// [offset] is the location of the method invocation in the source file.
- /// [receiver] is the object whose method is being invoked, and [methodName]
- /// is the name of the method. [explicitTypeArguments] is the set of type
- /// arguments explicitly provided, or `null` if no type arguments were
- /// provided. [forEachArgument] is a callback which can be used to iterate
- /// through all invocation arguments (both named and positional).
- /// [setInferredTypeArguments] is a callback which can be used to record the
- /// inferred type arguments. [setInterfaceTarget] is a callback which can be
- /// used to record the method being invoked.
- DartType inferMethodInvocation(
- DartType typeContext,
- bool typeNeeded,
- int offset,
- Expression receiver,
- Name methodName,
- List<DartType> explicitTypeArguments,
- void forEachArgument(void callback(String name, Expression expression)),
- void setInferredTypeArguments(List<DartType> types),
- void setInterfaceTarget(Procedure procedure)) {
- typeNeeded = listener.methodInvocationEnter(typeContext) || typeNeeded;
- // First infer the receiver so we can look up the method that was invoked.
- var receiverType = inferExpression(receiver, null, true);
- bool isOverloadedArithmeticOperator = false;
- Member interfaceMember;
- if (receiverType is InterfaceType) {
- interfaceMember =
- classHierarchy.getInterfaceMember(receiverType.classNode, methodName);
- if (interfaceMember is Procedure) {
- setInterfaceTarget(interfaceMember);
- isOverloadedArithmeticOperator = typeSchemaEnvironment
- .isOverloadedArithmeticOperator(interfaceMember);
- }
- }
- var calleeType = _getCalleeFunctionType(
- interfaceMember, receiverType, methodName, offset);
- var inferredType = _inferInvocation(
- typeContext,
- typeNeeded,
- offset,
- calleeType,
- calleeType.returnType,
- explicitTypeArguments,
- forEachArgument,
- setInferredTypeArguments,
- isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
- receiverType: receiverType);
- listener.methodInvocationExit(inferredType);
- return inferredType;
- }
-
- /// Performs the core type inference algorithm for null literals.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- DartType inferNullLiteral(DartType typeContext, bool typeNeeded) {
- typeNeeded = listener.nullLiteralEnter(typeContext) || typeNeeded;
- var inferredType = typeNeeded ? coreTypes.nullClass.rawType : null;
- listener.nullLiteralExit(inferredType);
- return inferredType;
- }
-
- /// Performs the core type inference algorithm for return statements.
- ///
- /// [body] is the expression being returned, or `null` for a bare return
- /// statement.
- void inferReturnStatement(Expression expression) {
- var closureContext = _closureContext;
- var typeContext = closureContext != null && !closureContext.isGenerator
- ? closureContext.returnContext
- : null;
- var inferredType = expression != null
- ? inferExpression(expression, typeContext, closureContext != null)
- : const VoidType();
- if (expression == null) {
- // Analyzer treats bare `return` statements as having no effect on the
- // inferred type of the closure. TODO(paulberry): is this what we want
- // for Fasta?
- return;
- }
- closureContext?.updateInferredReturnType(this, inferredType);
- }
-
- /// Modifies a type as appropriate when inferring a closure return type.
- DartType inferReturnType(DartType returnType, bool isExpressionFunction) {
- if (returnType == null) {
- // Analyzer infers `Null` if there is no `return` expression; the spec
- // says to return `void`. TODO(paulberry): resolve this difference.
- return coreTypes.nullClass.rawType;
- }
- if (isExpressionFunction &&
- returnType is InterfaceType &&
- identical(returnType.classNode, coreTypes.nullClass)) {
- // Analyzer coerces `Null` to `dynamic` in expression functions; the spec
- // doesn't say to do this. TODO(paulberry): resolve this difference.
- return const DynamicType();
- }
- return returnType;
- }
-
- /// Performs the core type inference algorithm for static variable getters.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- ///
- /// [getterType] is the type of the field being referenced, or the return type
- /// of the getter.
- DartType inferStaticGet(
- DartType typeContext, bool typeNeeded, DartType getterType) {
- typeNeeded = listener.staticGetEnter(typeContext) || typeNeeded;
- var inferredType = typeNeeded ? getterType : null;
- listener.staticGetExit(inferredType);
- return inferredType;
- }
-
- /// Performs the core type inference algorithm for method invocations.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- ///
- /// [offset] is the location of the method invocation in the source file.
- /// [receiver] is the object whose method is being invoked, and [methodName]
- /// is the name of the method. [explicitTypeArguments] is the set of type
- /// arguments explicitly provided, or `null` if no type arguments were
- /// provided. [forEachArgument] is a callback which can be used to iterate
- /// through all invocation arguments (both named and positional).
- /// [setInferredTypeArguments] is a callback which can be used to record the
- /// inferred type arguments. [setInterfaceTarget] is a callback which can be
- /// used to record the method being invoked.
- DartType inferStaticInvocation(
- DartType typeContext,
- bool typeNeeded,
- int offset,
- Procedure target,
- Name methodName,
- List<DartType> explicitTypeArguments,
- void forEachArgument(void callback(String name, Expression expression)),
- void setInferredTypeArguments(List<DartType> types)) {
- typeNeeded = listener.staticInvocationEnter(typeContext) || typeNeeded;
- var calleeType = target.function.functionType;
- var inferredType = _inferInvocation(
- typeContext,
- typeNeeded,
- offset,
- calleeType,
- calleeType.returnType,
- explicitTypeArguments,
- forEachArgument,
- setInferredTypeArguments);
- listener.staticInvocationExit(inferredType);
- return inferredType;
- }
-
- /// Performs the core type inference algorithm for string concatenations.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- DartType inferStringConcatenation(
- DartType typeContext, bool typeNeeded, Iterable<Expression> expressions) {
- typeNeeded = listener.stringConcatenationEnter(typeContext) || typeNeeded;
- for (Expression expression in expressions) {
- inferExpression(expression, null, false);
- }
- var inferredType = typeNeeded ? coreTypes.stringClass.rawType : null;
- listener.stringConcatenationExit(inferredType);
- return inferredType;
- }
-
- /// Performs the core type inference algorithm for string literals.
- ///
- /// [typeContext], [typeNeeded], and the return value behave as described in
- /// [inferExpression].
- DartType inferStringLiteral(DartType typeContext, bool typeNeeded) {
- typeNeeded = listener.stringLiteralEnter(typeContext) || typeNeeded;
- var inferredType = typeNeeded ? coreTypes.stringClass.rawType : null;
- listener.stringLiteralExit(inferredType);
- return inferredType;
- }
-
- /// Performs the core type inference algorithm for variable declarations.
- ///
- /// [declaredType] is the declared type of the variable, or `null` if the type
- /// should be inferred. [initializer] is the initializer expression.
- /// [offset] is the character offset of the variable declaration (for
- /// instrumentation). [setType] is a callback that will be used to set the
- /// inferred type.
- void inferVariableDeclaration(DartType declaredType, Expression initializer,
- int offset, void setType(DartType type)) {
- if (initializer == null) return;
- var inferredType = inferDeclarationType(
- inferExpression(initializer, declaredType, declaredType == null));
- if (strongMode && declaredType == null) {
- instrumentation?.record(Uri.parse(uri), offset, 'type',
- new InstrumentationValueForType(inferredType));
- setType(inferredType);
- }
- }
-
- DartType inferVariableGet(
- DartType typeContext,
- bool typeNeeded,
- bool mutatedInClosure,
- TypePromotionFact<VariableDeclaration> typePromotionFact,
- TypePromotionScope typePromotionScope,
- int offset,
- DartType declaredOrInferredType,
- void setPromotedType(DartType type)) {
- typeNeeded = listener.variableGetEnter(typeContext) || typeNeeded;
- DartType promotedType = typePromoter.computePromotedType(
- typePromotionFact, typePromotionScope, mutatedInClosure);
- if (promotedType != null) {
- instrumentation?.record(Uri.parse(uri), offset, 'promotedType',
- new InstrumentationValueForType(promotedType));
- }
- setPromotedType(promotedType);
- var inferredType =
- typeNeeded ? (promotedType ?? declaredOrInferredType) : null;
- listener.variableGetExit(inferredType);
- return inferredType;
- }
-
- DartType inferVariableSet(DartType typeContext, bool typeNeeded,
- DartType declaredType, Expression value) {
- typeNeeded = listener.variableSetEnter(typeContext) || typeNeeded;
- var inferredType = inferExpression(value, declaredType, typeNeeded);
- listener.variableSetExit(inferredType);
- return inferredType;
- }
-
- FunctionType _getCalleeFunctionType(Member interfaceMember,
+ FunctionType getCalleeFunctionType(Member interfaceMember,
DartType receiverType, Name methodName, int offset) {
if (receiverType is InterfaceType) {
if (interfaceMember == null) return _functionReturningDynamic;
@@ -793,11 +169,15 @@ abstract class TypeInferrerImpl extends TypeInferrer {
}
}
- DartType _getNamedParameterType(FunctionType functionType, String name) {
+ /// Gets the initializer for the given [field], or `null` if there is no
+ /// initializer.
+ Expression getFieldInitializer(KernelField field);
+
+ DartType getNamedParameterType(FunctionType functionType, String name) {
return functionType.getNamedParameter(name) ?? const DynamicType();
}
- DartType _getPositionalParameterType(FunctionType functionType, int i) {
+ DartType getPositionalParameterType(FunctionType functionType, int i) {
if (i < functionType.positionalParameters.length) {
return functionType.positionalParameters[i];
} else {
@@ -805,7 +185,7 @@ abstract class TypeInferrerImpl extends TypeInferrer {
}
}
- DartType _getTypeArgumentOf(DartType type, Class class_) {
+ DartType getTypeArgumentOf(DartType type, Class class_) {
if (type is InterfaceType && identical(type.classNode, class_)) {
return type.typeArguments[0];
} else {
@@ -813,9 +193,42 @@ abstract class TypeInferrerImpl extends TypeInferrer {
}
}
+ /// Modifies a type as appropriate when inferring a declared variable's type.
+ DartType inferDeclarationType(DartType initializerType) {
+ if (initializerType is BottomType ||
+ (initializerType is InterfaceType &&
+ initializerType.classNode == coreTypes.nullClass)) {
+ // If the initializer type is Null or bottom, the inferred type is
+ // dynamic.
+ // TODO(paulberry): this rule is inherited from analyzer behavior but is
+ // not spec'ed anywhere.
+ return const DynamicType();
+ }
+ return initializerType;
+ }
+
+ /// Performs type inference on the given [expression].
+ ///
+ /// [typeContext] is the expected type of the expression, based on surrounding
+ /// code. [typeNeeded] indicates whether it is necessary to compute the
+ /// actual type of the expression. If [typeNeeded] is `true`, the actual type
+ /// of the expression is returned; otherwise `null` is returned.
+ ///
+ /// Derived classes should override this method with logic that dispatches on
+ /// the expression type and calls the appropriate specialized "infer" method.
+ DartType inferExpression(
+ Expression expression, DartType typeContext, bool typeNeeded);
+
+ /// Performs type inference on the given [field]'s initializer expression.
+ ///
+ /// Derived classes should provide an implementation that calls
+ /// [inferExpression] for the given [field]'s initializer expression.
+ DartType inferFieldInitializer(
+ KernelField field, DartType type, bool typeNeeded);
+
/// Performs the type inference steps that are shared by all kinds of
/// invocations (constructors, instance methods, and static methods).
- DartType _inferInvocation(
+ DartType inferInvocation(
DartType typeContext,
bool typeNeeded,
int offset,
@@ -856,8 +269,8 @@ abstract class TypeInferrerImpl extends TypeInferrer {
int i = 0;
forEachArgument((name, expression) {
DartType formalType = name != null
- ? _getNamedParameterType(calleeType, name)
- : _getPositionalParameterType(calleeType, i++);
+ ? getNamedParameterType(calleeType, name)
+ : getPositionalParameterType(calleeType, i++);
DartType inferredFormalType = substitution != null
? substitution.substituteType(formalType)
: formalType;
@@ -895,38 +308,24 @@ abstract class TypeInferrerImpl extends TypeInferrer {
return inferredType;
}
- DartType _wrapType(DartType type, Class class_) {
- return new InterfaceType(class_, <DartType>[type]);
- }
-}
-
-/// Keeps track of information about the innermost function or closure being
-/// inferred.
-class _ClosureContext {
- final bool isAsync;
-
- final bool isGenerator;
-
- final DartType returnContext;
-
- DartType _inferredReturnType;
-
- _ClosureContext(this.isAsync, this.isGenerator, this.returnContext);
-
- /// Gets the return type that was inferred for the current closure, or `null`
- /// if there were no `return` statements.
- get inferredReturnType {
- return _inferredReturnType;
+ /// Modifies a type as appropriate when inferring a closure return type.
+ DartType inferReturnType(DartType returnType, bool isExpressionFunction) {
+ if (returnType == null) {
+ // Analyzer infers `Null` if there is no `return` expression; the spec
+ // says to return `void`. TODO(paulberry): resolve this difference.
+ return coreTypes.nullClass.rawType;
+ }
+ if (isExpressionFunction &&
+ returnType is InterfaceType &&
+ identical(returnType.classNode, coreTypes.nullClass)) {
+ // Analyzer coerces `Null` to `dynamic` in expression functions; the spec
+ // doesn't say to do this. TODO(paulberry): resolve this difference.
+ return const DynamicType();
+ }
+ return returnType;
}
- /// Updates the inferred return type based on the presence of a return
- /// statement returning the given [type].
- void updateInferredReturnType(TypeInferrerImpl inferrer, DartType type) {
- if (_inferredReturnType == null) {
- _inferredReturnType = type;
- } else {
- _inferredReturnType = inferrer.typeSchemaEnvironment
- .getLeastUpperBound(_inferredReturnType, type);
- }
+ DartType wrapType(DartType type, Class class_) {
+ return new InterfaceType(class_, <DartType>[type]);
}
}
« no previous file with comments | « pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698