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

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

Issue 2878173002: Infer return types of closures (basic support). (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
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);
+ }
+ }
}

Powered by Google App Engine
This is Rietveld 408576698