Skip to content

Commit 3927f56

Browse files
committed
[ConstraintSystem] Warn about discarded expressions found in multi-statement closures
1 parent 990d8c8 commit 3927f56

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
@@ -436,6 +436,8 @@ class Constraint final : public llvm::ilist_node<Constraint>,
436436
ASTNode Element;
437437
/// Contextual information associated with the element (if any).
438438
ContextualTypeInfo Context;
439+
/// Identifies whether result of this node is unused.
440+
bool IsDiscarded;
439441
} ClosureElement;
440442
};
441443

@@ -489,7 +491,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
489491
SmallPtrSetImpl<TypeVariableType *> &typeVars);
490492

491493
/// Construct a closure body element constraint.
492-
Constraint(ASTNode node, ContextualTypeInfo context,
494+
Constraint(ASTNode node, ContextualTypeInfo context, bool isDiscarded,
493495
ConstraintLocator *locator,
494496
SmallPtrSetImpl<TypeVariableType *> &typeVars);
495497

@@ -579,12 +581,14 @@ class Constraint final : public llvm::ilist_node<Constraint>,
579581

580582
static Constraint *createClosureBodyElement(ConstraintSystem &cs,
581583
ASTNode node,
582-
ConstraintLocator *locator);
584+
ConstraintLocator *locator,
585+
bool isDiscarded = false);
583586

584587
static Constraint *createClosureBodyElement(ConstraintSystem &cs,
585588
ASTNode node,
586589
ContextualTypeInfo context,
587-
ConstraintLocator *locator);
590+
ConstraintLocator *locator,
591+
bool isDiscarded = false);
588592

589593
/// Determine the kind of constraint.
590594
ConstraintKind getKind() const { return Kind; }
@@ -850,6 +854,11 @@ class Constraint final : public llvm::ilist_node<Constraint>,
850854
return ClosureElement.Context;
851855
}
852856

857+
bool isDiscardedElement() const {
858+
assert(Kind == ConstraintKind::ClosureBodyElement);
859+
return ClosureElement.IsDiscarded;
860+
}
861+
853862
/// For an applicable function constraint, retrieve the trailing closure
854863
/// matching rule.
855864
Optional<TrailingClosureMatching> getTrailingClosureMatching() const;

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4845,8 +4845,8 @@ class ConstraintSystem {
48454845
/// Simplify a closure body element constraint by generating required
48464846
/// constraints to represent the given element in constraint system.
48474847
SolutionKind simplifyClosureBodyElementConstraint(
4848-
ASTNode element, ContextualTypeInfo context, TypeMatchOptions flags,
4849-
ConstraintLocatorBuilder locator);
4848+
ASTNode element, ContextualTypeInfo context, bool isDiscarded,
4849+
TypeMatchOptions flags, ConstraintLocatorBuilder locator);
48504850

48514851
public: // FIXME: Public for use by static functions.
48524852
/// 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
@@ -12587,6 +12587,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
1258712587
case ConstraintKind::ClosureBodyElement:
1258812588
return simplifyClosureBodyElementConstraint(
1258912589
constraint.getClosureElement(), constraint.getElementContext(),
12590+
constraint.isDiscardedElement(),
1259012591
/*flags=*/None, constraint.getLocator());
1259112592
}
1259212593

lib/Sema/Constraint.cpp

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

258258
Constraint::Constraint(ASTNode node, ContextualTypeInfo context,
259-
ConstraintLocator *locator,
259+
bool isDiscarded, ConstraintLocator *locator,
260260
SmallPtrSetImpl<TypeVariableType *> &typeVars)
261261
: Kind(ConstraintKind::ClosureBodyElement), TheFix(nullptr),
262262
HasRestriction(false), IsActive(false), IsDisabled(false),
263263
IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false),
264264
IsIsolated(false),
265-
NumTypeVariables(typeVars.size()), ClosureElement{node, context},
265+
NumTypeVariables(typeVars.size()), ClosureElement{node, context,
266+
isDiscarded},
266267
Locator(locator) {
267268
std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
268269
}
@@ -340,7 +341,8 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
340341
getLocator());
341342

342343
case ConstraintKind::ClosureBodyElement:
343-
return createClosureBodyElement(cs, getClosureElement(), getLocator());
344+
return createClosureBodyElement(cs, getClosureElement(), getLocator(),
345+
isDiscardedElement());
344346
}
345347

346348
llvm_unreachable("Unhandled ConstraintKind in switch.");
@@ -1004,18 +1006,21 @@ Constraint *Constraint::createApplicableFunction(
10041006

10051007
Constraint *Constraint::createClosureBodyElement(ConstraintSystem &cs,
10061008
ASTNode node,
1007-
ConstraintLocator *locator) {
1008-
return createClosureBodyElement(cs, node, ContextualTypeInfo(), locator);
1009+
ConstraintLocator *locator,
1010+
bool isDiscarded) {
1011+
return createClosureBodyElement(cs, node, ContextualTypeInfo(), locator,
1012+
isDiscarded);
10091013
}
10101014

10111015
Constraint *Constraint::createClosureBodyElement(ConstraintSystem &cs,
10121016
ASTNode node,
10131017
ContextualTypeInfo context,
1014-
ConstraintLocator *locator) {
1018+
ConstraintLocator *locator,
1019+
bool isDiscarded) {
10151020
SmallPtrSet<TypeVariableType *, 4> typeVars;
10161021
unsigned size = totalSizeToAlloc<TypeVariableType *>(typeVars.size());
10171022
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
1018-
return new (mem) Constraint(node, context, locator, typeVars);
1023+
return new (mem) Constraint(node, context, isDiscarded, locator, typeVars);
10191024
}
10201025

10211026
Optional<TrailingClosureMatching>

0 commit comments

Comments
 (0)