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

Side by Side Diff: pkg/analyzer/lib/src/generated/resolver.dart

Issue 2647833002: fix #28008, fix #28009 implement FutureOr<T> (Closed)
Patch Set: add test Created 3 years, 11 months 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 unified diff | Download patch
OLDNEW
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/standard_resolution_map.dart'; 10 import 'package:analyzer/dart/ast/standard_resolution_map.dart';
(...skipping 4173 matching lines...) Expand 10 before | Expand all | Expand 10 after
4184 * bound of all types added with [addReturnOrYieldType]. 4184 * bound of all types added with [addReturnOrYieldType].
4185 */ 4185 */
4186 void popReturnContext(BlockFunctionBody node) { 4186 void popReturnContext(BlockFunctionBody node) {
4187 if (_returnStack.isNotEmpty && _inferredReturn.isNotEmpty) { 4187 if (_returnStack.isNotEmpty && _inferredReturn.isNotEmpty) {
4188 DartType context = _returnStack.removeLast() ?? DynamicTypeImpl.instance; 4188 DartType context = _returnStack.removeLast() ?? DynamicTypeImpl.instance;
4189 DartType inferred = _inferredReturn.removeLast(); 4189 DartType inferred = _inferredReturn.removeLast();
4190 if (inferred.isBottom) { 4190 if (inferred.isBottom) {
4191 return; 4191 return;
4192 } 4192 }
4193 4193
4194 if (context is FutureUnionType) { 4194 if (_typeSystem.isSubtypeOf(inferred, context)) {
4195 // Try and match the Future type first.
4196 if (_typeSystem.isSubtypeOf(inferred, context.futureOfType) ||
4197 _typeSystem.isSubtypeOf(inferred, context.type)) {
4198 setType(node, inferred);
4199 }
4200 } else if (_typeSystem.isSubtypeOf(inferred, context)) {
4201 setType(node, inferred); 4195 setType(node, inferred);
4202 } 4196 }
4203 } else { 4197 } else {
4204 assert(false); 4198 assert(false);
4205 } 4199 }
4206 } 4200 }
4207 4201
4208 /** 4202 /**
4209 * Push a block function body's return type onto the return stack. 4203 * Push a block function body's return type onto the return stack.
4210 */ 4204 */
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
4353 /** 4347 /**
4354 * Look for contextual type information attached to [node]. Returns 4348 * Look for contextual type information attached to [node]. Returns
4355 * the type if found, otherwise null. 4349 * the type if found, otherwise null.
4356 * 4350 *
4357 * If [node] has a contextual union type like `T | Future<T>` this will be 4351 * If [node] has a contextual union type like `T | Future<T>` this will be
4358 * returned. You can use [getType] if you prefer to only get the `T`. 4352 * returned. You can use [getType] if you prefer to only get the `T`.
4359 */ 4353 */
4360 static DartType getContext(AstNode node) => node?.getProperty(_typeProperty); 4354 static DartType getContext(AstNode node) => node?.getProperty(_typeProperty);
4361 4355
4362 /** 4356 /**
4363 * Look for a single contextual type attached to [node], and returns the type 4357 * Look for a single contextual type attached to [node], and returns the type
4364 * if found, otherwise null. 4358 * if found, otherwise null.
4365 * 4359 *
4366 * If [node] has a contextual union type like `T | Future<T>` this will 4360 * If [node] has a contextual union type like `T | Future<T>` this will
4367 * simplify it to only return `T`. If the caller can handle a union type, 4361 * simplify it to only return `T`. If the caller can handle a union type,
4368 * [getContext] should be used instead. 4362 * [getContext] should be used instead.
4369 */ 4363 */
4370 static DartType getType(AstNode node) { 4364 static DartType getType(AstNode node) {
4371 DartType t = getContext(node); 4365 DartType t = getContext(node);
4372 if (t is FutureUnionType) { 4366 if (t is InterfaceType && t.isDartAsyncFutureOr) {
4373 return t.type; 4367 return t.typeArguments[0]; // The T in FutureOr<T>
4374 } 4368 }
4375 return t; 4369 return t;
4376 } 4370 }
4377 4371
4378 /** 4372 /**
4379 * Like [getContext] but expands a union type into a list of types. 4373 * Like [getContext] but expands a union type into a list of types.
4380 */ 4374 */
4381 static Iterable<DartType> getTypes(AstNode node) { 4375 Iterable<DartType> getTypes(AstNode node) {
4382 DartType t = getContext(node); 4376 DartType t = getContext(node);
4383 if (t == null) { 4377 if (t == null) {
4384 return DartType.EMPTY_LIST; 4378 return DartType.EMPTY_LIST;
4385 } 4379 }
4386 if (t is FutureUnionType) { 4380 if (t is InterfaceType && t.isDartAsyncFutureOr) {
4387 return t.types; 4381 var tArg = t.typeArguments[0]; // The T in FutureOr<T>
4382 return [
4383 _typeProvider.futureType.instantiate([tArg]),
4384 tArg
4385 ];
4388 } 4386 }
4389 return <DartType>[t]; 4387 return [t];
4390 } 4388 }
4391 4389
4392 /** 4390 /**
4393 * Attach contextual type information [type] to [node] for use during 4391 * Attach contextual type information [type] to [node] for use during
4394 * inference. 4392 * inference.
4395 */ 4393 */
4396 static void setType(AstNode node, DartType type) { 4394 static void setType(AstNode node, DartType type) {
4397 if (type == null || type.isDynamic) { 4395 if (type == null || type.isDynamic) {
4398 clearType(node); 4396 clearType(node);
4399 } else { 4397 } else {
(...skipping 810 matching lines...) Expand 10 before | Expand all | Expand 10 after
5210 } 5208 }
5211 5209
5212 /** 5210 /**
5213 * Prepares this [ResolverVisitor] to using it for incremental resolution. 5211 * Prepares this [ResolverVisitor] to using it for incremental resolution.
5214 */ 5212 */
5215 void initForIncrementalResolution() { 5213 void initForIncrementalResolution() {
5216 _overrideManager.enterScope(); 5214 _overrideManager.enterScope();
5217 } 5215 }
5218 5216
5219 /** 5217 /**
5220 * Returns true if this method is `Future.then` or an override thereof.
5221 *
5222 * If so we will apply special typing rules in strong mode, to handle the
5223 * implicit union of `S | Future<S>`
5224 */
5225 bool isFutureThen(Element element) {
5226 // If we are a method named then
5227 if (element is MethodElement && element.name == 'then') {
5228 DartType type = element.enclosingElement.type;
5229 // On Future or a subtype, then we're good.
5230 return (type.isDartAsyncFuture || isSubtypeOfFuture(type));
5231 }
5232 return false;
5233 }
5234
5235 /**
5236 * Returns true if this type is any subtype of the built in Future type. 5218 * Returns true if this type is any subtype of the built in Future type.
5237 */ 5219 */
5238 bool isSubtypeOfFuture(DartType type) => 5220 bool isSubtypeOfFuture(DartType type) =>
5239 typeSystem.isSubtypeOf(type, typeProvider.futureDynamicType); 5221 typeSystem.isSubtypeOf(type, typeProvider.futureDynamicType);
5240 5222
5241 /** 5223 /**
5242 * Given a downward inference type [fnType], and the declared 5224 * Given a downward inference type [fnType], and the declared
5243 * [typeParameterList] for a function expression, determines if we can enable 5225 * [typeParameterList] for a function expression, determines if we can enable
5244 * downward inference and if so, returns the function type to use for 5226 * downward inference and if so, returns the function type to use for
5245 * inference. 5227 * inference.
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after
5521 node.rightHandSide?.accept(this); 5503 node.rightHandSide?.accept(this);
5522 node.accept(elementResolver); 5504 node.accept(elementResolver);
5523 node.accept(typeAnalyzer); 5505 node.accept(typeAnalyzer);
5524 return null; 5506 return null;
5525 } 5507 }
5526 5508
5527 @override 5509 @override
5528 Object visitAwaitExpression(AwaitExpression node) { 5510 Object visitAwaitExpression(AwaitExpression node) {
5529 DartType contextType = InferenceContext.getContext(node); 5511 DartType contextType = InferenceContext.getContext(node);
5530 if (contextType != null) { 5512 if (contextType != null) {
5531 var futureUnion = 5513 var futureUnion = _createFutureOr(contextType);
5532 FutureUnionType.from(contextType, typeProvider, typeSystem);
5533 InferenceContext.setType(node.expression, futureUnion); 5514 InferenceContext.setType(node.expression, futureUnion);
5534 } 5515 }
5535 return super.visitAwaitExpression(node); 5516 return super.visitAwaitExpression(node);
5536 } 5517 }
5537 5518
5538 @override 5519 @override
5539 Object visitBinaryExpression(BinaryExpression node) { 5520 Object visitBinaryExpression(BinaryExpression node) {
5540 TokenType operatorType = node.operator.type; 5521 TokenType operatorType = node.operator.type;
5541 Expression leftOperand = node.leftOperand; 5522 Expression leftOperand = node.leftOperand;
5542 Expression rightOperand = node.rightOperand; 5523 Expression rightOperand = node.rightOperand;
(...skipping 520 matching lines...) Expand 10 before | Expand all | Expand 10 after
6063 _currentFunctionBody = node.body; 6044 _currentFunctionBody = node.body;
6064 _enclosingFunction = node.element; 6045 _enclosingFunction = node.element;
6065 _overrideManager.enterScope(); 6046 _overrideManager.enterScope();
6066 try { 6047 try {
6067 DartType functionType = InferenceContext.getType(node); 6048 DartType functionType = InferenceContext.getType(node);
6068 if (functionType is FunctionType) { 6049 if (functionType is FunctionType) {
6069 functionType = 6050 functionType =
6070 matchFunctionTypeParameters(node.typeParameters, functionType); 6051 matchFunctionTypeParameters(node.typeParameters, functionType);
6071 if (functionType is FunctionType) { 6052 if (functionType is FunctionType) {
6072 _inferFormalParameterList(node.parameters, functionType); 6053 _inferFormalParameterList(node.parameters, functionType);
6073 6054 InferenceContext.setType(
6074 DartType returnType; 6055 node.body, _computeReturnOrYieldType(functionType.returnType));
6075 ParameterElement parameterElement =
6076 resolutionMap.staticParameterElementForExpression(node);
6077 if (isFutureThen(parameterElement?.enclosingElement)) {
6078 var futureThenType =
6079 InferenceContext.getContext(node.parent) as FunctionType;
6080
6081 // Pretend the return type of Future<T>.then<S> first parameter is
6082 //
6083 // T -> (S | Future<S>)
6084 //
6085 // We can't represent this in Dart so we populate it here during
6086 // inference.
6087 var typeParamS =
6088 futureThenType.returnType.flattenFutures(typeSystem);
6089 returnType =
6090 FutureUnionType.from(typeParamS, typeProvider, typeSystem);
6091 } else {
6092 returnType = _computeReturnOrYieldType(functionType.returnType);
6093 }
6094
6095 InferenceContext.setType(node.body, returnType);
6096 } 6056 }
6097 } 6057 }
6098 super.visitFunctionExpression(node); 6058 super.visitFunctionExpression(node);
6099 } finally { 6059 } finally {
6100 _overrideManager.exitScope(); 6060 _overrideManager.exitScope();
6101 } 6061 }
6102 } finally { 6062 } finally {
6103 _currentFunctionBody = outerFunctionBody; 6063 _currentFunctionBody = outerFunctionBody;
6104 _enclosingFunction = outerFunction; 6064 _enclosingFunction = outerFunction;
6105 } 6065 }
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
6214 // have not already inferred something. However, the obvious ways to 6174 // have not already inferred something. However, the obvious ways to
6215 // check this don't work, since we may have been instantiated 6175 // check this don't work, since we may have been instantiated
6216 // to bounds in an earlier phase, and we *do* want to do inference 6176 // to bounds in an earlier phase, and we *do* want to do inference
6217 // in that case. 6177 // in that case.
6218 if (classTypeName.typeArguments == null) { 6178 if (classTypeName.typeArguments == null) {
6219 // Given a union of context types ` T0 | T1 | ... | Tn`, find the first 6179 // Given a union of context types ` T0 | T1 | ... | Tn`, find the first
6220 // valid instantiation `new C<Ti>`, if it exists. 6180 // valid instantiation `new C<Ti>`, if it exists.
6221 // TODO(jmesserly): if we support union types for real, `new C<Ti | Tj>` 6181 // TODO(jmesserly): if we support union types for real, `new C<Ti | Tj>`
6222 // will become a valid possibility. Right now the only allowed union is 6182 // will become a valid possibility. Right now the only allowed union is
6223 // `T | Future<T>` so we can take a simple approach. 6183 // `T | Future<T>` so we can take a simple approach.
6224 for (var contextType in InferenceContext.getTypes(node)) { 6184 for (var contextType in inferenceContext.getTypes(node)) {
6225 if (contextType is InterfaceType && 6185 if (contextType is InterfaceType &&
6226 contextType.typeArguments != null && 6186 contextType.typeArguments != null &&
6227 contextType.typeArguments.isNotEmpty) { 6187 contextType.typeArguments.isNotEmpty) {
6228 // TODO(jmesserly): for generic methods we use the 6188 // TODO(jmesserly): for generic methods we use the
6229 // StrongTypeSystemImpl.inferGenericFunctionCall, which appears to 6189 // StrongTypeSystemImpl.inferGenericFunctionCall, which appears to
6230 // be a tad more powerful than matchTypes. 6190 // be a tad more powerful than matchTypes.
6231 // 6191 //
6232 // For example it can infer this case: 6192 // For example it can infer this case:
6233 // 6193 //
6234 // class E<S, T> extends A<C<S>, T> { ... } 6194 // class E<S, T> extends A<C<S>, T> { ... }
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after
6650 InterfaceType rawType = isAsynchronous 6610 InterfaceType rawType = isAsynchronous
6651 ? typeProvider.streamDynamicType 6611 ? typeProvider.streamDynamicType
6652 : typeProvider.iterableDynamicType; 6612 : typeProvider.iterableDynamicType;
6653 // Match the types to instantiate the type arguments if possible 6613 // Match the types to instantiate the type arguments if possible
6654 List<DartType> typeArgs = 6614 List<DartType> typeArgs =
6655 inferenceContext.matchTypes(rawType, declaredType); 6615 inferenceContext.matchTypes(rawType, declaredType);
6656 return (typeArgs?.length == 1) ? typeArgs[0] : null; 6616 return (typeArgs?.length == 1) ? typeArgs[0] : null;
6657 } 6617 }
6658 // async functions expect `Future<T> | T` 6618 // async functions expect `Future<T> | T`
6659 var futureTypeParam = declaredType.flattenFutures(typeSystem); 6619 var futureTypeParam = declaredType.flattenFutures(typeSystem);
6660 return FutureUnionType.from(futureTypeParam, typeProvider, typeSystem); 6620 return _createFutureOr(futureTypeParam);
6661 } 6621 }
6662 return declaredType; 6622 return declaredType;
6663 } 6623 }
6664 6624
6665 /** 6625 /**
6626 * Creates a union of `T | Future<T>`, unless `T` is already a future or a
6627 * future-union, in which case it simply returns `T`.
6628 *
6629 * Conceptually this is used as the inverse of the `flatten(T)` operation,
6630 * defined as:
6631 *
6632 * - `flatten(Future<T>) -> T`
6633 * - `flatten(T) -> T`
6634 *
6635 * Thus the inverse will give us `T | Future<T>`.
6636 *
6637 * If [type] is top (dynamic or Object) then the resulting union type is
Leaf 2017/01/24 21:56:26 Can you give some examples of why you want to do t
Jennifer Messerly 2017/01/25 00:33:35 This code already existed -- it was moved from "Fu
6638 * equivalent to top, so we simply return it.
6639 *
6640 * If [type] is bottom, it is equivalent to `Future<bottom>`
6641 *
6642 * For a similar reason `Future<T> | Future<Future<T>>` is equivalent to just
Leaf 2017/01/24 21:56:26 I'd really like to avoid putting this in if at all
Jennifer Messerly 2017/01/25 00:33:35 (same comment as above -- this code already existe
6643 * `Future<T>`, so we return it. Note that it is not possible to get a
6644 * `Future<T>` as a result of `flatten`, so a this case likely indicates a
6645 * type error in the code, but it will be reported elsewhere.
6646 */
6647 DartType _createFutureOr(DartType type) {
6648 if (type.isObject || type.isDynamic) {
6649 return type;
6650 }
6651 if (!identical(type, type.flattenFutures(typeSystem))) {
6652 // As noted above, this most likely represents erroneous input.
6653 return type;
6654 }
6655 if (type.isDartAsyncFutureOr) {
6656 return type;
6657 }
6658 if (type.isBottom) {
6659 return typeProvider.futureType.instantiate([type]);
6660 }
6661 return typeProvider.futureOrType.instantiate([type]);
6662 }
6663
6664 /**
6666 * The given expression is the expression used to compute the iterator for a 6665 * The given expression is the expression used to compute the iterator for a
6667 * for-each statement. Attempt to compute the type of objects that will be 6666 * for-each statement. Attempt to compute the type of objects that will be
6668 * assigned to the loop variable and return that type. Return `null` if the 6667 * assigned to the loop variable and return that type. Return `null` if the
6669 * type could not be determined. The [iteratorExpression] is the expression 6668 * type could not be determined. The [iteratorExpression] is the expression
6670 * that will return the Iterable being iterated over. 6669 * that will return the Iterable being iterated over.
6671 */ 6670 */
6672 DartType _getIteratorElementType(Expression iteratorExpression) { 6671 DartType _getIteratorElementType(Expression iteratorExpression) {
6673 DartType expressionType = iteratorExpression.bestType; 6672 DartType expressionType = iteratorExpression.bestType;
6674 if (expressionType is InterfaceType) { 6673 if (expressionType is InterfaceType) {
6675 PropertyAccessorElement iteratorFunction = 6674 PropertyAccessorElement iteratorFunction =
(...skipping 1604 matching lines...) Expand 10 before | Expand all | Expand 10 after
8280 if (!elementValid) { 8279 if (!elementValid) {
8281 if (element is MultiplyDefinedElement) { 8280 if (element is MultiplyDefinedElement) {
8282 _setElement(typeName, element); 8281 _setElement(typeName, element);
8283 } 8282 }
8284 typeName.staticType = undefinedType; 8283 typeName.staticType = undefinedType;
8285 node.type = undefinedType; 8284 node.type = undefinedType;
8286 return; 8285 return;
8287 } 8286 }
8288 DartType type = null; 8287 DartType type = null;
8289 if (element is ClassElement) { 8288 if (element is ClassElement) {
8289 type = element.type;
8290 // In non-strong mode `FutureOr<T>` is treated as `dynamic`
8291 if (!typeSystem.isStrong && type.isDartAsyncFutureOr) {
8292 type = dynamicType;
8293 _setElement(typeName, type.element);
8294 typeName.staticType = type;
8295 node.type = type;
8296 if (argumentList != null) {
8297 NodeList<TypeAnnotation> arguments = argumentList.arguments;
8298 if (arguments.length != 1) {
8299 reportErrorForNode(_getInvalidTypeParametersErrorCode(node), node,
8300 [typeName.name, 1, arguments.length]);
8301 }
8302 }
8303 return;
8304 }
8290 _setElement(typeName, element); 8305 _setElement(typeName, element);
8291 type = element.type;
8292 } else if (element is FunctionTypeAliasElement) { 8306 } else if (element is FunctionTypeAliasElement) {
8293 _setElement(typeName, element); 8307 _setElement(typeName, element);
8294 type = element.type; 8308 type = element.type;
8295 } else if (element is TypeParameterElement) { 8309 } else if (element is TypeParameterElement) {
8296 _setElement(typeName, element); 8310 _setElement(typeName, element);
8297 type = element.type; 8311 type = element.type;
8298 // if (argumentList != null) { 8312 // if (argumentList != null) {
8299 // // Type parameters cannot have type arguments. 8313 // // Type parameters cannot have type arguments.
8300 // // TODO(brianwilkerson) Report this error. 8314 // // TODO(brianwilkerson) Report this error.
8301 // // resolver.reportError(ResolverErrorCode.?, keyType); 8315 // // resolver.reportError(ResolverErrorCode.?, keyType);
(...skipping 2520 matching lines...) Expand 10 before | Expand all | Expand 10 after
10822 return null; 10836 return null;
10823 } 10837 }
10824 if (identical(node.staticElement, variable)) { 10838 if (identical(node.staticElement, variable)) {
10825 if (node.inSetterContext()) { 10839 if (node.inSetterContext()) {
10826 result = true; 10840 result = true;
10827 } 10841 }
10828 } 10842 }
10829 return null; 10843 return null;
10830 } 10844 }
10831 } 10845 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698