Chromium Code Reviews| Index: pkg/analyzer/lib/src/generated/resolver.dart |
| diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart |
| index df3ad03b5db7488cf0265ee48f554e1d04641400..adf6ab360712a2cf7833ba613bf75a070eae4b06 100644 |
| --- a/pkg/analyzer/lib/src/generated/resolver.dart |
| +++ b/pkg/analyzer/lib/src/generated/resolver.dart |
| @@ -4318,9 +4318,9 @@ class InferenceContext { |
| static DartType getType(AstNode node) { |
| DartType t = getContext(node); |
| if (t is FutureUnionType) { |
| - return t.type; |
| + return _substituteForUnknown(t.type); |
| } |
| - return t; |
| + return _substituteForUnknown(t); |
| } |
| /** |
| @@ -4331,10 +4331,20 @@ class InferenceContext { |
| if (t == null) { |
| return DartType.EMPTY_LIST; |
| } |
| - if (t is FutureUnionType) { |
| - return t.types; |
| - } |
| - return <DartType>[t]; |
| + Iterable<DartType> result = t is FutureUnionType ? t.types : [t]; |
| + return result.map(_substituteForUnknown).where((t) => t != null); |
| + } |
| + |
| + static DartType _substituteForUnknown(DartType t) { |
| + if (t == null) return null; |
| + // Since the type is being used for downwards inference, the expression |
| + // type E must be a subtype of the context type T, i.e. T is an upper bound. |
| + // |
| + // TODO(jmesserly): our downwards inference code is not designed to handle |
| + // the bottom type, so we need to prevent it from resulting here. |
| + // Instead use `dynamic`. |
| + //return UnknownInferredType.upperBoundForType(t); |
|
vsm
2016/11/30 04:05:32
Did you mean to keep this commented line?
Jennifer Messerly
2016/11/30 04:35:04
Yeah, I can remove it. I kinda put it there to go
|
| + return UnknownInferredType.substituteDynamic(t); |
| } |
| /** |
| @@ -5398,7 +5408,7 @@ class ResolverVisitor extends ScopedVisitor { |
| @override |
| Object visitArgumentList(ArgumentList node) { |
| - DartType callerType = InferenceContext.getType(node); |
| + DartType callerType = InferenceContext.getContext(node); |
| if (callerType is FunctionType) { |
| Map<String, DartType> namedParameterTypes = |
| callerType.namedParameterTypes; |
| @@ -6155,18 +6165,23 @@ class ResolverVisitor extends ScopedVisitor { |
| // check this don't work, since we may have been instantiated |
| // to bounds in an earlier phase, and we *do* want to do inference |
| // in that case. |
| - if (classTypeName.typeArguments == null) { |
| + |
| + if (strongMode && classTypeName.typeArguments == null) { |
| // Given a union of context types ` T0 | T1 | ... | Tn`, find the first |
| // valid instantiation `new C<Ti>`, if it exists. |
| // TODO(jmesserly): if we support union types for real, `new C<Ti | Tj>` |
| // will become a valid possibility. Right now the only allowed union is |
| // `T | Future<T>` so we can take a simple approach. |
| - for (var contextType in InferenceContext.getTypes(node)) { |
| + |
| + TypeDefiningElement classElement = classTypeName.type?.element; |
| + DartType rawType = classElement?.type; |
|
Leaf
2016/11/30 05:24:29
Comment here, just for the reader, maybe? Here's
Jennifer Messerly
2016/11/30 21:19:28
sure :) to be honest I don't understand this code
|
| + Iterable<DartType> contextTypes = InferenceContext.getTypes(node); |
| + for (var contextType in contextTypes) { |
| if (contextType is InterfaceType && |
| contextType.typeArguments != null && |
| contextType.typeArguments.isNotEmpty) { |
| // TODO(jmesserly): for generic methods we use the |
| - // StrongTypeSystemImpl.inferGenericFunctionCall, which appears to |
| + // StrongTypeSystemImpl.inferGenericFunctionOrType, which appears to |
| // be a tad more powerful than matchTypes. |
| // |
| // For example it can infer this case: |
| @@ -6177,9 +6192,9 @@ class ResolverVisitor extends ScopedVisitor { |
| // See _inferArgumentTypesFromContext in this file for use of it. |
| List<DartType> targs = |
| inferenceContext.matchTypes(classTypeName.type, contextType); |
|
Leaf
2016/11/30 05:24:29
Aargh... I'm lost again. What's the difference be
Jennifer Messerly
2016/11/30 21:19:28
I would but.... I don't understand this code eithe
|
| - if (targs != null && targs.any((t) => !t.isDynamic)) { |
| - ClassElement classElement = classTypeName.type.element; |
| - InterfaceType rawType = classElement.type; |
| + if (targs != null && |
| + targs.any((t) => !t.isDynamic) && |
| + rawType is InterfaceType) { |
|
Leaf
2016/11/30 05:24:29
Can matchTypes return ? for one of the targs? If
Jennifer Messerly
2016/11/30 21:19:28
it shouldn't be able to, because` InferenceContext
|
| InterfaceType fullType = |
| rawType.substitute2(targs, rawType.typeArguments); |
| // The element resolver uses the type on the constructor name, so |
| @@ -6189,10 +6204,19 @@ class ResolverVisitor extends ScopedVisitor { |
| } |
| } |
| } |
| + if (contextTypes.isEmpty && |
|
Leaf
2016/11/30 05:24:29
//comment
I think this is instance failure? In w
Jennifer Messerly
2016/11/30 21:19:28
I think the idea was: for downwards inference, e.g
Leaf
2016/12/01 04:36:27
Ok, I think this makes sense then. I didn't get t
Jennifer Messerly
2017/01/06 22:31:45
yeah, I think so. Maybe I should take a shot at un
Jennifer Messerly
2017/01/11 02:24:38
Hello again! I've now removed matchTypes and this
|
| + rawType is InterfaceType && |
| + rawType.typeArguments.isNotEmpty) { |
| + node.constructorName.type.type = rawType.substitute2( |
| + new List.filled( |
| + rawType.typeArguments.length, UnknownInferredType.instance), |
| + rawType.typeArguments); |
| + } |
| } |
| node.constructorName?.accept(this); |
| - FunctionType constructorType = node.constructorName.staticElement?.type; |
| - if (constructorType != null) { |
| + ConstructorElement constructor = node.constructorName.staticElement; |
| + FunctionType constructorType = constructor?.type; |
| + if (strongMode && constructorType != null) { |
| InferenceContext.setType(node.argumentList, constructorType); |
| } |
| node.argumentList?.accept(this); |
| @@ -6209,7 +6233,10 @@ class ResolverVisitor extends ScopedVisitor { |
| @override |
| Object visitListLiteral(ListLiteral node) { |
| - DartType contextType = InferenceContext.getType(node); |
| + DartType contextType = InferenceContext.getContext(node); |
| + if (contextType is FutureUnionType) { |
|
Leaf
2016/11/30 05:24:29
Consider making this pattern a method on Inference
Jennifer Messerly
2016/11/30 21:19:28
great idea, done!
|
| + contextType = (contextType as FutureUnionType).type; |
| + } |
| List<DartType> targs = null; |
| if (node.typeArguments != null) { |
| targs = node.typeArguments.arguments.map((t) => t.type).toList(); |
| @@ -6234,7 +6261,10 @@ class ResolverVisitor extends ScopedVisitor { |
| @override |
| Object visitMapLiteral(MapLiteral node) { |
| - DartType contextType = InferenceContext.getType(node); |
| + DartType contextType = InferenceContext.getContext(node); |
| + if (contextType is FutureUnionType) { |
| + contextType = (contextType as FutureUnionType).type; |
| + } |
| List<DartType> targs = null; |
| if (node.typeArguments != null) { |
| targs = node.typeArguments.arguments.map((t) => t.type).toList(); |
| @@ -6686,18 +6716,18 @@ class ResolverVisitor extends ScopedVisitor { |
| DartType originalType = node.function.staticType; |
| DartType returnContextType = InferenceContext.getContext(node); |
| TypeSystem ts = typeSystem; |
| - if (returnContextType != null && |
| - node.typeArguments == null && |
| + if (node.typeArguments == null && |
| originalType is FunctionType && |
| originalType.typeFormals.isNotEmpty && |
| ts is StrongTypeSystemImpl) { |
| - contextType = ts.inferGenericFunctionCall( |
| + contextType = ts.inferGenericFunctionOrType/*<FunctionType>*/( |
| typeProvider, |
| originalType, |
| - DartType.EMPTY_LIST, |
| + ParameterElement.EMPTY_LIST, |
| DartType.EMPTY_LIST, |
| originalType.returnType, |
| - returnContextType); |
| + returnContextType, |
| + downwards: true); |
| } |
| InferenceContext.setType(node.argumentList, contextType); |