Skip to content

CSGen: Infer generic arguments for explicit closure result types #33663

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 28 additions & 38 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2062,48 +2062,38 @@ namespace {
// parameter or return type is omitted, a fresh type variable is used to
// stand in for that parameter or return type, allowing it to be inferred
// from context.
auto getExplicitResultType = [&]() -> Type {
if (!closure->hasExplicitResultType()) {
return Type();
}
Type resultTy = [&] {
if (closure->hasExplicitResultType()) {
if (auto declaredTy = closure->getExplicitResultType()) {
return declaredTy;
}

if (auto declaredTy = closure->getExplicitResultType()) {
return declaredTy;
const auto resolvedTy = resolveTypeReferenceInExpression(
closure->getExplicitResultTypeRepr(),
TypeResolverContext::InExpression,
// Introduce type variables for unbound generics.
OpenUnboundGenericType(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please split this into two commits - first one to add OpenUnboundGenericType to the original code which is an actual functionality change here and second which does this resultTy refactoring?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Easy

CS, CS.getConstraintLocator(
closure, ConstraintLocator::ClosureResult)));
if (resolvedTy)
return resolvedTy;
}

return resolveTypeReferenceInExpression(
closure->getExplicitResultTypeRepr(),
TypeResolverContext::InExpression, nullptr);
};

Type resultTy;
auto *resultLoc =
CS.getConstraintLocator(closure, ConstraintLocator::ClosureResult);
if (auto explicityTy = getExplicitResultType()) {
resultTy = explicityTy;
} else {
auto getContextualResultType = [&]() -> Type {
if (auto contextualType = CS.getContextualType(closure)) {
if (auto fnType = contextualType->getAs<FunctionType>())
return fnType->getResult();
}
return Type();
};

if (auto contextualResultTy = getContextualResultType()) {
resultTy = contextualResultTy;
} else {
// If no return type was specified, create a fresh type
// variable for it and mark it as possible hole.
//
// If this is a multi-statement closure, let's mark result
// as potential hole right away.
resultTy = CS.createTypeVariable(
resultLoc,
shouldTypeCheckInEnclosingExpression(closure)
? 0 : TVO_CanBindToHole);
if (auto contextualType = CS.getContextualType(closure)) {
if (auto fnType = contextualType->getAs<FunctionType>())
return fnType->getResult();
}
}

// If no return type was specified, create a fresh type
// variable for it and mark it as possible hole.
//
// If this is a multi-statement closure, let's mark result
// as potential hole right away.
return Type(CS.createTypeVariable(
CS.getConstraintLocator(closure, ConstraintLocator::ClosureResult),
shouldTypeCheckInEnclosingExpression(closure) ? 0
: TVO_CanBindToHole));
}();

return FunctionType::get(closureParams, resultTy, extInfo);
}
Expand Down
12 changes: 12 additions & 0 deletions test/Constraints/closures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1030,3 +1030,15 @@ func sr12815() {
.doesntExist2() { $0 }
}
}

// Make sure we can infer generic arguments in an explicit result type.
let explicitUnboundResult1 = { () -> Array in [0] }
let explicitUnboundResult2: (Array<Bool>) -> Array<Int> = {
(arr: Array) -> Array in [0]
}
// FIXME: Should we prioritize the contextual result type and infer Array<Int>
// rather than using a type variable in these cases?
// expected-error@+1 {{unable to infer closure type in the current context}}
let explicitUnboundResult3: (Array<Bool>) -> Array<Int> = {
(arr: Array) -> Array in [true]
}