@@ -4299,14 +4299,26 @@ class InferenceContext {
4299
4299
}
4300
4300
4301
4301
/**
4302
- * Look for contextual type information attached to [node] . Returns
4303
- * the type if found, otherwise null .
4302
+ * Look for contextual type information attached to [node] , and returns
4303
+ * the type if found.
4304
4304
*
4305
- * If [node] has a contextual union type like `T | Future<T>` this will be
4306
- * returned. You can use [getType] if you prefer to only get the `T` .
4305
+ * If [node] has a contextual union type like `T | Future<T>` or a type that
4306
+ * contains `?` this will be returned. You can use [getValueContext] if you
4307
+ * prefer to eliminate the Future union, or [getType] to eliminate both.
4307
4308
*/
4308
4309
static DartType getContext (AstNode node) => node? .getProperty (_typeProperty);
4309
4310
4311
+ /**
4312
+ * Look for contextual type information attached to [node] and returns it,
4313
+ * eliminating future unions by choosing `T` from `T | Future<T>` .
4314
+ *
4315
+ * See also [getContext] .
4316
+ */
4317
+ static DartType getValueContext (AstNode node) {
4318
+ var context = getContext (node);
4319
+ return context is FutureUnionType ? context.type : context;
4320
+ }
4321
+
4310
4322
/**
4311
4323
* Look for a single contextual type attached to [node] , and returns the type
4312
4324
* if found, otherwise null.
@@ -4318,9 +4330,9 @@ class InferenceContext {
4318
4330
static DartType getType (AstNode node) {
4319
4331
DartType t = getContext (node);
4320
4332
if (t is FutureUnionType ) {
4321
- return t.type;
4333
+ return _substituteForUnknown ( t.type) ;
4322
4334
}
4323
- return t ;
4335
+ return _substituteForUnknown (t) ;
4324
4336
}
4325
4337
4326
4338
/**
@@ -4331,10 +4343,19 @@ class InferenceContext {
4331
4343
if (t == null ) {
4332
4344
return DartType .EMPTY_LIST ;
4333
4345
}
4334
- if (t is FutureUnionType ) {
4335
- return t.types;
4336
- }
4337
- return < DartType > [t];
4346
+ Iterable <DartType > result = t is FutureUnionType ? t.types : [t];
4347
+ return result.map (_substituteForUnknown).where ((t) => t != null );
4348
+ }
4349
+
4350
+ static DartType _substituteForUnknown (DartType t) {
4351
+ if (t == null ) return null ;
4352
+ // Since the type is being used for downwards inference, the expression
4353
+ // type E must be a subtype of the context type T, i.e. T is an upper bound.
4354
+ //
4355
+ // TODO(jmesserly): our downwards inference code is not designed to handle
4356
+ // the bottom type, so we need to prevent it from resulting here.
4357
+ // Instead use `dynamic`. See `UnknownInferredType.upperBoundForType`.
4358
+ return UnknownInferredType .substituteDynamic (t);
4338
4359
}
4339
4360
4340
4361
/**
@@ -5398,7 +5419,7 @@ class ResolverVisitor extends ScopedVisitor {
5398
5419
5399
5420
@override
5400
5421
Object visitArgumentList (ArgumentList node) {
5401
- DartType callerType = InferenceContext .getType (node);
5422
+ DartType callerType = InferenceContext .getContext (node);
5402
5423
if (callerType is FunctionType ) {
5403
5424
Map <String , DartType > namedParameterTypes =
5404
5425
callerType.namedParameterTypes;
@@ -6155,18 +6176,26 @@ class ResolverVisitor extends ScopedVisitor {
6155
6176
// check this don't work, since we may have been instantiated
6156
6177
// to bounds in an earlier phase, and we *do* want to do inference
6157
6178
// in that case.
6158
- if (classTypeName.typeArguments == null ) {
6179
+
6180
+ if (strongMode && classTypeName.typeArguments == null ) {
6159
6181
// Given a union of context types ` T0 | T1 | ... | Tn`, find the first
6160
6182
// valid instantiation `new C<Ti>`, if it exists.
6161
6183
// TODO(jmesserly): if we support union types for real, `new C<Ti | Tj>`
6162
6184
// will become a valid possibility. Right now the only allowed union is
6163
6185
// `T | Future<T>` so we can take a simple approach.
6164
- for (var contextType in InferenceContext .getTypes (node)) {
6186
+
6187
+ TypeDefiningElement classElement = classTypeName.type? .element;
6188
+ // At this point rawType is the interface type whose class is the class
6189
+ // being created, and whose type arguments are the type parameters of the
6190
+ // class declaration.
6191
+ DartType rawType = classElement? .type;
6192
+ Iterable <DartType > contextTypes = InferenceContext .getTypes (node);
6193
+ for (var contextType in contextTypes) {
6165
6194
if (contextType is InterfaceType &&
6166
6195
contextType.typeArguments != null &&
6167
6196
contextType.typeArguments.isNotEmpty) {
6168
6197
// TODO(jmesserly): for generic methods we use the
6169
- // StrongTypeSystemImpl.inferGenericFunctionCall , which appears to
6198
+ // StrongTypeSystemImpl.inferGenericFunctionOrType , which appears to
6170
6199
// be a tad more powerful than matchTypes.
6171
6200
//
6172
6201
// For example it can infer this case:
@@ -6175,11 +6204,16 @@ class ResolverVisitor extends ScopedVisitor {
6175
6204
// A<C<int>, String> a0 = /*infer<int, String>*/new E("hello");
6176
6205
//
6177
6206
// See _inferArgumentTypesFromContext in this file for use of it.
6207
+
6208
+ // TODO(jmesserly): classTypeName.type is the default dynamic
6209
+ // substitution, this is required by matchTypes implementation.
6210
+ // TODO(jmesserly): does this mean we fail when the type has an upper
6211
+ // bound?
6178
6212
List <DartType > targs =
6179
6213
inferenceContext.matchTypes (classTypeName.type, contextType);
6180
- if (targs != null && targs. any ((t) => ! t.isDynamic)) {
6181
- ClassElement classElement = classTypeName.type.element;
6182
- InterfaceType rawType = classElement.type;
6214
+ if (targs != null &&
6215
+ targs. any ((t) => ! t.isDynamic) &&
6216
+ rawType is InterfaceType ) {
6183
6217
InterfaceType fullType =
6184
6218
rawType.substitute2 (targs, rawType.typeArguments);
6185
6219
// The element resolver uses the type on the constructor name, so
@@ -6191,8 +6225,9 @@ class ResolverVisitor extends ScopedVisitor {
6191
6225
}
6192
6226
}
6193
6227
node.constructorName? .accept (this );
6194
- FunctionType constructorType = node.constructorName.staticElement? .type;
6195
- if (constructorType != null ) {
6228
+ ConstructorElement constructor = node.constructorName.staticElement;
6229
+ FunctionType constructorType = constructor? .type;
6230
+ if (strongMode && constructorType != null ) {
6196
6231
InferenceContext .setType (node.argumentList, constructorType);
6197
6232
}
6198
6233
node.argumentList? .accept (this );
@@ -6209,7 +6244,7 @@ class ResolverVisitor extends ScopedVisitor {
6209
6244
6210
6245
@override
6211
6246
Object visitListLiteral (ListLiteral node) {
6212
- DartType contextType = InferenceContext .getType (node);
6247
+ DartType contextType = InferenceContext .getValueContext (node);
6213
6248
List <DartType > targs = null ;
6214
6249
if (node.typeArguments != null ) {
6215
6250
targs = node.typeArguments.arguments.map ((t) => t.type).toList ();
@@ -6234,7 +6269,7 @@ class ResolverVisitor extends ScopedVisitor {
6234
6269
6235
6270
@override
6236
6271
Object visitMapLiteral (MapLiteral node) {
6237
- DartType contextType = InferenceContext .getType (node);
6272
+ DartType contextType = InferenceContext .getValueContext (node);
6238
6273
List <DartType > targs = null ;
6239
6274
if (node.typeArguments != null ) {
6240
6275
targs = node.typeArguments.arguments.map ((t) => t.type).toList ();
@@ -6686,18 +6721,18 @@ class ResolverVisitor extends ScopedVisitor {
6686
6721
DartType originalType = node.function.staticType;
6687
6722
DartType returnContextType = InferenceContext .getContext (node);
6688
6723
TypeSystem ts = typeSystem;
6689
- if (returnContextType != null &&
6690
- node.typeArguments == null &&
6724
+ if (node.typeArguments == null &&
6691
6725
originalType is FunctionType &&
6692
6726
originalType.typeFormals.isNotEmpty &&
6693
6727
ts is StrongTypeSystemImpl ) {
6694
- contextType = ts.inferGenericFunctionCall (
6728
+ contextType = ts.inferGenericFunctionOrType /*<FunctionType>*/ (
6695
6729
typeProvider,
6696
6730
originalType,
6697
- DartType .EMPTY_LIST ,
6731
+ ParameterElement .EMPTY_LIST ,
6698
6732
DartType .EMPTY_LIST ,
6699
6733
originalType.returnType,
6700
- returnContextType);
6734
+ returnContextType,
6735
+ downwards: true );
6701
6736
}
6702
6737
6703
6738
InferenceContext .setType (node.argumentList, contextType);
0 commit comments