Skip to content

Commit 46ff410

Browse files
committed
[ConstraintSystem] Warn about discarded expressions found in multi-statement closures
1 parent b337360 commit 46ff410

File tree

5 files changed

+62
-37
lines changed

5 files changed

+62
-37
lines changed

include/swift/Sema/Constraint.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,8 @@ class Constraint final : public llvm::ilist_node<Constraint>,
442442
ASTNode Element;
443443
/// Contextual information associated with the element (if any).
444444
ContextualTypeInfo Context;
445+
/// Identifies whether result of this node is unused.
446+
bool IsDiscarded;
445447
} ClosureElement;
446448
};
447449

@@ -495,7 +497,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
495497
SmallPtrSetImpl<TypeVariableType *> &typeVars);
496498

497499
/// Construct a closure body element constraint.
498-
Constraint(ASTNode node, ContextualTypeInfo context,
500+
Constraint(ASTNode node, ContextualTypeInfo context, bool isDiscarded,
499501
ConstraintLocator *locator,
500502
SmallPtrSetImpl<TypeVariableType *> &typeVars);
501503

@@ -585,12 +587,14 @@ class Constraint final : public llvm::ilist_node<Constraint>,
585587

586588
static Constraint *createClosureBodyElement(ConstraintSystem &cs,
587589
ASTNode node,
588-
ConstraintLocator *locator);
590+
ConstraintLocator *locator,
591+
bool isDiscarded = false);
589592

590593
static Constraint *createClosureBodyElement(ConstraintSystem &cs,
591594
ASTNode node,
592595
ContextualTypeInfo context,
593-
ConstraintLocator *locator);
596+
ConstraintLocator *locator,
597+
bool isDiscarded = false);
594598

595599
/// Determine the kind of constraint.
596600
ConstraintKind getKind() const { return Kind; }
@@ -857,6 +861,11 @@ class Constraint final : public llvm::ilist_node<Constraint>,
857861
return ClosureElement.Context;
858862
}
859863

864+
bool isDiscardedElement() const {
865+
assert(Kind == ConstraintKind::ClosureBodyElement);
866+
return ClosureElement.IsDiscarded;
867+
}
868+
860869
/// For an applicable function constraint, retrieve the trailing closure
861870
/// matching rule.
862871
Optional<TrailingClosureMatching> getTrailingClosureMatching() const;

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4854,8 +4854,8 @@ class ConstraintSystem {
48544854
/// Simplify a closure body element constraint by generating required
48554855
/// constraints to represent the given element in constraint system.
48564856
SolutionKind simplifyClosureBodyElementConstraint(
4857-
ASTNode element, ContextualTypeInfo context, TypeMatchOptions flags,
4858-
ConstraintLocatorBuilder locator);
4857+
ASTNode element, ContextualTypeInfo context, bool isDiscarded,
4858+
TypeMatchOptions flags, ConstraintLocatorBuilder locator);
48594859

48604860
public: // FIXME: Public for use by static functions.
48614861
/// Simplify a conversion constraint with a fix applied to it.

lib/Sema/CSClosure.cpp

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ static bool isViableElement(ASTNode element) {
162162
return true;
163163
}
164164

165-
using ElementInfo =
166-
std::tuple<ASTNode, ContextualTypeInfo, ConstraintLocator *>;
165+
using ElementInfo = std::tuple<ASTNode, ContextualTypeInfo,
166+
/*isDiscarded=*/bool, ConstraintLocator *>;
167167

168168
static void createConjunction(ConstraintSystem &cs,
169169
ArrayRef<ElementInfo> elements,
@@ -190,7 +190,8 @@ static void createConjunction(ConstraintSystem &cs,
190190
for (const auto &entry : elements) {
191191
ASTNode element = std::get<0>(entry);
192192
ContextualTypeInfo context = std::get<1>(entry);
193-
ConstraintLocator *elementLoc = std::get<2>(entry);
193+
bool isDiscarded = std::get<2>(entry);
194+
ConstraintLocator *elementLoc = std::get<3>(entry);
194195

195196
if (!isViableElement(element))
196197
continue;
@@ -201,8 +202,8 @@ static void createConjunction(ConstraintSystem &cs,
201202
if (isIsolated)
202203
element.walk(paramCollector);
203204

204-
constraints.push_back(
205-
Constraint::createClosureBodyElement(cs, element, context, elementLoc));
205+
constraints.push_back(Constraint::createClosureBodyElement(
206+
cs, element, context, elementLoc, isDiscarded));
206207
}
207208

208209
// It's possible that there are no viable elements in the body,
@@ -220,8 +221,9 @@ static void createConjunction(ConstraintSystem &cs,
220221
}
221222

222223
ElementInfo makeElement(ASTNode node, ConstraintLocator *locator,
223-
ContextualTypeInfo context = ContextualTypeInfo()) {
224-
return std::make_tuple(node, context, locator);
224+
ContextualTypeInfo context = ContextualTypeInfo(),
225+
bool isDiscarded = false) {
226+
return std::make_tuple(node, context, isDiscarded, locator);
225227
}
226228

227229
static ProtocolDecl *getSequenceProtocol(ASTContext &ctx, SourceLoc loc,
@@ -751,6 +753,8 @@ class ClosureConstraintGenerator
751753

752754
void visitBraceStmt(BraceStmt *braceStmt) {
753755
if (isSupportedMultiStatementClosure()) {
756+
auto &ctx = cs.getASTContext();
757+
754758
if (isChildOf(StmtKind::Case)) {
755759
auto *caseStmt = cast<CaseStmt>(
756760
locator->castLastElementTo<LocatorPathElt::ClosureBodyElement>()
@@ -765,10 +769,15 @@ class ClosureConstraintGenerator
765769

766770
SmallVector<ElementInfo, 4> elements;
767771
for (auto element : braceStmt->getElements()) {
772+
bool isDiscarded =
773+
element.is<Expr *>() &&
774+
(!ctx.LangOpts.Playground && !ctx.LangOpts.DebuggerSupport);
775+
768776
elements.push_back(makeElement(
769777
element,
770778
cs.getConstraintLocator(
771-
locator, LocatorPathElt::ClosureBodyElement(element))));
779+
locator, LocatorPathElt::ClosureBodyElement(element)),
780+
/*contextualInfo=*/{}, isDiscarded));
772781
}
773782

774783
createConjunction(cs, elements, locator);
@@ -925,28 +934,22 @@ bool isConditionOfStmt(ConstraintLocatorBuilder locator) {
925934

926935
ConstraintSystem::SolutionKind
927936
ConstraintSystem::simplifyClosureBodyElementConstraint(
928-
ASTNode element, ContextualTypeInfo context, TypeMatchOptions flags,
929-
ConstraintLocatorBuilder locator) {
937+
ASTNode element, ContextualTypeInfo context, bool isDiscarded,
938+
TypeMatchOptions flags, ConstraintLocatorBuilder locator) {
930939
auto *closure = castToExpr<ClosureExpr>(locator.getAnchor());
931940

932941
ClosureConstraintGenerator generator(*this, closure,
933942
getConstraintLocator(locator));
934943

935944
if (auto *expr = element.dyn_cast<Expr *>()) {
936-
if (context.purpose != CTP_Unused) {
937-
SolutionApplicationTarget target(expr, closure, context.purpose,
938-
context.getType(),
939-
/*isDiscarded=*/false);
940-
941-
if (generateConstraints(target, FreeTypeVariableBinding::Disallow))
942-
return SolutionKind::Error;
943-
944-
setSolutionApplicationTarget(expr, target);
945-
return SolutionKind::Solved;
946-
}
945+
SolutionApplicationTarget target(expr, closure, context.purpose,
946+
context.getType(), isDiscarded);
947947

948-
if (!generateConstraints(expr, closure, /*isInputExpression=*/false))
948+
if (generateConstraints(target, FreeTypeVariableBinding::Disallow))
949949
return SolutionKind::Error;
950+
951+
setSolutionApplicationTarget(expr, target);
952+
return SolutionKind::Solved;
950953
} else if (auto *stmt = element.dyn_cast<Stmt *>()) {
951954
generator.visit(stmt);
952955
} else if (auto *cond = element.dyn_cast<StmtCondition *>()) {
@@ -1241,13 +1244,20 @@ class ClosureConstraintApplication
12411244
}
12421245

12431246
ASTNode visitBraceStmt(BraceStmt *braceStmt) {
1247+
auto &cs = solution.getConstraintSystem();
1248+
12441249
for (auto &node : braceStmt->getElements()) {
12451250
if (auto expr = node.dyn_cast<Expr *>()) {
12461251
// Rewrite the expression.
1247-
if (auto rewrittenExpr = rewriteExpr(expr))
1248-
node = rewrittenExpr;
1249-
else
1252+
auto target = *cs.getSolutionApplicationTarget(expr);
1253+
if (auto rewrittenTarget = rewriteTarget(target)) {
1254+
node = rewrittenTarget->getAsExpr();
1255+
1256+
if (target.isDiscardedExpr())
1257+
TypeChecker::checkIgnoredExpr(castToExpr(node));
1258+
} else {
12501259
hadError = true;
1260+
}
12511261
} else if (auto stmt = node.dyn_cast<Stmt *>()) {
12521262
node = visit(stmt);
12531263
} else {

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12709,6 +12709,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
1270912709
case ConstraintKind::ClosureBodyElement:
1271012710
return simplifyClosureBodyElementConstraint(
1271112711
constraint.getClosureElement(), constraint.getElementContext(),
12712+
constraint.isDiscardedElement(),
1271212713
/*flags=*/None, constraint.getLocator());
1271312714

1271412715
case ConstraintKind::BindTupleOfFunctionParams:

lib/Sema/Constraint.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -258,13 +258,14 @@ Constraint::Constraint(ConstraintKind kind, ConstraintFix *fix, Type first,
258258
}
259259

260260
Constraint::Constraint(ASTNode node, ContextualTypeInfo context,
261-
ConstraintLocator *locator,
261+
bool isDiscarded, ConstraintLocator *locator,
262262
SmallPtrSetImpl<TypeVariableType *> &typeVars)
263263
: Kind(ConstraintKind::ClosureBodyElement), TheFix(nullptr),
264264
HasRestriction(false), IsActive(false), IsDisabled(false),
265265
IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false),
266266
IsIsolated(false),
267-
NumTypeVariables(typeVars.size()), ClosureElement{node, context},
267+
NumTypeVariables(typeVars.size()), ClosureElement{node, context,
268+
isDiscarded},
268269
Locator(locator) {
269270
std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
270271
}
@@ -343,7 +344,8 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
343344
getLocator());
344345

345346
case ConstraintKind::ClosureBodyElement:
346-
return createClosureBodyElement(cs, getClosureElement(), getLocator());
347+
return createClosureBodyElement(cs, getClosureElement(), getLocator(),
348+
isDiscardedElement());
347349
}
348350

349351
llvm_unreachable("Unhandled ConstraintKind in switch.");
@@ -1012,18 +1014,21 @@ Constraint *Constraint::createApplicableFunction(
10121014

10131015
Constraint *Constraint::createClosureBodyElement(ConstraintSystem &cs,
10141016
ASTNode node,
1015-
ConstraintLocator *locator) {
1016-
return createClosureBodyElement(cs, node, ContextualTypeInfo(), locator);
1017+
ConstraintLocator *locator,
1018+
bool isDiscarded) {
1019+
return createClosureBodyElement(cs, node, ContextualTypeInfo(), locator,
1020+
isDiscarded);
10171021
}
10181022

10191023
Constraint *Constraint::createClosureBodyElement(ConstraintSystem &cs,
10201024
ASTNode node,
10211025
ContextualTypeInfo context,
1022-
ConstraintLocator *locator) {
1026+
ConstraintLocator *locator,
1027+
bool isDiscarded) {
10231028
SmallPtrSet<TypeVariableType *, 4> typeVars;
10241029
unsigned size = totalSizeToAlloc<TypeVariableType *>(typeVars.size());
10251030
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
1026-
return new (mem) Constraint(node, context, locator, typeVars);
1031+
return new (mem) Constraint(node, context, isDiscarded, locator, typeVars);
10271032
}
10281033

10291034
Optional<TrailingClosureMatching>

0 commit comments

Comments
 (0)