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

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

Issue 2950213002: Infer the return types of local functions where appropriate. (Closed)
Patch Set: Created 3 years, 6 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/kernel/kernel_shadow_ast.dart ('k') | pkg/front_end/test/fasta/kompile.status » ('j') | 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 34a3e3dc720021be87b60adb1dc94f049c926e6a..f9adf852bee599f65b52c93efca7ccb788279804 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
@@ -22,6 +22,7 @@ import 'package:kernel/ast.dart'
DynamicType,
Expression,
Field,
+ FunctionNode,
FunctionType,
Initializer,
InterfaceType,
@@ -33,10 +34,12 @@ import 'package:kernel/ast.dart'
ProcedureKind,
PropertyGet,
PropertySet,
+ ReturnStatement,
Statement,
SuperMethodInvocation,
SuperPropertyGet,
SuperPropertySet,
+ TypeParameter,
TypeParameterType,
VariableDeclaration,
VoidType;
@@ -637,6 +640,136 @@ abstract class TypeInferrerImpl extends TypeInferrer {
return inferredType;
}
+ DartType inferLocalFunction(FunctionNode function, DartType typeContext,
Siggi Cherem (dart-lang) 2017/06/21 22:34:27 I assume this just moved, but otherwise is the sam
Paul Berry 2017/06/22 17:44:20 There are two small changes. See comments below.
+ bool typeNeeded, int fileOffset, DartType returnContext, bool isNamed) {
Paul Berry 2017/06/22 17:44:20 Previously, returnContext was always initially `nu
+ bool hasImplicitReturnType = returnContext == null;
+ if (!isTopLevel) {
+ for (var parameter in function.positionalParameters) {
+ if (parameter.initializer != null) {
+ inferExpression(parameter.initializer, parameter.type, false);
+ }
+ }
+ for (var parameter in function.namedParameters) {
+ if (parameter.initializer != null) {
+ inferExpression(parameter.initializer, parameter.type, false);
+ }
+ }
+ }
+
+ // 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);
+ 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
Siggi Cherem (dart-lang) 2017/06/21 22:34:27 nit: wrap
Paul Berry 2017/06/22 17:44:20 Done.
+ // 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)) {
+ DartType inferredType;
+ if (formalTypesFromContext[i] != null) {
+ inferredType = greatestClosure(coreTypes,
+ substitution.substituteType(formalTypesFromContext[i]));
+ } else {
+ inferredType = const DynamicType();
+ }
+ instrumentation?.record(Uri.parse(uri), formal.fileOffset, 'type',
+ new InstrumentationValueForType(inferredType));
+ formal.type = inferredType;
+ }
+ }
+
+ // Let `N'` be `N[T/S]`. The [ClosureContext] constructor will adjust
+ // accordingly if the closure is declared with `async`, `async*`, or
+ // `sync*`.
+ if (returnContext != null) {
+ returnContext = substitution.substituteType(returnContext);
+ }
+
+ // 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 = hasImplicitReturnType &&
Paul Berry 2017/06/22 17:44:20 Previously this was: bool needToSetReturnType = i
+ ((isExpressionFunction && !isNamed) || strongMode);
+ ClosureContext oldClosureContext = this.closureContext;
+ ClosureContext closureContext =
+ new ClosureContext(this, function.asyncMarker, returnContext);
+ this.closureContext = closureContext;
+ 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 =
+ closureContext.inferReturnType(this, isExpressionFunction);
+ }
+
+ // 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), fileOffset, 'returnType',
+ new InstrumentationValueForType(inferredReturnType));
+ function.returnType = inferredReturnType;
+ }
+ this.closureContext = oldClosureContext;
+ return typeNeeded ? function.functionType : null;
+ }
+
/// Performs the core type inference algorithm for method invocations (this
/// handles both null-aware and non-null-aware method invocations).
DartType inferMethodInvocation(
« no previous file with comments | « pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart ('k') | pkg/front_end/test/fasta/kompile.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698