| 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 81d3b539cc7fed3a547a5af7ba43370e4ad757ff..bebf868c938c6ca1bba594ec38d87b333d064240 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
|
| @@ -7,6 +7,7 @@ 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
|
| @@ -21,7 +22,8 @@ import 'package:kernel/ast.dart'
|
| Name,
|
| Procedure,
|
| TypeParameter,
|
| - TypeParameterType;
|
| + TypeParameterType,
|
| + VoidType;
|
| import 'package:kernel/class_hierarchy.dart';
|
| import 'package:kernel/core_types.dart';
|
| import 'package:kernel/type_algebra.dart';
|
| @@ -238,9 +240,9 @@ abstract class TypeInferrerImpl<S, E, V, F> extends TypeInferrer<S, E, V, F> {
|
| return inferredType;
|
| }
|
|
|
| - /// Maps the type of a variable's initializer expression to the correct
|
| - /// inferred type for the variable.
|
| - DartType inferDeclarationType(DartType initializerType) {
|
| + /// Modifies a type as appropriate when inferring a variable's type or a
|
| + /// closure return type.
|
| + DartType inferDeclarationOrReturnType(DartType initializerType) {
|
| if (initializerType is BottomType ||
|
| (initializerType is InterfaceType &&
|
| initializerType.classNode == coreTypes.nullClass)) {
|
| @@ -325,16 +327,26 @@ abstract class TypeInferrerImpl<S, E, V, F> extends TypeInferrer<S, E, V, F> {
|
| // TODO(paulberry): do we also need to visit default parameter values?
|
| // TODO(paulberry): infer argument types and type parameters.
|
| // TODO(paulberry): full support for generators.
|
| - // TODO(paulberry): Dart 1.0 rules say we only need to set the function
|
| - // node's return type if it uses expression syntax. Does that make sense
|
| - // for Dart 2.0?
|
| - bool needToSetReturnType = isExpressionFunction;
|
| + DartType returnContext =
|
| + typeContext is FunctionType ? typeContext.returnType : null;
|
| + bool needToSetReturnType = isExpressionFunction || strongMode;
|
| _ClosureContext oldClosureContext = _closureContext;
|
| - _closureContext = new _ClosureContext(isAsync, isGenerator);
|
| + _closureContext = new _ClosureContext(isAsync, isGenerator, returnContext);
|
| inferStatement(body);
|
| DartType inferredReturnType;
|
| if (needToSetReturnType || typeNeeded) {
|
| - inferredReturnType = _closureContext.inferredReturnType;
|
| + inferredReturnType =
|
| + inferDeclarationOrReturnType(_closureContext.inferredReturnType);
|
| + 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);
|
| + }
|
| if (isAsync) {
|
| inferredReturnType = new InterfaceType(
|
| coreTypes.futureClass, <DartType>[inferredReturnType]);
|
| @@ -549,6 +561,21 @@ abstract class TypeInferrerImpl<S, E, V, F> extends TypeInferrer<S, E, V, F> {
|
| 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(E expression) {
|
| + var closureContext = _closureContext;
|
| + var typeContext = closureContext != null && !closureContext.isGenerator
|
| + ? closureContext.returnContext
|
| + : null;
|
| + var inferredType = expression != null
|
| + ? inferExpression(expression, typeContext, closureContext != null)
|
| + : const VoidType();
|
| + closureContext?.updateInferredReturnType(this, inferredType);
|
| + }
|
| +
|
| /// Performs the core type inference algorithm for static variable getters.
|
| ///
|
| /// [typeContext], [typeNeeded], and the return value behave as described in
|
| @@ -600,7 +627,7 @@ abstract class TypeInferrerImpl<S, E, V, F> extends TypeInferrer<S, E, V, F> {
|
| void inferVariableDeclaration(DartType declaredType, E initializer,
|
| int offset, void setType(DartType type)) {
|
| if (initializer == null) return;
|
| - var inferredType = inferDeclarationType(
|
| + var inferredType = inferDeclarationOrReturnType(
|
| inferExpression(initializer, declaredType, declaredType == null));
|
| if (strongMode && declaredType == null) {
|
| instrumentation?.record(Uri.parse(uri), offset, 'type',
|
| @@ -704,17 +731,29 @@ class _ClosureContext {
|
|
|
| final bool isGenerator;
|
|
|
| + final DartType returnContext;
|
| +
|
| DartType _inferredReturnType;
|
|
|
| - _ClosureContext(this.isAsync, this.isGenerator);
|
| + _ClosureContext(this.isAsync, this.isGenerator, this.returnContext);
|
|
|
| /// Gets the return type that was inferred for the current closure.
|
| get inferredReturnType {
|
| if (_inferredReturnType == null) {
|
| // No return statement found.
|
| - // TODO(paulberry): is it correct to infer `dynamic`?
|
| - return const DynamicType();
|
| + return const VoidType();
|
| }
|
| 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);
|
| + }
|
| + }
|
| }
|
|
|