mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Sema][MiscDiag] Fix constantness diag to handle result builder patterns
We currently have a problem with how constantness diagnostics traverse the AST to look for function calls to diagnose. We special case closure bodies and don't check them (unless they're single expression closures) because closure bodies are type- checked separately and will be covered later. This poses a problem in certain AST structures, such as what we see with result builders, because the call expressions are rooted in declarations, which aren't checked in the closure body type-checking covered by MiscDiag. This patch fixes the problem by manually checking all closure bodies and stopping misc diagnostics from checking the bodies separately. rdar://85737300
This commit is contained in:
@@ -334,9 +334,10 @@ void swift::diagnoseConstantArgumentRequirement(
|
||||
const Expr *expr, const DeclContext *declContext) {
|
||||
class ConstantReqCallWalker : public ASTWalker {
|
||||
DeclContext *DC;
|
||||
bool insideClosure;
|
||||
|
||||
public:
|
||||
ConstantReqCallWalker(DeclContext *DC) : DC(DC) {}
|
||||
ConstantReqCallWalker(DeclContext *DC) : DC(DC), insideClosure(false) {}
|
||||
|
||||
// Descend until we find a call expressions. Note that the input expression
|
||||
// could be an assign expression or another expression that contains the
|
||||
@@ -347,10 +348,15 @@ void swift::diagnoseConstantArgumentRequirement(
|
||||
if (auto *closureExpr = dyn_cast<ClosureExpr>(expr)) {
|
||||
return walkToClosureExprPre(closureExpr);
|
||||
}
|
||||
|
||||
// Interpolated expressions' bodies will be type checked
|
||||
// separately so exit early to avoid duplicate diagnostics.
|
||||
// The caveat is that they won't be checked inside closure
|
||||
// bodies because we manually check all closures to avoid
|
||||
// duplicate diagnostics. Therefore we must still descend into
|
||||
// interpolated expressions if we are inside of a closure.
|
||||
if (!expr || isa<ErrorExpr>(expr) || !expr->getType() ||
|
||||
isa<InterpolatedStringLiteralExpr>(expr))
|
||||
(isa<InterpolatedStringLiteralExpr>(expr) && !insideClosure))
|
||||
return {false, expr};
|
||||
if (auto *callExpr = dyn_cast<CallExpr>(expr)) {
|
||||
diagnoseConstantArgumentRequirementOfCall(callExpr, DC->getASTContext());
|
||||
@@ -359,33 +365,30 @@ void swift::diagnoseConstantArgumentRequirement(
|
||||
}
|
||||
|
||||
std::pair<bool, Expr *> walkToClosureExprPre(ClosureExpr *closure) {
|
||||
auto &ctx = DC->getASTContext();
|
||||
|
||||
if (closure->hasSingleExpressionBody() ||
|
||||
ctx.TypeCheckerOpts.EnableMultiStatementClosureInference) {
|
||||
// Closure bodies are not visited directly by the ASTVisitor,
|
||||
// so we must descend into the body manuall and set the
|
||||
// DeclContext to that of the closure.
|
||||
DC = closure;
|
||||
return {true, closure};
|
||||
}
|
||||
return {false, closure};
|
||||
DC = closure;
|
||||
insideClosure = true;
|
||||
return {true, closure};
|
||||
}
|
||||
|
||||
Expr *walkToExprPost(Expr *expr) override {
|
||||
if (auto *closureExpr = dyn_cast<ClosureExpr>(expr)) {
|
||||
// Reset the DeclContext to the outer scope if we descended
|
||||
// into a closure expr.
|
||||
// into a closure expr and check whether or not we are still
|
||||
// within a closure context.
|
||||
DC = closureExpr->getParent();
|
||||
insideClosure = isa<ClosureExpr>(DC);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override {
|
||||
return {true, stmt};
|
||||
}
|
||||
};
|
||||
|
||||
// We manually check closure bodies from their outer contexts,
|
||||
// so bail early if we are being called directly on expressions
|
||||
// inside of a closure body.
|
||||
if (isa<ClosureExpr>(declContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConstantReqCallWalker walker(const_cast<DeclContext *>(declContext));
|
||||
const_cast<Expr *>(expr)->walk(walker);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user