Skip to content

Commit d113b4a

Browse files
committed
[CSApply] Refactor ExprRewriter to handle @autoclosure from parameter flag
1 parent a1df238 commit d113b4a

File tree

4 files changed

+75
-97
lines changed

4 files changed

+75
-97
lines changed

lib/Sema/CSApply.cpp

Lines changed: 35 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -4370,11 +4370,6 @@ namespace {
43704370

43714371
auto dc = subscript->getInnermostDeclContext();
43724372

4373-
// FIXME: It's not correct to turn the subscript's parameter list
4374-
// into a single type here. Further down we pass it to coerceToType(),
4375-
// but the rules for argument list conversions are different than
4376-
// tuple conversions, and coerceToType() doesn't handle varargs or
4377-
// default arguments.
43784373
auto indexType = AnyFunctionType::composeInput(
43794374
cs.TC.Context,
43804375
subscript->getInterfaceType()
@@ -4409,19 +4404,18 @@ namespace {
44094404
/*trailingClosure*/nullptr);
44104405
cs.setType(origComponent.getIndexExpr(), index->getType());
44114406
}
4412-
4413-
auto resolvedTy = foundDecl->openedType->castTo<AnyFunctionType>()
4414-
->getResult();
4415-
4416-
resolvedTy = simplifyType(resolvedTy);
4417-
4407+
4408+
auto subscriptType =
4409+
simplifyType(foundDecl->openedType)->castTo<AnyFunctionType>();
4410+
auto resolvedTy = subscriptType->getResult();
44184411
auto ref = ConcreteDeclRef(subscript, subs);
4419-
4412+
44204413
// Coerce the indices to the type the subscript expects.
4421-
auto indexExpr = coerceToType(origComponent.getIndexExpr(),
4422-
indexType,
4423-
locator);
4424-
4414+
auto indexExpr = coerceCallArguments(
4415+
origComponent.getIndexExpr(), subscriptType,
4416+
/*applyExpr*/ nullptr, origComponent.getSubscriptLabels(),
4417+
/* hasTrailingClosure */ false, locator);
4418+
44254419
component = KeyPathExpr::Component
44264420
::forSubscriptWithPrebuiltIndexExpr(ref, indexExpr,
44274421
origComponent.getSubscriptLabels(),
@@ -5645,9 +5639,29 @@ Expr *ExprRewriter::coerceCallArguments(
56455639
continue;
56465640
}
56475641

5648-
// Convert the argument.
5649-
auto convertedArg = coerceToType(arg, paramType,
5650-
getArgLocator(argIdx, paramIdx));
5642+
Expr *convertedArg = nullptr;
5643+
5644+
// Since it was allowed to pass function types to @autoclosure
5645+
// parameters in Swift versions < 5, it has to be handled as
5646+
// a regular function coversion by `coerceToType`.
5647+
if (param.isAutoClosure() && !argType->is<FunctionType>()) {
5648+
// If parameter is an autoclosure, we need to make sure that:
5649+
// - argument type is coerced to parameter result type
5650+
// - impilict autoclosure is created to wrap argument expression
5651+
// - new types are propagated to constraint system
5652+
auto *closureType = param.getPlainType()->castTo<FunctionType>();
5653+
5654+
arg = coerceToType(
5655+
arg, closureType->getResult(),
5656+
locator.withPathElement(ConstraintLocator::AutoclosureResult));
5657+
5658+
convertedArg = cs.TC.buildAutoClosureExpr(dc, arg, closureType);
5659+
cs.cacheExprTypes(convertedArg);
5660+
} else {
5661+
convertedArg =
5662+
coerceToType(arg, paramType, getArgLocator(argIdx, paramIdx));
5663+
}
5664+
56515665
if (!convertedArg)
56525666
return nullptr;
56535667

@@ -6536,59 +6550,10 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
65366550
isInDefaultArgumentContext = (initalizerCtx->getInitializerKind() ==
65376551
InitializerKind::DefaultArgument);
65386552
auto toEI = toFunc->getExtInfo();
6539-
6540-
auto fromFunc = fromType->getAs<FunctionType>();
6541-
6542-
// Coercion to an autoclosure type produces an implicit closure.
6543-
// The constraint solver only performs this conversion when the source
6544-
// type is not an autoclosure function type. That's a weird rule in
6545-
// some rules, but it's easy to follow here. Really we just shouldn't
6546-
// represent autoclosures as a bit on function types.
6547-
// FIXME: The type checker is more lenient, and allows @autoclosures to
6548-
// be subtypes of non-@autoclosures, which is bogus.
6549-
if (toFunc->isAutoClosure() &&
6550-
(!fromFunc || !fromFunc->isAutoClosure())) {
6551-
// The function type without @noescape if we are in the default argument
6552-
// context.
6553-
auto newToFuncType = toFunc;
6554-
6555-
// Remove the noescape attribute so that we can apply a separate function
6556-
// conversion instruction if we are in a default argument context.
6557-
if (isInDefaultArgumentContext && toEI.isNoEscape())
6558-
newToFuncType = toFunc->withExtInfo(toEI.withNoEscape(false))
6559-
->castTo<FunctionType>();
6560-
6561-
// Convert the value to the expected result type of the function.
6562-
expr = coerceToType(
6563-
expr, toFunc->getResult(),
6564-
locator.withPathElement(ConstraintLocator::AutoclosureResult));
6565-
6566-
// We'll set discriminator values on all the autoclosures in a
6567-
// later pass.
6568-
auto discriminator = AutoClosureExpr::InvalidDiscriminator;
6569-
auto closure = cs.cacheType(new (tc.Context) AutoClosureExpr(
6570-
expr, newToFuncType, discriminator, dc));
6571-
closure->setParameterList(ParameterList::createEmpty(tc.Context));
6572-
6573-
// Compute the capture list, now that we have analyzed the expression.
6574-
tc.ClosuresWithUncomputedCaptures.push_back(closure);
6575-
6576-
// Apply the noescape conversion.
6577-
if (!newToFuncType->isEqual(toFunc)) {
6578-
assert(isInDefaultArgumentContext);
6579-
assert(newToFuncType
6580-
->withExtInfo(newToFuncType->getExtInfo().withNoEscape(true))
6581-
->isEqual(toFunc));
6582-
return cs.cacheType(new (tc.Context)
6583-
FunctionConversionExpr(closure, toFunc));
6584-
}
6585-
6586-
return closure;
6587-
}
6588-
65896553
// Coercion from one function type to another, this produces a
65906554
// FunctionConversionExpr in its full generality.
6591-
if (fromFunc) {
6555+
if (auto fromFunc = fromType->getAs<FunctionType>()) {
6556+
assert(toType->is<FunctionType>());
65926557
// If we have a ClosureExpr, then we can safely propagate the 'no escape'
65936558
// bit to the closure without invalidating prior analysis.
65946559
auto fromEI = fromFunc->getExtInfo();

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2093,33 +2093,8 @@ Type TypeChecker::typeCheckParameterDefault(Expr *&defaultValue,
20932093
Expr *appliedSolution(constraints::Solution &solution,
20942094
Expr *expr) override {
20952095
auto &cs = solution.getConstraintSystem();
2096-
auto &ctx = cs.getASTContext();
2097-
2098-
bool isInDefaultArgumentContext = isInDefaultArgContext();
2099-
2100-
auto paramInfo = ParamType->getExtInfo();
2101-
auto newParamType = ParamType;
2102-
2103-
if (isInDefaultArgumentContext && paramInfo.isNoEscape())
2104-
newParamType = ParamType->withExtInfo(paramInfo.withNoEscape(false))
2105-
->castTo<FunctionType>();
2106-
2107-
auto *closure = cs.cacheType(new (ctx) AutoClosureExpr(
2108-
expr, newParamType, AutoClosureExpr::InvalidDiscriminator, DC));
2109-
closure->setParameterList(ParameterList::createEmpty(ctx));
2110-
2111-
cs.TC.ClosuresWithUncomputedCaptures.push_back(closure);
2112-
2113-
if (!newParamType->isEqual(ParamType)) {
2114-
assert(isInDefaultArgumentContext);
2115-
assert(
2116-
newParamType
2117-
->withExtInfo(newParamType->getExtInfo().withNoEscape(true))
2118-
->isEqual(ParamType));
2119-
return cs.cacheType(new (ctx)
2120-
FunctionConversionExpr(closure, ParamType));
2121-
}
2122-
2096+
auto *closure = cs.TC.buildAutoClosureExpr(DC, expr, ParamType);
2097+
cs.cacheExprTypes(closure);
21232098
return closure;
21242099
}
21252100

lib/Sema/TypeCheckExpr.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/AST/NameLookup.h"
2020
#include "swift/AST/Decl.h"
2121
#include "swift/AST/Initializer.h"
22+
#include "swift/AST/ParameterList.h"
2223
#include "swift/Parse/Lexer.h"
2324
using namespace swift;
2425

@@ -539,6 +540,38 @@ Expr *TypeChecker::buildRefExpr(ArrayRef<ValueDecl *> Decls,
539540
return result;
540541
}
541542

543+
Expr *TypeChecker::buildAutoClosureExpr(DeclContext *DC, Expr *expr,
544+
FunctionType *closureType) {
545+
bool isInDefaultArgumentContext = false;
546+
if (auto *init = dyn_cast<Initializer>(DC))
547+
isInDefaultArgumentContext =
548+
init->getInitializerKind() == InitializerKind::DefaultArgument;
549+
550+
auto info = closureType->getExtInfo();
551+
auto newClosureType = closureType;
552+
553+
if (isInDefaultArgumentContext && info.isNoEscape())
554+
newClosureType = closureType->withExtInfo(info.withNoEscape(false))
555+
->castTo<FunctionType>();
556+
557+
auto *closure = new (Context) AutoClosureExpr(
558+
expr, newClosureType, AutoClosureExpr::InvalidDiscriminator, DC);
559+
560+
closure->setParameterList(ParameterList::createEmpty(Context));
561+
562+
ClosuresWithUncomputedCaptures.push_back(closure);
563+
564+
if (!newClosureType->isEqual(closureType)) {
565+
assert(isInDefaultArgumentContext);
566+
assert(newClosureType
567+
->withExtInfo(newClosureType->getExtInfo().withNoEscape(true))
568+
->isEqual(closureType));
569+
return new (Context) FunctionConversionExpr(closure, closureType);
570+
}
571+
572+
return closure;
573+
}
574+
542575
static Type lookupDefaultLiteralType(TypeChecker &TC, DeclContext *dc,
543576
StringRef name) {
544577
auto lookupOptions = defaultUnqualifiedLookupOptions;

lib/Sema/TypeChecker.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,6 +1906,11 @@ class TypeChecker final : public LazyResolver {
19061906
Expr *buildRefExpr(ArrayRef<ValueDecl *> Decls, DeclContext *UseDC,
19071907
DeclNameLoc NameLoc, bool Implicit,
19081908
FunctionRefKind functionRefKind);
1909+
1910+
/// Build implicit autoclosure expression wrapping a given expression.
1911+
/// Given expression represents computed result of the closure.
1912+
Expr *buildAutoClosureExpr(DeclContext *DC, Expr *expr,
1913+
FunctionType *closureType);
19091914
/// @}
19101915

19111916
/// \brief Retrieve a specific, known protocol.

0 commit comments

Comments
 (0)