@@ -1374,9 +1374,10 @@ Optional<BraceStmt *> TypeChecker::applyFunctionBuilderBodyTransform(
1374
1374
// If we encountered an error or there was an explicit result type,
1375
1375
// bail out and report that to the caller.
1376
1376
auto &ctx = func->getASTContext ();
1377
- auto request = PreCheckFunctionBuilderRequest{func, func->getBody ()};
1378
- switch (evaluateOrDefault (
1379
- ctx.evaluator , request, FunctionBuilderBodyPreCheck::Error)) {
1377
+ auto request = PreCheckFunctionBuilderRequest{func, func->getBody (),
1378
+ /* suppressDiagnostics=*/ false };
1379
+ switch (evaluateOrDefault (ctx.evaluator , request,
1380
+ FunctionBuilderBodyPreCheck::Error)) {
1380
1381
case FunctionBuilderBodyPreCheck::Okay:
1381
1382
// If the pre-check was okay, apply the function-builder transform.
1382
1383
break ;
@@ -1524,16 +1525,27 @@ ConstraintSystem::matchFunctionBuilder(
1524
1525
1525
1526
// Pre-check the body: pre-check any expressions in it and look
1526
1527
// for return statements.
1527
- auto request = PreCheckFunctionBuilderRequest{fn, fn.getBody ()};
1528
+ auto request = PreCheckFunctionBuilderRequest{fn, fn.getBody (),
1529
+ /* SuppressDiagnostics=*/ true };
1528
1530
switch (evaluateOrDefault (getASTContext ().evaluator , request,
1529
1531
FunctionBuilderBodyPreCheck::Error)) {
1530
1532
case FunctionBuilderBodyPreCheck::Okay:
1531
1533
// If the pre-check was okay, apply the function-builder transform.
1532
1534
break ;
1533
1535
1534
- case FunctionBuilderBodyPreCheck::Error:
1535
- // If the pre-check had an error, flag that.
1536
+ case FunctionBuilderBodyPreCheck::Error: {
1537
+ if (!shouldAttemptFixes ())
1538
+ return getTypeMatchFailure (locator);
1539
+
1540
+ if (auto *closure =
1541
+ dyn_cast_or_null<ClosureExpr>(fn.getAbstractClosureExpr ())) {
1542
+ auto failed = recordFix (IgnoreInvalidFunctionBuilderBody::create (
1543
+ *this , getConstraintLocator (closure)));
1544
+ return failed ? getTypeMatchFailure (locator) : getTypeMatchSuccess ();
1545
+ }
1546
+
1536
1547
return getTypeMatchFailure (locator);
1548
+ }
1537
1549
1538
1550
case FunctionBuilderBodyPreCheck::HasReturnStmt:
1539
1551
// If the body has a return statement, suppress the transform but
@@ -1626,14 +1638,17 @@ namespace {
1626
1638
class PreCheckFunctionBuilderApplication : public ASTWalker {
1627
1639
AnyFunctionRef Fn;
1628
1640
bool SkipPrecheck = false ;
1641
+ bool SuppressDiagnostics = false ;
1629
1642
std::vector<ReturnStmt *> ReturnStmts;
1630
1643
bool HasError = false ;
1631
1644
1632
1645
bool hasReturnStmt () const { return !ReturnStmts.empty (); }
1633
1646
1634
1647
public:
1635
- PreCheckFunctionBuilderApplication (AnyFunctionRef fn, bool skipPrecheck)
1636
- : Fn(fn), SkipPrecheck(skipPrecheck) {}
1648
+ PreCheckFunctionBuilderApplication (AnyFunctionRef fn, bool skipPrecheck,
1649
+ bool suppressDiagnostics)
1650
+ : Fn(fn), SkipPrecheck(skipPrecheck),
1651
+ SuppressDiagnostics (suppressDiagnostics) {}
1637
1652
1638
1653
const std::vector<ReturnStmt *> getReturnStmts () const { return ReturnStmts; }
1639
1654
@@ -1657,16 +1672,28 @@ class PreCheckFunctionBuilderApplication : public ASTWalker {
1657
1672
}
1658
1673
1659
1674
std::pair<bool , Expr *> walkToExprPre (Expr *E) override {
1675
+ if (SkipPrecheck)
1676
+ return std::make_pair (false , E);
1677
+
1660
1678
// Pre-check the expression. If this fails, abort the walk immediately.
1661
1679
// Otherwise, replace the expression with the result of pre-checking.
1662
1680
// In either case, don't recurse into the expression.
1663
- if (!SkipPrecheck &&
1664
- ConstraintSystem::preCheckExpression (E, /* DC*/ Fn.getAsDeclContext ())) {
1665
- HasError = true ;
1666
- return std::make_pair (false , nullptr );
1667
- }
1681
+ {
1682
+ auto *DC = Fn.getAsDeclContext ();
1683
+ auto &diagEngine = DC->getASTContext ().Diags ;
1684
+
1685
+ // Suppress any diangostics which could be produced by this expression.
1686
+ DiagnosticTransaction transaction (diagEngine);
1668
1687
1669
- return std::make_pair (false , E);
1688
+ HasError |= ConstraintSystem::preCheckExpression (
1689
+ E, DC, /* replaceInvalidRefsWithErrors=*/ false );
1690
+ HasError |= transaction.hasDiagnostics ();
1691
+
1692
+ if (SuppressDiagnostics)
1693
+ transaction.abort ();
1694
+
1695
+ return std::make_pair (false , HasError ? nullptr : E);
1696
+ }
1670
1697
}
1671
1698
1672
1699
std::pair<bool , Stmt *> walkToStmtPre (Stmt *S) override {
@@ -1692,18 +1719,20 @@ class PreCheckFunctionBuilderApplication : public ASTWalker {
1692
1719
1693
1720
FunctionBuilderBodyPreCheck
1694
1721
PreCheckFunctionBuilderRequest::evaluate (Evaluator &eval, AnyFunctionRef fn,
1695
- BraceStmt *body) const {
1722
+ BraceStmt *body,
1723
+ bool suppressDiagnostics) const {
1696
1724
// NOTE: 'body' is passed only for the request evaluater caching key.
1697
1725
// Since source tooling (e.g. code completion) might replace the body,
1698
1726
// the function alone is not sufficient for the key.
1699
1727
assert (fn.getBody () == body &&
1700
1728
" body must be the current body of the function" );
1701
1729
1702
- return PreCheckFunctionBuilderApplication (fn, false ).run ();
1730
+ return PreCheckFunctionBuilderApplication (fn, false , suppressDiagnostics ).run ();
1703
1731
}
1704
1732
1705
1733
std::vector<ReturnStmt *> TypeChecker::findReturnStatements (AnyFunctionRef fn) {
1706
- PreCheckFunctionBuilderApplication precheck (fn, true );
1734
+ PreCheckFunctionBuilderApplication precheck (fn, /* skipPreCheck=*/ true ,
1735
+ /* SuppressDiagnostics=*/ true );
1707
1736
(void )precheck.run ();
1708
1737
return precheck.getReturnStmts ();
1709
1738
}
0 commit comments