| 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 343872c577705469ef4b9a4e3987e58b98dd209d..b6b11317291f7bb6ce18d4edc8e26a9c9e3991ec 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,8 +7,16 @@ import 'package:front_end/src/fasta/type_inference/type_inference_engine.dart';
|
| import 'package:front_end/src/fasta/type_inference/type_promotion.dart';
|
| import 'package:front_end/src/fasta/type_inference/type_schema_environment.dart';
|
| import 'package:kernel/ast.dart'
|
| - show BottomType, DartType, DynamicType, InterfaceType, Member;
|
| + show
|
| + BottomType,
|
| + Constructor,
|
| + DartType,
|
| + DynamicType,
|
| + FunctionNode,
|
| + InterfaceType,
|
| + Member;
|
| import 'package:kernel/core_types.dart';
|
| +import 'package:kernel/type_algebra.dart';
|
|
|
| /// Keeps track of the local state for the type inference that occurs during
|
| /// compilation of a single method body or top level initializer.
|
| @@ -122,6 +130,81 @@ abstract class TypeInferrerImpl<S, E, V, F> extends TypeInferrer<S, E, V, F> {
|
| return typeNeeded ? type : null;
|
| }
|
|
|
| + /// Performs the core type inference algorithm for constructor invocations.
|
| + ///
|
| + /// [typeContext], [typeNeeded], and the return value behave as described in
|
| + /// [inferExpression].
|
| + ///
|
| + /// [offset] is the location of the constructor invocation in the source file.
|
| + /// [target] is the constructor that is being called. [explicitTypeArguments]
|
| + /// is the set of type arguments explicitly provided, or `null` if no type
|
| + /// arguments were provided. [forEachArgument] is a callback which can be
|
| + /// used to iterate through all constructor arguments (both named and
|
| + /// positional). [setClassType] is a callback which can be used to record the
|
| + /// inferred type.
|
| + DartType inferConstructorInvocation(
|
| + DartType typeContext,
|
| + bool typeNeeded,
|
| + int offset,
|
| + Constructor target,
|
| + List<DartType> explicitTypeArguments,
|
| + void forEachArgument(void callback(String name, E expression)),
|
| + void setClassType(InterfaceType type)) {
|
| + List<DartType> typesFromDownwardsInference;
|
| + InterfaceType inferredClassType;
|
| + Substitution substitution;
|
| + List<DartType> formalTypes;
|
| + List<DartType> actualTypes;
|
| + var targetClass = target.enclosingClass;
|
| + var targetTypeParameters = targetClass.typeParameters;
|
| + bool inferenceNeeded = explicitTypeArguments == null &&
|
| + strongMode &&
|
| + targetTypeParameters.isNotEmpty;
|
| + if (inferenceNeeded) {
|
| + typesFromDownwardsInference =
|
| + new List<DartType>.filled(targetTypeParameters.length, null);
|
| + inferredClassType = typeSchemaEnvironment.inferGenericFunctionOrType(
|
| + targetClass.typeParameters,
|
| + targetClass.thisType,
|
| + [],
|
| + [],
|
| + typeContext,
|
| + typesFromDownwardsInference);
|
| + substitution = Substitution.fromPairs(
|
| + targetTypeParameters, typesFromDownwardsInference);
|
| + } else {
|
| + inferredClassType = targetClass.rawType;
|
| + }
|
| + int i = 0;
|
| + forEachArgument((name, expression) {
|
| + DartType formalType = name != null
|
| + ? _getNamedParameterType(target.function, name)
|
| + : _getPositionalParameterType(target.function, i++);
|
| + DartType inferredFormalType = substitution != null
|
| + ? substitution.substituteType(formalType)
|
| + : formalType;
|
| + var expressionType =
|
| + inferExpression(expression, inferredFormalType, inferenceNeeded);
|
| + if (inferenceNeeded) {
|
| + formalTypes.add(formalType);
|
| + actualTypes.add(expressionType);
|
| + }
|
| + });
|
| + if (inferenceNeeded) {
|
| + inferredClassType = typeSchemaEnvironment.inferGenericFunctionOrType(
|
| + targetClass.typeParameters,
|
| + targetClass.thisType,
|
| + formalTypes,
|
| + actualTypes,
|
| + typeContext,
|
| + typesFromDownwardsInference);
|
| + instrumentation?.record(Uri.parse(uri), offset, 'typeArgs',
|
| + new InstrumentationValueForTypeArgs(inferredClassType.typeArguments));
|
| + setClassType(inferredClassType);
|
| + }
|
| + return typeNeeded ? inferredClassType : null;
|
| + }
|
| +
|
| /// Maps the type of a variable's initializer expression to the correct
|
| /// inferred type for the variable.
|
| DartType inferDeclarationType(DartType initializerType) {
|
| @@ -395,6 +478,32 @@ abstract class TypeInferrerImpl<S, E, V, F> extends TypeInferrer<S, E, V, F> {
|
| DartType typeContext, bool typeNeeded, DartType declaredType, E value) {
|
| return inferExpression(value, declaredType, typeNeeded);
|
| }
|
| +
|
| + DartType _getNamedParameterType(FunctionNode function, String name) {
|
| + // TODO(paulberry): is there a kernel function that does this binary search?
|
| + int lower = 0;
|
| + int upper = function.namedParameters.length - 1;
|
| + while (lower <= upper) {
|
| + int pivot = (lower + upper) ~/ 2;
|
| + int comparison = name.compareTo(function.namedParameters[pivot].name);
|
| + if (comparison == 0) {
|
| + return function.namedParameters[pivot].type;
|
| + } else if (comparison < 0) {
|
| + upper = pivot - 1;
|
| + } else {
|
| + lower = pivot + 1;
|
| + }
|
| + }
|
| + return const DynamicType();
|
| + }
|
| +
|
| + DartType _getPositionalParameterType(FunctionNode function, int i) {
|
| + if (i < function.positionalParameters.length) {
|
| + return function.positionalParameters[i].type;
|
| + } else {
|
| + return const DynamicType();
|
| + }
|
| + }
|
| }
|
|
|
| /// Keeps track of information about the innermost function or closure being
|
|
|