Skip to content

Commit 883efed

Browse files
authored
Merge pull request #19699 from xedin/simplify-applicable-fn-to-create-constraints-for-args
[ConstraintSystem] Form argument constraints instead of using `matchT…
2 parents f08c2b0 + 0e7d761 commit 883efed

File tree

3 files changed

+60
-25
lines changed

3 files changed

+60
-25
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,14 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
551551
/// a subscript and offer a fixit if the inputs are compatible.
552552
bool diagnoseSubscriptMisuse(ApplyExpr *callExpr);
553553

554+
/// Try to diagnose common errors involving implicitly non-escaping parameters
555+
/// of function type, giving more specific and simpler diagnostics, attaching
556+
/// notes on the parameter, and offering fixits to insert @escaping. Returns
557+
/// true if it detects and issues an error, false if it does nothing.
558+
bool diagnoseNonEscapingParameterToEscaping(Expr *expr, Type srcType,
559+
Type dstType,
560+
ContextualTypePurpose dstPurpose);
561+
554562
bool visitExpr(Expr *E);
555563
bool visitIdentityExpr(IdentityExpr *E);
556564
bool visitTryExpr(TryExpr *E);
@@ -1441,12 +1449,14 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){
14411449
return true;
14421450
}
14431451

1444-
if (srcFT->isNoEscape() && !destFT->isNoEscape()) {
1445-
diagnose(expr->getLoc(), diag::noescape_functiontype_mismatch,
1446-
fromType, toType)
1447-
.highlight(expr->getSourceRange());
1452+
auto destPurpose = CTP_Unused;
1453+
if (constraint->getKind() == ConstraintKind::ArgumentConversion ||
1454+
constraint->getKind() == ConstraintKind::OperatorArgumentConversion)
1455+
destPurpose = CTP_CallArgument;
1456+
1457+
if (diagnoseNonEscapingParameterToEscaping(anchor, fromType, toType,
1458+
destPurpose))
14481459
return true;
1449-
}
14501460
}
14511461

14521462
// If this is a callee that mismatches an expected return type, we can emit a
@@ -2344,9 +2354,8 @@ static bool addTypeCoerceFixit(InFlightDiagnostic &diag, ConstraintSystem &CS,
23442354
/// of function type, giving more specific and simpler diagnostics, attaching
23452355
/// notes on the parameter, and offering fixits to insert @escaping. Returns
23462356
/// true if it detects and issues an error, false if it does nothing.
2347-
static bool tryDiagnoseNonEscapingParameterToEscaping(
2348-
Expr *expr, Type srcType, Type dstType, ContextualTypePurpose dstPurpose,
2349-
ConstraintSystem &CS) {
2357+
bool FailureDiagnosis::diagnoseNonEscapingParameterToEscaping(
2358+
Expr *expr, Type srcType, Type dstType, ContextualTypePurpose dstPurpose) {
23502359
assert(expr);
23512360
// Need to be referencing a parameter of function type
23522361
auto declRef = dyn_cast<DeclRefExpr>(expr);
@@ -2684,8 +2693,8 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
26842693
}
26852694

26862695
// Try for better/more specific diagnostics for non-escaping to @escaping
2687-
if (tryDiagnoseNonEscapingParameterToEscaping(expr, exprType, contextualType,
2688-
CTP, CS))
2696+
if (diagnoseNonEscapingParameterToEscaping(expr, exprType, contextualType,
2697+
CTP))
26892698
return true;
26902699

26912700
// Don't attempt fixits if we have an unsolved type variable, since
@@ -5482,21 +5491,52 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
54825491
}
54835492
}
54845493

5494+
auto isFailingConstraintRelevant = [&]() -> bool {
5495+
auto *constraint = CS.failedConstraint;
5496+
if (!constraint)
5497+
return false;
5498+
5499+
auto *locator = constraint->getLocator();
5500+
return locator && locator->getAnchor() == callExpr;
5501+
};
5502+
54855503
// If there is a failing constraint associated with current constraint
54865504
// system which points to the argument/parameter mismatch, let's use
54875505
// that information while re-typechecking argument expression, this
54885506
// makes it a lot easier to determine contextual mismatch.
5489-
if (CS.failedConstraint && !hasTrailingClosure) {
5507+
if (isFailingConstraintRelevant() && !hasTrailingClosure) {
54905508
auto *constraint = CS.failedConstraint;
54915509
if (constraint->getKind() == ConstraintKind::ApplicableFunction) {
5492-
if (auto *locator = constraint->getLocator()) {
5493-
if (locator->getAnchor() == callExpr) {
5494-
auto calleeType = CS.simplifyType(constraint->getSecondType());
5495-
if (auto *fnType = calleeType->getAs<FunctionType>())
5496-
argType = AnyFunctionType::composeInput(fnType->getASTContext(),
5497-
fnType->getParams(),
5510+
auto calleeType = CS.simplifyType(constraint->getSecondType());
5511+
if (auto *fnType = calleeType->getAs<FunctionType>())
5512+
argType = AnyFunctionType::composeInput(fnType->getASTContext(),
5513+
fnType->getParams(),
5514+
/*canonicalVararg=*/false);
5515+
} else if (constraint->getKind() == ConstraintKind::ArgumentConversion ||
5516+
constraint->getKind() ==
5517+
ConstraintKind::OperatorArgumentConversion) {
5518+
using PathEltKind = ConstraintLocator::PathElementKind;
5519+
// Dig up type variable which represents the overload choice that fit
5520+
// this call expression after simplifying `ApplicableFunction` constraint.
5521+
for (auto *typeVar : CS.getTypeVariables()) {
5522+
auto *locator = typeVar->getImpl().getLocator();
5523+
auto path = locator->getPath();
5524+
5525+
// Check whether this type variable in anchored at current
5526+
// expression and path ends with `apply function`, which means
5527+
// that it's related to `ApplicableFunction` constraint.
5528+
if (locator->getAnchor() != callExpr || path.empty() ||
5529+
path.back().getKind() != PathEltKind::ApplyFunction)
5530+
continue;
5531+
5532+
if (auto type = typeVar->getImpl().getFixedType(nullptr)) {
5533+
fnType = type;
5534+
if (auto *FT = fnType->getAs<AnyFunctionType>())
5535+
argType = AnyFunctionType::composeInput(FT->getASTContext(),
5536+
FT->getParams(),
54985537
/*canonicalVararg=*/false);
54995538
}
5539+
break;
55005540
}
55015541
}
55025542
}

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -816,10 +816,6 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
816816
parameterBindings))
817817
return cs.getTypeMatchFailure(locator);
818818

819-
// Check the argument types for each of the parameters.
820-
ConstraintSystem::TypeMatchOptions subflags =
821-
ConstraintSystem::TMF_GenerateConstraints;
822-
823819
// If this application is part of an operator, then we allow an implicit
824820
// lvalue to be compatible with inout arguments. This is used by
825821
// assignment operators.
@@ -848,9 +844,7 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
848844
getApplyArgToParam(argIdx,
849845
paramIdx));
850846
auto argTy = argsWithLabels[argIdx].getOldType();
851-
auto result = cs.matchTypes(argTy, paramTy, subKind, subflags, loc);
852-
if (result.isFailure())
853-
return result;
847+
cs.addConstraint(subKind, argTy, paramTy, loc, /*isFavored=*/false);
854848
}
855849
}
856850

test/attr/attr_noescape.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func takesNoEscapeClosure(_ fn : () -> Int) {
3232
// expected-note@-5{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
3333
// expected-note@-6{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
3434
// expected-note@-7{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
35+
// expected-note@-8{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
3536
takesNoEscapeClosure { 4 } // ok
3637

3738
_ = fn() // ok
@@ -56,7 +57,7 @@ func takesNoEscapeClosure(_ fn : () -> Int) {
5657
takesGenericClosure(4) { fn() } // ok.
5758

5859
_ = [fn] // expected-error {{converting non-escaping value to 'Element' may allow it to escape}}
59-
_ = [doesEscape(fn)] // expected-error {{'(() -> Int) -> ()' is not convertible to '(@escaping () -> Int) -> ()'}}
60+
_ = [doesEscape(fn)] // expected-error {{passing non-escaping parameter 'fn' to function expecting an @escaping closure}}
6061
_ = [1 : fn] // expected-error {{converting non-escaping value to 'Value' may allow it to escape}}
6162
_ = [1 : doesEscape(fn)] // expected-error {{passing non-escaping parameter 'fn' to function expecting an @escaping closure}}
6263
_ = "\(doesEscape(fn))" // expected-error {{passing non-escaping parameter 'fn' to function expecting an @escaping closure}}

0 commit comments

Comments
 (0)