Skip to content

Commit 967465e

Browse files
author
Josh Learn
authored
Merge pull request #40579 from guitard0g/constantness-result-builders
[Sema][MiscDiag] Fix constantness diag to handle result builder patterns
2 parents 3df1e72 + f748c84 commit 967465e

File tree

2 files changed

+50
-18
lines changed

2 files changed

+50
-18
lines changed

lib/Sema/ConstantnessSemaDiagnostics.cpp

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,10 @@ void swift::diagnoseConstantArgumentRequirement(
334334
const Expr *expr, const DeclContext *declContext) {
335335
class ConstantReqCallWalker : public ASTWalker {
336336
DeclContext *DC;
337+
bool insideClosure;
337338

338339
public:
339-
ConstantReqCallWalker(DeclContext *DC) : DC(DC) {}
340+
ConstantReqCallWalker(DeclContext *DC) : DC(DC), insideClosure(false) {}
340341

341342
// Descend until we find a call expressions. Note that the input expression
342343
// could be an assign expression or another expression that contains the
@@ -347,10 +348,15 @@ void swift::diagnoseConstantArgumentRequirement(
347348
if (auto *closureExpr = dyn_cast<ClosureExpr>(expr)) {
348349
return walkToClosureExprPre(closureExpr);
349350
}
351+
350352
// Interpolated expressions' bodies will be type checked
351353
// separately so exit early to avoid duplicate diagnostics.
354+
// The caveat is that they won't be checked inside closure
355+
// bodies because we manually check all closures to avoid
356+
// duplicate diagnostics. Therefore we must still descend into
357+
// interpolated expressions if we are inside of a closure.
352358
if (!expr || isa<ErrorExpr>(expr) || !expr->getType() ||
353-
isa<InterpolatedStringLiteralExpr>(expr))
359+
(isa<InterpolatedStringLiteralExpr>(expr) && !insideClosure))
354360
return {false, expr};
355361
if (auto *callExpr = dyn_cast<CallExpr>(expr)) {
356362
diagnoseConstantArgumentRequirementOfCall(callExpr, DC->getASTContext());
@@ -359,33 +365,30 @@ void swift::diagnoseConstantArgumentRequirement(
359365
}
360366

361367
std::pair<bool, Expr *> walkToClosureExprPre(ClosureExpr *closure) {
362-
auto &ctx = DC->getASTContext();
363-
364-
if (closure->hasSingleExpressionBody() ||
365-
ctx.TypeCheckerOpts.EnableMultiStatementClosureInference) {
366-
// Closure bodies are not visited directly by the ASTVisitor,
367-
// so we must descend into the body manuall and set the
368-
// DeclContext to that of the closure.
369-
DC = closure;
370-
return {true, closure};
371-
}
372-
return {false, closure};
368+
DC = closure;
369+
insideClosure = true;
370+
return {true, closure};
373371
}
374372

375373
Expr *walkToExprPost(Expr *expr) override {
376374
if (auto *closureExpr = dyn_cast<ClosureExpr>(expr)) {
377375
// Reset the DeclContext to the outer scope if we descended
378-
// into a closure expr.
376+
// into a closure expr and check whether or not we are still
377+
// within a closure context.
379378
DC = closureExpr->getParent();
379+
insideClosure = isa<ClosureExpr>(DC);
380380
}
381381
return expr;
382382
}
383-
384-
std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override {
385-
return {true, stmt};
386-
}
387383
};
388384

385+
// We manually check closure bodies from their outer contexts,
386+
// so bail early if we are being called directly on expressions
387+
// inside of a closure body.
388+
if (isa<ClosureExpr>(declContext)) {
389+
return;
390+
}
391+
389392
ConstantReqCallWalker walker(const_cast<DeclContext *>(declContext));
390393
const_cast<Expr *>(expr)->walk(walker);
391394
}

test/Sema/diag_constantness_check.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,3 +424,32 @@ func testCallsWithinClosures(s: String, x: Int) {
424424
constantArgumentFunction("string with a single interpolation \(x)")
425425
}
426426
}
427+
428+
@resultBuilder
429+
struct MyArrayBuilder {
430+
typealias Component = [Int]
431+
typealias Expression = Int
432+
static func buildExpression(_ element: Expression) -> Component {
433+
return [element]
434+
}
435+
static func buildBlock(_ components: Component...) -> Component {
436+
return Array(components.joined())
437+
}
438+
}
439+
440+
struct MyArray {
441+
public init(@MyArrayBuilder arr: () -> [Int]) {}
442+
}
443+
444+
func testResultBuilder(x: Int, y: Int) -> MyArray {
445+
let _: MyArray = MyArray {
446+
constantArgumentFunctionReturningInt(x)
447+
// expected-error@-1 {{argument must be an integer literal}}
448+
constantArgumentFunctionReturningInt(y)
449+
// expected-error@-1 {{argument must be an integer literal}}
450+
}
451+
let _: MyArray = MyArray {
452+
constantArgumentFunctionReturningInt(x)
453+
// expected-error@-1 {{argument must be an integer literal}}
454+
}
455+
}

0 commit comments

Comments
 (0)