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

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

Issue 2829223007: Introduce initial plumbing for type promotion in fasta. (Closed)
Patch Set: Add missing copyrights Created 3 years, 8 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 caa08103a55fbb2c0c783274d018a83a1db49b85..e65065716c1d1e6585c8fbc08047d49fdf86b6fb 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
@@ -4,7 +4,9 @@
import 'package:front_end/src/base/instrumentation.dart';
import 'package:front_end/src/fasta/type_inference/type_inference_engine.dart';
-import 'package:kernel/ast.dart' show DartType, Member;
+import 'package:front_end/src/fasta/type_inference/type_promotion.dart';
+import 'package:kernel/ast.dart'
+ show DartType, DynamicType, InterfaceType, Member;
import 'package:kernel/core_types.dart';
/// Keeps track of the local state for the type inference that occurs during
@@ -21,6 +23,10 @@ import 'package:kernel/core_types.dart';
/// This class describes the interface for use by clients of type inference
/// (e.g. BodyBuilder). Derived classes should derive from [TypeInferrerImpl].
abstract class TypeInferrer<S, E, V, F> {
+ /// Gets the [TypePromoter] that can be used to perform type promotion within
+ /// this method body or initializer.
+ TypePromoter<E, V> get typePromoter;
+
/// The URI of the code for which type inference is currently being
/// performed--this is used for testing.
String get uri;
@@ -35,7 +41,7 @@ abstract class TypeInferrer<S, E, V, F> {
void inferStatement(S statement);
}
-/// Derived class containing generic implementations of [TypeInferrerImpl].
+/// Derived class containing generic implementations of [TypeInferrer].
///
/// This class contains as much of the implementation of type inference as
/// possible without knowing the identity of the type parameters. It defers to
@@ -55,10 +61,20 @@ abstract class TypeInferrerImpl<S, E, V, F> extends TypeInferrer<S, E, V, F> {
final Instrumentation instrumentation;
+ _InferenceContext _context;
+
TypeInferrerImpl(TypeInferenceEngineImpl<F> engine, this.uri)
: coreTypes = engine.coreTypes,
strongMode = engine.strongMode,
- instrumentation = engine.instrumentation;
+ instrumentation = engine.instrumentation {
+ // The return type only needs to be inferred for closures, so we can safely
+ // set isAsync and isGenerator to false in the outermost context.
ahe 2017/04/25 13:17:00 Brittle?
Paul Berry 2017/04/25 15:49:26 Good point. I actually think it might be ok to ju
+ _context = new _InferenceContext(false, false);
+ }
+
+ /// Gets the type promoter that should be used to promote types during
+ /// inference.
+ TypePromoter<E, V> get typePromoter;
/// Gets the initializer for the given [field], or `null` if there is no
/// initializer.
@@ -75,12 +91,79 @@ abstract class TypeInferrerImpl<S, E, V, F> extends TypeInferrer<S, E, V, F> {
/// the expression type and calls the appropriate specialized "infer" method.
DartType inferExpression(E expression, DartType typeContext, bool typeNeeded);
+ /// Performs the core type inference algorithm for expression statements.
+ void inferExpressionStatement(E 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(F field, DartType type, bool typeNeeded);
+ /// 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,
+ S body,
+ bool isExpressionFunction,
+ bool isAsync,
+ bool isGenerator,
+ int offset,
+ void setReturnType(DartType type),
+ DartType getFunctionType()) {
+ // 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;
+ _InferenceContext oldContext = _context;
+ _context = new _InferenceContext(isAsync, isGenerator);
+ inferStatement(body);
+ DartType inferredReturnType;
+ if (needToSetReturnType || typeNeeded) {
+ inferredReturnType = _context.inferredReturnType;
+ if (isAsync) {
+ inferredReturnType = new InterfaceType(
+ coreTypes.futureClass, <DartType>[inferredReturnType]);
+ }
+ }
+ if (needToSetReturnType) {
+ instrumentation?.record('returnType', Uri.parse(uri), offset,
+ new InstrumentationValueForType(inferredReturnType));
+ setReturnType(inferredReturnType);
+ }
+ _context = oldContext;
+ if (typeNeeded) {
+ return getFunctionType();
+ } else {
+ return null;
+ }
+ }
+
+ /// Performs the core type inference algorithm for if statements.
+ void inferIfStatement(E condition, S then, S 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
@@ -89,6 +172,17 @@ abstract class TypeInferrerImpl<S, E, V, F> extends TypeInferrer<S, E, V, F> {
return typeNeeded ? coreTypes.intClass.rawType : null;
}
+ /// 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, E operand) {
+ inferExpression(operand, null, false);
+ return typeNeeded ? coreTypes.boolClass.rawType : null;
+ }
+
/// Performs the core type inference algorithm for static variable getters.
///
/// [typeContext], [typeNeeded], and the return value behave as described in
@@ -119,4 +213,50 @@ abstract class TypeInferrerImpl<S, E, V, F> extends TypeInferrer<S, E, V, F> {
setType(inferredType);
}
}
+
+ DartType inferVariableGet(
+ DartType typeContext,
+ bool typeNeeded,
+ bool mutatedInClosure,
+ TypePromotionFact<V> typePromotionFact,
+ TypePromotionScope typePromotionScope,
+ int offset,
+ DartType declaredType,
+ void setPromotedType(DartType type)) {
+ DartType promotedType = typePromoter.computePromotedType(
+ typePromotionFact, typePromotionScope, mutatedInClosure);
+ instrumentation?.record(
+ 'promotedType',
+ Uri.parse(uri),
+ offset,
+ promotedType != null
+ ? new InstrumentationValueForType(promotedType)
+ : const InstrumentationValueLiteral('none'));
+ setPromotedType(promotedType);
+ return typeNeeded
+ ? (promotedType ?? declaredType ?? const DynamicType())
+ : null;
+ }
+}
+
+/// Keeps track of information about the innermost function or closure being
+/// inferred.
+class _InferenceContext {
+ final bool isAsync;
+
+ final bool isGenerator;
+
+ DartType _inferredReturnType;
+
+ _InferenceContext(this.isAsync, this.isGenerator);
+
+ /// 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 _inferredReturnType;
+ }
}

Powered by Google App Engine
This is Rietveld 408576698