Skip to content

Commit fac59ce

Browse files
committed
[Diagnostics] Improve diagnostics of self assignment of the anonymous closure parameters
1 parent d37e93d commit fac59ce

File tree

5 files changed

+68
-48
lines changed

5 files changed

+68
-48
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4290,6 +4290,59 @@ void ConstraintSystem::diagnoseAssignmentFailure(Expr *dest, Type destTy,
42904290
diag::assignment_lhs_not_lvalue);
42914291
}
42924292

4293+
//===----------------------------------------------------------------------===//
4294+
// Diagnose assigning variable to itself.
4295+
//===----------------------------------------------------------------------===//
4296+
4297+
static Decl *findSimpleReferencedDecl(const Expr *E) {
4298+
if (auto *LE = dyn_cast<LoadExpr>(E))
4299+
E = LE->getSubExpr();
4300+
4301+
if (auto *DRE = dyn_cast<DeclRefExpr>(E))
4302+
return DRE->getDecl();
4303+
4304+
return nullptr;
4305+
}
4306+
4307+
static std::pair<Decl *, Decl *> findReferencedDecl(const Expr *E) {
4308+
E = E->getValueProvidingExpr();
4309+
4310+
if (auto *LE = dyn_cast<LoadExpr>(E))
4311+
return findReferencedDecl(LE->getSubExpr());
4312+
4313+
if (auto *AE = dyn_cast<AssignExpr>(E))
4314+
return findReferencedDecl(AE->getDest());
4315+
4316+
if (auto *D = findSimpleReferencedDecl(E))
4317+
return std::make_pair(nullptr, D);
4318+
4319+
if (auto *MRE = dyn_cast<MemberRefExpr>(E)) {
4320+
if (auto *BaseDecl = findSimpleReferencedDecl(MRE->getBase()))
4321+
return std::make_pair(BaseDecl, MRE->getMember().getDecl());
4322+
}
4323+
4324+
return std::make_pair(nullptr, nullptr);
4325+
}
4326+
4327+
bool TypeChecker::diagnoseSelfAssignment(const Expr *E) {
4328+
auto AE = dyn_cast<AssignExpr>(E);
4329+
if (!AE)
4330+
return false;
4331+
4332+
auto LHSDecl = findReferencedDecl(AE->getDest());
4333+
auto RHSDecl = findReferencedDecl(AE->getSrc());
4334+
4335+
if (LHSDecl.second && LHSDecl == RHSDecl) {
4336+
diagnose(AE->getLoc(), LHSDecl.first ? diag::self_assignment_prop
4337+
: diag::self_assignment_var)
4338+
.highlight(AE->getDest()->getSourceRange())
4339+
.highlight(AE->getSrc()->getSourceRange());
4340+
return true;
4341+
}
4342+
4343+
return false;
4344+
}
4345+
42934346
static bool isSymmetricBinaryOperator(const CalleeCandidateInfo &CCI) {
42944347
// If we don't have at least one known candidate, don't trigger.
42954348
if (CCI.candidates.empty()) return false;
@@ -6041,6 +6094,9 @@ bool FailureDiagnosis::visitAssignExpr(AssignExpr *assignExpr) {
60416094
return true;
60426095
}
60436096

6097+
if (CS->TC.diagnoseSelfAssignment(assignExpr))
6098+
return true;
6099+
60446100
// Type check the destination first, so we can coerce the source to it.
60456101
auto destExpr = typeCheckChildIndependently(assignExpr->getDest(),
60466102
TCC_AllowLValue);

lib/Sema/CSGen.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,12 @@ namespace {
150150

151151
// We'd like to look at the elements of arrays and dictionaries.
152152
isa<ArrayExpr>(expr) ||
153-
isa<DictionaryExpr>(expr)) {
153+
isa<DictionaryExpr>(expr) ||
154+
155+
// assignment expression can involve anonymous closure parameters
156+
// as source and destination, so it's beneficial for diagnostics if
157+
// we look at the assignment.
158+
isa<AssignExpr>(expr)) {
154159
LinkedExprs.push_back(expr);
155160
return {false, expr};
156161
}

lib/Sema/MiscDiagnostics.cpp

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -38,52 +38,6 @@ static Expr *isImplicitPromotionToOptional(Expr *E) {
3838
return nullptr;
3939
}
4040

41-
//===----------------------------------------------------------------------===//
42-
// Diagnose assigning variable to itself.
43-
//===----------------------------------------------------------------------===//
44-
45-
static Decl *findSimpleReferencedDecl(const Expr *E) {
46-
if (auto *LE = dyn_cast<LoadExpr>(E))
47-
E = LE->getSubExpr();
48-
49-
if (auto *DRE = dyn_cast<DeclRefExpr>(E))
50-
return DRE->getDecl();
51-
52-
return nullptr;
53-
}
54-
55-
static std::pair<Decl *, Decl *> findReferencedDecl(const Expr *E) {
56-
if (auto *LE = dyn_cast<LoadExpr>(E))
57-
E = LE->getSubExpr();
58-
59-
if (auto *D = findSimpleReferencedDecl(E))
60-
return std::make_pair(nullptr, D);
61-
62-
if (auto *MRE = dyn_cast<MemberRefExpr>(E)) {
63-
if (auto *BaseDecl = findSimpleReferencedDecl(MRE->getBase()))
64-
return std::make_pair(BaseDecl, MRE->getMember().getDecl());
65-
}
66-
67-
return std::make_pair(nullptr, nullptr);
68-
}
69-
70-
/// Diagnose assigning variable to itself.
71-
static void diagSelfAssignment(TypeChecker &TC, const Expr *E) {
72-
auto *AE = dyn_cast<AssignExpr>(E);
73-
if (!AE)
74-
return;
75-
76-
auto LHSDecl = findReferencedDecl(AE->getDest());
77-
auto RHSDecl = findReferencedDecl(AE->getSrc());
78-
if (LHSDecl.second && LHSDecl == RHSDecl) {
79-
TC.diagnose(AE->getLoc(), LHSDecl.first ? diag::self_assignment_prop
80-
: diag::self_assignment_var)
81-
.highlight(AE->getDest()->getSourceRange())
82-
.highlight(AE->getSrc()->getSourceRange());
83-
}
84-
}
85-
86-
8741
/// Diagnose syntactic restrictions of expressions.
8842
///
8943
/// - Module values may only occur as part of qualification.
@@ -3802,7 +3756,7 @@ static void diagnoseUnintendedOptionalBehavior(TypeChecker &TC, const Expr *E,
38023756
void swift::performSyntacticExprDiagnostics(TypeChecker &TC, const Expr *E,
38033757
const DeclContext *DC,
38043758
bool isExprStmt) {
3805-
diagSelfAssignment(TC, E);
3759+
TC.diagnoseSelfAssignment(E);
38063760
diagSyntacticUseRestrictions(TC, E, DC, isExprStmt);
38073761
diagRecursivePropertyAccess(TC, E, DC);
38083762
diagnoseImplicitSelfUseInClosure(TC, E, DC);

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,6 +2016,9 @@ class TypeChecker final : public LazyResolver {
20162016
VarDecl *getSelfForInitDelegationInConstructor(DeclContext *DC,
20172017
UnresolvedDotExpr *ctorRef);
20182018

2019+
/// Diagnose assigning variable to itself.
2020+
bool diagnoseSelfAssignment(const Expr *E);
2021+
20192022
/// When referencing a class initializer, check that the base expression is
20202023
/// either a static metatype or that the initializer is 'required'.
20212024
bool

test/Constraints/closures.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,3 +384,5 @@ func g_2994(arg: Int) -> Double {
384384
C_2994<S_2994>(arg: { (r: S_2994) in f_2994(arg: g_2994(arg: r.dataOffset)) }) // expected-error {{cannot convert value of type 'Double' to expected argument type 'String'}}
385385

386386
let _ = { $0[$1] }(1, 1) // expected-error {{cannot subscript a value of incorrect or ambiguous type}}
387+
let _ = { $0 = ($0 = {}) } // expected-error {{assigning a variable to itself}}
388+
let _ = { $0 = $0 = 42 } // expected-error {{assigning a variable to itself}}

0 commit comments

Comments
 (0)