Skip to content

Commit

Permalink
[cfe] Refactor FunctionNode.futureValueType into emitted value type
Browse files Browse the repository at this point in the history
Previously we would encode the type of the value returned in `async`
functions as the field `futureValueType` on `FunctionNode`. For all
other kinds of functions, such as `sync`, `sync*`, and `async*`, that
field would be null. This CL renames `futureValueType` into
`emittedVAlueType`, and for functions of kinds `async`, `sync*`, and
`async*` that is expected to be the type of values emitted via
`return` or `yield` statements. For `sync` functions that field is
supposed to contain `null`.

In response to #54159

TEST=existing

Change-Id: I1efdbcc4e75d150f5618c7ca50cfe49a0e54fce6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/341662
Reviewed-by: Alexander Markov <[email protected]>
Reviewed-by: Johnni Winther <[email protected]>
Reviewed-by: Ömer Ağacan <[email protected]>
Commit-Queue: Chloe Stefantsova <[email protected]>
Reviewed-by: Mayank Patke <[email protected]>
  • Loading branch information
chloestefantsova authored and Commit Queue committed Dec 19, 2023
1 parent 8d8c4c6 commit 3eeba4a
Show file tree
Hide file tree
Showing 755 changed files with 2,289 additions and 2,266 deletions.
2 changes: 1 addition & 1 deletion pkg/compiler/lib/src/ir/impact_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ class ImpactBuilder extends StaticTypeVisitor implements ImpactRegistry {
break;

case ir.AsyncMarker.Async:
registerAsync(function.futureValueType!);
registerAsync(function.emittedValueType!);
break;

case ir.AsyncMarker.AsyncStar:
Expand Down
2 changes: 1 addition & 1 deletion pkg/compiler/lib/src/js_model/element_map_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2254,7 +2254,7 @@ class JsElementEnvironment extends ElementEnvironment
return _getSyncStarElementType(returnType);
case AsyncMarker.ASYNC:
return elementMap.getDartType(
getFunctionNode(elementMap, function)!.futureValueType!);
getFunctionNode(elementMap, function)!.emittedValueType!);
case AsyncMarker.ASYNC_STAR:
return _getAsyncStarElementType(returnType);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class AsyncLowering {

bool _shouldTryAsyncLowering(FunctionNode node) =>
node.asyncMarker == AsyncMarker.Async &&
node.futureValueType != null &&
node.emittedValueType != null &&
_functions.last.shouldLower;

void enterFunction(FunctionNode node) {
Expand All @@ -54,7 +54,7 @@ class AsyncLowering {

void _wrapBodySync(FunctionNode node) {
node.asyncMarker = AsyncMarker.Sync;
final futureValueType = node.futureValueType!;
final futureValueType = node.emittedValueType!;
_updateFunctionBody(
node,
ReturnStatement(StaticInvocation(
Expand All @@ -69,7 +69,7 @@ class AsyncLowering {
}

void _wrapReturns(_FunctionData functionData, FunctionNode node) {
final futureValueType = node.futureValueType!;
final futureValueType = node.emittedValueType!;
for (final returnStatement in functionData.returnStatements) {
final expression = returnStatement.expression;
// Ensure the returned future has a runtime type (T) matching the
Expand Down
4 changes: 2 additions & 2 deletions pkg/dart2wasm/lib/transformers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ class _WasmTransformer extends Transformer {
_addCompleterToController(controller, completer, fileOffset)),
tryFinally,
]),
futureValueType: const VoidType(),
emittedValueType: const VoidType(),
returnType: InterfaceType(
coreTypes.futureClass, Nullability.nonNullable, [const VoidType()]),
asyncMarker: AsyncMarker.Async,
Expand Down Expand Up @@ -544,7 +544,7 @@ class _WasmTransformer extends Transformer {
coreTypes.objectNullableRawType, Nullability.nonNullable),
asyncMarker: AsyncMarker.Async,
dartAsyncMarker: AsyncMarker.Async,
futureValueType: coreTypes.objectNullableRawType,
emittedValueType: coreTypes.objectNullableRawType,
));

// Call `asyncMap`.
Expand Down
2 changes: 1 addition & 1 deletion pkg/dev_compiler/lib/src/kernel/compiler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4192,7 +4192,7 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
// In the body of an `async`, `await` is generated simply as `yield`.
var gen = emitGeneratorFn((_) => []);
var returnType = _currentLibrary!.isNonNullableByDefault
? function.futureValueType!
? function.emittedValueType!
// Otherwise flatten the return type because futureValueType(T) is not
// defined for legacy libraries.
: _types.flatten(function
Expand Down
8 changes: 3 additions & 5 deletions pkg/front_end/lib/src/fasta/kernel/body_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1305,11 +1305,9 @@ class BodyBuilder extends StackListenerImpl
asyncModifier,
body);
body = inferredFunctionBody.body;
function.futureValueType = inferredFunctionBody.futureValueType;
assert(
!(function.asyncMarker == AsyncMarker.Async &&
function.futureValueType == null),
"No future value type computed.");
function.emittedValueType = inferredFunctionBody.emittedValueType;
assert(function.asyncMarker == AsyncMarker.Sync ||
function.emittedValueType != null);
}

if (_context.returnType is! OmittedTypeBuilder) {
Expand Down
72 changes: 45 additions & 27 deletions pkg/front_end/lib/src/fasta/type_inference/closure_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ abstract class ClosureContext {
/// the unknown type.
DartType get yieldContext;

DartType? get futureValueType;
DartType? get emittedValueType;

factory ClosureContext(InferenceVisitorBase inferrer, AsyncMarker asyncMarker,
DartType returnContext, bool needToInferReturnType) {
Expand Down Expand Up @@ -142,6 +142,9 @@ class _SyncClosureContext implements ClosureContext {
@override
DartType get yieldContext => const UnknownType();

@override
DartType? get emittedValueType => null;

final DartType _declaredReturnType;

final bool _needToInferReturnType;
Expand All @@ -161,9 +164,6 @@ class _SyncClosureContext implements ClosureContext {
/// being inferred.
List<DartType>? _returnExpressionTypes;

@override
DartType? get futureValueType => null;

_SyncClosureContext(this.inferrer, this._returnContext,
this._declaredReturnType, this._needToInferReturnType) {
if (_needToInferReturnType) {
Expand Down Expand Up @@ -493,6 +493,9 @@ class _AsyncClosureContext implements ClosureContext {
@override
DartType get yieldContext => const UnknownType();

@override
DartType? emittedValueType;

final DartType _declaredReturnType;

final bool _needToInferReturnType;
Expand All @@ -512,15 +515,12 @@ class _AsyncClosureContext implements ClosureContext {
/// being inferred.
List<DartType>? _returnExpressionTypes;

@override
DartType? futureValueType;

_AsyncClosureContext(
this.inferrer,
this._returnContext,
this._declaredReturnType,
this._needToInferReturnType,
this.futureValueType) {
this.emittedValueType) {
if (_needToInferReturnType) {
_returnStatements = [];
_returnExpressionTypes = [];
Expand All @@ -531,14 +531,14 @@ class _AsyncClosureContext implements ClosureContext {
DartType returnType, ReturnStatement statement, DartType expressionType) {
if (inferrer.isNonNullableByDefault) {
assert(
futureValueType != null, "Future value type has not been computed.");
emittedValueType != null, "Future value type has not been computed.");

if (statement.expression == null) {
// It is a compile-time error if s is `return;`, unless T_v is void,
// dynamic, or Null.
if (futureValueType is VoidType ||
futureValueType is DynamicType ||
futureValueType is NullType) {
if (emittedValueType is VoidType ||
emittedValueType is DynamicType ||
emittedValueType is NullType) {
// Valid return;
} else {
statement.expression = inferrer.helper.wrapInProblem(
Expand All @@ -560,7 +560,7 @@ class _AsyncClosureContext implements ClosureContext {

DartType flattenedExpressionType =
inferrer.typeSchemaEnvironment.flatten(expressionType);
if (futureValueType is VoidType &&
if (emittedValueType is VoidType &&
!(flattenedExpressionType is VoidType ||
flattenedExpressionType is DynamicType ||
flattenedExpressionType is NullType)) {
Expand All @@ -573,8 +573,8 @@ class _AsyncClosureContext implements ClosureContext {
statement.expression!.fileOffset,
noLength)
..parent = statement;
} else if (!(futureValueType is VoidType ||
futureValueType is DynamicType) &&
} else if (!(emittedValueType is VoidType ||
emittedValueType is DynamicType) &&
flattenedExpressionType is VoidType) {
// It is a compile-time error if s is `return e;`, T_v is neither void
// nor dynamic, and flatten(S) is void.
Expand All @@ -588,13 +588,13 @@ class _AsyncClosureContext implements ClosureContext {
} else if (flattenedExpressionType is! VoidType &&
!inferrer.typeSchemaEnvironment
.performNullabilityAwareSubtypeCheck(
flattenedExpressionType, futureValueType!)
flattenedExpressionType, emittedValueType!)
.isSubtypeWhenUsingNullabilities()) {
// It is a compile-time error if s is `return e;`, flatten(S) is not
// void, S is not assignable to T_v, and flatten(S) is not a subtype
// of T_v.
statement.expression = inferrer.ensureAssignable(
futureValueType!, expressionType, statement.expression!,
emittedValueType!, expressionType, statement.expression!,
fileOffset: statement.expression!.fileOffset,
runtimeCheckedType:
inferrer.computeGreatestClosure2(_returnContext),
Expand Down Expand Up @@ -831,10 +831,10 @@ class _AsyncClosureContext implements ClosureContext {
}

if (inferrer.isNonNullableByDefault) {
futureValueType =
emittedValueType =
computeFutureValueType(inferrer.coreTypes, inferredType);
} else {
futureValueType = inferrer.typeSchemaEnvironment.flatten(inferredType);
emittedValueType = inferrer.typeSchemaEnvironment.flatten(inferredType);
}

for (int i = 0; i < _returnStatements!.length; ++i) {
Expand Down Expand Up @@ -915,21 +915,25 @@ class _SyncStarClosureContext implements ClosureContext {
@override
DartType get yieldContext => _yieldElementContext;

@override
DartType? get emittedValueType => _emittedValueType;

final DartType _declaredReturnType;

DartType? _emittedValueType;

final bool _needToInferReturnType;

/// A list of return expression types in functions whose return type is
/// being inferred.
List<DartType>? _yieldElementTypes;

@override
DartType? get futureValueType => null;

_SyncStarClosureContext(this.inferrer, this._yieldElementContext,
this._declaredReturnType, this._needToInferReturnType) {
if (_needToInferReturnType) {
_yieldElementTypes = [];
} else {
_emittedValueType = inferrer.computeGreatestClosure(_yieldElementContext);
}
}

Expand Down Expand Up @@ -1009,8 +1013,13 @@ class _SyncStarClosureContext implements ClosureContext {
inferredType = inferrer.computeGreatestClosure2(_declaredReturnType);
}

return demoteTypeInLibrary(inferredType,
DartType demotedType = demoteTypeInLibrary(inferredType,
isNonNullableByDefault: inferrer.isNonNullableByDefault);
_emittedValueType = inferrer.getTypeArgumentOf(
inferrer.typeSchemaEnvironment.getUnionFreeType(demotedType,
isNonNullableByDefault: inferrer.isNonNullableByDefault),
inferrer.coreTypes.iterableClass);
return demotedType;
}

@override
Expand Down Expand Up @@ -1050,21 +1059,25 @@ class _AsyncStarClosureContext implements ClosureContext {
@override
DartType get yieldContext => _yieldElementContext;

@override
DartType? get emittedValueType => _emittedValueType;

final DartType _declaredReturnType;

DartType? _emittedValueType;

final bool _needToInferReturnType;

/// A list of return expression types in functions whose return type is
/// being inferred.
List<DartType>? _yieldElementTypes;

@override
DartType? get futureValueType => null;

_AsyncStarClosureContext(this.inferrer, this._yieldElementContext,
this._declaredReturnType, this._needToInferReturnType) {
if (_needToInferReturnType) {
_yieldElementTypes = [];
} else {
_emittedValueType = inferrer.computeGreatestClosure(_yieldElementContext);
}
}

Expand Down Expand Up @@ -1142,8 +1155,13 @@ class _AsyncStarClosureContext implements ClosureContext {
inferredType = inferrer.computeGreatestClosure2(_declaredReturnType);
}

return demoteTypeInLibrary(inferredType,
DartType demotedType = demoteTypeInLibrary(inferredType,
isNonNullableByDefault: inferrer.isNonNullableByDefault);
_emittedValueType = inferrer.getTypeArgumentOf(
inferrer.typeSchemaEnvironment.getUnionFreeType(demotedType,
isNonNullableByDefault: inferrer.isNonNullableByDefault),
inferrer.coreTypes.streamClass);
return demotedType;
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2326,11 +2326,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
}
bodyResult = closureContext.handleImplicitReturn(
this, function.body!, bodyResult, fileOffset);
function.futureValueType = closureContext.futureValueType;
assert(
!(function.asyncMarker == AsyncMarker.Async &&
function.futureValueType == null),
"No future value type computed.");
function.emittedValueType = closureContext.emittedValueType;

if (bodyResult.hasChanged) {
function.body = bodyResult.statement..parent = function;
Expand Down Expand Up @@ -3778,7 +3774,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {

/// Computes the `futureValueTypeSchema` for the type schema [type].
///
/// This is the same as the [futureValueType] except that this handles
/// This is the same as the [emittedValueType] except that this handles
/// the unknown type.
DartType computeFutureValueTypeSchema(DartType type) {
return type.accept1(new FutureValueTypeVisitor(unhandledTypeHandler:
Expand Down
11 changes: 5 additions & 6 deletions pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,11 @@ class TypeInferrerImpl implements TypeInferrer {
result =
closureContext.handleImplicitReturn(visitor, body, result, fileOffset);
visitor.checkCleanState();
DartType? futureValueType = closureContext.futureValueType;
assert(!(asyncMarker == AsyncMarker.Async && futureValueType == null),
"No future value type computed.");
DartType? emittedValueType = closureContext.emittedValueType;
assert(asyncMarker == AsyncMarker.Sync || emittedValueType != null);
flowAnalysis.finish();
return new InferredFunctionBody(
result.hasChanged ? result.statement : body, futureValueType);
result.hasChanged ? result.statement : body, emittedValueType);
}

@override
Expand Down Expand Up @@ -432,7 +431,7 @@ class TypeInferrerImplBenchmarked implements TypeInferrer {

class InferredFunctionBody {
final Statement body;
final DartType? futureValueType;
final DartType? emittedValueType;

InferredFunctionBody(this.body, this.futureValueType);
InferredFunctionBody(this.body, this.emittedValueType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ macro class MethodMacro extends core::Object implements api::ClassDeclarationsMa
: super core::Object::•()
;
@#C2
method buildDeclarationsForClass(api::ClassDeclaration clazz, api::MemberDeclarationBuilder builder) → FutureOr<void> async /* futureValueType= void */ {}
method buildDeclarationsForClass(api::ClassDeclaration clazz, api::MemberDeclarationBuilder builder) → FutureOr<void> async /* emittedValueType= void */ {}
}

library;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ macro class MethodMacro extends core::Object implements api::ClassDeclarationsMa
: super core::Object::•()
;
@#C2
method buildDeclarationsForClass(api::ClassDeclaration clazz, api::MemberDeclarationBuilder builder) → FutureOr<void> async /* futureValueType= void */ {
method buildDeclarationsForClass(api::ClassDeclaration clazz, api::MemberDeclarationBuilder builder) → FutureOr<void> async /* emittedValueType= void */ {
builder.{api::MemberDeclarationBuilder::declareInType}(new api::DeclarationCode::fromString(mac2::generateBody())){(api::DeclarationCode) → void};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ macro class MethodMacro extends core::Object implements api::ClassDeclarationsMa
: super core::Object::•()
;
@#C2
method buildDeclarationsForClass(api::ClassDeclaration clazz, api::MemberDeclarationBuilder builder) → FutureOr<void> async /* futureValueType= void */ {
method buildDeclarationsForClass(api::ClassDeclaration clazz, api::MemberDeclarationBuilder builder) → FutureOr<void> async /* emittedValueType= void */ {
builder.{api::MemberDeclarationBuilder::declareInType}(new api::DeclarationCode::fromString(mac2::generateBody())){(api::DeclarationCode) → void};
}
}
Expand Down
Loading

0 comments on commit 3eeba4a

Please sign in to comment.