Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library analyzer.src.generated.resolver; | 5 library analyzer.src.generated.resolver; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/token.dart'; | 10 import 'package:analyzer/dart/ast/token.dart'; |
| (...skipping 4300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4311 * Look for a single contextual type attached to [node], and returns the type | 4311 * Look for a single contextual type attached to [node], and returns the type |
| 4312 * if found, otherwise null. | 4312 * if found, otherwise null. |
| 4313 * | 4313 * |
| 4314 * If [node] has a contextual union type like `T | Future<T>` this will | 4314 * If [node] has a contextual union type like `T | Future<T>` this will |
| 4315 * simplify it to only return `T`. If the caller can handle a union type, | 4315 * simplify it to only return `T`. If the caller can handle a union type, |
| 4316 * [getContext] should be used instead. | 4316 * [getContext] should be used instead. |
| 4317 */ | 4317 */ |
| 4318 static DartType getType(AstNode node) { | 4318 static DartType getType(AstNode node) { |
| 4319 DartType t = getContext(node); | 4319 DartType t = getContext(node); |
| 4320 if (t is FutureUnionType) { | 4320 if (t is FutureUnionType) { |
| 4321 return t.type; | 4321 return _substituteForUnknown(t.type); |
| 4322 } | 4322 } |
| 4323 return t; | 4323 return _substituteForUnknown(t); |
| 4324 } | 4324 } |
| 4325 | 4325 |
| 4326 /** | 4326 /** |
| 4327 * Like [getContext] but expands a union type into a list of types. | 4327 * Like [getContext] but expands a union type into a list of types. |
| 4328 */ | 4328 */ |
| 4329 static Iterable<DartType> getTypes(AstNode node) { | 4329 static Iterable<DartType> getTypes(AstNode node) { |
| 4330 DartType t = getContext(node); | 4330 DartType t = getContext(node); |
| 4331 if (t == null) { | 4331 if (t == null) { |
| 4332 return DartType.EMPTY_LIST; | 4332 return DartType.EMPTY_LIST; |
| 4333 } | 4333 } |
| 4334 if (t is FutureUnionType) { | 4334 Iterable<DartType> result = t is FutureUnionType ? t.types : [t]; |
| 4335 return t.types; | 4335 return result.map(_substituteForUnknown).where((t) => t != null); |
| 4336 } | 4336 } |
| 4337 return <DartType>[t]; | 4337 |
| 4338 static DartType _substituteForUnknown(DartType t) { | |
| 4339 if (t == null) return null; | |
| 4340 // Since the type is being used for downwards inference, the expression | |
| 4341 // type E must be a subtype of the context type T, i.e. T is an upper bound. | |
| 4342 // | |
| 4343 // TODO(jmesserly): our downwards inference code is not designed to handle | |
| 4344 // the bottom type, so we need to prevent it from resulting here. | |
| 4345 // Instead use `dynamic`. | |
| 4346 //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
| |
| 4347 return UnknownInferredType.substituteDynamic(t); | |
| 4338 } | 4348 } |
| 4339 | 4349 |
| 4340 /** | 4350 /** |
| 4341 * Attach contextual type information [type] to [node] for use during | 4351 * Attach contextual type information [type] to [node] for use during |
| 4342 * inference. | 4352 * inference. |
| 4343 */ | 4353 */ |
| 4344 static void setType(AstNode node, DartType type) { | 4354 static void setType(AstNode node, DartType type) { |
| 4345 if (type == null || type.isDynamic) { | 4355 if (type == null || type.isDynamic) { |
| 4346 clearType(node); | 4356 clearType(node); |
| 4347 } else { | 4357 } else { |
| (...skipping 1043 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5391 assert(parent is PartOfDirective); | 5401 assert(parent is PartOfDirective); |
| 5392 } else { | 5402 } else { |
| 5393 elementAnnotationImpl.annotationAst = | 5403 elementAnnotationImpl.annotationAst = |
| 5394 new ConstantAstCloner().cloneNode(node); | 5404 new ConstantAstCloner().cloneNode(node); |
| 5395 } | 5405 } |
| 5396 return null; | 5406 return null; |
| 5397 } | 5407 } |
| 5398 | 5408 |
| 5399 @override | 5409 @override |
| 5400 Object visitArgumentList(ArgumentList node) { | 5410 Object visitArgumentList(ArgumentList node) { |
| 5401 DartType callerType = InferenceContext.getType(node); | 5411 DartType callerType = InferenceContext.getContext(node); |
| 5402 if (callerType is FunctionType) { | 5412 if (callerType is FunctionType) { |
| 5403 Map<String, DartType> namedParameterTypes = | 5413 Map<String, DartType> namedParameterTypes = |
| 5404 callerType.namedParameterTypes; | 5414 callerType.namedParameterTypes; |
| 5405 List<DartType> normalParameterTypes = callerType.normalParameterTypes; | 5415 List<DartType> normalParameterTypes = callerType.normalParameterTypes; |
| 5406 List<DartType> optionalParameterTypes = callerType.optionalParameterTypes; | 5416 List<DartType> optionalParameterTypes = callerType.optionalParameterTypes; |
| 5407 int normalCount = normalParameterTypes.length; | 5417 int normalCount = normalParameterTypes.length; |
| 5408 int optionalCount = optionalParameterTypes.length; | 5418 int optionalCount = optionalParameterTypes.length; |
| 5409 | 5419 |
| 5410 NodeList<Expression> arguments = node.arguments; | 5420 NodeList<Expression> arguments = node.arguments; |
| 5411 Iterable<Expression> positional = | 5421 Iterable<Expression> positional = |
| (...skipping 736 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6148 | 6158 |
| 6149 @override | 6159 @override |
| 6150 Object visitInstanceCreationExpression(InstanceCreationExpression node) { | 6160 Object visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 6151 TypeName classTypeName = node.constructorName.type; | 6161 TypeName classTypeName = node.constructorName.type; |
| 6152 // TODO(leafp): Currently, we may re-infer types here, since we | 6162 // TODO(leafp): Currently, we may re-infer types here, since we |
| 6153 // sometimes resolve multiple times. We should really check that we | 6163 // sometimes resolve multiple times. We should really check that we |
| 6154 // have not already inferred something. However, the obvious ways to | 6164 // have not already inferred something. However, the obvious ways to |
| 6155 // check this don't work, since we may have been instantiated | 6165 // check this don't work, since we may have been instantiated |
| 6156 // to bounds in an earlier phase, and we *do* want to do inference | 6166 // to bounds in an earlier phase, and we *do* want to do inference |
| 6157 // in that case. | 6167 // in that case. |
| 6158 if (classTypeName.typeArguments == null) { | 6168 |
| 6169 if (strongMode && classTypeName.typeArguments == null) { | |
| 6159 // Given a union of context types ` T0 | T1 | ... | Tn`, find the first | 6170 // Given a union of context types ` T0 | T1 | ... | Tn`, find the first |
| 6160 // valid instantiation `new C<Ti>`, if it exists. | 6171 // valid instantiation `new C<Ti>`, if it exists. |
| 6161 // TODO(jmesserly): if we support union types for real, `new C<Ti | Tj>` | 6172 // TODO(jmesserly): if we support union types for real, `new C<Ti | Tj>` |
| 6162 // will become a valid possibility. Right now the only allowed union is | 6173 // will become a valid possibility. Right now the only allowed union is |
| 6163 // `T | Future<T>` so we can take a simple approach. | 6174 // `T | Future<T>` so we can take a simple approach. |
| 6164 for (var contextType in InferenceContext.getTypes(node)) { | 6175 |
| 6176 TypeDefiningElement classElement = classTypeName.type?.element; | |
| 6177 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
| |
| 6178 Iterable<DartType> contextTypes = InferenceContext.getTypes(node); | |
| 6179 for (var contextType in contextTypes) { | |
| 6165 if (contextType is InterfaceType && | 6180 if (contextType is InterfaceType && |
| 6166 contextType.typeArguments != null && | 6181 contextType.typeArguments != null && |
| 6167 contextType.typeArguments.isNotEmpty) { | 6182 contextType.typeArguments.isNotEmpty) { |
| 6168 // TODO(jmesserly): for generic methods we use the | 6183 // TODO(jmesserly): for generic methods we use the |
| 6169 // StrongTypeSystemImpl.inferGenericFunctionCall, which appears to | 6184 // StrongTypeSystemImpl.inferGenericFunctionOrType, which appears to |
| 6170 // be a tad more powerful than matchTypes. | 6185 // be a tad more powerful than matchTypes. |
| 6171 // | 6186 // |
| 6172 // For example it can infer this case: | 6187 // For example it can infer this case: |
| 6173 // | 6188 // |
| 6174 // class E<S, T> extends A<C<S>, T> { ... } | 6189 // class E<S, T> extends A<C<S>, T> { ... } |
| 6175 // A<C<int>, String> a0 = /*infer<int, String>*/new E("hello"); | 6190 // A<C<int>, String> a0 = /*infer<int, String>*/new E("hello"); |
| 6176 // | 6191 // |
| 6177 // See _inferArgumentTypesFromContext in this file for use of it. | 6192 // See _inferArgumentTypesFromContext in this file for use of it. |
| 6178 List<DartType> targs = | 6193 List<DartType> targs = |
| 6179 inferenceContext.matchTypes(classTypeName.type, contextType); | 6194 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
| |
| 6180 if (targs != null && targs.any((t) => !t.isDynamic)) { | 6195 if (targs != null && |
| 6181 ClassElement classElement = classTypeName.type.element; | 6196 targs.any((t) => !t.isDynamic) && |
| 6182 InterfaceType rawType = classElement.type; | 6197 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
| |
| 6183 InterfaceType fullType = | 6198 InterfaceType fullType = |
| 6184 rawType.substitute2(targs, rawType.typeArguments); | 6199 rawType.substitute2(targs, rawType.typeArguments); |
| 6185 // The element resolver uses the type on the constructor name, so | 6200 // The element resolver uses the type on the constructor name, so |
| 6186 // infer it first | 6201 // infer it first |
| 6187 typeAnalyzer.inferConstructorName(node.constructorName, fullType); | 6202 typeAnalyzer.inferConstructorName(node.constructorName, fullType); |
| 6188 break; | 6203 break; |
| 6189 } | 6204 } |
| 6190 } | 6205 } |
| 6191 } | 6206 } |
| 6207 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
| |
| 6208 rawType is InterfaceType && | |
| 6209 rawType.typeArguments.isNotEmpty) { | |
| 6210 node.constructorName.type.type = rawType.substitute2( | |
| 6211 new List.filled( | |
| 6212 rawType.typeArguments.length, UnknownInferredType.instance), | |
| 6213 rawType.typeArguments); | |
| 6214 } | |
| 6192 } | 6215 } |
| 6193 node.constructorName?.accept(this); | 6216 node.constructorName?.accept(this); |
| 6194 FunctionType constructorType = node.constructorName.staticElement?.type; | 6217 ConstructorElement constructor = node.constructorName.staticElement; |
| 6195 if (constructorType != null) { | 6218 FunctionType constructorType = constructor?.type; |
| 6219 if (strongMode && constructorType != null) { | |
| 6196 InferenceContext.setType(node.argumentList, constructorType); | 6220 InferenceContext.setType(node.argumentList, constructorType); |
| 6197 } | 6221 } |
| 6198 node.argumentList?.accept(this); | 6222 node.argumentList?.accept(this); |
| 6199 node.accept(elementResolver); | 6223 node.accept(elementResolver); |
| 6200 node.accept(typeAnalyzer); | 6224 node.accept(typeAnalyzer); |
| 6201 return null; | 6225 return null; |
| 6202 } | 6226 } |
| 6203 | 6227 |
| 6204 @override | 6228 @override |
| 6205 Object visitLabel(Label node) => null; | 6229 Object visitLabel(Label node) => null; |
| 6206 | 6230 |
| 6207 @override | 6231 @override |
| 6208 Object visitLibraryIdentifier(LibraryIdentifier node) => null; | 6232 Object visitLibraryIdentifier(LibraryIdentifier node) => null; |
| 6209 | 6233 |
| 6210 @override | 6234 @override |
| 6211 Object visitListLiteral(ListLiteral node) { | 6235 Object visitListLiteral(ListLiteral node) { |
| 6212 DartType contextType = InferenceContext.getType(node); | 6236 DartType contextType = InferenceContext.getContext(node); |
| 6237 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!
| |
| 6238 contextType = (contextType as FutureUnionType).type; | |
| 6239 } | |
| 6213 List<DartType> targs = null; | 6240 List<DartType> targs = null; |
| 6214 if (node.typeArguments != null) { | 6241 if (node.typeArguments != null) { |
| 6215 targs = node.typeArguments.arguments.map((t) => t.type).toList(); | 6242 targs = node.typeArguments.arguments.map((t) => t.type).toList(); |
| 6216 } else if (contextType is InterfaceType) { | 6243 } else if (contextType is InterfaceType) { |
| 6217 InterfaceType listD = | 6244 InterfaceType listD = |
| 6218 typeProvider.listType.instantiate([typeProvider.dynamicType]); | 6245 typeProvider.listType.instantiate([typeProvider.dynamicType]); |
| 6219 targs = inferenceContext.matchTypes(listD, contextType); | 6246 targs = inferenceContext.matchTypes(listD, contextType); |
| 6220 } | 6247 } |
| 6221 if (targs != null && targs.length == 1 && !targs[0].isDynamic) { | 6248 if (targs != null && targs.length == 1 && !targs[0].isDynamic) { |
| 6222 DartType eType = targs[0]; | 6249 DartType eType = targs[0]; |
| 6223 InterfaceType listT = typeProvider.listType.instantiate([eType]); | 6250 InterfaceType listT = typeProvider.listType.instantiate([eType]); |
| 6224 for (Expression child in node.elements) { | 6251 for (Expression child in node.elements) { |
| 6225 InferenceContext.setType(child, eType); | 6252 InferenceContext.setType(child, eType); |
| 6226 } | 6253 } |
| 6227 InferenceContext.setType(node, listT); | 6254 InferenceContext.setType(node, listT); |
| 6228 } else { | 6255 } else { |
| 6229 InferenceContext.clearType(node); | 6256 InferenceContext.clearType(node); |
| 6230 } | 6257 } |
| 6231 super.visitListLiteral(node); | 6258 super.visitListLiteral(node); |
| 6232 return null; | 6259 return null; |
| 6233 } | 6260 } |
| 6234 | 6261 |
| 6235 @override | 6262 @override |
| 6236 Object visitMapLiteral(MapLiteral node) { | 6263 Object visitMapLiteral(MapLiteral node) { |
| 6237 DartType contextType = InferenceContext.getType(node); | 6264 DartType contextType = InferenceContext.getContext(node); |
| 6265 if (contextType is FutureUnionType) { | |
| 6266 contextType = (contextType as FutureUnionType).type; | |
| 6267 } | |
| 6238 List<DartType> targs = null; | 6268 List<DartType> targs = null; |
| 6239 if (node.typeArguments != null) { | 6269 if (node.typeArguments != null) { |
| 6240 targs = node.typeArguments.arguments.map((t) => t.type).toList(); | 6270 targs = node.typeArguments.arguments.map((t) => t.type).toList(); |
| 6241 } else if (contextType is InterfaceType) { | 6271 } else if (contextType is InterfaceType) { |
| 6242 InterfaceType mapD = typeProvider.mapType | 6272 InterfaceType mapD = typeProvider.mapType |
| 6243 .instantiate([typeProvider.dynamicType, typeProvider.dynamicType]); | 6273 .instantiate([typeProvider.dynamicType, typeProvider.dynamicType]); |
| 6244 targs = inferenceContext.matchTypes(mapD, contextType); | 6274 targs = inferenceContext.matchTypes(mapD, contextType); |
| 6245 } | 6275 } |
| 6246 if (targs != null && targs.length == 2 && targs.any((t) => !t.isDynamic)) { | 6276 if (targs != null && targs.length == 2 && targs.any((t) => !t.isDynamic)) { |
| 6247 DartType kType = targs[0]; | 6277 DartType kType = targs[0]; |
| (...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6679 // Use propagated type inference for lambdas if not in strong mode. | 6709 // Use propagated type inference for lambdas if not in strong mode. |
| 6680 _inferFunctionExpressionsParametersTypes(node.argumentList); | 6710 _inferFunctionExpressionsParametersTypes(node.argumentList); |
| 6681 return; | 6711 return; |
| 6682 } | 6712 } |
| 6683 | 6713 |
| 6684 DartType contextType = node.staticInvokeType; | 6714 DartType contextType = node.staticInvokeType; |
| 6685 if (contextType is FunctionType) { | 6715 if (contextType is FunctionType) { |
| 6686 DartType originalType = node.function.staticType; | 6716 DartType originalType = node.function.staticType; |
| 6687 DartType returnContextType = InferenceContext.getContext(node); | 6717 DartType returnContextType = InferenceContext.getContext(node); |
| 6688 TypeSystem ts = typeSystem; | 6718 TypeSystem ts = typeSystem; |
| 6689 if (returnContextType != null && | 6719 if (node.typeArguments == null && |
| 6690 node.typeArguments == null && | |
| 6691 originalType is FunctionType && | 6720 originalType is FunctionType && |
| 6692 originalType.typeFormals.isNotEmpty && | 6721 originalType.typeFormals.isNotEmpty && |
| 6693 ts is StrongTypeSystemImpl) { | 6722 ts is StrongTypeSystemImpl) { |
| 6694 contextType = ts.inferGenericFunctionCall( | 6723 contextType = ts.inferGenericFunctionOrType/*<FunctionType>*/( |
| 6695 typeProvider, | 6724 typeProvider, |
| 6696 originalType, | 6725 originalType, |
| 6697 DartType.EMPTY_LIST, | 6726 ParameterElement.EMPTY_LIST, |
| 6698 DartType.EMPTY_LIST, | 6727 DartType.EMPTY_LIST, |
| 6699 originalType.returnType, | 6728 originalType.returnType, |
| 6700 returnContextType); | 6729 returnContextType, |
| 6730 downwards: true); | |
| 6701 } | 6731 } |
| 6702 | 6732 |
| 6703 InferenceContext.setType(node.argumentList, contextType); | 6733 InferenceContext.setType(node.argumentList, contextType); |
| 6704 } | 6734 } |
| 6705 } | 6735 } |
| 6706 | 6736 |
| 6707 void _inferFormalParameterList(FormalParameterList node, DartType type) { | 6737 void _inferFormalParameterList(FormalParameterList node, DartType type) { |
| 6708 if (typeAnalyzer.inferFormalParameterList(node, type)) { | 6738 if (typeAnalyzer.inferFormalParameterList(node, type)) { |
| 6709 // TODO(leafp): This gets dropped on the floor if we're in the field | 6739 // TODO(leafp): This gets dropped on the floor if we're in the field |
| 6710 // inference task. We should probably keep these infos. | 6740 // inference task. We should probably keep these infos. |
| (...skipping 4051 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10762 return null; | 10792 return null; |
| 10763 } | 10793 } |
| 10764 if (identical(node.staticElement, variable)) { | 10794 if (identical(node.staticElement, variable)) { |
| 10765 if (node.inSetterContext()) { | 10795 if (node.inSetterContext()) { |
| 10766 result = true; | 10796 result = true; |
| 10767 } | 10797 } |
| 10768 } | 10798 } |
| 10769 return null; | 10799 return null; |
| 10770 } | 10800 } |
| 10771 } | 10801 } |
| OLD | NEW |