Skip to content

Commit 89a3390

Browse files
committed
[Sema] Move SingleValueStmtUsageChecker into pre-checking
These diagnostics are better suited for pre-checking since we ought to be emitting them even if there's some other error with the expression.
1 parent 1139b0e commit 89a3390

12 files changed

+248
-253
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 3 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -4378,206 +4378,6 @@ void VarDeclUsageChecker::handleIfConfig(IfConfigDecl *ICD) {
43784378
}
43794379
}
43804380

4381-
namespace {
4382-
class SingleValueStmtUsageChecker final : public ASTWalker {
4383-
ASTContext &Ctx;
4384-
DiagnosticEngine &Diags;
4385-
llvm::DenseSet<SingleValueStmtExpr *> ValidSingleValueStmtExprs;
4386-
4387-
public:
4388-
SingleValueStmtUsageChecker(
4389-
ASTContext &ctx, ASTNode root,
4390-
std::optional<ContextualTypePurpose> contextualPurpose)
4391-
: Ctx(ctx), Diags(ctx.Diags) {
4392-
assert(!root.is<Expr *>() || contextualPurpose &&
4393-
"Must provide contextual purpose for expr");
4394-
4395-
// If we have a contextual purpose, this is for an expression. Check if it's
4396-
// an expression in a valid position.
4397-
if (contextualPurpose) {
4398-
markAnyValidTopLevelSingleValueStmt(root.get<Expr *>(),
4399-
*contextualPurpose);
4400-
}
4401-
}
4402-
4403-
private:
4404-
/// Mark a given expression as a valid position for a SingleValueStmtExpr.
4405-
void markValidSingleValueStmt(Expr *E) {
4406-
if (!E)
4407-
return;
4408-
4409-
if (auto *SVE = SingleValueStmtExpr::tryDigOutSingleValueStmtExpr(E))
4410-
ValidSingleValueStmtExprs.insert(SVE);
4411-
}
4412-
4413-
/// Mark a valid top-level expression with a given contextual purpose.
4414-
void markAnyValidTopLevelSingleValueStmt(Expr *E, ContextualTypePurpose ctp) {
4415-
// Allowed in returns, throws, and bindings.
4416-
switch (ctp) {
4417-
case CTP_ReturnStmt:
4418-
case CTP_ThrowStmt:
4419-
case CTP_Initialization:
4420-
markValidSingleValueStmt(E);
4421-
break;
4422-
default:
4423-
break;
4424-
}
4425-
}
4426-
4427-
MacroWalking getMacroWalkingBehavior() const override {
4428-
return MacroWalking::ArgumentsAndExpansion;
4429-
}
4430-
4431-
AssignExpr *findAssignment(Expr *E) const {
4432-
// Don't consider assignments if we have a parent expression (as otherwise
4433-
// this would be effectively allowing it in an arbitrary expression
4434-
// position).
4435-
if (Parent.getAsExpr())
4436-
return nullptr;
4437-
4438-
// Look through optional exprs, which are present for e.g x?.y = z, as
4439-
// we wrap the entire assign in the optional evaluation of the destination.
4440-
if (auto *OEE = dyn_cast<OptionalEvaluationExpr>(E)) {
4441-
E = OEE->getSubExpr();
4442-
while (auto *IIO = dyn_cast<InjectIntoOptionalExpr>(E))
4443-
E = IIO->getSubExpr();
4444-
}
4445-
return dyn_cast<AssignExpr>(E);
4446-
}
4447-
4448-
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
4449-
if (auto *SVE = dyn_cast<SingleValueStmtExpr>(E)) {
4450-
// Diagnose a SingleValueStmtExpr in a context that we do not currently
4451-
// support. If we start allowing these in arbitrary places, we'll need
4452-
// to ensure that autoclosures correctly contextualize them.
4453-
if (!ValidSingleValueStmtExprs.contains(SVE)) {
4454-
Diags.diagnose(SVE->getLoc(), diag::single_value_stmt_out_of_place,
4455-
SVE->getStmt()->getKind());
4456-
}
4457-
4458-
// Diagnose invalid SingleValueStmtExprs. This should only happen for
4459-
// expressions in positions that we didn't support before
4460-
// (e.g assignment or *explicit* return).
4461-
auto *S = SVE->getStmt();
4462-
auto mayProduceSingleValue = S->mayProduceSingleValue(Ctx);
4463-
switch (mayProduceSingleValue.getKind()) {
4464-
case IsSingleValueStmtResult::Kind::Valid:
4465-
break;
4466-
case IsSingleValueStmtResult::Kind::UnterminatedBranches: {
4467-
for (auto *branch : mayProduceSingleValue.getUnterminatedBranches()) {
4468-
if (auto *BS = dyn_cast<BraceStmt>(branch)) {
4469-
if (BS->empty()) {
4470-
Diags.diagnose(branch->getStartLoc(),
4471-
diag::single_value_stmt_branch_empty,
4472-
S->getKind());
4473-
continue;
4474-
}
4475-
}
4476-
// TODO: The wording of this diagnostic will need tweaking if either
4477-
// implicit last expressions or 'then' statements are enabled by
4478-
// default.
4479-
Diags.diagnose(branch->getEndLoc(),
4480-
diag::single_value_stmt_branch_must_end_in_result,
4481-
S->getKind(), isa<SwitchStmt>(S));
4482-
}
4483-
break;
4484-
}
4485-
case IsSingleValueStmtResult::Kind::NonExhaustiveIf: {
4486-
Diags.diagnose(S->getStartLoc(),
4487-
diag::if_expr_must_be_syntactically_exhaustive);
4488-
break;
4489-
}
4490-
case IsSingleValueStmtResult::Kind::NonExhaustiveDoCatch: {
4491-
Diags.diagnose(S->getStartLoc(),
4492-
diag::do_catch_expr_must_be_syntactically_exhaustive);
4493-
break;
4494-
}
4495-
case IsSingleValueStmtResult::Kind::HasLabel: {
4496-
// FIXME: We should offer a fix-it to remove (currently we don't track
4497-
// the colon SourceLoc).
4498-
auto label = cast<LabeledStmt>(S)->getLabelInfo();
4499-
Diags.diagnose(label.Loc,
4500-
diag::single_value_stmt_must_be_unlabeled, S->getKind())
4501-
.highlight(label.Loc);
4502-
break;
4503-
}
4504-
case IsSingleValueStmtResult::Kind::InvalidJumps: {
4505-
// Diagnose each invalid jump.
4506-
for (auto *jump : mayProduceSingleValue.getInvalidJumps()) {
4507-
Diags.diagnose(jump->getStartLoc(),
4508-
diag::cannot_jump_in_single_value_stmt,
4509-
jump->getKind(), S->getKind())
4510-
.highlight(jump->getSourceRange());
4511-
}
4512-
break;
4513-
}
4514-
case IsSingleValueStmtResult::Kind::NoResult:
4515-
// This is fine, we will have typed the expression as Void (we verify
4516-
// as such in the ASTVerifier).
4517-
break;
4518-
case IsSingleValueStmtResult::Kind::CircularReference:
4519-
// Already diagnosed.
4520-
break;
4521-
case IsSingleValueStmtResult::Kind::UnhandledStmt:
4522-
break;
4523-
}
4524-
return Action::Continue(E);
4525-
}
4526-
4527-
// Valid as the source of an assignment.
4528-
if (auto *AE = findAssignment(E))
4529-
markValidSingleValueStmt(AE->getSrc());
4530-
4531-
// Valid as a single expression body of a closure. This is needed in
4532-
// addition to ReturnStmt checking, as we will remove the return if the
4533-
// expression is inferred to be Never.
4534-
if (auto *ACE = dyn_cast<ClosureExpr>(E)) {
4535-
if (ACE->hasSingleExpressionBody())
4536-
markValidSingleValueStmt(ACE->getSingleExpressionBody());
4537-
}
4538-
return Action::Continue(E);
4539-
}
4540-
4541-
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
4542-
// Valid in a return/throw/then.
4543-
if (auto *RS = dyn_cast<ReturnStmt>(S)) {
4544-
if (RS->hasResult())
4545-
markValidSingleValueStmt(RS->getResult());
4546-
}
4547-
if (auto *TS = dyn_cast<ThrowStmt>(S))
4548-
markValidSingleValueStmt(TS->getSubExpr());
4549-
4550-
if (auto *TS = dyn_cast<ThenStmt>(S))
4551-
markValidSingleValueStmt(TS->getResult());
4552-
4553-
return Action::Continue(S);
4554-
}
4555-
4556-
PreWalkAction walkToDeclPre(Decl *D) override {
4557-
// Valid as an initializer of a pattern binding.
4558-
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
4559-
for (auto idx : range(PBD->getNumPatternEntries()))
4560-
markValidSingleValueStmt(PBD->getInit(idx));
4561-
4562-
return Action::Continue();
4563-
}
4564-
// We don't want to walk into any other decl, we will visit them as part of
4565-
// typeCheckDecl.
4566-
return Action::SkipNode();
4567-
}
4568-
};
4569-
} // end anonymous namespace
4570-
4571-
void swift::diagnoseOutOfPlaceExprs(
4572-
ASTContext &ctx, ASTNode root,
4573-
std::optional<ContextualTypePurpose> contextualPurpose) {
4574-
// TODO: We ought to consider moving this into pre-checking such that we can
4575-
// still diagnose on invalid code, and don't have to traverse over implicit
4576-
// exprs. We need to first separate out SequenceExpr folding though.
4577-
SingleValueStmtUsageChecker sveChecker(ctx, root, contextualPurpose);
4578-
root.walk(sveChecker);
4579-
}
4580-
45814381
/// Apply the warnings managed by VarDeclUsageChecker to the top level
45824382
/// code declarations that haven't been checked yet.
45834383
void swift::
@@ -6426,10 +6226,9 @@ diagnoseDictionaryLiteralDuplicateKeyEntries(const Expr *E,
64266226
//===----------------------------------------------------------------------===//
64276227

64286228
/// Emit diagnostics for syntactic restrictions on a given expression.
6429-
void swift::performSyntacticExprDiagnostics(
6430-
const Expr *E, const DeclContext *DC,
6431-
std::optional<ContextualTypePurpose> contextualPurpose, bool isExprStmt,
6432-
bool disableOutOfPlaceExprChecking) {
6229+
void swift::performSyntacticExprDiagnostics(const Expr *E,
6230+
const DeclContext *DC,
6231+
bool isExprStmt) {
64336232
auto &ctx = DC->getASTContext();
64346233
TypeChecker::diagnoseSelfAssignment(E);
64356234
diagSyntacticUseRestrictions(E, DC, isExprStmt);
@@ -6448,8 +6247,6 @@ void swift::performSyntacticExprDiagnostics(
64486247
diagnoseConstantArgumentRequirement(E, DC);
64496248
diagUnqualifiedAccessToMethodNamedSelf(E, DC);
64506249
diagnoseDictionaryLiteralDuplicateKeyEntries(E, DC);
6451-
if (!disableOutOfPlaceExprChecking)
6452-
diagnoseOutOfPlaceExprs(ctx, const_cast<Expr *>(E), contextualPurpose);
64536250
}
64546251

64556252
void swift::performStmtDiagnostics(const Stmt *S, DeclContext *DC) {

lib/Sema/MiscDiagnostics.h

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,9 @@ namespace swift {
3838
class ValueDecl;
3939
class ForEachStmt;
4040

41-
/// Diagnose any expressions that appear in an unsupported position. If visiting
42-
/// an expression directly, its \p contextualPurpose should be provided to
43-
/// evaluate its position.
44-
void diagnoseOutOfPlaceExprs(
45-
ASTContext &ctx, ASTNode root,
46-
std::optional<ContextualTypePurpose> contextualPurpose);
47-
4841
/// Emit diagnostics for syntactic restrictions on a given expression.
49-
///
50-
/// Note: \p contextualPurpose must be non-nil, unless
51-
/// \p disableOutOfPlaceExprChecking is set to \c true.
52-
void performSyntacticExprDiagnostics(
53-
const Expr *E, const DeclContext *DC,
54-
std::optional<ContextualTypePurpose> contextualPurpose, bool isExprStmt,
55-
bool disableOutOfPlaceExprChecking = false);
42+
void performSyntacticExprDiagnostics(const Expr *E, const DeclContext *DC,
43+
bool isExprStmt);
5644

5745
/// Emit diagnostics for a given statement.
5846
void performStmtDiagnostics(const Stmt *S, DeclContext *DC);

0 commit comments

Comments
 (0)