Skip to content

Commit 923b1fb

Browse files
authored
Merge pull request swiftlang#33762 from xedin/rdar-65983237
[ConstraintSystem] Extend invalid function body fix to cover constraint generation failures
2 parents 5c3cb36 + d2f5e63 commit 923b1fb

File tree

6 files changed

+92
-18
lines changed

6 files changed

+92
-18
lines changed

include/swift/AST/DiagnosticEngine.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,10 +1058,19 @@ namespace swift {
10581058
}
10591059
}
10601060

1061-
bool hasDiagnostics() const {
1062-
return std::distance(Engine.TentativeDiagnostics.begin() +
1063-
PrevDiagnostics,
1064-
Engine.TentativeDiagnostics.end()) > 0;
1061+
bool hasErrors() const {
1062+
ArrayRef<Diagnostic> diagnostics(Engine.TentativeDiagnostics.begin() +
1063+
PrevDiagnostics,
1064+
Engine.TentativeDiagnostics.end());
1065+
1066+
for (auto &diagnostic : diagnostics) {
1067+
auto behavior = Engine.state.determineBehavior(diagnostic.getID());
1068+
if (behavior == DiagnosticState::Behavior::Fatal ||
1069+
behavior == DiagnosticState::Behavior::Error)
1070+
return true;
1071+
}
1072+
1073+
return false;
10651074
}
10661075

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

lib/Sema/BuilderTransform.cpp

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,6 +1655,13 @@ ConstraintSystem::matchFunctionBuilder(
16551655
assert(builder && "Bad function builder type");
16561656
assert(builder->getAttrs().hasAttribute<FunctionBuilderAttr>());
16571657

1658+
if (InvalidFunctionBuilderBodies.count(fn)) {
1659+
(void)recordFix(
1660+
IgnoreInvalidFunctionBuilderBody::duringConstraintGeneration(
1661+
*this, getConstraintLocator(fn.getBody())));
1662+
return getTypeMatchSuccess();
1663+
}
1664+
16581665
// Pre-check the body: pre-check any expressions in it and look
16591666
// for return statements.
16601667
auto request =
@@ -1669,7 +1676,7 @@ ConstraintSystem::matchFunctionBuilder(
16691676
if (!shouldAttemptFixes())
16701677
return getTypeMatchFailure(locator);
16711678

1672-
if (recordFix(IgnoreInvalidFunctionBuilderBody::create(
1679+
if (recordFix(IgnoreInvalidFunctionBuilderBody::duringPreCheck(
16731680
*this, getConstraintLocator(fn.getBody()))))
16741681
return getTypeMatchFailure(locator);
16751682

@@ -1711,9 +1718,25 @@ ConstraintSystem::matchFunctionBuilder(
17111718
BuilderClosureVisitor visitor(getASTContext(), this, dc, builderType,
17121719
bodyResultType);
17131720

1714-
auto applied = visitor.apply(fn.getBody());
1715-
if (!applied)
1716-
return getTypeMatchFailure(locator);
1721+
Optional<AppliedBuilderTransform> applied = None;
1722+
{
1723+
DiagnosticTransaction transaction(dc->getASTContext().Diags);
1724+
1725+
applied = visitor.apply(fn.getBody());
1726+
if (!applied)
1727+
return getTypeMatchFailure(locator);
1728+
1729+
if (transaction.hasErrors()) {
1730+
InvalidFunctionBuilderBodies.insert(fn);
1731+
1732+
if (recordFix(
1733+
IgnoreInvalidFunctionBuilderBody::duringConstraintGeneration(
1734+
*this, getConstraintLocator(fn.getBody()))))
1735+
return getTypeMatchFailure(locator);
1736+
1737+
return getTypeMatchSuccess();
1738+
}
1739+
}
17171740

17181741
Type transformedType = getType(applied->returnExpr);
17191742
assert(transformedType && "Missing type");
@@ -1800,7 +1823,7 @@ class PreCheckFunctionBuilderApplication : public ASTWalker {
18001823

18011824
HasError |= ConstraintSystem::preCheckExpression(
18021825
E, DC, /*replaceInvalidRefsWithErrors=*/false);
1803-
HasError |= transaction.hasDiagnostics();
1826+
HasError |= transaction.hasErrors();
18041827

18051828
if (SuppressDiagnostics)
18061829
transaction.abort();

lib/Sema/CSFix.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,6 +1554,14 @@ AllowKeyPathWithoutComponents::create(ConstraintSystem &cs,
15541554

15551555
bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution,
15561556
bool asNote) const {
1557+
switch (Phase) {
1558+
// Handled below
1559+
case ErrorInPhase::PreCheck:
1560+
break;
1561+
case ErrorInPhase::ConstraintGeneration:
1562+
return true; // Already diagnosed by `matchFunctionBuilder`.
1563+
}
1564+
15571565
auto *S = getAnchor().get<Stmt *>();
15581566

15591567
class PreCheckWalker : public ASTWalker {
@@ -1580,7 +1588,7 @@ bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution,
15801588
}
15811589

15821590
bool diagnosed() const {
1583-
return Transaction.hasDiagnostics();
1591+
return Transaction.hasErrors();
15841592
}
15851593
};
15861594

@@ -1590,8 +1598,8 @@ bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution,
15901598
return walker.diagnosed();
15911599
}
15921600

1593-
IgnoreInvalidFunctionBuilderBody *
1594-
IgnoreInvalidFunctionBuilderBody::create(ConstraintSystem &cs,
1595-
ConstraintLocator *locator) {
1596-
return new (cs.getAllocator()) IgnoreInvalidFunctionBuilderBody(cs, locator);
1601+
IgnoreInvalidFunctionBuilderBody *IgnoreInvalidFunctionBuilderBody::create(
1602+
ConstraintSystem &cs, ErrorInPhase phase, ConstraintLocator *locator) {
1603+
return new (cs.getAllocator())
1604+
IgnoreInvalidFunctionBuilderBody(cs, phase, locator);
15971605
}

lib/Sema/CSFix.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,9 +1984,17 @@ class AllowKeyPathWithoutComponents final : public ConstraintFix {
19841984
};
19851985

19861986
class IgnoreInvalidFunctionBuilderBody final : public ConstraintFix {
1987-
IgnoreInvalidFunctionBuilderBody(ConstraintSystem &cs,
1987+
enum class ErrorInPhase {
1988+
PreCheck,
1989+
ConstraintGeneration,
1990+
};
1991+
1992+
ErrorInPhase Phase;
1993+
1994+
IgnoreInvalidFunctionBuilderBody(ConstraintSystem &cs, ErrorInPhase phase,
19881995
ConstraintLocator *locator)
1989-
: ConstraintFix(cs, FixKind::IgnoreInvalidFunctionBuilderBody, locator) {}
1996+
: ConstraintFix(cs, FixKind::IgnoreInvalidFunctionBuilderBody, locator),
1997+
Phase(phase) {}
19901998

19911999
public:
19922000
std::string getName() const override {
@@ -1999,8 +2007,19 @@ class IgnoreInvalidFunctionBuilderBody final : public ConstraintFix {
19992007
return diagnose(*commonFixes.front().first);
20002008
}
20012009

2002-
static IgnoreInvalidFunctionBuilderBody *create(ConstraintSystem &cs,
2003-
ConstraintLocator *locator);
2010+
static IgnoreInvalidFunctionBuilderBody *
2011+
duringPreCheck(ConstraintSystem &cs, ConstraintLocator *locator) {
2012+
return create(cs, ErrorInPhase::PreCheck, locator);
2013+
}
2014+
2015+
static IgnoreInvalidFunctionBuilderBody *
2016+
duringConstraintGeneration(ConstraintSystem &cs, ConstraintLocator *locator) {
2017+
return create(cs, ErrorInPhase::ConstraintGeneration, locator);
2018+
}
2019+
2020+
private:
2021+
static IgnoreInvalidFunctionBuilderBody *
2022+
create(ConstraintSystem &cs, ErrorInPhase phase, ConstraintLocator *locator);
20042023
};
20052024

20062025
} // end namespace constraints

lib/Sema/ConstraintSystem.h

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

2028+
/// This is a *global* list of all function builder bodies that have
2029+
/// been determined to be incorrect by failing constraint generation.
2030+
///
2031+
/// Tracking this information is useful to avoid producing duplicate
2032+
/// diagnostics when function builder has multiple overloads.
2033+
llvm::SmallDenseSet<AnyFunctionRef> InvalidFunctionBuilderBodies;
2034+
20282035
/// Maps node types used within all portions of the constraint
20292036
/// system, instead of directly using the types on the
20302037
/// 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
@@ -619,6 +619,14 @@ struct MyView {
619619
} // expected-error {{expected identifier after '.' expression}}
620620
}
621621

622+
@TupleBuilder var invalidCaseWithoutDot: some P {
623+
switch Optional.some(1) {
624+
case none: 42 // expected-error {{cannot find 'none' in scope}}
625+
case .some(let x):
626+
0
627+
}
628+
}
629+
622630
@TupleBuilder var invalidConversion: Int { // expected-error {{cannot convert value of type 'String' to specified type 'Int'}}
623631
""
624632
}

0 commit comments

Comments
 (0)