Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(397)

Unified Diff: pkg/analyzer/lib/src/generated/resolver.dart

Issue 2456803004: fixes #27586, prefer context type in generic inference (Closed)
Patch Set: more tweaks Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);

Powered by Google App Engine
This is Rietveld 408576698