@@ -236,12 +236,7 @@ class StrongTypeSystemImpl extends TypeSystem {
236
236
// subtypes (or supertypes) as necessary, and track the constraints that
237
237
// are implied by this.
238
238
var inferrer = new _GenericInferrer (typeProvider, this , fnType.typeFormals);
239
-
240
- // Since we're trying to infer the instantiation, we want to ignore type
241
- // formals as we check the parameters and return type.
242
- var inferFnType =
243
- fnType.instantiate (TypeParameterTypeImpl .getTypes (fnType.typeFormals));
244
- inferrer.constrainReturnType (inferFnType, contextType);
239
+ inferrer.constrainGenericFunctionInContext (fnType, contextType);
245
240
246
241
// Infer and instantiate the resulting type.
247
242
return inferrer.infer (fnType, fnType.typeFormals,
@@ -1603,6 +1598,19 @@ class _GenericInferrer {
1603
1598
_matchSubtypeOf (declaredType, contextType, null , origin, covariant : true );
1604
1599
}
1605
1600
1601
+ /// Constrain a universal function type [fnType] used in a context
1602
+ /// [contextType] .
1603
+ void constrainGenericFunctionInContext (
1604
+ FunctionType fnType, DartType contextType) {
1605
+ var origin = new _TypeConstraintFromFunctionContext (fnType, contextType);
1606
+
1607
+ // Since we're trying to infer the instantiation, we want to ignore type
1608
+ // formals as we check the parameters and return type.
1609
+ var inferFnType =
1610
+ fnType.instantiate (TypeParameterTypeImpl .getTypes (fnType.typeFormals));
1611
+ _matchSubtypeOf (inferFnType, contextType, null , origin, covariant : true );
1612
+ }
1613
+
1606
1614
/// Apply an argument constraint, which asserts that the [argument] staticType
1607
1615
/// is a subtype of the [parameterType] .
1608
1616
void constrainArgument (
@@ -1851,20 +1859,31 @@ class _GenericInferrer {
1851
1859
var constraints = _constraints[typeParam.element];
1852
1860
var typeParamBound =
1853
1861
typeParam.bound.substitute2 (inferredTypes, fnTypeParams);
1854
- if (! typeParamBound.isDynamic) {
1855
- constraints
1856
- .add (new _TypeConstraint .fromExtends (typeParam, typeParamBound));
1857
- }
1862
+
1858
1863
var inferred = inferredTypes[i];
1859
- if (constraints.any ((c) => ! c.isSatisifedBy (_typeSystem, inferred))) {
1860
- // Heuristic: keep the erroneous type, it should satisfy at least some
1861
- // of the constraints (e.g. the return context). If we fall back to
1862
- // instantiateToBounds, we'll typically get more errors (e.g. because
1863
- // `dynamic` is the most common bound).
1864
- knownTypes[typeParam] = inferred;
1865
- errorReporter? .reportErrorForNode (StrongModeCode .COULD_NOT_INFER ,
1866
- errorNode, [typeParam, _formatError (inferred, constraints)]);
1867
- } else if (UnknownInferredType .isKnown (inferred)) {
1864
+ bool success =
1865
+ constraints.every ((c) => c.isSatisifedBy (_typeSystem, inferred));
1866
+ if (success && ! typeParamBound.isDynamic) {
1867
+ // If everything else succeeded, check the `extends` constraint.
1868
+ var extendsConstraint =
1869
+ new _TypeConstraint .fromExtends (typeParam, typeParamBound);
1870
+ constraints.add (extendsConstraint);
1871
+ success = extendsConstraint.isSatisifedBy (_typeSystem, inferred);
1872
+ }
1873
+
1874
+ if (! success) {
1875
+ errorReporter? .reportErrorForNode (
1876
+ StrongModeCode .COULD_NOT_INFER ,
1877
+ errorNode,
1878
+ [typeParam, _formatError (typeParam, inferred, constraints)]);
1879
+
1880
+ // Heuristic: even if we failed, keep the erroneous type.
1881
+ // It should satisfy at least some of the constraints (e.g. the return
1882
+ // context). If we fall back to instantiateToBounds, we'll typically get
1883
+ // more errors (e.g. because `dynamic` is the most common bound).
1884
+ }
1885
+
1886
+ if (UnknownInferredType .isKnown (inferred)) {
1868
1887
knownTypes[typeParam] = inferred;
1869
1888
}
1870
1889
}
@@ -2039,22 +2058,23 @@ class _GenericInferrer {
2039
2058
return result;
2040
2059
}
2041
2060
2042
- String _formatError (
2043
- DartType inferred, Iterable <_TypeConstraint > constraints) {
2044
- var intro = "Inferred type '$inferred ' does not work with constraints:" ;
2061
+ String _formatError (TypeParameterType typeParam, DartType inferred,
2062
+ Iterable <_TypeConstraint > constraints) {
2063
+ var intro = "Tried to infer '$inferred ' for '$typeParam '"
2064
+ " which doesn't work:" ;
2045
2065
2046
2066
var constraintsByOrigin = < _TypeConstraintOrigin , List <_TypeConstraint >> {};
2047
2067
for (var c in constraints) {
2048
2068
constraintsByOrigin.putIfAbsent (c.origin, () => []).add (c);
2049
2069
}
2050
2070
2071
+ // Only report unique constraint origins.
2051
2072
Iterable <_TypeConstraint > isSatisified (bool expected) => constraintsByOrigin
2052
2073
.values
2053
2074
.where ((l) =>
2054
2075
l.every ((c) => c.isSatisifedBy (_typeSystem, inferred)) == expected)
2055
2076
.expand ((i) => i);
2056
2077
2057
- // Only report unique constraint origins.
2058
2078
String unsatisified = _formatConstraints (isSatisified (false ));
2059
2079
String satisified = _formatConstraints (isSatisified (true ));
2060
2080
@@ -2074,16 +2094,19 @@ class _GenericInferrer {
2074
2094
.toList ();
2075
2095
2076
2096
int prefixMax = lineParts.map ((p) => p[0 ].length).fold (0 , math.max);
2077
- int middleMax = lineParts.map ((p) => p[1 ].length).fold (0 , math.max);
2078
2097
2079
2098
// Use a set to prevent identical message lines.
2080
2099
// (It's not uncommon for the same constraint to show up in a few places.)
2081
2100
var messageLines = new Set <String >.from (lineParts.map ((parts) {
2082
2101
var prefix = parts[0 ];
2083
2102
var middle = parts[1 ];
2084
2103
var prefixPad = ' ' * (prefixMax - prefix.length);
2085
- var middlePad = ' ' * (middleMax - middle.length);
2086
- return ' $prefix $prefixPad $middle $middlePad ${parts [2 ]}' .trimRight ();
2104
+ var middlePad = ' ' * (prefixMax);
2105
+ var end = "" ;
2106
+ if (parts.length > 2 ) {
2107
+ end = '\n $middlePad ${parts [2 ]}' ;
2108
+ }
2109
+ return ' $prefix $prefixPad $middle $end ' ;
2087
2110
}));
2088
2111
2089
2112
return messageLines.join ('\n ' );
@@ -2121,13 +2144,13 @@ class _TypeConstraintFromArgument extends _TypeConstraintOrigin {
2121
2144
// "Map value"
2122
2145
prefix = "${genericType .name } $parameterName " ;
2123
2146
} else {
2124
- prefix = "Argument '$parameterName '" ;
2147
+ prefix = "Parameter '$parameterName '" ;
2125
2148
}
2126
2149
2127
2150
return [
2128
2151
prefix,
2129
- "inferred as '$ argumentType '" ,
2130
- "must be a '$parameterType '."
2152
+ "declared as '$ parameterType '" ,
2153
+ "but argument is '$argumentType '."
2131
2154
];
2132
2155
}
2133
2156
}
@@ -2143,7 +2166,23 @@ class _TypeConstraintFromReturnType extends _TypeConstraintOrigin {
2143
2166
return [
2144
2167
"Return type" ,
2145
2168
"declared as '$declaredType '" ,
2146
- "used where a '$contextType ' is required."
2169
+ "used where '$contextType ' is required."
2170
+ ];
2171
+ }
2172
+ }
2173
+
2174
+ class _TypeConstraintFromFunctionContext extends _TypeConstraintOrigin {
2175
+ final DartType contextType;
2176
+ final DartType functionType;
2177
+
2178
+ _TypeConstraintFromFunctionContext (this .functionType, this .contextType);
2179
+
2180
+ @override
2181
+ formatError () {
2182
+ return [
2183
+ "Function type" ,
2184
+ "declared as '$functionType '" ,
2185
+ "used where '$contextType ' is required."
2147
2186
];
2148
2187
}
2149
2188
}
@@ -2158,8 +2197,7 @@ class _TypeConstraintFromExtendsClause extends _TypeConstraintOrigin {
2158
2197
formatError () {
2159
2198
return [
2160
2199
"Type parameter '$typeParam '" ,
2161
- "declared to extend '$extendsType '." ,
2162
- ""
2200
+ "declared to extend '$extendsType '."
2163
2201
];
2164
2202
}
2165
2203
}
0 commit comments