Skip to content

Commit 3e1715e

Browse files
committed
[ConstraintSystem] Extend invalid function body fix to cover constraint generation failures
Ignore function builder body if it emits at least one diagnostic during constraint generation. Resolves: rdar://problem/65983237
1 parent 8a07bc2 commit 3e1715e

File tree

6 files changed

+95
-18
lines changed

6 files changed

+95
-18
lines changed

include/swift/AST/DiagnosticEngine.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,10 +1025,19 @@ namespace swift {
10251025
}
10261026
}
10271027

1028-
bool hasDiagnostics() const {
1029-
return std::distance(Engine.TentativeDiagnostics.begin() +
1030-
PrevDiagnostics,
1031-
Engine.TentativeDiagnostics.end()) > 0;
1028+
bool hasErrors() const {
1029+
ArrayRef<Diagnostic> diagnostics(Engine.TentativeDiagnostics.begin() +
1030+
PrevDiagnostics,
1031+
Engine.TentativeDiagnostics.end());
1032+
1033+
for (auto &diagnostic : diagnostics) {
1034+
auto behavior = Engine.state.determineBehavior(diagnostic.getID());
1035+
if (behavior == DiagnosticState::Behavior::Fatal ||
1036+
behavior == DiagnosticState::Behavior::Error)
1037+
return true;
1038+
}
1039+
1040+
return false;
10321041
}
10331042

10341043
/// Abort and close this transaction and erase all diagnostics

lib/Sema/BuilderTransform.cpp

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,6 +1523,14 @@ ConstraintSystem::matchFunctionBuilder(
15231523
assert(builder && "Bad function builder type");
15241524
assert(builder->getAttrs().hasAttribute<FunctionBuilderAttr>());
15251525

1526+
if (InvalidFunctionBuilderBodies.count(fn)) {
1527+
auto *closure = cast<ClosureExpr>(fn.getAbstractClosureExpr());
1528+
(void)recordFix(
1529+
IgnoreInvalidFunctionBuilderBody::duringConstraintGeneration(
1530+
*this, getConstraintLocator(closure)));
1531+
return getTypeMatchSuccess();
1532+
}
1533+
15261534
// Pre-check the body: pre-check any expressions in it and look
15271535
// for return statements.
15281536
auto request = PreCheckFunctionBuilderRequest{fn, fn.getBody(),
@@ -1539,7 +1547,7 @@ ConstraintSystem::matchFunctionBuilder(
15391547

15401548
if (auto *closure =
15411549
dyn_cast_or_null<ClosureExpr>(fn.getAbstractClosureExpr())) {
1542-
auto failed = recordFix(IgnoreInvalidFunctionBuilderBody::create(
1550+
auto failed = recordFix(IgnoreInvalidFunctionBuilderBody::duringPreCheck(
15431551
*this, getConstraintLocator(closure)));
15441552
return failed ? getTypeMatchFailure(locator) : getTypeMatchSuccess();
15451553
}
@@ -1598,9 +1606,27 @@ ConstraintSystem::matchFunctionBuilder(
15981606
BuilderClosureVisitor visitor(getASTContext(), this, dc, builderType,
15991607
bodyResultType);
16001608

1601-
auto applied = visitor.apply(fn.getBody());
1602-
if (!applied)
1603-
return getTypeMatchFailure(locator);
1609+
Optional<AppliedBuilderTransform> applied = None;
1610+
{
1611+
DiagnosticTransaction transaction(dc->getASTContext().Diags);
1612+
1613+
applied = visitor.apply(fn.getBody());
1614+
if (!applied)
1615+
return getTypeMatchFailure(locator);
1616+
1617+
if (transaction.hasErrors()) {
1618+
if (auto *closure =
1619+
dyn_cast_or_null<ClosureExpr>(fn.getAbstractClosureExpr())) {
1620+
InvalidFunctionBuilderBodies.insert(fn);
1621+
auto failed = recordFix(
1622+
IgnoreInvalidFunctionBuilderBody::duringConstraintGeneration(
1623+
*this, getConstraintLocator(closure)));
1624+
return failed ? getTypeMatchFailure(locator) : getTypeMatchSuccess();
1625+
}
1626+
1627+
return getTypeMatchFailure(locator);
1628+
}
1629+
}
16041630

16051631
Type transformedType = getType(applied->returnExpr);
16061632
assert(transformedType && "Missing type");
@@ -1687,7 +1713,7 @@ class PreCheckFunctionBuilderApplication : public ASTWalker {
16871713

16881714
HasError |= ConstraintSystem::preCheckExpression(
16891715
E, DC, /*replaceInvalidRefsWithErrors=*/false);
1690-
HasError |= transaction.hasDiagnostics();
1716+
HasError |= transaction.hasErrors();
16911717

16921718
if (SuppressDiagnostics)
16931719
transaction.abort();

lib/Sema/CSFix.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,14 @@ bool SpecifyKeyPathRootType::diagnose(const Solution &solution,
13661366

13671367
bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution,
13681368
bool asNote) const {
1369+
switch (Phase) {
1370+
// Handled below
1371+
case ErrorInPhase::PreCheck:
1372+
break;
1373+
case ErrorInPhase::ConstraintGeneration:
1374+
return true; // Already diagnosed by `matchFunctionBuilder`.
1375+
}
1376+
13691377
auto *S = cast<ClosureExpr>(getAnchor())->getBody();
13701378

13711379
class PreCheckWalker : public ASTWalker {
@@ -1392,7 +1400,7 @@ bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution,
13921400
}
13931401

13941402
bool diagnosed() const {
1395-
return Transaction.hasDiagnostics();
1403+
return Transaction.hasErrors();
13961404
}
13971405
};
13981406

@@ -1403,8 +1411,8 @@ bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution,
14031411
return walker.diagnosed();
14041412
}
14051413

1406-
IgnoreInvalidFunctionBuilderBody *
1407-
IgnoreInvalidFunctionBuilderBody::create(ConstraintSystem &cs,
1408-
ConstraintLocator *locator) {
1409-
return new (cs.getAllocator()) IgnoreInvalidFunctionBuilderBody(cs, locator);
1414+
IgnoreInvalidFunctionBuilderBody *IgnoreInvalidFunctionBuilderBody::create(
1415+
ConstraintSystem &cs, ErrorInPhase phase, ConstraintLocator *locator) {
1416+
return new (cs.getAllocator())
1417+
IgnoreInvalidFunctionBuilderBody(cs, phase, locator);
14101418
}

lib/Sema/CSFix.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,9 +1844,17 @@ class SpecifyKeyPathRootType final : public ConstraintFix {
18441844
};
18451845

18461846
class IgnoreInvalidFunctionBuilderBody final : public ConstraintFix {
1847-
IgnoreInvalidFunctionBuilderBody(ConstraintSystem &cs,
1847+
enum class ErrorInPhase {
1848+
PreCheck,
1849+
ConstraintGeneration,
1850+
};
1851+
1852+
ErrorInPhase Phase;
1853+
1854+
IgnoreInvalidFunctionBuilderBody(ConstraintSystem &cs, ErrorInPhase phase,
18481855
ConstraintLocator *locator)
1849-
: ConstraintFix(cs, FixKind::IgnoreInvalidFunctionBuilderBody, locator) {}
1856+
: ConstraintFix(cs, FixKind::IgnoreInvalidFunctionBuilderBody, locator),
1857+
Phase(phase) {}
18501858

18511859
public:
18521860
std::string getName() const override {
@@ -1859,8 +1867,19 @@ class IgnoreInvalidFunctionBuilderBody final : public ConstraintFix {
18591867
return diagnose(*commonFixes.front().first);
18601868
}
18611869

1862-
static IgnoreInvalidFunctionBuilderBody *create(ConstraintSystem &cs,
1863-
ConstraintLocator *locator);
1870+
static IgnoreInvalidFunctionBuilderBody *
1871+
duringPreCheck(ConstraintSystem &cs, ConstraintLocator *locator) {
1872+
return create(cs, ErrorInPhase::PreCheck, locator);
1873+
}
1874+
1875+
static IgnoreInvalidFunctionBuilderBody *
1876+
duringConstraintGeneration(ConstraintSystem &cs, ConstraintLocator *locator) {
1877+
return create(cs, ErrorInPhase::ConstraintGeneration, locator);
1878+
}
1879+
1880+
private:
1881+
static IgnoreInvalidFunctionBuilderBody *
1882+
create(ConstraintSystem &cs, ErrorInPhase phase, ConstraintLocator *locator);
18641883
};
18651884

18661885
} // end namespace constraints

lib/Sema/ConstraintSystem.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,6 +1727,13 @@ class ConstraintSystem {
17271727
/// from declared parameters/result and body.
17281728
llvm::MapVector<const ClosureExpr *, FunctionType *> ClosureTypes;
17291729

1730+
/// This is a *global* list of all function builder bodies that have
1731+
/// been determined to be incorrect by failing constraint generation.
1732+
///
1733+
/// Tracking this information is useful to avoid producing duplicate
1734+
/// diagnostics when function builder has multiple overloads.
1735+
llvm::SmallDenseSet<AnyFunctionRef> InvalidFunctionBuilderBodies;
1736+
17301737
/// Maps node types used within all portions of the constraint
17311738
/// system, instead of directly using the types on the
17321739
/// nodes themselves. This allows us to typecheck and

test/Constraints/function_builder_diags.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,14 @@ struct MyView {
606606
} // expected-error {{expected identifier after '.' expression}}
607607
}
608608

609+
@TupleBuilder var invalidCaseWithoutDot: some P {
610+
switch Optional.some(1) {
611+
case none: 42 // expected-error {{cannot find 'none' in scope}}
612+
case .some(let x):
613+
0
614+
}
615+
}
616+
609617
@TupleBuilder var invalidConversion: Int {
610618
"" // expected-error {{cannot convert value of type 'String' to specified type 'Int'}}
611619
}

0 commit comments

Comments
 (0)