| 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 38fda54600efd850d7abe06aa87e58bd29076acb..645f9fa0d900cc58886e5b8264165a2b0e8ac2dc 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
|
| @@ -195,9 +195,8 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
| return inferredType;
|
| }
|
|
|
| - /// Modifies a type as appropriate when inferring a variable's type or a
|
| - /// closure return type.
|
| - DartType inferDeclarationOrReturnType(DartType initializerType) {
|
| + /// 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)) {
|
| @@ -386,8 +385,8 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
| // if `B’` contains no `return` expressions.
|
| DartType inferredReturnType;
|
| if (needToSetReturnType || typeNeeded) {
|
| - inferredReturnType =
|
| - inferDeclarationOrReturnType(_closureContext.inferredReturnType);
|
| + inferredReturnType = inferReturnType(
|
| + _closureContext.inferredReturnType, isExpressionFunction);
|
| if (!isExpressionFunction &&
|
| returnContext != null &&
|
| !typeSchemaEnvironment.isSubtypeOf(
|
| @@ -598,9 +597,32 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
| 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
|
| @@ -690,7 +712,7 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
| void inferVariableDeclaration(DartType declaredType, Expression initializer,
|
| int offset, void setType(DartType type)) {
|
| if (initializer == null) return;
|
| - var inferredType = inferDeclarationOrReturnType(
|
| + var inferredType = inferDeclarationType(
|
| inferExpression(initializer, declaredType, declaredType == null));
|
| if (strongMode && declaredType == null) {
|
| instrumentation?.record(Uri.parse(uri), offset, 'type',
|
| @@ -891,12 +913,9 @@ class _ClosureContext {
|
|
|
| _ClosureContext(this.isAsync, this.isGenerator, this.returnContext);
|
|
|
| - /// Gets the return type that was inferred for the current closure.
|
| + /// Gets the return type that was inferred for the current closure, or `null`
|
| + /// if there were no `return` statements.
|
| get inferredReturnType {
|
| - if (_inferredReturnType == null) {
|
| - // No return statement found.
|
| - return const VoidType();
|
| - }
|
| return _inferredReturnType;
|
| }
|
|
|
|
|