mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:51:29 +00:00
[cfe] Refactor return type checking in preparation for nnbd spec change
Change-Id: Ie73726b59b23be4c5e35b207ec72732c8be7dada Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/150982 Reviewed-by: Dmitry Stefantsov <dmitryas@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
parent
1d3fbbed7c
commit
cc5df58bd2
|
@ -4887,9 +4887,7 @@ class InferenceVisitor
|
|||
StatementInferenceResult visitReturnStatement(
|
||||
covariant ReturnStatementImpl node) {
|
||||
ClosureContext closureContext = inferrer.closureContext;
|
||||
DartType typeContext = !closureContext.isGenerator
|
||||
? closureContext.returnOrYieldContext
|
||||
: const UnknownType();
|
||||
DartType typeContext = closureContext.returnContext;
|
||||
DartType inferredType;
|
||||
if (node.expression != null) {
|
||||
ExpressionInferenceResult expressionResult = inferrer.inferExpression(
|
||||
|
@ -5682,24 +5680,18 @@ class InferenceVisitor
|
|||
StatementInferenceResult visitYieldStatement(YieldStatement node) {
|
||||
ClosureContext closureContext = inferrer.closureContext;
|
||||
ExpressionInferenceResult expressionResult;
|
||||
if (closureContext.isGenerator) {
|
||||
DartType typeContext = closureContext.returnOrYieldContext;
|
||||
if (node.isYieldStar && typeContext != null) {
|
||||
typeContext = inferrer.wrapType(
|
||||
typeContext,
|
||||
closureContext.isAsync
|
||||
? inferrer.coreTypes.streamClass
|
||||
: inferrer.coreTypes.iterableClass,
|
||||
inferrer.library.nonNullable);
|
||||
}
|
||||
expressionResult = inferrer.inferExpression(
|
||||
node.expression, typeContext, true,
|
||||
isVoidAllowed: true);
|
||||
} else {
|
||||
expressionResult = inferrer.inferExpression(
|
||||
node.expression, const UnknownType(), true,
|
||||
isVoidAllowed: true);
|
||||
DartType typeContext = closureContext.yieldContext;
|
||||
if (node.isYieldStar && typeContext is! UnknownType) {
|
||||
typeContext = inferrer.wrapType(
|
||||
typeContext,
|
||||
closureContext.isAsync
|
||||
? inferrer.coreTypes.streamClass
|
||||
: inferrer.coreTypes.iterableClass,
|
||||
inferrer.library.nonNullable);
|
||||
}
|
||||
expressionResult = inferrer.inferExpression(
|
||||
node.expression, typeContext, true,
|
||||
isVoidAllowed: true);
|
||||
closureContext.handleYield(inferrer, node, expressionResult);
|
||||
return const StatementInferenceResult();
|
||||
}
|
||||
|
|
856
pkg/front_end/lib/src/fasta/type_inference/closure_context.dart
Normal file
856
pkg/front_end/lib/src/fasta/type_inference/closure_context.dart
Normal file
|
@ -0,0 +1,856 @@
|
|||
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE.md file.
|
||||
|
||||
part of 'type_inferrer.dart';
|
||||
|
||||
/// Keeps track of information about the innermost function or closure being
|
||||
/// inferred.
|
||||
abstract class ClosureContext {
|
||||
/// Returns `true` if this is an `async` or an `async*` function.
|
||||
bool get isAsync;
|
||||
|
||||
/// The typing expectation for the subexpression of a `return` statement
|
||||
/// inside the function.
|
||||
///
|
||||
/// For an `async` function, this is a "FutureOr" type (since it is
|
||||
/// permissible for such a function to return either a direct value or a
|
||||
/// future).
|
||||
///
|
||||
/// For generator functions (which do not allow return statements) this is the
|
||||
/// unknown type.
|
||||
DartType get returnContext;
|
||||
|
||||
/// The typing expectation for the subexpression of a `yield` statement inside
|
||||
/// the function.
|
||||
///
|
||||
/// For `sync*` and `async*` functions, the expected type is the element type
|
||||
/// of the generated `Iterable` or `Stream`, respectively.
|
||||
///
|
||||
/// For non-generator functions (which do not allow yield statements) this is
|
||||
/// the unknown type.
|
||||
DartType get yieldContext;
|
||||
|
||||
factory ClosureContext(TypeInferrerImpl inferrer, AsyncMarker asyncMarker,
|
||||
DartType returnContext, bool needToInferReturnType) {
|
||||
assert(returnContext != null);
|
||||
DartType declaredReturnType =
|
||||
inferrer.computeGreatestClosure(returnContext);
|
||||
bool isAsync = asyncMarker == AsyncMarker.Async ||
|
||||
asyncMarker == AsyncMarker.AsyncStar;
|
||||
bool isGenerator = asyncMarker == AsyncMarker.SyncStar ||
|
||||
asyncMarker == AsyncMarker.AsyncStar;
|
||||
if (isGenerator) {
|
||||
if (isAsync) {
|
||||
DartType yieldContext = inferrer.getTypeArgumentOf(
|
||||
returnContext, inferrer.coreTypes.streamClass);
|
||||
return new _AsyncStarClosureContext(
|
||||
yieldContext, declaredReturnType, needToInferReturnType);
|
||||
} else {
|
||||
DartType yieldContext = inferrer.getTypeArgumentOf(
|
||||
returnContext, inferrer.coreTypes.iterableClass);
|
||||
return new _SyncStarClosureContext(
|
||||
yieldContext, declaredReturnType, needToInferReturnType);
|
||||
}
|
||||
} else if (isAsync) {
|
||||
returnContext = inferrer.wrapFutureOrType(
|
||||
inferrer.typeSchemaEnvironment.unfutureType(returnContext));
|
||||
return new _AsyncClosureContext(
|
||||
returnContext, declaredReturnType, needToInferReturnType);
|
||||
} else {
|
||||
return new _SyncClosureContext(
|
||||
returnContext, declaredReturnType, needToInferReturnType);
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles an explicit return statement.
|
||||
///
|
||||
/// If the return type is declared, the expression type is checked. If the
|
||||
/// return type is inferred the expression type registered for inference
|
||||
/// in [inferReturnType].
|
||||
void handleReturn(TypeInferrerImpl inferrer, ReturnStatement statement,
|
||||
DartType type, bool isArrow);
|
||||
|
||||
/// Handles an explicit yield statement.
|
||||
///
|
||||
/// If the return type is declared, the expression type is checked. If the
|
||||
/// return type is inferred the expression type registered for inference
|
||||
/// in [inferReturnType].
|
||||
void handleYield(TypeInferrerImpl inferrer, YieldStatement node,
|
||||
ExpressionInferenceResult expressionResult);
|
||||
|
||||
/// Handles an implicit return statement.
|
||||
///
|
||||
/// If the return type is declared, the expression type is checked. If the
|
||||
/// return type is inferred the expression type registered for inference
|
||||
/// in [inferReturnType].
|
||||
StatementInferenceResult handleImplicitReturn(TypeInferrerImpl inferrer,
|
||||
Statement body, StatementInferenceResult inferenceResult, int fileOffset);
|
||||
|
||||
/// Infers the return type for the function.
|
||||
///
|
||||
/// If the function is a non-generator function this is based on the explicit
|
||||
/// and implicit return statements registered in [handleReturn] and
|
||||
/// [handleImplicitReturn].
|
||||
///
|
||||
/// If the function is a generator function this is based on the explicit
|
||||
/// yield statements registered in [handleYield].
|
||||
DartType inferReturnType(TypeInferrerImpl inferrer, {bool hasImplicitReturn});
|
||||
}
|
||||
|
||||
class _SyncClosureContext implements ClosureContext {
|
||||
bool get isAsync => false;
|
||||
|
||||
/// The typing expectation for the subexpression of a `return` or `yield`
|
||||
/// statement inside the function.
|
||||
///
|
||||
/// For non-generator async functions, this will be a "FutureOr" type (since
|
||||
/// it is permissible for such a function to return either a direct value or
|
||||
/// a future).
|
||||
///
|
||||
/// For generator functions containing a `yield*` statement, the expected type
|
||||
/// for the subexpression of the `yield*` statement is the result of wrapping
|
||||
/// this typing expectation in `Stream` or `Iterator`, as appropriate.
|
||||
final DartType _returnContext;
|
||||
|
||||
@override
|
||||
DartType get returnContext => _returnContext;
|
||||
|
||||
@override
|
||||
DartType get yieldContext => const UnknownType();
|
||||
|
||||
final DartType _declaredReturnType;
|
||||
|
||||
final bool _needToInferReturnType;
|
||||
|
||||
DartType _inferredReturnType;
|
||||
|
||||
/// Whether the function is an arrow function.
|
||||
bool _isArrow;
|
||||
|
||||
/// A list of return statements in functions whose return type is being
|
||||
/// inferred.
|
||||
///
|
||||
/// The returns are checked for validity after the return type is inferred.
|
||||
List<ReturnStatement> _returnStatements;
|
||||
|
||||
/// A list of return expression types in functions whose return type is
|
||||
/// being inferred.
|
||||
List<DartType> _returnExpressionTypes;
|
||||
|
||||
_SyncClosureContext(this._returnContext, this._declaredReturnType,
|
||||
this._needToInferReturnType) {
|
||||
if (_needToInferReturnType) {
|
||||
_returnStatements = [];
|
||||
_returnExpressionTypes = [];
|
||||
}
|
||||
}
|
||||
|
||||
void _checkValidReturn(TypeInferrerImpl inferrer, DartType returnType,
|
||||
ReturnStatement statement, DartType expressionType) {
|
||||
// The rules for valid returns for functions with [returnType] `T` and
|
||||
// a return expression with static [expressionType] `S`.
|
||||
if (statement.expression == null) {
|
||||
// `return;` is a valid return if T is void, dynamic, or Null.
|
||||
if (returnType is VoidType ||
|
||||
returnType is DynamicType ||
|
||||
returnType == inferrer.coreTypes.nullType) {
|
||||
// Valid return;
|
||||
} else {
|
||||
statement.expression = inferrer.helper.wrapInProblem(
|
||||
new NullLiteral()..fileOffset = statement.fileOffset,
|
||||
messageReturnWithoutExpression,
|
||||
statement.fileOffset,
|
||||
noLength)
|
||||
..parent = statement;
|
||||
}
|
||||
} else {
|
||||
void ensureAssignability() {
|
||||
Expression expression = inferrer.ensureAssignable(
|
||||
_returnContext, expressionType, statement.expression,
|
||||
fileOffset: statement.fileOffset, isVoidAllowed: true);
|
||||
statement.expression = expression..parent = statement;
|
||||
}
|
||||
|
||||
if (_isArrow && returnType is VoidType) {
|
||||
// Arrow functions are valid if: T is void or return exp; is a valid for
|
||||
// a block-bodied function.
|
||||
ensureAssignability();
|
||||
} else if (returnType is VoidType &&
|
||||
expressionType is! VoidType &&
|
||||
expressionType is! DynamicType &&
|
||||
expressionType != inferrer.coreTypes.nullType) {
|
||||
// Invalid if T is void and S is not void, dynamic, or Null
|
||||
statement.expression = inferrer.helper.wrapInProblem(
|
||||
statement.expression,
|
||||
messageReturnFromVoidFunction,
|
||||
statement.expression.fileOffset,
|
||||
noLength)
|
||||
..parent = statement;
|
||||
} else if (expressionType is VoidType &&
|
||||
returnType is! VoidType &&
|
||||
returnType is! DynamicType &&
|
||||
returnType != inferrer.coreTypes.nullType) {
|
||||
// Invalid if S is void and T is not void, dynamic, or Null.
|
||||
statement.expression = inferrer.helper.wrapInProblem(
|
||||
statement.expression,
|
||||
messageVoidExpression,
|
||||
statement.expression.fileOffset,
|
||||
noLength)
|
||||
..parent = statement;
|
||||
} else {
|
||||
ensureAssignability();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the inferred return type based on the presence of a return
|
||||
/// statement returning the given [type].
|
||||
@override
|
||||
void handleReturn(TypeInferrerImpl inferrer, ReturnStatement statement,
|
||||
DartType type, bool isArrow) {
|
||||
// The first return we see tells us if we have an arrow function.
|
||||
if (this._isArrow == null) {
|
||||
this._isArrow = isArrow;
|
||||
} else {
|
||||
assert(this._isArrow == isArrow);
|
||||
}
|
||||
|
||||
if (_needToInferReturnType) {
|
||||
// Add the return to a list to be checked for validity after we've
|
||||
// inferred the return type.
|
||||
_returnStatements.add(statement);
|
||||
_returnExpressionTypes.add(type);
|
||||
} else {
|
||||
_checkValidReturn(inferrer, _declaredReturnType, statement, type);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void handleYield(TypeInferrerImpl inferrer, YieldStatement node,
|
||||
ExpressionInferenceResult expressionResult) {
|
||||
node.expression = expressionResult.expression..parent = node;
|
||||
}
|
||||
|
||||
@override
|
||||
DartType inferReturnType(TypeInferrerImpl inferrer,
|
||||
{bool hasImplicitReturn}) {
|
||||
assert(_needToInferReturnType);
|
||||
assert(hasImplicitReturn != null);
|
||||
DartType inferredType;
|
||||
if (_returnStatements.isNotEmpty) {
|
||||
// Use the types seen from the explicit return statements.
|
||||
for (int i = 0; i < _returnStatements.length; i++) {
|
||||
ReturnStatement statement = _returnStatements[i];
|
||||
DartType type = _returnExpressionTypes[i];
|
||||
// The return expression has to be assignable to the return type
|
||||
// expectation from the downwards inference context.
|
||||
if (statement.expression != null) {
|
||||
if (!inferrer.isAssignable(_returnContext, type)) {
|
||||
type = inferrer.computeGreatestClosure(_returnContext);
|
||||
}
|
||||
}
|
||||
if (inferredType == null) {
|
||||
inferredType = type;
|
||||
} else {
|
||||
inferredType = inferrer.typeSchemaEnvironment.getStandardUpperBound(
|
||||
inferredType, type, inferrer.library.library);
|
||||
}
|
||||
}
|
||||
} else if (hasImplicitReturn) {
|
||||
// No explicit returns we have an implicit `return null`.
|
||||
inferredType = inferrer.typeSchemaEnvironment.nullType;
|
||||
} else {
|
||||
// No explicit return and the function doesn't complete normally; that is,
|
||||
// it throws.
|
||||
if (inferrer.isNonNullableByDefault) {
|
||||
inferredType = new NeverType(inferrer.library.nonNullable);
|
||||
} else {
|
||||
inferredType = inferrer.typeSchemaEnvironment.nullType;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inferrer.typeSchemaEnvironment.isSubtypeOf(
|
||||
inferredType, _returnContext, SubtypeCheckMode.withNullabilities)) {
|
||||
// If the inferred return type isn't a subtype of the context, we use the
|
||||
// context.
|
||||
inferredType = inferrer.computeGreatestClosure2(_declaredReturnType);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _returnStatements.length; ++i) {
|
||||
_checkValidReturn(inferrer, inferredType, _returnStatements[i],
|
||||
_returnExpressionTypes[i]);
|
||||
}
|
||||
|
||||
return _inferredReturnType =
|
||||
demoteTypeInLibrary(inferredType, inferrer.library.library);
|
||||
}
|
||||
|
||||
@override
|
||||
StatementInferenceResult handleImplicitReturn(
|
||||
TypeInferrerImpl inferrer,
|
||||
Statement body,
|
||||
StatementInferenceResult inferenceResult,
|
||||
int fileOffset) {
|
||||
DartType returnType;
|
||||
if (_needToInferReturnType) {
|
||||
assert(_inferredReturnType != null,
|
||||
"Return type has not yet been inferred.");
|
||||
returnType = _inferredReturnType;
|
||||
} else {
|
||||
returnType = _declaredReturnType;
|
||||
}
|
||||
if (inferrer.library.isNonNullableByDefault &&
|
||||
(containsInvalidType(returnType) ||
|
||||
returnType.isPotentiallyNonNullable) &&
|
||||
inferrer.flowAnalysis.isReachable) {
|
||||
Statement resultStatement =
|
||||
inferenceResult.hasChanged ? inferenceResult.statement : body;
|
||||
// Create a synthetic return statement with the error.
|
||||
Statement returnStatement = new ReturnStatement(inferrer.helper
|
||||
.wrapInProblem(
|
||||
new NullLiteral()..fileOffset = fileOffset,
|
||||
templateImplicitReturnNull.withArguments(
|
||||
returnType, inferrer.library.isNonNullableByDefault),
|
||||
fileOffset,
|
||||
noLength))
|
||||
..fileOffset = fileOffset;
|
||||
if (resultStatement is Block) {
|
||||
resultStatement.statements.add(returnStatement);
|
||||
} else {
|
||||
resultStatement =
|
||||
new Block(<Statement>[resultStatement, returnStatement])
|
||||
..fileOffset = fileOffset;
|
||||
}
|
||||
return new StatementInferenceResult.single(resultStatement);
|
||||
}
|
||||
return inferenceResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// Keeps track of information about the innermost function or closure being
|
||||
/// inferred.
|
||||
class _AsyncClosureContext implements ClosureContext {
|
||||
bool get isAsync => true;
|
||||
|
||||
/// The typing expectation for the subexpression of a `return` or `yield`
|
||||
/// statement inside the function.
|
||||
///
|
||||
/// For non-generator async functions, this will be a "FutureOr" type (since
|
||||
/// it is permissible for such a function to return either a direct value or
|
||||
/// a future).
|
||||
///
|
||||
/// For generator functions containing a `yield*` statement, the expected type
|
||||
/// for the subexpression of the `yield*` statement is the result of wrapping
|
||||
/// this typing expectation in `Stream` or `Iterator`, as appropriate.
|
||||
final DartType _returnContext;
|
||||
|
||||
@override
|
||||
DartType get returnContext => _returnContext;
|
||||
|
||||
@override
|
||||
DartType get yieldContext => const UnknownType();
|
||||
|
||||
final DartType _declaredReturnType;
|
||||
|
||||
final bool _needToInferReturnType;
|
||||
|
||||
DartType _inferredReturnType;
|
||||
|
||||
/// Whether the function is an arrow function.
|
||||
bool _isArrow;
|
||||
|
||||
/// A list of return statements in functions whose return type is being
|
||||
/// inferred.
|
||||
///
|
||||
/// The returns are checked for validity after the return type is inferred.
|
||||
List<ReturnStatement> _returnStatements;
|
||||
|
||||
/// A list of return expression types in functions whose return type is
|
||||
/// being inferred.
|
||||
List<DartType> _returnExpressionTypes;
|
||||
|
||||
_AsyncClosureContext(this._returnContext, this._declaredReturnType,
|
||||
this._needToInferReturnType) {
|
||||
if (_needToInferReturnType) {
|
||||
_returnStatements = [];
|
||||
_returnExpressionTypes = [];
|
||||
}
|
||||
}
|
||||
|
||||
void _checkValidReturn(TypeInferrerImpl inferrer, DartType returnType,
|
||||
ReturnStatement statement, DartType expressionType) {
|
||||
// The rules for valid returns for async functions with [returnType] `T` and
|
||||
// a return expression with static [expressionType] `S`.
|
||||
DartType flattenedReturnType =
|
||||
inferrer.typeSchemaEnvironment.unfutureType(returnType);
|
||||
if (statement.expression == null) {
|
||||
// `return;` is a valid return if flatten(T) is void, dynamic, or Null.
|
||||
if (flattenedReturnType is VoidType ||
|
||||
flattenedReturnType is DynamicType ||
|
||||
flattenedReturnType == inferrer.coreTypes.nullType) {
|
||||
// Valid return;
|
||||
} else {
|
||||
statement.expression = inferrer.helper.wrapInProblem(
|
||||
new NullLiteral()..fileOffset = statement.fileOffset,
|
||||
messageReturnWithoutExpression,
|
||||
statement.fileOffset,
|
||||
noLength)
|
||||
..parent = statement;
|
||||
}
|
||||
} else {
|
||||
DartType flattenedExpressionType =
|
||||
inferrer.typeSchemaEnvironment.unfutureType(expressionType);
|
||||
|
||||
void ensureAssignability() {
|
||||
DartType wrappedType = inferrer.typeSchemaEnvironment
|
||||
.futureType(flattenedExpressionType, Nullability.nonNullable);
|
||||
Expression expression = inferrer.ensureAssignable(
|
||||
computeAssignableType(inferrer, _returnContext, wrappedType),
|
||||
wrappedType,
|
||||
statement.expression,
|
||||
fileOffset: statement.fileOffset,
|
||||
isVoidAllowed: true,
|
||||
runtimeCheckedType: _returnContext);
|
||||
statement.expression = expression..parent = statement;
|
||||
}
|
||||
|
||||
if (_isArrow && flattenedReturnType is VoidType) {
|
||||
// Arrow functions are valid if: flatten(T) is void or return exp; is
|
||||
// valid for a block-bodied function.
|
||||
ensureAssignability();
|
||||
} else if (returnType is VoidType &&
|
||||
flattenedExpressionType is! VoidType &&
|
||||
flattenedExpressionType is! DynamicType &&
|
||||
flattenedExpressionType != inferrer.coreTypes.nullType) {
|
||||
// Invalid if T is void and flatten(S) is not void, dynamic, or Null.
|
||||
statement.expression = inferrer.helper.wrapInProblem(
|
||||
statement.expression,
|
||||
messageReturnFromVoidFunction,
|
||||
statement.expression.fileOffset,
|
||||
noLength)
|
||||
..parent = statement;
|
||||
} else if (flattenedExpressionType is VoidType &&
|
||||
flattenedReturnType is! VoidType &&
|
||||
flattenedReturnType is! DynamicType &&
|
||||
flattenedReturnType != inferrer.coreTypes.nullType) {
|
||||
// Invalid if flatten(S) is void and flatten(T) is not void, dynamic,
|
||||
// or Null.
|
||||
statement.expression = inferrer.helper.wrapInProblem(
|
||||
statement.expression,
|
||||
messageVoidExpression,
|
||||
statement.expression.fileOffset,
|
||||
noLength)
|
||||
..parent = statement;
|
||||
} else {
|
||||
// The caller will check that the return expression is assignable to the
|
||||
// return type.
|
||||
ensureAssignability();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the inferred return type based on the presence of a return
|
||||
/// statement returning the given [type].
|
||||
@override
|
||||
void handleReturn(TypeInferrerImpl inferrer, ReturnStatement statement,
|
||||
DartType type, bool isArrow) {
|
||||
// The first return we see tells us if we have an arrow function.
|
||||
if (this._isArrow == null) {
|
||||
this._isArrow = isArrow;
|
||||
} else {
|
||||
assert(this._isArrow == isArrow);
|
||||
}
|
||||
|
||||
if (_needToInferReturnType) {
|
||||
// Add the return to a list to be checked for validity after we've
|
||||
// inferred the return type.
|
||||
_returnStatements.add(statement);
|
||||
_returnExpressionTypes.add(type);
|
||||
} else {
|
||||
_checkValidReturn(inferrer, _declaredReturnType, statement, type);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void handleYield(TypeInferrerImpl inferrer, YieldStatement node,
|
||||
ExpressionInferenceResult expressionResult) {
|
||||
node.expression = expressionResult.expression..parent = node;
|
||||
}
|
||||
|
||||
DartType computeAssignableType(TypeInferrerImpl inferrer,
|
||||
DartType contextType, DartType expressionType) {
|
||||
contextType = inferrer.computeGreatestClosure(contextType);
|
||||
|
||||
DartType initialContextType = contextType;
|
||||
if (!inferrer.isAssignable(initialContextType, expressionType)) {
|
||||
// If the body of the function is async, the expected return type has the
|
||||
// shape FutureOr<T>. We check both branches for FutureOr here: both T
|
||||
// and Future<T>.
|
||||
DartType unfuturedExpectedType =
|
||||
inferrer.typeSchemaEnvironment.unfutureType(contextType);
|
||||
DartType futuredExpectedType = inferrer.wrapFutureType(
|
||||
unfuturedExpectedType, inferrer.library.nonNullable);
|
||||
if (inferrer.isAssignable(unfuturedExpectedType, expressionType)) {
|
||||
contextType = unfuturedExpectedType;
|
||||
} else if (inferrer.isAssignable(futuredExpectedType, expressionType)) {
|
||||
contextType = futuredExpectedType;
|
||||
}
|
||||
}
|
||||
return contextType;
|
||||
}
|
||||
|
||||
@override
|
||||
DartType inferReturnType(TypeInferrerImpl inferrer,
|
||||
{bool hasImplicitReturn}) {
|
||||
assert(_needToInferReturnType);
|
||||
assert(hasImplicitReturn != null);
|
||||
DartType inferredType;
|
||||
if (_returnStatements.isNotEmpty) {
|
||||
// Use the types seen from the explicit return statements.
|
||||
for (int i = 0; i < _returnStatements.length; i++) {
|
||||
ReturnStatement statement = _returnStatements[i];
|
||||
DartType type = _returnExpressionTypes[i];
|
||||
|
||||
// The return expression has to be assignable to the return type
|
||||
// expectation from the downwards inference context.
|
||||
if (statement.expression != null) {
|
||||
if (!inferrer.isAssignable(
|
||||
computeAssignableType(inferrer, _returnContext, type), type)) {
|
||||
// Not assignable, use the expectation.
|
||||
type = inferrer.computeGreatestClosure(_returnContext);
|
||||
}
|
||||
}
|
||||
DartType unwrappedType =
|
||||
inferrer.typeSchemaEnvironment.unfutureType(type);
|
||||
if (inferredType == null) {
|
||||
inferredType = unwrappedType;
|
||||
} else {
|
||||
inferredType = inferrer.typeSchemaEnvironment.getStandardUpperBound(
|
||||
inferredType, unwrappedType, inferrer.library.library);
|
||||
}
|
||||
}
|
||||
} else if (hasImplicitReturn) {
|
||||
// No explicit returns we have an implicit `return null`.
|
||||
inferredType = inferrer.typeSchemaEnvironment.nullType;
|
||||
} else {
|
||||
// No explicit return and the function doesn't complete normally; that is,
|
||||
// it throws.
|
||||
if (inferrer.isNonNullableByDefault) {
|
||||
inferredType = new NeverType(inferrer.library.nonNullable);
|
||||
} else {
|
||||
inferredType = inferrer.typeSchemaEnvironment.nullType;
|
||||
}
|
||||
}
|
||||
|
||||
inferredType =
|
||||
inferrer.wrapFutureType(inferredType, inferrer.library.nonNullable);
|
||||
|
||||
if (!inferrer.typeSchemaEnvironment.isSubtypeOf(
|
||||
inferredType, _returnContext, SubtypeCheckMode.withNullabilities)) {
|
||||
// If the inferred return type isn't a subtype of the context, we use the
|
||||
// context.
|
||||
inferredType = inferrer.computeGreatestClosure2(_declaredReturnType);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _returnStatements.length; ++i) {
|
||||
_checkValidReturn(inferrer, inferredType, _returnStatements[i],
|
||||
_returnExpressionTypes[i]);
|
||||
}
|
||||
|
||||
return _inferredReturnType =
|
||||
demoteTypeInLibrary(inferredType, inferrer.library.library);
|
||||
}
|
||||
|
||||
@override
|
||||
StatementInferenceResult handleImplicitReturn(
|
||||
TypeInferrerImpl inferrer,
|
||||
Statement body,
|
||||
StatementInferenceResult inferenceResult,
|
||||
int fileOffset) {
|
||||
DartType returnType;
|
||||
if (_needToInferReturnType) {
|
||||
assert(_inferredReturnType != null,
|
||||
"Return type has not yet been inferred.");
|
||||
returnType = _inferredReturnType;
|
||||
} else {
|
||||
returnType = _declaredReturnType;
|
||||
}
|
||||
returnType = inferrer.typeSchemaEnvironment.unfutureType(returnType);
|
||||
if (inferrer.library.isNonNullableByDefault &&
|
||||
(containsInvalidType(returnType) ||
|
||||
returnType.isPotentiallyNonNullable) &&
|
||||
inferrer.flowAnalysis.isReachable) {
|
||||
Statement resultStatement =
|
||||
inferenceResult.hasChanged ? inferenceResult.statement : body;
|
||||
// Create a synthetic return statement with the error.
|
||||
Statement returnStatement = new ReturnStatement(inferrer.helper
|
||||
.wrapInProblem(
|
||||
new NullLiteral()..fileOffset = fileOffset,
|
||||
templateImplicitReturnNull.withArguments(
|
||||
returnType, inferrer.library.isNonNullableByDefault),
|
||||
fileOffset,
|
||||
noLength))
|
||||
..fileOffset = fileOffset;
|
||||
if (resultStatement is Block) {
|
||||
resultStatement.statements.add(returnStatement);
|
||||
} else {
|
||||
resultStatement =
|
||||
new Block(<Statement>[resultStatement, returnStatement])
|
||||
..fileOffset = fileOffset;
|
||||
}
|
||||
return new StatementInferenceResult.single(resultStatement);
|
||||
}
|
||||
return inferenceResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// Keeps track of information about the innermost function or closure being
|
||||
/// inferred.
|
||||
class _SyncStarClosureContext implements ClosureContext {
|
||||
bool get isAsync => false;
|
||||
|
||||
/// The typing expectation for the subexpression of a `return` or `yield`
|
||||
/// statement inside the function.
|
||||
///
|
||||
/// For non-generator async functions, this will be a "FutureOr" type (since
|
||||
/// it is permissible for such a function to return either a direct value or
|
||||
/// a future).
|
||||
///
|
||||
/// For generator functions containing a `yield*` statement, the expected type
|
||||
/// for the subexpression of the `yield*` statement is the result of wrapping
|
||||
/// this typing expectation in `Stream` or `Iterator`, as appropriate.
|
||||
final DartType _yieldElementContext;
|
||||
|
||||
@override
|
||||
DartType get returnContext => const UnknownType();
|
||||
|
||||
@override
|
||||
DartType get yieldContext => _yieldElementContext;
|
||||
|
||||
final DartType _declaredReturnType;
|
||||
|
||||
final bool _needToInferReturnType;
|
||||
|
||||
/// A list of return expression types in functions whose return type is
|
||||
/// being inferred.
|
||||
List<DartType> _yieldElementTypes;
|
||||
|
||||
_SyncStarClosureContext(this._yieldElementContext, this._declaredReturnType,
|
||||
this._needToInferReturnType) {
|
||||
if (_needToInferReturnType) {
|
||||
_yieldElementTypes = [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the inferred return type based on the presence of a return
|
||||
/// statement returning the given [type].
|
||||
@override
|
||||
void handleReturn(TypeInferrerImpl inferrer, ReturnStatement statement,
|
||||
DartType type, bool isArrow) {}
|
||||
|
||||
@override
|
||||
void handleYield(TypeInferrerImpl inferrer, YieldStatement node,
|
||||
ExpressionInferenceResult expressionResult) {
|
||||
DartType expectedType = node.isYieldStar
|
||||
? inferrer.wrapType(_yieldElementContext,
|
||||
inferrer.coreTypes.iterableClass, inferrer.library.nonNullable)
|
||||
: _yieldElementContext;
|
||||
Expression expression = inferrer.ensureAssignableResult(
|
||||
expectedType, expressionResult,
|
||||
fileOffset: node.fileOffset);
|
||||
node.expression = expression..parent = node;
|
||||
DartType type = expressionResult.inferredType;
|
||||
if (!identical(expressionResult.expression, expression)) {
|
||||
type = inferrer.computeGreatestClosure(expectedType);
|
||||
}
|
||||
if (_needToInferReturnType) {
|
||||
DartType elementType = type;
|
||||
if (node.isYieldStar) {
|
||||
elementType = inferrer.getDerivedTypeArgumentOf(
|
||||
type, inferrer.coreTypes.iterableClass) ??
|
||||
elementType;
|
||||
}
|
||||
_yieldElementTypes.add(elementType);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
DartType inferReturnType(TypeInferrerImpl inferrer,
|
||||
{bool hasImplicitReturn}) {
|
||||
assert(_needToInferReturnType);
|
||||
assert(hasImplicitReturn != null);
|
||||
DartType inferredElementType;
|
||||
if (_yieldElementTypes.isNotEmpty) {
|
||||
// Use the types seen from the explicit return statements.
|
||||
for (int i = 0; i < _yieldElementTypes.length; i++) {
|
||||
DartType type = _yieldElementTypes[i];
|
||||
if (inferredElementType == null) {
|
||||
inferredElementType = type;
|
||||
} else {
|
||||
inferredElementType = inferrer.typeSchemaEnvironment
|
||||
.getStandardUpperBound(
|
||||
inferredElementType, type, inferrer.library.library);
|
||||
}
|
||||
}
|
||||
} else if (hasImplicitReturn) {
|
||||
// No explicit returns we have an implicit `return null`.
|
||||
inferredElementType = inferrer.typeSchemaEnvironment.nullType;
|
||||
} else {
|
||||
// No explicit return and the function doesn't complete normally; that is,
|
||||
// it throws.
|
||||
if (inferrer.isNonNullableByDefault) {
|
||||
inferredElementType = new NeverType(inferrer.library.nonNullable);
|
||||
} else {
|
||||
inferredElementType = inferrer.typeSchemaEnvironment.nullType;
|
||||
}
|
||||
}
|
||||
|
||||
DartType inferredType = inferrer.wrapType(inferredElementType,
|
||||
inferrer.coreTypes.iterableClass, inferrer.library.nonNullable);
|
||||
|
||||
if (!inferrer.typeSchemaEnvironment.isSubtypeOf(inferredType,
|
||||
_yieldElementContext, SubtypeCheckMode.withNullabilities)) {
|
||||
// If the inferred return type isn't a subtype of the context, we use the
|
||||
// context.
|
||||
inferredType = inferrer.computeGreatestClosure2(_declaredReturnType);
|
||||
}
|
||||
|
||||
return demoteTypeInLibrary(inferredType, inferrer.library.library);
|
||||
}
|
||||
|
||||
@override
|
||||
StatementInferenceResult handleImplicitReturn(
|
||||
TypeInferrerImpl inferrer,
|
||||
Statement body,
|
||||
StatementInferenceResult inferenceResult,
|
||||
int fileOffset) {
|
||||
// There is no implicit return.
|
||||
return inferenceResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// Keeps track of information about the innermost function or closure being
|
||||
/// inferred.
|
||||
class _AsyncStarClosureContext implements ClosureContext {
|
||||
bool get isAsync => true;
|
||||
|
||||
/// The typing expectation for the subexpression of a `return` or `yield`
|
||||
/// statement inside the function.
|
||||
///
|
||||
/// For non-generator async functions, this will be a "FutureOr" type (since
|
||||
/// it is permissible for such a function to return either a direct value or
|
||||
/// a future).
|
||||
///
|
||||
/// For generator functions containing a `yield*` statement, the expected type
|
||||
/// for the subexpression of the `yield*` statement is the result of wrapping
|
||||
/// this typing expectation in `Stream` or `Iterator`, as appropriate.
|
||||
final DartType _yieldElementContext;
|
||||
|
||||
@override
|
||||
DartType get returnContext => const UnknownType();
|
||||
|
||||
@override
|
||||
DartType get yieldContext => _yieldElementContext;
|
||||
|
||||
final DartType _declaredReturnType;
|
||||
|
||||
final bool _needToInferReturnType;
|
||||
|
||||
/// A list of return expression types in functions whose return type is
|
||||
/// being inferred.
|
||||
List<DartType> _yieldElementTypes;
|
||||
|
||||
_AsyncStarClosureContext(this._yieldElementContext, this._declaredReturnType,
|
||||
this._needToInferReturnType) {
|
||||
if (_needToInferReturnType) {
|
||||
_yieldElementTypes = [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the inferred return type based on the presence of a return
|
||||
/// statement returning the given [type].
|
||||
@override
|
||||
void handleReturn(TypeInferrerImpl inferrer, ReturnStatement statement,
|
||||
DartType type, bool isArrow) {}
|
||||
|
||||
@override
|
||||
void handleYield(TypeInferrerImpl inferrer, YieldStatement node,
|
||||
ExpressionInferenceResult expressionResult) {
|
||||
DartType expectedType = node.isYieldStar
|
||||
? inferrer.wrapType(_yieldElementContext,
|
||||
inferrer.coreTypes.streamClass, inferrer.library.nonNullable)
|
||||
: _yieldElementContext;
|
||||
|
||||
Expression expression = inferrer.ensureAssignableResult(
|
||||
expectedType, expressionResult,
|
||||
fileOffset: node.fileOffset);
|
||||
node.expression = expression..parent = node;
|
||||
DartType type = expressionResult.inferredType;
|
||||
if (!identical(expressionResult.expression, expression)) {
|
||||
type = inferrer.computeGreatestClosure(expectedType);
|
||||
}
|
||||
if (_needToInferReturnType) {
|
||||
DartType elementType = type;
|
||||
if (node.isYieldStar) {
|
||||
elementType = inferrer.getDerivedTypeArgumentOf(
|
||||
type, inferrer.coreTypes.streamClass) ??
|
||||
type;
|
||||
}
|
||||
_yieldElementTypes.add(elementType);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
DartType inferReturnType(TypeInferrerImpl inferrer,
|
||||
{bool hasImplicitReturn}) {
|
||||
assert(_needToInferReturnType);
|
||||
assert(hasImplicitReturn != null);
|
||||
DartType inferredElementType;
|
||||
if (_yieldElementTypes.isNotEmpty) {
|
||||
// Use the types seen from the explicit return statements.
|
||||
for (DartType elementType in _yieldElementTypes) {
|
||||
if (inferredElementType == null) {
|
||||
inferredElementType = elementType;
|
||||
} else {
|
||||
inferredElementType = inferrer.typeSchemaEnvironment
|
||||
.getStandardUpperBound(
|
||||
inferredElementType, elementType, inferrer.library.library);
|
||||
}
|
||||
}
|
||||
} else if (hasImplicitReturn) {
|
||||
// No explicit returns we have an implicit `return null`.
|
||||
inferredElementType = inferrer.typeSchemaEnvironment.nullType;
|
||||
} else {
|
||||
// No explicit return and the function doesn't complete normally; that is,
|
||||
// it throws.
|
||||
if (inferrer.isNonNullableByDefault) {
|
||||
inferredElementType = new NeverType(inferrer.library.nonNullable);
|
||||
} else {
|
||||
inferredElementType = inferrer.typeSchemaEnvironment.nullType;
|
||||
}
|
||||
}
|
||||
|
||||
DartType inferredType = inferrer.wrapType(inferredElementType,
|
||||
inferrer.coreTypes.streamClass, inferrer.library.nonNullable);
|
||||
|
||||
if (!inferrer.typeSchemaEnvironment.isSubtypeOf(inferredType,
|
||||
_yieldElementContext, SubtypeCheckMode.withNullabilities)) {
|
||||
// If the inferred return type isn't a subtype of the context, we use the
|
||||
// context.
|
||||
inferredType = inferrer.computeGreatestClosure2(_declaredReturnType);
|
||||
}
|
||||
|
||||
return demoteTypeInLibrary(inferredType, inferrer.library.library);
|
||||
}
|
||||
|
||||
@override
|
||||
StatementInferenceResult handleImplicitReturn(
|
||||
TypeInferrerImpl inferrer,
|
||||
Statement body,
|
||||
StatementInferenceResult inferenceResult,
|
||||
int fileOffset) {
|
||||
// There is no implicit return.
|
||||
return inferenceResult;
|
||||
}
|
||||
}
|
|
@ -78,6 +78,8 @@ import 'type_schema_environment.dart'
|
|||
TypeVariableEliminator,
|
||||
TypeSchemaEnvironment;
|
||||
|
||||
part 'closure_context.dart';
|
||||
|
||||
/// Given a [FunctionNode], gets the named parameter identified by [name], or
|
||||
/// `null` if there is no parameter with the given name.
|
||||
VariableDeclaration getNamedFormal(FunctionNode function, String name) {
|
||||
|
@ -104,361 +106,6 @@ bool isOverloadableArithmeticOperator(String name) {
|
|||
identical(name, '%');
|
||||
}
|
||||
|
||||
/// Keeps track of information about the innermost function or closure being
|
||||
/// inferred.
|
||||
class ClosureContext {
|
||||
final bool isAsync;
|
||||
|
||||
final bool isGenerator;
|
||||
|
||||
/// The typing expectation for the subexpression of a `return` or `yield`
|
||||
/// statement inside the function.
|
||||
///
|
||||
/// For non-generator async functions, this will be a "FutureOr" type (since
|
||||
/// it is permissible for such a function to return either a direct value or
|
||||
/// a future).
|
||||
///
|
||||
/// For generator functions containing a `yield*` statement, the expected type
|
||||
/// for the subexpression of the `yield*` statement is the result of wrapping
|
||||
/// this typing expectation in `Stream` or `Iterator`, as appropriate.
|
||||
final DartType returnOrYieldContext;
|
||||
|
||||
final DartType declaredReturnType;
|
||||
|
||||
final bool _needToInferReturnType;
|
||||
|
||||
DartType _inferredReturnType;
|
||||
|
||||
/// The type that actually appeared as the subexpression of `return` or
|
||||
/// `yield` statements inside the function.
|
||||
///
|
||||
/// For non-generator async functions, this is the "unwrapped" type (e.g. if
|
||||
/// the function is expected to return `Future<int>`, this is `int`).
|
||||
///
|
||||
/// For generator functions containing a `yield*` statement, the type that
|
||||
/// appeared as the subexpression of the `yield*` statement was the result of
|
||||
/// wrapping this type in `Stream` or `Iterator`, as appropriate.
|
||||
DartType _inferredUnwrappedReturnOrYieldType;
|
||||
|
||||
/// Whether the function is an arrow function.
|
||||
bool isArrow;
|
||||
|
||||
/// A list of return statements in functions whose return type is being
|
||||
/// inferred.
|
||||
///
|
||||
/// The returns are checked for validity after the return type is inferred.
|
||||
List<ReturnStatement> returnStatements;
|
||||
|
||||
/// A list of return expression types in functions whose return type is
|
||||
/// being inferred.
|
||||
List<DartType> returnExpressionTypes;
|
||||
|
||||
factory ClosureContext(TypeInferrerImpl inferrer, AsyncMarker asyncMarker,
|
||||
DartType returnContext, bool needToInferReturnType) {
|
||||
assert(returnContext != null);
|
||||
DartType declaredReturnType =
|
||||
inferrer.computeGreatestClosure(returnContext);
|
||||
bool isAsync = asyncMarker == AsyncMarker.Async ||
|
||||
asyncMarker == AsyncMarker.AsyncStar;
|
||||
bool isGenerator = asyncMarker == AsyncMarker.SyncStar ||
|
||||
asyncMarker == AsyncMarker.AsyncStar;
|
||||
if (isGenerator) {
|
||||
if (isAsync) {
|
||||
returnContext = inferrer.getTypeArgumentOf(
|
||||
returnContext, inferrer.coreTypes.streamClass);
|
||||
} else {
|
||||
returnContext = inferrer.getTypeArgumentOf(
|
||||
returnContext, inferrer.coreTypes.iterableClass);
|
||||
}
|
||||
} else if (isAsync) {
|
||||
returnContext = inferrer.wrapFutureOrType(
|
||||
inferrer.typeSchemaEnvironment.unfutureType(returnContext));
|
||||
}
|
||||
return new ClosureContext._(isAsync, isGenerator, returnContext,
|
||||
declaredReturnType, needToInferReturnType);
|
||||
}
|
||||
|
||||
ClosureContext._(this.isAsync, this.isGenerator, this.returnOrYieldContext,
|
||||
this.declaredReturnType, this._needToInferReturnType) {
|
||||
if (_needToInferReturnType) {
|
||||
returnStatements = [];
|
||||
returnExpressionTypes = [];
|
||||
}
|
||||
}
|
||||
|
||||
bool checkValidReturn(TypeInferrerImpl inferrer, DartType returnType,
|
||||
ReturnStatement statement, DartType expressionType) {
|
||||
// The rules for valid returns for functions with return type T and possibly
|
||||
// a return expression with static type S.
|
||||
DartType flattenedReturnType = isAsync
|
||||
? inferrer.typeSchemaEnvironment.unfutureType(returnType)
|
||||
: returnType;
|
||||
if (statement.expression == null) {
|
||||
// Sync: return; is a valid return if T is void, dynamic, or Null.
|
||||
// Async: return; is a valid return if flatten(T) is void, dynamic, or
|
||||
// Null.
|
||||
if (flattenedReturnType is VoidType ||
|
||||
flattenedReturnType is DynamicType ||
|
||||
flattenedReturnType == inferrer.coreTypes.nullType) {
|
||||
return true;
|
||||
}
|
||||
statement.expression = inferrer.helper.wrapInProblem(
|
||||
new NullLiteral()..fileOffset = statement.fileOffset,
|
||||
messageReturnWithoutExpression,
|
||||
statement.fileOffset,
|
||||
noLength)
|
||||
..parent = statement;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Arrow functions are valid if:
|
||||
// Sync: T is void or return exp; is a valid for a block-bodied function.
|
||||
// Async: flatten(T) is void or return exp; is valid for a block-bodied
|
||||
// function.
|
||||
if (isArrow && flattenedReturnType is VoidType) return true;
|
||||
|
||||
// Sync: invalid if T is void and S is not void, dynamic, or Null
|
||||
// Async: invalid if T is void and flatten(S) is not void, dynamic, or Null.
|
||||
DartType flattenedExpressionType = isAsync
|
||||
? inferrer.typeSchemaEnvironment.unfutureType(expressionType)
|
||||
: expressionType;
|
||||
if (returnType is VoidType &&
|
||||
flattenedExpressionType is! VoidType &&
|
||||
flattenedExpressionType is! DynamicType &&
|
||||
flattenedExpressionType != inferrer.coreTypes.nullType) {
|
||||
statement.expression = inferrer.helper.wrapInProblem(
|
||||
statement.expression,
|
||||
messageReturnFromVoidFunction,
|
||||
statement.expression.fileOffset,
|
||||
noLength)
|
||||
..parent = statement;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sync: invalid if S is void and T is not void, dynamic, or Null.
|
||||
// Async: invalid if flatten(S) is void and flatten(T) is not void, dynamic,
|
||||
// or Null.
|
||||
if (flattenedExpressionType is VoidType &&
|
||||
flattenedReturnType is! VoidType &&
|
||||
flattenedReturnType is! DynamicType &&
|
||||
flattenedReturnType != inferrer.coreTypes.nullType) {
|
||||
statement.expression = inferrer.helper.wrapInProblem(statement.expression,
|
||||
messageVoidExpression, statement.expression.fileOffset, noLength)
|
||||
..parent = statement;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The caller will check that the return expression is assignable to the
|
||||
// return type.
|
||||
return true;
|
||||
}
|
||||
|
||||
void _updateInferredUnwrappedReturnOrYieldType(
|
||||
TypeInferrerImpl inferrer, DartType unwrappedType) {
|
||||
if (_inferredUnwrappedReturnOrYieldType == null) {
|
||||
_inferredUnwrappedReturnOrYieldType = unwrappedType;
|
||||
} else {
|
||||
_inferredUnwrappedReturnOrYieldType = inferrer.typeSchemaEnvironment
|
||||
.getStandardUpperBound(_inferredUnwrappedReturnOrYieldType,
|
||||
unwrappedType, inferrer.library.library);
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the inferred return type based on the presence of a return
|
||||
/// statement returning the given [type].
|
||||
void handleReturn(TypeInferrerImpl inferrer, ReturnStatement statement,
|
||||
DartType type, bool isArrow) {
|
||||
if (isGenerator) return;
|
||||
// The first return we see tells us if we have an arrow function.
|
||||
if (this.isArrow == null) {
|
||||
this.isArrow = isArrow;
|
||||
} else {
|
||||
assert(this.isArrow == isArrow);
|
||||
}
|
||||
|
||||
if (_needToInferReturnType) {
|
||||
// Add the return to a list to be checked for validity after we've
|
||||
// inferred the return type.
|
||||
returnStatements.add(statement);
|
||||
returnExpressionTypes.add(type);
|
||||
|
||||
// The return expression has to be assignable to the return type
|
||||
// expectation from the downwards inference context.
|
||||
if (statement.expression != null) {
|
||||
Expression expression = inferrer.ensureAssignable(
|
||||
returnOrYieldContext, type, statement.expression,
|
||||
fileOffset: statement.fileOffset,
|
||||
isReturnFromAsync: isAsync,
|
||||
isVoidAllowed: true);
|
||||
if (!identical(statement.expression, expression)) {
|
||||
statement.expression = expression..parent = statement;
|
||||
// Not assignable, use the expectation.
|
||||
type = inferrer.computeGreatestClosure(returnOrYieldContext);
|
||||
}
|
||||
}
|
||||
DartType unwrappedType = type;
|
||||
if (isAsync) {
|
||||
unwrappedType = inferrer.typeSchemaEnvironment.unfutureType(type);
|
||||
}
|
||||
_updateInferredUnwrappedReturnOrYieldType(inferrer, unwrappedType);
|
||||
} else if (checkValidReturn(
|
||||
inferrer, declaredReturnType, statement, type) &&
|
||||
statement.expression != null) {
|
||||
// If we are not inferring a type we can immediately check that the return
|
||||
// is valid.
|
||||
DartType wrappedType = type;
|
||||
if (isAsync) {
|
||||
wrappedType = inferrer.typeSchemaEnvironment.futureType(
|
||||
inferrer.typeSchemaEnvironment.unfutureType(type),
|
||||
Nullability.nonNullable);
|
||||
}
|
||||
Expression expression = inferrer.ensureAssignable(
|
||||
returnOrYieldContext, wrappedType, statement.expression,
|
||||
fileOffset: statement.fileOffset,
|
||||
isReturnFromAsync: isAsync,
|
||||
isVoidAllowed: true);
|
||||
statement.expression = expression..parent = statement;
|
||||
}
|
||||
}
|
||||
|
||||
void handleYield(TypeInferrerImpl inferrer, YieldStatement node,
|
||||
ExpressionInferenceResult expressionResult) {
|
||||
if (!isGenerator) {
|
||||
node.expression = expressionResult.expression..parent = node;
|
||||
return;
|
||||
}
|
||||
DartType expectedType = node.isYieldStar
|
||||
? _wrapAsyncOrGenerator(
|
||||
inferrer, returnOrYieldContext, inferrer.library.nonNullable)
|
||||
: returnOrYieldContext;
|
||||
Expression expression = inferrer.ensureAssignableResult(
|
||||
expectedType, expressionResult,
|
||||
fileOffset: node.fileOffset, isReturnFromAsync: isAsync);
|
||||
node.expression = expression..parent = node;
|
||||
DartType type = expressionResult.inferredType;
|
||||
if (!identical(expressionResult.expression, expression)) {
|
||||
type = inferrer.computeGreatestClosure(expectedType);
|
||||
}
|
||||
if (_needToInferReturnType) {
|
||||
DartType unwrappedType = type;
|
||||
if (node.isYieldStar) {
|
||||
unwrappedType = inferrer.getDerivedTypeArgumentOf(
|
||||
type,
|
||||
isAsync
|
||||
? inferrer.coreTypes.streamClass
|
||||
: inferrer.coreTypes.iterableClass) ??
|
||||
type;
|
||||
}
|
||||
_updateInferredUnwrappedReturnOrYieldType(inferrer, unwrappedType);
|
||||
}
|
||||
}
|
||||
|
||||
DartType inferReturnType(TypeInferrerImpl inferrer,
|
||||
{bool hasImplicitReturn}) {
|
||||
assert(_needToInferReturnType);
|
||||
assert(hasImplicitReturn != null);
|
||||
DartType inferredType;
|
||||
if (_inferredUnwrappedReturnOrYieldType != null) {
|
||||
// Use the types seen from the explicit return statements.
|
||||
inferredType = _inferredUnwrappedReturnOrYieldType;
|
||||
} else if (hasImplicitReturn) {
|
||||
// No explicit returns we have an implicit `return null`.
|
||||
inferredType = inferrer.typeSchemaEnvironment.nullType;
|
||||
} else {
|
||||
// No explicit return and the function doesn't complete normally; that is,
|
||||
// it throws.
|
||||
if (inferrer.isNonNullableByDefault) {
|
||||
inferredType = new NeverType(inferrer.library.nonNullable);
|
||||
} else {
|
||||
inferredType = inferrer.typeSchemaEnvironment.nullType;
|
||||
}
|
||||
}
|
||||
|
||||
inferredType = _wrapAsyncOrGenerator(
|
||||
inferrer, inferredType, inferrer.library.nonNullable);
|
||||
|
||||
if (!inferrer.typeSchemaEnvironment.isSubtypeOf(inferredType,
|
||||
returnOrYieldContext, SubtypeCheckMode.withNullabilities)) {
|
||||
// If the inferred return type isn't a subtype of the context, we use the
|
||||
// context.
|
||||
inferredType = inferrer.computeGreatestClosure2(declaredReturnType);
|
||||
}
|
||||
|
||||
for (int i = 0; i < returnStatements.length; ++i) {
|
||||
checkValidReturn(inferrer, inferredType, returnStatements[i],
|
||||
returnExpressionTypes[i]);
|
||||
}
|
||||
|
||||
return _inferredReturnType =
|
||||
demoteTypeInLibrary(inferredType, inferrer.library.library);
|
||||
}
|
||||
|
||||
StatementInferenceResult handleImplicitReturn(
|
||||
TypeInferrerImpl inferrer,
|
||||
Statement body,
|
||||
StatementInferenceResult inferenceResult,
|
||||
int fileOffset) {
|
||||
if (isGenerator) {
|
||||
// There is no implicit return.
|
||||
return inferenceResult;
|
||||
}
|
||||
|
||||
DartType returnType;
|
||||
if (_needToInferReturnType) {
|
||||
assert(_inferredReturnType != null,
|
||||
"Return type has not yet been inferred.");
|
||||
returnType = _inferredReturnType;
|
||||
} else {
|
||||
returnType = declaredReturnType;
|
||||
}
|
||||
if (isAsync) {
|
||||
returnType = inferrer.typeSchemaEnvironment.unfutureType(returnType);
|
||||
}
|
||||
if (inferrer.library.isNonNullableByDefault &&
|
||||
(containsInvalidType(returnType) ||
|
||||
returnType.isPotentiallyNonNullable) &&
|
||||
inferrer.flowAnalysis.isReachable) {
|
||||
Statement resultStatement =
|
||||
inferenceResult.hasChanged ? inferenceResult.statement : body;
|
||||
// Create a synthetic return statement with the error.
|
||||
Statement returnStatement = new ReturnStatement(inferrer.helper
|
||||
.wrapInProblem(
|
||||
new NullLiteral()..fileOffset = fileOffset,
|
||||
templateImplicitReturnNull.withArguments(
|
||||
returnType, inferrer.library.isNonNullableByDefault),
|
||||
fileOffset,
|
||||
noLength))
|
||||
..fileOffset = fileOffset;
|
||||
if (resultStatement is Block) {
|
||||
resultStatement.statements.add(returnStatement);
|
||||
} else {
|
||||
resultStatement =
|
||||
new Block(<Statement>[resultStatement, returnStatement])
|
||||
..fileOffset = fileOffset;
|
||||
}
|
||||
return new StatementInferenceResult.single(resultStatement);
|
||||
}
|
||||
return inferenceResult;
|
||||
}
|
||||
|
||||
DartType _wrapAsyncOrGenerator(
|
||||
TypeInferrerImpl inferrer, DartType type, Nullability nullability) {
|
||||
if (isGenerator) {
|
||||
if (isAsync) {
|
||||
return inferrer.wrapType(
|
||||
type, inferrer.coreTypes.streamClass, nullability);
|
||||
} else {
|
||||
return inferrer.wrapType(
|
||||
type, inferrer.coreTypes.iterableClass, nullability);
|
||||
}
|
||||
} else if (isAsync) {
|
||||
return inferrer.wrapFutureType(type, nullability);
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum denoting the kinds of contravariance check that might need to be
|
||||
/// inserted for a method call.
|
||||
enum MethodContravarianceCheckKind {
|
||||
|
@ -731,13 +378,11 @@ class TypeInferrerImpl implements TypeInferrer {
|
|||
DartType expectedType, ExpressionInferenceResult result,
|
||||
{int fileOffset,
|
||||
bool isVoidAllowed: false,
|
||||
bool isReturnFromAsync: false,
|
||||
Template<Message Function(DartType, DartType, bool)> errorTemplate}) {
|
||||
return ensureAssignable(
|
||||
expectedType, result.inferredType, result.expression,
|
||||
fileOffset: fileOffset,
|
||||
isVoidAllowed: isVoidAllowed,
|
||||
isReturnFromAsync: isReturnFromAsync,
|
||||
errorTemplate: errorTemplate);
|
||||
}
|
||||
|
||||
|
@ -746,10 +391,16 @@ class TypeInferrerImpl implements TypeInferrer {
|
|||
/// Checks whether [expressionType] can be assigned to the greatest closure of
|
||||
/// [contextType], and inserts an implicit downcast, inserts a tear-off, or
|
||||
/// reports an error if appropriate.
|
||||
///
|
||||
/// If [runtimeCheckedType] is provided, this is used for the implicit cast,
|
||||
/// otherwise [contextType] is used. This is used for return from async
|
||||
/// where the returned expression is wrapped in a `Future`, if necessary,
|
||||
/// before returned and therefore shouldn't be checked to be a `Future`
|
||||
/// directly.
|
||||
Expression ensureAssignable(
|
||||
DartType contextType, DartType expressionType, Expression expression,
|
||||
{int fileOffset,
|
||||
bool isReturnFromAsync: false,
|
||||
DartType runtimeCheckedType,
|
||||
bool isVoidAllowed: false,
|
||||
Template<Message Function(DartType, DartType, bool)> errorTemplate}) {
|
||||
assert(contextType != null);
|
||||
|
@ -762,22 +413,7 @@ class TypeInferrerImpl implements TypeInferrer {
|
|||
fileOffset ??= expression.fileOffset;
|
||||
contextType = computeGreatestClosure(contextType);
|
||||
|
||||
DartType initialContextType = contextType;
|
||||
if (isReturnFromAsync &&
|
||||
!isAssignable(initialContextType, expressionType)) {
|
||||
// If the body of the function is async, the expected return type has the
|
||||
// shape FutureOr<T>. We check both branches for FutureOr here: both T
|
||||
// and Future<T>.
|
||||
DartType unfuturedExpectedType =
|
||||
typeSchemaEnvironment.unfutureType(contextType);
|
||||
DartType futuredExpectedType =
|
||||
wrapFutureType(unfuturedExpectedType, library.nonNullable);
|
||||
if (isAssignable(unfuturedExpectedType, expressionType)) {
|
||||
contextType = unfuturedExpectedType;
|
||||
} else if (isAssignable(futuredExpectedType, expressionType)) {
|
||||
contextType = futuredExpectedType;
|
||||
}
|
||||
}
|
||||
DartType initialContextType = runtimeCheckedType ?? contextType;
|
||||
|
||||
Template<Message Function(DartType, DartType, bool)>
|
||||
preciseTypeErrorTemplate = _getPreciseTypeErrorTemplate(expression);
|
||||
|
|
51
pkg/front_end/testcases/general/future_return.dart
Normal file
51
pkg/front_end/testcases/general/future_return.dart
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
class Class {}
|
||||
|
||||
dynamic returnDynamic() => new Class();
|
||||
|
||||
Class returnClass() async => new Class();
|
||||
|
||||
Future<Class> returnFutureClass() async => new Class();
|
||||
|
||||
FutureOr<Class> returnFutureOrClass() async => new Class();
|
||||
|
||||
Class returnClassFromDynamic() async => returnDynamic();
|
||||
|
||||
Future<Class> returnFutureClassDynamic() async => returnDynamic();
|
||||
|
||||
FutureOr<Class> returnFutureOrClassDynamic() async => returnDynamic();
|
||||
|
||||
Class returnClassFromFutureClass() async => returnFutureClass();
|
||||
|
||||
Future<Class> returnFutureClassFromFutureClass() async => returnFutureClass();
|
||||
|
||||
FutureOr<Class> returnFutureOrClassFromFutureClass() async =>
|
||||
returnFutureClass();
|
||||
|
||||
Class returnClassFromFutureOrClass() async => returnFutureOrClass();
|
||||
|
||||
Future<Class> returnFutureClassFromFutureOrClass() async =>
|
||||
returnFutureOrClass();
|
||||
|
||||
FutureOr<Class> returnFutureOrClassFromFutureOrClass() async =>
|
||||
returnFutureOrClass();
|
||||
|
||||
main() async {
|
||||
await returnClass();
|
||||
await returnFutureClass();
|
||||
await returnFutureOrClass();
|
||||
await returnClassFromDynamic();
|
||||
await returnFutureClassDynamic();
|
||||
await returnFutureOrClassDynamic();
|
||||
await returnClassFromFutureClass();
|
||||
await returnFutureClassFromFutureClass();
|
||||
await returnFutureOrClassFromFutureClass();
|
||||
await returnClassFromFutureOrClass();
|
||||
await returnFutureClassFromFutureOrClass();
|
||||
await returnFutureOrClassFromFutureOrClass();
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:async" as asy;
|
||||
|
||||
import "dart:async";
|
||||
|
||||
class Class extends core::Object {
|
||||
synthetic constructor •() → self::Class*
|
||||
;
|
||||
abstract member-signature get _identityHashCode() → core::int*;
|
||||
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
|
||||
abstract member-signature operator ==(dynamic other) → core::bool*;
|
||||
abstract member-signature get hashCode() → core::int*;
|
||||
abstract member-signature method toString() → core::String*;
|
||||
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
|
||||
abstract member-signature get runtimeType() → core::Type*;
|
||||
}
|
||||
static method returnDynamic() → dynamic
|
||||
;
|
||||
static method returnClass() → self::Class*
|
||||
;
|
||||
static method returnFutureClass() → asy::Future<self::Class*>*
|
||||
;
|
||||
static method returnFutureOrClass() → FutureOr<self::Class*>*
|
||||
;
|
||||
static method returnClassFromDynamic() → self::Class*
|
||||
;
|
||||
static method returnFutureClassDynamic() → asy::Future<self::Class*>*
|
||||
;
|
||||
static method returnFutureOrClassDynamic() → FutureOr<self::Class*>*
|
||||
;
|
||||
static method returnClassFromFutureClass() → self::Class*
|
||||
;
|
||||
static method returnFutureClassFromFutureClass() → asy::Future<self::Class*>*
|
||||
;
|
||||
static method returnFutureOrClassFromFutureClass() → FutureOr<self::Class*>*
|
||||
;
|
||||
static method returnClassFromFutureOrClass() → self::Class*
|
||||
;
|
||||
static method returnFutureClassFromFutureOrClass() → asy::Future<self::Class*>*
|
||||
;
|
||||
static method returnFutureOrClassFromFutureOrClass() → FutureOr<self::Class*>*
|
||||
;
|
||||
static method main() → dynamic
|
||||
;
|
|
@ -0,0 +1,81 @@
|
|||
library;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/general/future_return.dart:11:7: Error: Functions marked 'async' must have a return type assignable to 'Future'.
|
||||
// Class returnClass() async => new Class();
|
||||
// ^^^^^^^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/future_return.dart:17:7: Error: Functions marked 'async' must have a return type assignable to 'Future'.
|
||||
// Class returnClassFromDynamic() async => returnDynamic();
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/future_return.dart:23:7: Error: Functions marked 'async' must have a return type assignable to 'Future'.
|
||||
// Class returnClassFromFutureClass() async => returnFutureClass();
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/future_return.dart:30:7: Error: Functions marked 'async' must have a return type assignable to 'Future'.
|
||||
// Class returnClassFromFutureOrClass() async => returnFutureOrClass();
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:async" as asy;
|
||||
|
||||
import "dart:async";
|
||||
|
||||
class Class extends core::Object {
|
||||
synthetic constructor •() → self::Class*
|
||||
: super core::Object::•()
|
||||
;
|
||||
abstract member-signature get _identityHashCode() → core::int*;
|
||||
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
|
||||
abstract member-signature operator ==(dynamic other) → core::bool*;
|
||||
abstract member-signature get hashCode() → core::int*;
|
||||
abstract member-signature method toString() → core::String*;
|
||||
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
|
||||
abstract member-signature get runtimeType() → core::Type*;
|
||||
}
|
||||
static method returnDynamic() → dynamic
|
||||
return new self::Class::•();
|
||||
static method returnClass() → self::Class* async
|
||||
return new self::Class::•();
|
||||
static method returnFutureClass() → asy::Future<self::Class*>* async
|
||||
return new self::Class::•();
|
||||
static method returnFutureOrClass() → FutureOr<self::Class*>* async
|
||||
return new self::Class::•();
|
||||
static method returnClassFromDynamic() → self::Class* async
|
||||
return self::returnDynamic() as{TypeError} FutureOr<self::Class*>*;
|
||||
static method returnFutureClassDynamic() → asy::Future<self::Class*>* async
|
||||
return self::returnDynamic() as{TypeError} FutureOr<self::Class*>*;
|
||||
static method returnFutureOrClassDynamic() → FutureOr<self::Class*>* async
|
||||
return self::returnDynamic() as{TypeError} FutureOr<self::Class*>*;
|
||||
static method returnClassFromFutureClass() → self::Class* async
|
||||
return self::returnFutureClass();
|
||||
static method returnFutureClassFromFutureClass() → asy::Future<self::Class*>* async
|
||||
return self::returnFutureClass();
|
||||
static method returnFutureOrClassFromFutureClass() → FutureOr<self::Class*>* async
|
||||
return self::returnFutureClass();
|
||||
static method returnClassFromFutureOrClass() → self::Class* async
|
||||
return self::returnFutureOrClass();
|
||||
static method returnFutureClassFromFutureOrClass() → asy::Future<self::Class*>* async
|
||||
return self::returnFutureOrClass();
|
||||
static method returnFutureOrClassFromFutureOrClass() → FutureOr<self::Class*>* async
|
||||
return self::returnFutureOrClass();
|
||||
static method main() → dynamic async {
|
||||
await self::returnClass();
|
||||
await self::returnFutureClass();
|
||||
await self::returnFutureOrClass();
|
||||
await self::returnClassFromDynamic();
|
||||
await self::returnFutureClassDynamic();
|
||||
await self::returnFutureOrClassDynamic();
|
||||
await self::returnClassFromFutureClass();
|
||||
await self::returnFutureClassFromFutureClass();
|
||||
await self::returnFutureOrClassFromFutureClass();
|
||||
await self::returnClassFromFutureOrClass();
|
||||
await self::returnFutureClassFromFutureOrClass();
|
||||
await self::returnFutureOrClassFromFutureOrClass();
|
||||
}
|
|
@ -0,0 +1,418 @@
|
|||
library;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/general/future_return.dart:11:7: Error: Functions marked 'async' must have a return type assignable to 'Future'.
|
||||
// Class returnClass() async => new Class();
|
||||
// ^^^^^^^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/future_return.dart:17:7: Error: Functions marked 'async' must have a return type assignable to 'Future'.
|
||||
// Class returnClassFromDynamic() async => returnDynamic();
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/future_return.dart:23:7: Error: Functions marked 'async' must have a return type assignable to 'Future'.
|
||||
// Class returnClassFromFutureClass() async => returnFutureClass();
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/future_return.dart:30:7: Error: Functions marked 'async' must have a return type assignable to 'Future'.
|
||||
// Class returnClassFromFutureOrClass() async => returnFutureOrClass();
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:async" as asy;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
import "dart:async";
|
||||
|
||||
class Class extends core::Object {
|
||||
synthetic constructor •() → self::Class*
|
||||
: super core::Object::•()
|
||||
;
|
||||
abstract member-signature get _identityHashCode() → core::int*;
|
||||
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
|
||||
abstract member-signature operator ==(dynamic other) → core::bool*;
|
||||
abstract member-signature get hashCode() → core::int*;
|
||||
abstract member-signature method toString() → core::String*;
|
||||
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
|
||||
abstract member-signature get runtimeType() → core::Type*;
|
||||
}
|
||||
static method returnDynamic() → dynamic
|
||||
return new self::Class::•();
|
||||
static method returnClass() → self::Class* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
|
||||
FutureOr<dynamic>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L1:
|
||||
{
|
||||
:return_value = new self::Class::•();
|
||||
break #L1;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method returnFutureClass() → asy::Future<self::Class*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<self::Class*>* :async_completer = new asy::_AsyncAwaitCompleter::•<self::Class*>();
|
||||
FutureOr<self::Class*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L2:
|
||||
{
|
||||
:return_value = new self::Class::•();
|
||||
break #L2;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method returnFutureOrClass() → FutureOr<self::Class*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<self::Class*>* :async_completer = new asy::_AsyncAwaitCompleter::•<self::Class*>();
|
||||
FutureOr<self::Class*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L3:
|
||||
{
|
||||
:return_value = new self::Class::•();
|
||||
break #L3;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method returnClassFromDynamic() → self::Class* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
|
||||
FutureOr<dynamic>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L4:
|
||||
{
|
||||
:return_value = self::returnDynamic() as{TypeError} FutureOr<self::Class*>*;
|
||||
break #L4;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method returnFutureClassDynamic() → asy::Future<self::Class*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<self::Class*>* :async_completer = new asy::_AsyncAwaitCompleter::•<self::Class*>();
|
||||
FutureOr<self::Class*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L5:
|
||||
{
|
||||
:return_value = self::returnDynamic() as{TypeError} FutureOr<self::Class*>*;
|
||||
break #L5;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method returnFutureOrClassDynamic() → FutureOr<self::Class*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<self::Class*>* :async_completer = new asy::_AsyncAwaitCompleter::•<self::Class*>();
|
||||
FutureOr<self::Class*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L6:
|
||||
{
|
||||
:return_value = self::returnDynamic() as{TypeError} FutureOr<self::Class*>*;
|
||||
break #L6;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method returnClassFromFutureClass() → self::Class* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
|
||||
FutureOr<dynamic>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L7:
|
||||
{
|
||||
:return_value = self::returnFutureClass();
|
||||
break #L7;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method returnFutureClassFromFutureClass() → asy::Future<self::Class*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<self::Class*>* :async_completer = new asy::_AsyncAwaitCompleter::•<self::Class*>();
|
||||
FutureOr<self::Class*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L8:
|
||||
{
|
||||
:return_value = self::returnFutureClass();
|
||||
break #L8;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method returnFutureOrClassFromFutureClass() → FutureOr<self::Class*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<self::Class*>* :async_completer = new asy::_AsyncAwaitCompleter::•<self::Class*>();
|
||||
FutureOr<self::Class*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L9:
|
||||
{
|
||||
:return_value = self::returnFutureClass();
|
||||
break #L9;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method returnClassFromFutureOrClass() → self::Class* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
|
||||
FutureOr<dynamic>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L10:
|
||||
{
|
||||
:return_value = self::returnFutureOrClass();
|
||||
break #L10;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method returnFutureClassFromFutureOrClass() → asy::Future<self::Class*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<self::Class*>* :async_completer = new asy::_AsyncAwaitCompleter::•<self::Class*>();
|
||||
FutureOr<self::Class*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L11:
|
||||
{
|
||||
:return_value = self::returnFutureOrClass();
|
||||
break #L11;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method returnFutureOrClassFromFutureOrClass() → FutureOr<self::Class*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<self::Class*>* :async_completer = new asy::_AsyncAwaitCompleter::•<self::Class*>();
|
||||
FutureOr<self::Class*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L12:
|
||||
{
|
||||
:return_value = self::returnFutureOrClass();
|
||||
break #L12;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method main() → dynamic /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
|
||||
FutureOr<dynamic>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
dynamic :saved_try_context_var0;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L13:
|
||||
{
|
||||
[yield] let dynamic #t1 = asy::_awaitHelper(self::returnClass(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
_in::unsafeCast<self::Class*>(:result);
|
||||
[yield] let dynamic #t2 = asy::_awaitHelper(self::returnFutureClass(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
_in::unsafeCast<self::Class*>(:result);
|
||||
[yield] let dynamic #t3 = asy::_awaitHelper(self::returnFutureOrClass(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
_in::unsafeCast<self::Class*>(:result);
|
||||
[yield] let dynamic #t4 = asy::_awaitHelper(self::returnClassFromDynamic(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
_in::unsafeCast<self::Class*>(:result);
|
||||
[yield] let dynamic #t5 = asy::_awaitHelper(self::returnFutureClassDynamic(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
_in::unsafeCast<self::Class*>(:result);
|
||||
[yield] let dynamic #t6 = asy::_awaitHelper(self::returnFutureOrClassDynamic(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
_in::unsafeCast<self::Class*>(:result);
|
||||
[yield] let dynamic #t7 = asy::_awaitHelper(self::returnClassFromFutureClass(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
_in::unsafeCast<self::Class*>(:result);
|
||||
[yield] let dynamic #t8 = asy::_awaitHelper(self::returnFutureClassFromFutureClass(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
_in::unsafeCast<self::Class*>(:result);
|
||||
[yield] let dynamic #t9 = asy::_awaitHelper(self::returnFutureOrClassFromFutureClass(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
_in::unsafeCast<self::Class*>(:result);
|
||||
[yield] let dynamic #t10 = asy::_awaitHelper(self::returnClassFromFutureOrClass(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
_in::unsafeCast<self::Class*>(:result);
|
||||
[yield] let dynamic #t11 = asy::_awaitHelper(self::returnFutureClassFromFutureOrClass(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
_in::unsafeCast<self::Class*>(:result);
|
||||
[yield] let dynamic #t12 = asy::_awaitHelper(self::returnFutureOrClassFromFutureOrClass(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
_in::unsafeCast<self::Class*>(:result);
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import 'dart:async';
|
||||
|
||||
class Class {}
|
||||
|
||||
dynamic returnDynamic() => new Class();
|
||||
Class returnClass() async => new Class();
|
||||
Future<Class> returnFutureClass() async => new Class();
|
||||
FutureOr<Class> returnFutureOrClass() async => new Class();
|
||||
Class returnClassFromDynamic() async => returnDynamic();
|
||||
Future<Class> returnFutureClassDynamic() async => returnDynamic();
|
||||
FutureOr<Class> returnFutureOrClassDynamic() async => returnDynamic();
|
||||
Class returnClassFromFutureClass() async => returnFutureClass();
|
||||
Future<Class> returnFutureClassFromFutureClass() async => returnFutureClass();
|
||||
FutureOr<Class> returnFutureOrClassFromFutureClass() async =>
|
||||
returnFutureClass();
|
||||
Class returnClassFromFutureOrClass() async => returnFutureOrClass();
|
||||
Future<Class> returnFutureClassFromFutureOrClass() async =>
|
||||
returnFutureOrClass();
|
||||
FutureOr<Class> returnFutureOrClassFromFutureOrClass() async =>
|
||||
returnFutureOrClass();
|
||||
main() async {}
|
|
@ -0,0 +1,22 @@
|
|||
import 'dart:async';
|
||||
|
||||
Class returnClass() async => new Class();
|
||||
Class returnClassFromDynamic() async => returnDynamic();
|
||||
Class returnClassFromFutureClass() async => returnFutureClass();
|
||||
Class returnClassFromFutureOrClass() async => returnFutureOrClass();
|
||||
Future<Class> returnFutureClass() async => new Class();
|
||||
Future<Class> returnFutureClassDynamic() async => returnDynamic();
|
||||
Future<Class> returnFutureClassFromFutureClass() async => returnFutureClass();
|
||||
Future<Class> returnFutureClassFromFutureOrClass() async =>
|
||||
returnFutureOrClass();
|
||||
FutureOr<Class> returnFutureOrClass() async => new Class();
|
||||
FutureOr<Class> returnFutureOrClassDynamic() async => returnDynamic();
|
||||
FutureOr<Class> returnFutureOrClassFromFutureClass() async =>
|
||||
returnFutureClass();
|
||||
FutureOr<Class> returnFutureOrClassFromFutureOrClass() async =>
|
||||
returnFutureOrClass();
|
||||
|
||||
class Class {}
|
||||
|
||||
dynamic returnDynamic() => new Class();
|
||||
main() async {}
|
31
pkg/front_end/testcases/general/stream_future.dart
Normal file
31
pkg/front_end/testcases/general/stream_future.dart
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
class Class {}
|
||||
|
||||
dynamic returnDynamic() => new Class();
|
||||
|
||||
Class returnClass() => new Class();
|
||||
|
||||
Future<dynamic> returnFutureDynamic() async => new Class();
|
||||
|
||||
Future<Class> returnFutureClass() async => new Class();
|
||||
|
||||
Stream<FutureOr<Class>> error() async* {
|
||||
yield returnFutureDynamic();
|
||||
}
|
||||
|
||||
Stream<FutureOr<Class>> stream() async* {
|
||||
yield returnDynamic();
|
||||
yield returnClass();
|
||||
yield returnFutureClass();
|
||||
}
|
||||
|
||||
main() async {
|
||||
await for (FutureOr<Class> cls in stream()) {
|
||||
print(cls);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:async" as asy;
|
||||
|
||||
import "dart:async";
|
||||
|
||||
class Class extends core::Object {
|
||||
synthetic constructor •() → self::Class*
|
||||
;
|
||||
abstract member-signature get _identityHashCode() → core::int*;
|
||||
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
|
||||
abstract member-signature operator ==(dynamic other) → core::bool*;
|
||||
abstract member-signature get hashCode() → core::int*;
|
||||
abstract member-signature method toString() → core::String*;
|
||||
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
|
||||
abstract member-signature get runtimeType() → core::Type*;
|
||||
}
|
||||
static method returnDynamic() → dynamic
|
||||
;
|
||||
static method returnClass() → self::Class*
|
||||
;
|
||||
static method returnFutureDynamic() → asy::Future<dynamic>*
|
||||
;
|
||||
static method returnFutureClass() → asy::Future<self::Class*>*
|
||||
;
|
||||
static method error() → asy::Stream<FutureOr<self::Class*>*>*
|
||||
;
|
||||
static method stream() → asy::Stream<FutureOr<self::Class*>*>*
|
||||
;
|
||||
static method main() → dynamic
|
||||
;
|
|
@ -0,0 +1,56 @@
|
|||
library;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/general/stream_future.dart:18:9: Error: A value of type 'Future<dynamic>' can't be assigned to a variable of type 'FutureOr<Class>'.
|
||||
// - 'Future' is from 'dart:async'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/general/stream_future.dart'.
|
||||
// yield returnFutureDynamic();
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:async" as asy;
|
||||
|
||||
import "dart:async";
|
||||
|
||||
class Class extends core::Object {
|
||||
synthetic constructor •() → self::Class*
|
||||
: super core::Object::•()
|
||||
;
|
||||
abstract member-signature get _identityHashCode() → core::int*;
|
||||
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
|
||||
abstract member-signature operator ==(dynamic other) → core::bool*;
|
||||
abstract member-signature get hashCode() → core::int*;
|
||||
abstract member-signature method toString() → core::String*;
|
||||
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
|
||||
abstract member-signature get runtimeType() → core::Type*;
|
||||
}
|
||||
static method returnDynamic() → dynamic
|
||||
return new self::Class::•();
|
||||
static method returnClass() → self::Class*
|
||||
return new self::Class::•();
|
||||
static method returnFutureDynamic() → asy::Future<dynamic>* async
|
||||
return new self::Class::•();
|
||||
static method returnFutureClass() → asy::Future<self::Class*>* async
|
||||
return new self::Class::•();
|
||||
static method error() → asy::Stream<FutureOr<self::Class*>*>* async* {
|
||||
yield let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/stream_future.dart:18:9: Error: A value of type 'Future<dynamic>' can't be assigned to a variable of type 'FutureOr<Class>'.
|
||||
- 'Future' is from 'dart:async'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/general/stream_future.dart'.
|
||||
yield returnFutureDynamic();
|
||||
^" in self::returnFutureDynamic() as{TypeError} FutureOr<self::Class*>*;
|
||||
}
|
||||
static method stream() → asy::Stream<FutureOr<self::Class*>*>* async* {
|
||||
yield self::returnDynamic() as{TypeError,ForDynamic} FutureOr<self::Class*>*;
|
||||
yield self::returnClass();
|
||||
yield self::returnFutureClass();
|
||||
}
|
||||
static method main() → dynamic async {
|
||||
await for (FutureOr<self::Class*>* cls in self::stream()) {
|
||||
core::print(cls);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
library;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/general/stream_future.dart:18:9: Error: A value of type 'Future<dynamic>' can't be assigned to a variable of type 'FutureOr<Class>'.
|
||||
// - 'Future' is from 'dart:async'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/general/stream_future.dart'.
|
||||
// yield returnFutureDynamic();
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:async" as asy;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
import "dart:async";
|
||||
|
||||
class Class extends core::Object {
|
||||
synthetic constructor •() → self::Class*
|
||||
: super core::Object::•()
|
||||
;
|
||||
abstract member-signature get _identityHashCode() → core::int*;
|
||||
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
|
||||
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
|
||||
abstract member-signature operator ==(dynamic other) → core::bool*;
|
||||
abstract member-signature get hashCode() → core::int*;
|
||||
abstract member-signature method toString() → core::String*;
|
||||
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
|
||||
abstract member-signature get runtimeType() → core::Type*;
|
||||
}
|
||||
static method returnDynamic() → dynamic
|
||||
return new self::Class::•();
|
||||
static method returnClass() → self::Class*
|
||||
return new self::Class::•();
|
||||
static method returnFutureDynamic() → asy::Future<dynamic>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
|
||||
FutureOr<dynamic>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L1:
|
||||
{
|
||||
:return_value = new self::Class::•();
|
||||
break #L1;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method returnFutureClass() → asy::Future<self::Class*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<self::Class*>* :async_completer = new asy::_AsyncAwaitCompleter::•<self::Class*>();
|
||||
FutureOr<self::Class*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L2:
|
||||
{
|
||||
:return_value = new self::Class::•();
|
||||
break #L2;
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
||||
static method error() → asy::Stream<FutureOr<self::Class*>*>* /* originally async* */ {
|
||||
asy::_AsyncStarStreamController<FutureOr<self::Class*>*>* :controller;
|
||||
dynamic :controller_stream;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
dynamic :saved_try_context_var0;
|
||||
dynamic :saved_try_context_var1;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try
|
||||
try {
|
||||
#L3:
|
||||
{
|
||||
if(:controller.{asy::_AsyncStarStreamController::add}(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/stream_future.dart:18:9: Error: A value of type 'Future<dynamic>' can't be assigned to a variable of type 'FutureOr<Class>'.
|
||||
- 'Future' is from 'dart:async'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/general/stream_future.dart'.
|
||||
yield returnFutureDynamic();
|
||||
^" in self::returnFutureDynamic() as{TypeError} FutureOr<self::Class*>*))
|
||||
return null;
|
||||
else
|
||||
[yield] null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:controller.{asy::_AsyncStarStreamController::addError}(exception, stack_trace);
|
||||
}
|
||||
finally {
|
||||
:controller.{asy::_AsyncStarStreamController::close}();
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:controller = new asy::_AsyncStarStreamController::•<FutureOr<self::Class*>*>(:async_op);
|
||||
:controller_stream = :controller.{asy::_AsyncStarStreamController::stream};
|
||||
return :controller_stream;
|
||||
}
|
||||
static method stream() → asy::Stream<FutureOr<self::Class*>*>* /* originally async* */ {
|
||||
asy::_AsyncStarStreamController<FutureOr<self::Class*>*>* :controller;
|
||||
dynamic :controller_stream;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
dynamic :saved_try_context_var0;
|
||||
dynamic :saved_try_context_var1;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try
|
||||
try {
|
||||
#L4:
|
||||
{
|
||||
if(:controller.{asy::_AsyncStarStreamController::add}(self::returnDynamic() as{TypeError,ForDynamic} FutureOr<self::Class*>*))
|
||||
return null;
|
||||
else
|
||||
[yield] null;
|
||||
if(:controller.{asy::_AsyncStarStreamController::add}(self::returnClass()))
|
||||
return null;
|
||||
else
|
||||
[yield] null;
|
||||
if(:controller.{asy::_AsyncStarStreamController::add}(self::returnFutureClass()))
|
||||
return null;
|
||||
else
|
||||
[yield] null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:controller.{asy::_AsyncStarStreamController::addError}(exception, stack_trace);
|
||||
}
|
||||
finally {
|
||||
:controller.{asy::_AsyncStarStreamController::close}();
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:controller = new asy::_AsyncStarStreamController::•<FutureOr<self::Class*>*>(:async_op);
|
||||
:controller_stream = :controller.{asy::_AsyncStarStreamController::stream};
|
||||
return :controller_stream;
|
||||
}
|
||||
static method main() → dynamic /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
|
||||
FutureOr<dynamic>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
(dynamic) →* dynamic :async_op_then;
|
||||
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
|
||||
core::int* :await_jump_var = 0;
|
||||
dynamic :await_ctx_var;
|
||||
dynamic :saved_try_context_var0;
|
||||
dynamic :saved_try_context_var1;
|
||||
dynamic :exception0;
|
||||
dynamic :stack_trace0;
|
||||
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
|
||||
try {
|
||||
#L5:
|
||||
{
|
||||
{
|
||||
asy::Stream<FutureOr<self::Class*>*>* :stream = self::stream();
|
||||
asy::_asyncStarListenHelper(:stream, :async_op);
|
||||
asy::_StreamIterator<FutureOr<self::Class*>*>* :for-iterator = new asy::_StreamIterator::•<FutureOr<self::Class*>*>(:stream);
|
||||
try
|
||||
#L6:
|
||||
while (true) {
|
||||
dynamic #t2 = asy::_asyncStarMoveNextHelper(:stream);
|
||||
[yield] let dynamic #t3 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
if(_in::unsafeCast<core::bool>(:result)) {
|
||||
FutureOr<self::Class*>* cls = :for-iterator.{asy::_StreamIterator::current};
|
||||
{
|
||||
core::print(cls);
|
||||
}
|
||||
}
|
||||
else
|
||||
break #L6;
|
||||
}
|
||||
finally
|
||||
if(!:for-iterator.{asy::_StreamIterator::_subscription}.{core::Object::==}(null)) {
|
||||
[yield] let dynamic #t4 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::cancel}(), :async_op_then, :async_op_error, :async_op) in null;
|
||||
:result;
|
||||
}
|
||||
}
|
||||
}
|
||||
asy::_completeOnAsyncReturn(:async_completer, :return_value);
|
||||
return;
|
||||
}
|
||||
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
|
||||
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
|
||||
}
|
||||
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
|
||||
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
|
||||
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
|
||||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import 'dart:async';
|
||||
|
||||
class Class {}
|
||||
|
||||
dynamic returnDynamic() => new Class();
|
||||
Class returnClass() => new Class();
|
||||
Future<dynamic> returnFutureDynamic() async => new Class();
|
||||
Future<Class> returnFutureClass() async => new Class();
|
||||
Stream<FutureOr<Class>> error() async* {}
|
||||
Stream<FutureOr<Class>> stream() async* {}
|
||||
main() async {}
|
|
@ -0,0 +1,12 @@
|
|||
import 'dart:async';
|
||||
|
||||
Class returnClass() => new Class();
|
||||
Future<Class> returnFutureClass() async => new Class();
|
||||
Future<dynamic> returnFutureDynamic() async => new Class();
|
||||
Stream<FutureOr<Class>> error() async* {}
|
||||
Stream<FutureOr<Class>> stream() async* {}
|
||||
|
||||
class Class {}
|
||||
|
||||
dynamic returnDynamic() => new Class();
|
||||
main() async {}
|
|
@ -20,7 +20,7 @@ void test() {
|
|||
/*@ returnType=Future<int*>* */ (/*@ type=bool* */ x) async =>
|
||||
x ? 2 : await new Future<int>.value(3));
|
||||
Future<int> t2 = f. /*@ typeArgs=int* */ /*@target=MyFuture.then*/ then(
|
||||
/*@ returnType=Future<int*>* */ (/*@ type=bool* */ x) async {
|
||||
/*@returnType=FutureOr<int*>**/ (/*@ type=bool* */ x) async {
|
||||
return /*info:DOWN_CAST_COMPOSITE*/ await x ? 2 : new Future<int>.value(3);
|
||||
});
|
||||
Future<int> t5 = f. /*@ typeArgs=int* */ /*@target=MyFuture.then*/ then(
|
||||
|
|
|
@ -35,7 +35,7 @@ class MyFuture<T extends core::Object* = dynamic> extends core::Object implement
|
|||
static method test() → void {
|
||||
self::MyFuture<core::bool*>* f;
|
||||
asy::Future<core::int*>* t1 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* async => x ?{core::int*} 2 : await asy::Future::value<core::int*>(3));
|
||||
asy::Future<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* async {
|
||||
asy::Future<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → FutureOr<core::int*>* async {
|
||||
return (await x ?{core::Object*} 2 : asy::Future::value<core::int*>(3)) as{TypeError} FutureOr<core::int*>*;
|
||||
});
|
||||
asy::Future<core::int*>* t5 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → FutureOr<core::int*>* => (x ?{core::Object*} 2 : asy::Future::value<core::int*>(3)) as{TypeError} FutureOr<core::int*>*);
|
||||
|
|
|
@ -71,7 +71,7 @@ static method test() → void {
|
|||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
});
|
||||
asy::Future<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* /* originally async */ {
|
||||
asy::Future<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → FutureOr<core::int*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<core::int*>* :async_completer = new asy::_AsyncAwaitCompleter::•<core::int*>();
|
||||
FutureOr<core::int*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
|
|
|
@ -20,7 +20,7 @@ void test() {
|
|||
/*@ returnType=Future<int*>* */ (/*@ type=bool* */ x) async =>
|
||||
x ? 2 : await new MyFuture<int>.value(3));
|
||||
Future<int> t2 = f. /*@ typeArgs=int* */ /*@target=MyFuture.then*/ then(
|
||||
/*@ returnType=Future<int*>* */ (/*@ type=bool* */ x) async {
|
||||
/*@returnType=FutureOr<int*>**/ (/*@ type=bool* */ x) async {
|
||||
return /*info:DOWN_CAST_COMPOSITE*/ await x
|
||||
? 2
|
||||
: new MyFuture<int>.value(3);
|
||||
|
|
|
@ -35,7 +35,7 @@ class MyFuture<T extends core::Object* = dynamic> extends core::Object implement
|
|||
static method test() → void {
|
||||
self::MyFuture<core::bool*>* f;
|
||||
asy::Future<core::int*>* t1 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* async => x ?{core::int*} 2 : await new self::MyFuture::value<core::int*>(3));
|
||||
asy::Future<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* async {
|
||||
asy::Future<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → FutureOr<core::int*>* async {
|
||||
return (await x ?{core::Object*} 2 : new self::MyFuture::value<core::int*>(3)) as{TypeError} FutureOr<core::int*>*;
|
||||
});
|
||||
asy::Future<core::int*>* t5 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → FutureOr<core::int*>* => (x ?{core::Object*} 2 : new self::MyFuture::value<core::int*>(3)) as{TypeError} FutureOr<core::int*>*);
|
||||
|
|
|
@ -71,7 +71,7 @@ static method test() → void {
|
|||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
});
|
||||
asy::Future<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* /* originally async */ {
|
||||
asy::Future<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → FutureOr<core::int*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<core::int*>* :async_completer = new asy::_AsyncAwaitCompleter::•<core::int*>();
|
||||
FutureOr<core::int*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
|
|
|
@ -20,7 +20,7 @@ void test() {
|
|||
/*@ returnType=Future<int*>* */ (/*@ type=bool* */ x) async =>
|
||||
x ? 2 : await new Future<int>.value(3));
|
||||
MyFuture<int> t2 = f. /*@ typeArgs=int* */ /*@target=MyFuture.then*/ then(
|
||||
/*@ returnType=Future<int*>* */ (/*@ type=bool* */ x) async {
|
||||
/*@returnType=FutureOr<int*>**/ (/*@ type=bool* */ x) async {
|
||||
return /*info:DOWN_CAST_COMPOSITE*/ await x ? 2 : new Future<int>.value(3);
|
||||
});
|
||||
MyFuture<int> t5 = f. /*@ typeArgs=int* */ /*@target=MyFuture.then*/ then(
|
||||
|
|
|
@ -35,7 +35,7 @@ class MyFuture<T extends core::Object* = dynamic> extends core::Object implement
|
|||
static method test() → void {
|
||||
self::MyFuture<core::bool*>* f;
|
||||
self::MyFuture<core::int*>* t1 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* async => x ?{core::int*} 2 : await asy::Future::value<core::int*>(3));
|
||||
self::MyFuture<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* async {
|
||||
self::MyFuture<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → FutureOr<core::int*>* async {
|
||||
return (await x ?{core::Object*} 2 : asy::Future::value<core::int*>(3)) as{TypeError} FutureOr<core::int*>*;
|
||||
});
|
||||
self::MyFuture<core::int*>* t5 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → FutureOr<core::int*>* => (x ?{core::Object*} 2 : asy::Future::value<core::int*>(3)) as{TypeError} FutureOr<core::int*>*);
|
||||
|
|
|
@ -71,7 +71,7 @@ static method test() → void {
|
|||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
});
|
||||
self::MyFuture<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* /* originally async */ {
|
||||
self::MyFuture<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → FutureOr<core::int*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<core::int*>* :async_completer = new asy::_AsyncAwaitCompleter::•<core::int*>();
|
||||
FutureOr<core::int*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
|
|
|
@ -20,7 +20,7 @@ void test() {
|
|||
/*@ returnType=Future<int*>* */ (/*@ type=bool* */ x) async =>
|
||||
x ? 2 : await new MyFuture<int>.value(3));
|
||||
MyFuture<int> t2 = f. /*@ typeArgs=int* */ /*@target=MyFuture.then*/ then(
|
||||
/*@ returnType=Future<int*>* */ (/*@ type=bool* */ x) async {
|
||||
/*@returnType=FutureOr<int*>**/ (/*@ type=bool* */ x) async {
|
||||
return /*info:DOWN_CAST_COMPOSITE*/ await x
|
||||
? 2
|
||||
: new MyFuture<int>.value(3);
|
||||
|
|
|
@ -35,7 +35,7 @@ class MyFuture<T extends core::Object* = dynamic> extends core::Object implement
|
|||
static method test() → void {
|
||||
self::MyFuture<core::bool*>* f;
|
||||
self::MyFuture<core::int*>* t1 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* async => x ?{core::int*} 2 : await new self::MyFuture::value<core::int*>(3));
|
||||
self::MyFuture<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* async {
|
||||
self::MyFuture<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → FutureOr<core::int*>* async {
|
||||
return (await x ?{core::Object*} 2 : new self::MyFuture::value<core::int*>(3)) as{TypeError} FutureOr<core::int*>*;
|
||||
});
|
||||
self::MyFuture<core::int*>* t5 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → FutureOr<core::int*>* => (x ?{core::Object*} 2 : new self::MyFuture::value<core::int*>(3)) as{TypeError} FutureOr<core::int*>*);
|
||||
|
|
|
@ -71,7 +71,7 @@ static method test() → void {
|
|||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
});
|
||||
self::MyFuture<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* /* originally async */ {
|
||||
self::MyFuture<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::bool* x) → FutureOr<core::int*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<core::int*>* :async_completer = new asy::_AsyncAwaitCompleter::•<core::int*>();
|
||||
FutureOr<core::int*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
|
|
|
@ -20,7 +20,7 @@ void test() {
|
|||
/*@ returnType=Future<int*>* */ (/*@ type=bool* */ x) async =>
|
||||
x ? 2 : await new MyFuture<int>.value(3));
|
||||
Future<int> t2 = f. /*@ typeArgs=int* */ /*@target=Future.then*/ then(
|
||||
/*@ returnType=Future<int*>* */ (/*@ type=bool* */ x) async {
|
||||
/*@returnType=FutureOr<int*>*/ (/*@ type=bool* */ x) async {
|
||||
return /*info:DOWN_CAST_COMPOSITE*/ await x
|
||||
? 2
|
||||
: new MyFuture<int>.value(3);
|
||||
|
|
|
@ -35,7 +35,7 @@ class MyFuture<T extends core::Object* = dynamic> extends core::Object implement
|
|||
static method test() → void {
|
||||
asy::Future<core::bool*>* f;
|
||||
asy::Future<core::int*>* t1 = f.{asy::Future::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* async => x ?{core::int*} 2 : await new self::MyFuture::value<core::int*>(3));
|
||||
asy::Future<core::int*>* t2 = f.{asy::Future::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* async {
|
||||
asy::Future<core::int*>* t2 = f.{asy::Future::then}<core::int*>((core::bool* x) → FutureOr<core::int*> async {
|
||||
return (await x ?{core::Object*} 2 : new self::MyFuture::value<core::int*>(3)) as{TypeError} FutureOr<core::int*>*;
|
||||
});
|
||||
asy::Future<core::int*>* t5 = f.{asy::Future::then}<core::int*>((core::bool* x) → FutureOr<core::int*> => (x ?{core::Object*} 2 : new self::MyFuture::value<core::int*>(3)) as{TypeError} FutureOr<core::int*>);
|
||||
|
|
|
@ -71,7 +71,7 @@ static method test() → void {
|
|||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
});
|
||||
asy::Future<core::int*>* t2 = f.{asy::Future::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* /* originally async */ {
|
||||
asy::Future<core::int*>* t2 = f.{asy::Future::then}<core::int*>((core::bool* x) → FutureOr<core::int*> /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<core::int*>* :async_completer = new asy::_AsyncAwaitCompleter::•<core::int*>();
|
||||
FutureOr<core::int*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
|
|
|
@ -20,7 +20,7 @@ void test() {
|
|||
/*@ returnType=Future<int*>* */ (/*@ type=bool* */ x) async =>
|
||||
x ? 2 : await new Future<int>.value(3));
|
||||
Future<int> t2 = f. /*@ typeArgs=int* */ /*@target=Future.then*/ then(
|
||||
/*@ returnType=Future<int*>* */ (/*@ type=bool* */ x) async {
|
||||
/*@returnType=FutureOr<int*>*/ (/*@ type=bool* */ x) async {
|
||||
return /*info:DOWN_CAST_COMPOSITE*/ await x ? 2 : new Future<int>.value(3);
|
||||
});
|
||||
Future<int> t5 = f. /*@ typeArgs=int* */ /*@target=Future.then*/ then(
|
||||
|
|
|
@ -35,7 +35,7 @@ class MyFuture<T extends core::Object* = dynamic> extends core::Object implement
|
|||
static method test() → void {
|
||||
asy::Future<core::bool*>* f;
|
||||
asy::Future<core::int*>* t1 = f.{asy::Future::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* async => x ?{core::int*} 2 : await asy::Future::value<core::int*>(3));
|
||||
asy::Future<core::int*>* t2 = f.{asy::Future::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* async {
|
||||
asy::Future<core::int*>* t2 = f.{asy::Future::then}<core::int*>((core::bool* x) → FutureOr<core::int*> async {
|
||||
return (await x ?{core::Object*} 2 : asy::Future::value<core::int*>(3)) as{TypeError} FutureOr<core::int*>*;
|
||||
});
|
||||
asy::Future<core::int*>* t5 = f.{asy::Future::then}<core::int*>((core::bool* x) → FutureOr<core::int*> => (x ?{core::Object*} 2 : asy::Future::value<core::int*>(3)) as{TypeError} FutureOr<core::int*>);
|
||||
|
|
|
@ -71,7 +71,7 @@ static method test() → void {
|
|||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
});
|
||||
asy::Future<core::int*>* t2 = f.{asy::Future::then}<core::int*>((core::bool* x) → asy::Future<core::int*>* /* originally async */ {
|
||||
asy::Future<core::int*>* t2 = f.{asy::Future::then}<core::int*>((core::bool* x) → FutureOr<core::int*> /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<core::int*>* :async_completer = new asy::_AsyncAwaitCompleter::•<core::int*>();
|
||||
FutureOr<core::int*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
|
|
|
@ -20,7 +20,7 @@ void test() {
|
|||
/*@ returnType=Future<int*>* */ (/*@ type=int* */ x) async =>
|
||||
x /*@target=num.==*/ ?? await new Future<int>.value(3));
|
||||
Future<int> t2 = f. /*@ typeArgs=int* */ /*@target=MyFuture.then*/ then(
|
||||
/*@ returnType=Future<int*>* */ (/*@ type=int* */ x) async {
|
||||
/*@returnType=FutureOr<int*>**/ (/*@ type=int* */ x) async {
|
||||
return /*info:DOWN_CAST_COMPOSITE*/ await x /*@target=num.==*/ ??
|
||||
new Future<int>.value(3);
|
||||
});
|
||||
|
|
|
@ -35,7 +35,7 @@ class MyFuture<T extends core::Object* = dynamic> extends core::Object implement
|
|||
static method test() → void {
|
||||
self::MyFuture<core::int*>* f;
|
||||
asy::Future<core::int*>* t1 = f.{self::MyFuture::then}<core::int*>((core::int* x) → asy::Future<core::int*>* async => let final core::int* #t1 = x in #t1.{core::num::==}(null) ?{core::int*} await asy::Future::value<core::int*>(3) : #t1);
|
||||
asy::Future<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::int* x) → asy::Future<core::int*>* async {
|
||||
asy::Future<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::int* x) → FutureOr<core::int*>* async {
|
||||
return (let final core::int* #t2 = await x in #t2.{core::num::==}(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t2) as{TypeError} FutureOr<core::int*>*;
|
||||
});
|
||||
asy::Future<core::int*>* t5 = f.{self::MyFuture::then}<core::int*>((core::int* x) → FutureOr<core::int*>* => (let final core::int* #t3 = x in #t3.{core::num::==}(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t3) as{TypeError} FutureOr<core::int*>*);
|
||||
|
|
|
@ -72,7 +72,7 @@ static method test() → void {
|
|||
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
|
||||
return :async_completer.{asy::Completer::future};
|
||||
});
|
||||
asy::Future<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::int* x) → asy::Future<core::int*>* /* originally async */ {
|
||||
asy::Future<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::int* x) → FutureOr<core::int*>* /* originally async */ {
|
||||
final asy::_AsyncAwaitCompleter<core::int*>* :async_completer = new asy::_AsyncAwaitCompleter::•<core::int*>();
|
||||
FutureOr<core::int*>* :return_value;
|
||||
dynamic :async_stack_trace;
|
||||
|
|
Loading…
Reference in a new issue