2
2
// for details. All rights reserved. Use of this source code is governed by a
3
3
// BSD-style license that can be found in the LICENSE.md file.
4
4
5
+ import 'package:_fe_analyzer_shared/src/deferred_function_literal_heuristic.dart' ;
5
6
import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart' ;
6
7
import 'package:_fe_analyzer_shared/src/testing/id.dart' ;
7
8
import 'package:_fe_analyzer_shared/src/util/link.dart' ;
@@ -82,6 +83,59 @@ bool isOverloadableArithmeticOperator(String name) {
82
83
identical (name, '%' );
83
84
}
84
85
86
+ /// Given a [FunctionExpression] , computes a set whose elements consist of (a)
87
+ /// an integer corresponding to the zero-based index of each positional
88
+ /// parameter of the function expression that has an explicit type annotation,
89
+ /// and (b) a string corresponding to the name of each named parameter of the
90
+ /// function expression that has an explicit type annotation.
91
+ Set <Object > _computeExplicitlyTypedParameterSet (
92
+ FunctionExpression functionExpression) {
93
+ Set <Object > result = {};
94
+ int unnamedParameterIndex = 0 ;
95
+ for (VariableDeclaration positionalParameter
96
+ in functionExpression.function.positionalParameters) {
97
+ int key = unnamedParameterIndex++ ;
98
+ if (! (positionalParameter as VariableDeclarationImpl ).isImplicitlyTyped) {
99
+ result.add (key);
100
+ }
101
+ }
102
+ for (VariableDeclaration namedParameter
103
+ in functionExpression.function.namedParameters) {
104
+ String key = namedParameter.name! ;
105
+ if (! (namedParameter as VariableDeclarationImpl ).isImplicitlyTyped) {
106
+ result.add (key);
107
+ }
108
+ }
109
+ return result;
110
+ }
111
+
112
+ /// Given an function type, computes a map based on the parameters whose keys
113
+ /// are either the parameter name (for named parameters) or the zero-based
114
+ /// integer index (for unnamed parameters), and whose values are the parameter
115
+ /// types.
116
+ Map <Object , DartType > _computeParameterMap (FunctionType functionType) => {
117
+ for (int i = 0 ; i < functionType.positionalParameters.length; i++ )
118
+ i: functionType.positionalParameters[i],
119
+ for (NamedType namedType in functionType.namedParameters)
120
+ namedType.name: namedType.type
121
+ };
122
+
123
+ /// Computes a list of [_ParamInfo] objects corresponding to the invocation
124
+ /// parameters that were *not* deferred.
125
+ List <_ParamInfo > _computeUndeferredParamInfo (List <DartType > formalTypes,
126
+ List <_DeferredParamInfo > deferredFunctionLiterals) {
127
+ // TODO(paulberry): test that the right thing happens when evaluation order differs from classic (positional/named) order.
128
+ Set <int > evaluationOrderIndicesAlreadyCovered = {
129
+ for (_DeferredParamInfo functionLiteral in deferredFunctionLiterals)
130
+ functionLiteral.evaluationOrderIndex
131
+ };
132
+ return [
133
+ for (int i = 0 ; i < formalTypes.length; i++ )
134
+ if (! evaluationOrderIndicesAlreadyCovered.contains (i))
135
+ new _ParamInfo (formalTypes[i])
136
+ ];
137
+ }
138
+
85
139
/// Enum denoting the kinds of contravariance check that might need to be
86
140
/// inserted for a method call.
87
141
enum MethodContravarianceCheckKind {
@@ -2290,7 +2344,8 @@ class TypeInferrerImpl implements TypeInferrer {
2290
2344
explicitTypeArguments == null &&
2291
2345
calleeTypeParameters.isNotEmpty;
2292
2346
bool typeChecksNeeded = ! isTopLevel;
2293
- bool useFormalAndActualTypes = typeChecksNeeded ||
2347
+ bool useFormalAndActualTypes = inferenceNeeded ||
2348
+ typeChecksNeeded ||
2294
2349
isSpecialCasedBinaryOperator ||
2295
2350
isSpecialCasedTernaryOperator;
2296
2351
@@ -2331,7 +2386,7 @@ class TypeInferrerImpl implements TypeInferrer {
2331
2386
calleeTypeParameters,
2332
2387
typeContext,
2333
2388
libraryBuilder.library);
2334
- typeSchemaEnvironment.downwardsInfer (gatherer, calleeTypeParameters,
2389
+ typeSchemaEnvironment.partialInfer (gatherer, calleeTypeParameters,
2335
2390
inferredTypes, libraryBuilder.library);
2336
2391
substitution =
2337
2392
Substitution .fromPairs (calleeTypeParameters, inferredTypes);
@@ -2471,6 +2526,7 @@ class TypeInferrerImpl implements TypeInferrer {
2471
2526
(deferredFunctionLiterals ?? = []).add (new _DeferredParamInfo (
2472
2527
formalType: formalType,
2473
2528
argumentExpression: argumentExpression,
2529
+ unparenthesizedExpression: unparenthesizedExpression,
2474
2530
isNamed: ! isExpression,
2475
2531
evaluationOrderIndex: evaluationOrderIndex,
2476
2532
index: index));
@@ -2510,26 +2566,44 @@ class TypeInferrerImpl implements TypeInferrer {
2510
2566
}
2511
2567
}
2512
2568
if (deferredFunctionLiterals != null ) {
2513
- for (_DeferredParamInfo deferredArgument in deferredFunctionLiterals) {
2514
- ExpressionInferenceResult result = inferArgument (
2515
- deferredArgument.formalType, deferredArgument.argumentExpression,
2516
- isNamed: deferredArgument.isNamed);
2517
- DartType inferredType = _computeInferredType (result);
2518
- Expression expression = result.expression;
2519
- identicalInfo? [deferredArgument.evaluationOrderIndex] =
2520
- flowAnalysis.equalityOperand_end (expression, inferredType);
2521
- if (deferredArgument.isNamed) {
2522
- NamedExpression namedArgument =
2523
- arguments.named[deferredArgument.index];
2524
- namedArgument.value = expression..parent = namedArgument;
2525
- } else {
2526
- arguments.positional[deferredArgument.index] = expression
2527
- ..parent = arguments;
2569
+ bool isFirstStage = true ;
2570
+ for (List <_DeferredParamInfo > stage in new _FunctionLiteralDependencies (
2571
+ deferredFunctionLiterals,
2572
+ calleeType.typeParameters.toSet (),
2573
+ inferenceNeeded
2574
+ ? _computeUndeferredParamInfo (
2575
+ formalTypes! , deferredFunctionLiterals)
2576
+ : const [])
2577
+ .planReconciliationStages ()) {
2578
+ if (gatherer != null && ! isFirstStage) {
2579
+ typeSchemaEnvironment.partialInfer (gatherer, calleeTypeParameters,
2580
+ inferredTypes! , libraryBuilder.library);
2581
+ substitution =
2582
+ Substitution .fromPairs (calleeTypeParameters, inferredTypes);
2528
2583
}
2529
- gatherer? .tryConstrainLower (deferredArgument.formalType, inferredType);
2530
- if (useFormalAndActualTypes) {
2531
- actualTypes! [deferredArgument.evaluationOrderIndex] = inferredType;
2584
+ for (_DeferredParamInfo deferredArgument in stage) {
2585
+ ExpressionInferenceResult result = inferArgument (
2586
+ deferredArgument.formalType, deferredArgument.argumentExpression,
2587
+ isNamed: deferredArgument.isNamed);
2588
+ DartType inferredType = _computeInferredType (result);
2589
+ Expression expression = result.expression;
2590
+ identicalInfo? [deferredArgument.evaluationOrderIndex] =
2591
+ flowAnalysis.equalityOperand_end (expression, inferredType);
2592
+ if (deferredArgument.isNamed) {
2593
+ NamedExpression namedArgument =
2594
+ arguments.named[deferredArgument.index];
2595
+ namedArgument.value = expression..parent = namedArgument;
2596
+ } else {
2597
+ arguments.positional[deferredArgument.index] = expression
2598
+ ..parent = arguments;
2599
+ }
2600
+ gatherer? .tryConstrainLower (
2601
+ deferredArgument.formalType, inferredType);
2602
+ if (useFormalAndActualTypes) {
2603
+ actualTypes! [deferredArgument.evaluationOrderIndex] = inferredType;
2604
+ }
2532
2605
}
2606
+ isFirstStage = false ;
2533
2607
}
2534
2608
}
2535
2609
if (identicalInfo != null ) {
@@ -5967,15 +6041,14 @@ class ImplicitInstantiation {
5967
6041
/// Information about an invocation argument that needs to be resolved later due
5968
6042
/// to the fact that it's a function literal and the `inference-update-1`
5969
6043
/// feature is enabled.
5970
- class _DeferredParamInfo {
5971
- /// The (unsubstituted) type of the formal parameter corresponding to this
5972
- /// argument.
5973
- final DartType formalType;
5974
-
6044
+ class _DeferredParamInfo extends _ParamInfo {
5975
6045
/// The argument expression (possibly wrapped in an arbitrary number of
5976
6046
/// ParenthesizedExpressions).
5977
6047
final Expression argumentExpression;
5978
6048
6049
+ /// The unparenthesized argument expression.
6050
+ final FunctionExpression unparenthesizedExpression;
6051
+
5979
6052
/// Indicates whether this is a named argument.
5980
6053
final bool isNamed;
5981
6054
@@ -5988,9 +6061,63 @@ class _DeferredParamInfo {
5988
6061
final int index;
5989
6062
5990
6063
_DeferredParamInfo (
5991
- {required this . formalType,
6064
+ {required DartType formalType,
5992
6065
required this .argumentExpression,
6066
+ required this .unparenthesizedExpression,
5993
6067
required this .isNamed,
5994
6068
required this .evaluationOrderIndex,
5995
- required this .index});
6069
+ required this .index})
6070
+ : super (formalType);
6071
+ }
6072
+
6073
+ /// Extension of the shared [FunctionLiteralDependencies] logic used by the
6074
+ /// front end.
6075
+ class _FunctionLiteralDependencies extends FunctionLiteralDependencies <
6076
+ TypeParameter , _ParamInfo , _DeferredParamInfo > {
6077
+ _FunctionLiteralDependencies (
6078
+ Iterable <_DeferredParamInfo > deferredParamInfo,
6079
+ Iterable <TypeParameter > typeVariables,
6080
+ List <_ParamInfo > undeferredParamInfo)
6081
+ : super (deferredParamInfo, typeVariables, undeferredParamInfo);
6082
+
6083
+ @override
6084
+ Iterable <TypeParameter > typeVarsFreeInParamParams (
6085
+ _DeferredParamInfo paramInfo) {
6086
+ DartType type = paramInfo.formalType;
6087
+ if (type is FunctionType ) {
6088
+ Map <Object , DartType > parameterMap = _computeParameterMap (type);
6089
+ Set <Object > explicitlyTypedParameters =
6090
+ _computeExplicitlyTypedParameterSet (
6091
+ paramInfo.unparenthesizedExpression);
6092
+ Set <TypeParameter > result = {};
6093
+ for (MapEntry <Object , DartType > entry in parameterMap.entries) {
6094
+ if (explicitlyTypedParameters.contains (entry.key)) continue ;
6095
+ result.addAll (allFreeTypeVariables (entry.value));
6096
+ }
6097
+ return result;
6098
+ } else {
6099
+ return const [];
6100
+ }
6101
+ }
6102
+
6103
+ @override
6104
+ Iterable <TypeParameter > typeVarsFreeInParamReturns (_ParamInfo paramInfo) {
6105
+ DartType type = paramInfo.formalType;
6106
+ if (type is FunctionType ) {
6107
+ return allFreeTypeVariables (type.returnType);
6108
+ } else {
6109
+ return allFreeTypeVariables (type);
6110
+ }
6111
+ }
6112
+ }
6113
+
6114
+ /// Information about an invocation argument that may or may not have already
6115
+ /// been resolved, as part of the deferred resolution mechanism for the
6116
+ /// `inference-update-1` feature.
6117
+ class _ParamInfo {
6118
+ /// The (unsubstituted) type of the formal parameter corresponding to this
6119
+ /// argument.
6120
+ final DartType formalType;
6121
+
6122
+ _ParamInfo (this .formalType);
5996
6123
}
0 commit comments