Skip to content

Commit 79be21f

Browse files
authored
Merge pull request #75528 from hamishknight/foldable-tangent
[Sema] Fold SequenceExpr in pre-checking pre-walk
2 parents 541ee12 + 7971056 commit 79be21f

File tree

5 files changed

+149
-150
lines changed

5 files changed

+149
-150
lines changed

lib/Sema/PreCheckExpr.cpp

Lines changed: 126 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -402,15 +402,108 @@ static BinaryExpr *getCompositionExpr(Expr *expr) {
402402
return nullptr;
403403
}
404404

405+
/// Diagnoses an unqualified `init` expression.
406+
///
407+
/// \param initExpr The \c init expression.
408+
/// \param dc The declaration context of \p initExpr.
409+
///
410+
/// \returns An expression matching `self.init` or `super.init` that can be used
411+
/// to recover, or `nullptr` if cannot recover.
412+
static UnresolvedDotExpr *
413+
diagnoseUnqualifiedInit(UnresolvedDeclRefExpr *initExpr, DeclContext *dc,
414+
ASTContext &ctx) {
415+
const auto loc = initExpr->getLoc();
416+
417+
enum class Suggestion : unsigned {
418+
None = 0,
419+
Self = 1,
420+
Super = 2,
421+
};
422+
423+
Suggestion suggestion = [dc]() {
424+
NominalTypeDecl *nominal = nullptr;
425+
{
426+
auto *typeDC = dc->getInnermostTypeContext();
427+
if (!typeDC) {
428+
// No type context--no suggestion.
429+
return Suggestion::None;
430+
}
431+
432+
nominal = typeDC->getSelfNominalTypeDecl();
433+
}
434+
435+
auto *classDecl = dyn_cast<ClassDecl>(nominal);
436+
if (!classDecl || !classDecl->hasSuperclass()) {
437+
// No class or no superclass--suggest 'self.'.
438+
return Suggestion::Self;
439+
}
440+
441+
if (auto *initDecl = dyn_cast<ConstructorDecl>(dc)) {
442+
if (initDecl->getAttrs().hasAttribute<ConvenienceAttr>()) {
443+
// Innermost context is a convenience initializer--suggest 'self.'.
444+
return Suggestion::Self;
445+
} else {
446+
// Innermost context is a designated initializer--suggest 'super.'.
447+
return Suggestion::Super;
448+
}
449+
}
450+
451+
// Class context but innermost context is not an initializer--suggest
452+
// 'self.'. 'super.' might be possible too, but is far lesss likely to be
453+
// the right answer.
454+
return Suggestion::Self;
455+
}();
456+
457+
auto diag =
458+
ctx.Diags.diagnose(loc, diag::unqualified_init, (unsigned)suggestion);
459+
460+
Expr *base = nullptr;
461+
switch (suggestion) {
462+
case Suggestion::None:
463+
return nullptr;
464+
case Suggestion::Self:
465+
diag.fixItInsert(loc, "self.");
466+
base = new (ctx)
467+
UnresolvedDeclRefExpr(DeclNameRef(ctx.Id_self), DeclRefKind::Ordinary,
468+
initExpr->getNameLoc());
469+
base->setImplicit(true);
470+
break;
471+
case Suggestion::Super:
472+
diag.fixItInsert(loc, "super.");
473+
base = new (ctx) SuperRefExpr(/*Self=*/nullptr, loc, /*Implicit=*/true);
474+
break;
475+
}
476+
477+
return new (ctx)
478+
UnresolvedDotExpr(base, /*dotloc=*/SourceLoc(), initExpr->getName(),
479+
initExpr->getNameLoc(), /*implicit=*/true);
480+
}
481+
405482
/// Bind an UnresolvedDeclRefExpr by performing name lookup and
406483
/// returning the resultant expression. Context is the DeclContext used
407484
/// for the lookup.
408485
Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE,
409486
DeclContext *DC) {
410-
// Process UnresolvedDeclRefExpr by doing an unqualified lookup.
487+
auto &Context = DC->getASTContext();
411488
DeclNameRef Name = UDRE->getName();
412489
SourceLoc Loc = UDRE->getLoc();
413490

491+
auto errorResult = [&]() -> Expr * {
492+
return new (Context) ErrorExpr(UDRE->getSourceRange());
493+
};
494+
495+
TypeChecker::checkForForbiddenPrefix(Context, Name.getBaseName());
496+
497+
// Try and recover if we have an unqualified 'init'.
498+
if (Name.getBaseName().isConstructor()) {
499+
auto *recoveryExpr = diagnoseUnqualifiedInit(UDRE, DC, Context);
500+
if (!recoveryExpr)
501+
return errorResult();
502+
503+
return recoveryExpr;
504+
}
505+
506+
// Process UnresolvedDeclRefExpr by doing an unqualified lookup.
414507
DeclNameRef LookupName = Name;
415508
if (Name.isCompoundName()) {
416509
auto &context = DC->getASTContext();
@@ -430,12 +523,6 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE,
430523
LookupName = DeclNameRef(lookupName);
431524
}
432525

433-
auto &Context = DC->getASTContext();
434-
435-
auto errorResult = [&]() -> Expr * {
436-
return new (Context) ErrorExpr(UDRE->getSourceRange());
437-
};
438-
439526
// Perform standard value name lookup.
440527
NameLookupOptions lookupOptions = defaultUnqualifiedLookupOptions;
441528
// TODO: Include all of the possible members to give a solver a
@@ -867,83 +954,6 @@ TypeChecker::getSelfForInitDelegationInConstructor(DeclContext *DC,
867954
return nullptr;
868955
}
869956

870-
/// Diagnoses an unqualified `init` expression.
871-
///
872-
/// \param initExpr The \c init expression.
873-
/// \param dc The declaration context of \p initExpr.
874-
///
875-
/// \returns An expression matching `self.init` or `super.init` that can be used
876-
/// to recover, or `nullptr` if cannot recover.
877-
static UnresolvedDotExpr *
878-
diagnoseUnqualifiedInit(UnresolvedDeclRefExpr *initExpr, DeclContext *dc,
879-
ASTContext &ctx) {
880-
const auto loc = initExpr->getLoc();
881-
882-
enum class Suggestion : unsigned {
883-
None = 0,
884-
Self = 1,
885-
Super = 2,
886-
};
887-
888-
Suggestion suggestion = [dc]() {
889-
NominalTypeDecl *nominal = nullptr;
890-
{
891-
auto *typeDC = dc->getInnermostTypeContext();
892-
if (!typeDC) {
893-
// No type context--no suggestion.
894-
return Suggestion::None;
895-
}
896-
897-
nominal = typeDC->getSelfNominalTypeDecl();
898-
}
899-
900-
auto *classDecl = dyn_cast<ClassDecl>(nominal);
901-
if (!classDecl || !classDecl->hasSuperclass()) {
902-
// No class or no superclass--suggest 'self.'.
903-
return Suggestion::Self;
904-
}
905-
906-
if (auto *initDecl = dyn_cast<ConstructorDecl>(dc)) {
907-
if (initDecl->getAttrs().hasAttribute<ConvenienceAttr>()) {
908-
// Innermost context is a convenience initializer--suggest 'self.'.
909-
return Suggestion::Self;
910-
} else {
911-
// Innermost context is a designated initializer--suggest 'super.'.
912-
return Suggestion::Super;
913-
}
914-
}
915-
916-
// Class context but innermost context is not an initializer--suggest
917-
// 'self.'. 'super.' might be possible too, but is far lesss likely to be
918-
// the right answer.
919-
return Suggestion::Self;
920-
}();
921-
922-
auto diag =
923-
ctx.Diags.diagnose(loc, diag::unqualified_init, (unsigned)suggestion);
924-
925-
Expr *base = nullptr;
926-
switch (suggestion) {
927-
case Suggestion::None:
928-
return nullptr;
929-
case Suggestion::Self:
930-
diag.fixItInsert(loc, "self.");
931-
base = new (ctx)
932-
UnresolvedDeclRefExpr(DeclNameRef(ctx.Id_self), DeclRefKind::Ordinary,
933-
initExpr->getNameLoc());
934-
base->setImplicit(true);
935-
break;
936-
case Suggestion::Super:
937-
diag.fixItInsert(loc, "super.");
938-
base = new (ctx) SuperRefExpr(/*Self=*/nullptr, loc, /*Implicit=*/true);
939-
break;
940-
}
941-
942-
return new (ctx)
943-
UnresolvedDotExpr(base, /*dotloc=*/SourceLoc(), initExpr->getName(),
944-
initExpr->getNameLoc(), /*implicit=*/true);
945-
}
946-
947957
namespace {
948958
/// Update the function reference kind based on adding a direct call to a
949959
/// callee with this kind.
@@ -1046,9 +1056,6 @@ namespace {
10461056
/// Keep track of acceptable DiscardAssignmentExpr's.
10471057
llvm::SmallPtrSet<DiscardAssignmentExpr*, 2> CorrectDiscardAssignmentExprs;
10481058

1049-
/// The current number of nested \c SequenceExprs that we're within.
1050-
unsigned SequenceExprDepth = 0;
1051-
10521059
/// The current number of nested \c SingleValueStmtExprs that we're within.
10531060
unsigned SingleValueStmtExprDepth = 0;
10541061

@@ -1117,6 +1124,16 @@ namespace {
11171124
PreWalkResult<Expr *> walkToExprPre(Expr *expr) override {
11181125
auto &diags = Ctx.Diags;
11191126

1127+
// Fold sequence expressions.
1128+
if (auto *seqExpr = dyn_cast<SequenceExpr>(expr)) {
1129+
auto result = TypeChecker::foldSequence(seqExpr, DC);
1130+
result = result->walk(*this);
1131+
if (!result)
1132+
return Action::Stop();
1133+
// Already walked.
1134+
return Action::SkipNode(result);
1135+
}
1136+
11201137
// FIXME(diagnostics): `InOutType` could appear here as a result
11211138
// of successful re-typecheck of the one of the sub-expressions e.g.
11221139
// `let _: Int = { (s: inout S) in s.bar() }`. On the first
@@ -1148,11 +1165,9 @@ namespace {
11481165
return Action::Stop();
11491166

11501167
// If we're going to recurse, record this expression on the stack.
1151-
if (recursive) {
1152-
if (isa<SequenceExpr>(expr))
1153-
SequenceExprDepth++;
1168+
if (recursive)
11541169
ExprStack.push_back(expr);
1155-
}
1170+
11561171
return Action::VisitNodeIf(recursive, expr);
11571172
};
11581173

@@ -1208,38 +1223,8 @@ namespace {
12081223
return finish(true, expr);
12091224
}
12101225

1211-
if (auto unresolved = dyn_cast<UnresolvedDeclRefExpr>(expr)) {
1212-
TypeChecker::checkForForbiddenPrefix(
1213-
getASTContext(), unresolved->getName().getBaseName());
1214-
1215-
if (unresolved->getName().getBaseName().isConstructor()) {
1216-
if (auto *recoveryExpr =
1217-
diagnoseUnqualifiedInit(unresolved, DC, Ctx)) {
1218-
return finish(true, recoveryExpr);
1219-
}
1220-
1221-
return finish(false,
1222-
new (Ctx) ErrorExpr(unresolved->getSourceRange()));
1223-
}
1224-
1225-
auto *refExpr = TypeChecker::resolveDeclRefExpr(unresolved, DC);
1226-
1227-
// Check whether this is standalone `self` in init accessor, which
1228-
// is invalid.
1229-
if (auto *accessor = DC->getInnermostPropertyAccessorContext()) {
1230-
if (accessor->isInitAccessor() && isa<DeclRefExpr>(refExpr)) {
1231-
auto *DRE = cast<DeclRefExpr>(refExpr);
1232-
if (accessor->getImplicitSelfDecl() == DRE->getDecl() &&
1233-
!isa_and_nonnull<UnresolvedDotExpr>(Parent.getAsExpr())) {
1234-
diags.diagnose(unresolved->getLoc(),
1235-
diag::invalid_use_of_self_in_init_accessor);
1236-
refExpr = new (Ctx) ErrorExpr(unresolved->getSourceRange());
1237-
}
1238-
}
1239-
}
1240-
1241-
return finish(true, refExpr);
1242-
}
1226+
if (auto *unresolved = dyn_cast<UnresolvedDeclRefExpr>(expr))
1227+
return finish(true, TypeChecker::resolveDeclRefExpr(unresolved, DC));
12431228

12441229
// Let's try to figure out if `InOutExpr` is out of place early
12451230
// otherwise there is a risk of producing solutions which can't
@@ -1312,23 +1297,26 @@ namespace {
13121297
assert(ExprStack.back() == expr);
13131298
ExprStack.pop_back();
13141299

1315-
// Fold sequence expressions.
1316-
if (auto *seqExpr = dyn_cast<SequenceExpr>(expr)) {
1317-
auto result = TypeChecker::foldSequence(seqExpr, DC);
1318-
SequenceExprDepth--;
1319-
result = result->walk(*this);
1320-
if (!result)
1321-
return Action::Stop();
1322-
1323-
return Action::Continue(result);
1324-
}
1325-
13261300
// Type check the type parameters in an UnresolvedSpecializeExpr.
13271301
if (auto *us = dyn_cast<UnresolvedSpecializeExpr>(expr)) {
13281302
if (auto *typeExpr = simplifyUnresolvedSpecializeExpr(us))
13291303
return Action::Continue(typeExpr);
13301304
}
1331-
1305+
1306+
// Check whether this is standalone `self` in init accessor, which
1307+
// is invalid.
1308+
if (auto *DRE = dyn_cast<DeclRefExpr>(expr)) {
1309+
if (auto *accessor = DC->getInnermostPropertyAccessorContext()) {
1310+
if (accessor->isInitAccessor() &&
1311+
accessor->getImplicitSelfDecl() == DRE->getDecl() &&
1312+
!isa_and_nonnull<UnresolvedDotExpr>(Parent.getAsExpr())) {
1313+
Ctx.Diags.diagnose(DRE->getLoc(),
1314+
diag::invalid_use_of_self_in_init_accessor);
1315+
return Action::Continue(new (Ctx) ErrorExpr(DRE->getSourceRange()));
1316+
}
1317+
}
1318+
}
1319+
13321320
// If we're about to step out of a ClosureExpr, restore the DeclContext.
13331321
if (auto *ce = dyn_cast<ClosureExpr>(expr)) {
13341322
assert(DC == ce && "DeclContext imbalance");
@@ -1432,12 +1420,9 @@ namespace {
14321420
return Action::Continue(simplified);
14331421

14341422
// Diagnose a '_' that isn't on the immediate LHS of an assignment. We
1435-
// skip diagnostics if we've explicitly marked the expression as valid,
1436-
// or if we're inside a SequenceExpr (since the whole tree will be
1437-
// re-checked when we finish folding anyway).
1423+
// skip diagnostics if we've explicitly marked the expression as valid.
14381424
if (auto *DAE = dyn_cast<DiscardAssignmentExpr>(expr)) {
1439-
if (!CorrectDiscardAssignmentExprs.count(DAE) &&
1440-
SequenceExprDepth == 0) {
1425+
if (!CorrectDiscardAssignmentExprs.count(DAE)) {
14411426
ctx.Diags.diagnose(expr->getLoc(),
14421427
diag::discard_expr_outside_of_assignment);
14431428
return Action::Stop();
@@ -1694,7 +1679,7 @@ bool PreCheckExpression::possiblyInTypeContext(Expr *E) {
16941679
/// been explicitly marked as correct, and the current AST state allows it.
16951680
bool PreCheckExpression::canSimplifyDiscardAssignmentExpr(
16961681
DiscardAssignmentExpr *DAE) {
1697-
return !CorrectDiscardAssignmentExprs.count(DAE) && SequenceExprDepth == 0 &&
1682+
return !CorrectDiscardAssignmentExprs.count(DAE) &&
16981683
possiblyInTypeContext(DAE);
16991684
}
17001685

lib/Sema/TypeCheckExpr.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -418,12 +418,8 @@ static Expr *foldSequence(DeclContext *DC,
418418
}
419419

420420
// Pull out the next binary operator.
421-
Op op2{S[0], TypeChecker::lookupPrecedenceGroupForInfixOperator(
422-
DC, S[0], /*diagnose=*/true)};
423-
424-
// If the second operator's precedence is lower than the
425-
// precedence bound, break out of the loop.
426-
if (!precedenceBound.shouldConsider(op2.precedence)) break;
421+
Op op2 = getNextOperator();
422+
if (!op2) break;
427423

428424
// If we're missing precedence info for either operator, treat them
429425
// as non-associative.
@@ -635,6 +631,15 @@ swift::DefaultTypeRequest::evaluate(Evaluator &evaluator,
635631
}
636632

637633
Expr *TypeChecker::foldSequence(SequenceExpr *expr, DeclContext *dc) {
634+
// First resolve any unresolved decl references in operator positions.
635+
for (auto i : indices(expr->getElements())) {
636+
if (i % 2 == 0)
637+
continue;
638+
auto *elt = expr->getElement(i);
639+
if (auto *UDRE = dyn_cast<UnresolvedDeclRefExpr>(elt))
640+
elt = TypeChecker::resolveDeclRefExpr(UDRE, dc);
641+
expr->setElement(i, elt);
642+
}
638643
ArrayRef<Expr*> Elts = expr->getElements();
639644
assert(Elts.size() > 1 && "inadequate number of elements in sequence");
640645
assert((Elts.size() & 1) == 1 && "even number of elements in sequence");

test/Constraints/argument_matching.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,3 +1810,14 @@ func test_extraneous_argument_with_inout() {
18101810
var x: Int = 0
18111811
test(42, &x) // expected-error {{extra argument in call}}
18121812
}
1813+
1814+
// https://github.com/swiftlang/swift/issues/75527
1815+
struct Issue75527 {
1816+
func foo(x: Int) {}
1817+
1818+
func bar() {
1819+
typealias Magic<T> = T
1820+
let fn = Issue75527.foo(self) as Magic
1821+
fn(0) // Make sure the argument label does not escape here.
1822+
}
1823+
}

0 commit comments

Comments
 (0)