Merge pull request #24615 from xedin/fix-autoclj-returning-fn-type

[ConstraintSystem] Allow arguments to be passed by value to `@autoclo…
This commit is contained in:
Pavel Yaskevich
2019-05-09 00:48:53 -07:00
committed by GitHub
7 changed files with 123 additions and 52 deletions

View File

@@ -973,30 +973,6 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
auto *anchor = locator.getAnchor();
assert(anchor && "locator without anchor expression?");
// Check whether argument of the call at given position refers to
// parameter marked as `@autoclosure`. This function is used to
// maintain source compatibility with Swift versions < 5,
// previously examples like following used to type-check:
//
// func foo(_ x: @autoclosure () -> Int) {}
// func bar(_ y: @autoclosure () -> Int) {
// foo(y)
// }
auto isAutoClosureArg = [&](Expr *anchor, unsigned argIdx) -> bool {
assert(anchor);
auto *argExpr = getArgumentExpr(anchor, argIdx);
if (!argExpr)
return false;
if (auto *DRE = dyn_cast<DeclRefExpr>(argExpr)) {
if (auto *param = dyn_cast<ParamDecl>(DRE->getDecl()))
return param->isAutoClosure();
}
return false;
};
for (unsigned paramIdx = 0, numParams = parameterBindings.size();
paramIdx != numParams; ++paramIdx){
// Skip unfulfilled parameters. There's nothing to do for them.
@@ -1007,9 +983,6 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
const auto &param = params[paramIdx];
auto paramTy = param.getOldType();
if (param.isAutoClosure())
paramTy = paramTy->castTo<FunctionType>()->getResult();
// Compare each of the bound arguments for this parameter.
for (auto argIdx : parameterBindings[paramIdx]) {
auto loc = locator.withPathElement(LocatorPathElt::
@@ -1017,19 +990,26 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
paramIdx));
auto argTy = argsWithLabels[argIdx].getOldType();
// If parameter was marked as `@autoclosure` and argument
// is itself `@autoclosure` function type in Swift < 5,
// let's fix that up by making it look like argument is
// called implicitly.
if (param.isAutoClosure() &&
isAutoClosureArg(locator.getAnchor(), argIdx)) {
argTy = argTy->castTo<FunctionType>()->getResult();
cs.increaseScore(SK_FunctionConversion);
bool matchingAutoClosureResult = param.isAutoClosure();
if (param.isAutoClosure()) {
auto &ctx = cs.getASTContext();
auto *fnType = paramTy->castTo<FunctionType>();
auto *argExpr = getArgumentExpr(locator.getAnchor(), argIdx);
if (cs.getASTContext().isSwiftVersionAtLeast(5)) {
auto *fixLoc = cs.getConstraintLocator(loc);
if (cs.recordFix(AutoClosureForwarding::create(cs, fixLoc)))
return cs.getTypeMatchFailure(loc);
// If the argument is not marked as @autoclosure or
// this is Swift version >= 5 where forwarding is not allowed,
// argument would always be wrapped into an implicit closure
// at the end, so we can safely match against result type.
if (ctx.isSwiftVersionAtLeast(5) || !isAutoClosureArgument(argExpr)) {
// In Swift >= 5 mode there is no @autoclosure forwarding,
// so let's match result types.
paramTy = fnType->getResult();
} else {
// Matching @autoclosure argument to @autoclosure parameter
// directly would mean introducting a function conversion
// in Swift <= 4 mode.
cs.increaseScore(SK_FunctionConversion);
matchingAutoClosureResult = false;
}
}
@@ -1040,7 +1020,7 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
cs.addConstraint(
subKind, argTy, paramTy,
param.isAutoClosure()
matchingAutoClosureResult
? loc.withPathElement(ConstraintLocator::AutoclosureResult)
: loc,
/*isFavored=*/false);
@@ -2187,6 +2167,18 @@ bool ConstraintSystem::repairFailures(
break;
}
case ConstraintLocator::FunctionResult: {
// `apply argument` -> `arg/param compare` ->
// `@autoclosure result` -> `function result`
if (path.size() > 3) {
const auto &elt = path[path.size() - 2];
if (elt.getKind() == ConstraintLocator::AutoclosureResult &&
repairByInsertingExplicitCall(lhs, rhs))
return true;
}
break;
}
case ConstraintLocator::AutoclosureResult: {
if (repairByInsertingExplicitCall(lhs, rhs))
return true;
@@ -6576,6 +6568,12 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
return result;
}
case FixKind::AutoClosureForwarding: {
if (recordFix(fix))
return SolutionKind::Error;
return matchTypes(type1, type2, matchKind, subflags, locator);
}
case FixKind::InsertCall:
case FixKind::RemoveReturn:
case FixKind::RemoveAddressOf:
@@ -6591,7 +6589,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
case FixKind::CoerceToCheckedCast:
case FixKind::RelabelArguments:
case FixKind::AddConformance:
case FixKind::AutoClosureForwarding:
case FixKind::RemoveUnwrap:
case FixKind::DefineMemberBasedOnUse:
case FixKind::AllowTypeOrInstanceMember: