Skip to content

Commit 8249593

Browse files
authored
Merge pull request #11047 from CodaFi/who-cleans-the-cleanser
[NFC] Merge ExprCleaner and ExprCleanser
2 parents b9f468e + ebfb3e8 commit 8249593

File tree

3 files changed

+55
-100
lines changed

3 files changed

+55
-100
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4635,14 +4635,27 @@ static bool diagnoseImplicitSelfErrors(Expr *fnExpr, Expr *argExpr,
46354635
// If argument wasn't properly type-checked, let's retry without changing AST.
46364636
if (!argType || argType->hasUnresolvedType() || argType->hasTypeVariable() ||
46374637
argType->hasTypeParameter()) {
4638-
// Let's type check argument expression without any contextual information.
4639-
ConcreteDeclRef ref = nullptr;
4640-
auto typeResult =
4641-
TC.getTypeOfExpressionWithoutApplying(argExpr, CS.DC, ref);
4642-
if (!typeResult.hasValue())
4638+
auto *argTuple = dyn_cast<TupleExpr>(argExpr);
4639+
if (!argTuple) {
4640+
// Bail out if we don't have a well-formed argument list.
46434641
return false;
4642+
}
4643+
4644+
// Let's type check individual argument expressions without any
4645+
// contextual information to try to recover an argument type that
4646+
// matches what the user actually wrote instead of what the typechecker
4647+
// expects.
4648+
SmallVector<TupleTypeElt, 4> elts;
4649+
for (auto *el : argTuple->getElements()) {
4650+
ConcreteDeclRef ref = nullptr;
4651+
auto typeResult =
4652+
TC.getTypeOfExpressionWithoutApplying(el, CS.DC, ref);
4653+
if (!typeResult.hasValue())
4654+
return false;
4655+
elts.push_back(typeResult.getValue());
4656+
}
46444657

4645-
argType = typeResult.getValue();
4658+
argType = TupleType::get(elts, CS.getASTContext());
46464659
}
46474660

46484661
auto typeKind = argType->getKind();
@@ -8758,6 +8771,10 @@ static void noteArchetypeSource(const TypeLoc &loc, ArchetypeType *archetype,
87588771
// `Pair<Any, Any>`.
87598772
// Right now we only handle this when the type that's at fault is the
87608773
// top-level type passed to this function.
8774+
if (loc.getType().isNull()) {
8775+
return;
8776+
}
8777+
87618778
ArrayRef<Type> genericArgs;
87628779
if (auto *boundGenericTy = loc.getType()->getAs<BoundGenericType>()) {
87638780
if (boundGenericTy->getDecl() == FoundDecl)

lib/Sema/ConstraintSystem.h

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3034,54 +3034,73 @@ ForcedCheckedCastExpr *findForcedDowncast(ASTContext &ctx, Expr *expr);
30343034
/// their type variables, and we don't want pointers into the original AST to
30353035
/// dereference these now-dangling types.
30363036
class ExprCleaner {
3037-
llvm::SmallDenseMap<Expr *, Type> Exprs;
3038-
llvm::SmallDenseMap<TypeLoc *, Type> TypeLocs;
3039-
llvm::SmallDenseMap<Pattern *, Type> Patterns;
3037+
llvm::SmallVector<Expr*,4> Exprs;
3038+
llvm::SmallVector<TypeLoc*, 4> TypeLocs;
3039+
llvm::SmallVector<Pattern*, 4> Patterns;
3040+
llvm::SmallVector<VarDecl*, 4> Vars;
30403041
public:
30413042

30423043
ExprCleaner(Expr *E) {
3043-
struct ExprCleanserImpl : public ASTWalker {
3044+
struct ExprCleanerImpl : public ASTWalker {
30443045
ExprCleaner *TS;
3045-
ExprCleanserImpl(ExprCleaner *TS) : TS(TS) {}
3046+
ExprCleanerImpl(ExprCleaner *TS) : TS(TS) {}
30463047

30473048
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
3048-
TS->Exprs.insert({ expr, expr->getType() });
3049+
TS->Exprs.push_back(expr);
30493050
return { true, expr };
30503051
}
30513052

30523053
bool walkToTypeLocPre(TypeLoc &TL) override {
3053-
TS->TypeLocs.insert({ &TL, TL.getType() });
3054+
TS->TypeLocs.push_back(&TL);
30543055
return true;
30553056
}
30563057

30573058
std::pair<bool, Pattern*> walkToPatternPre(Pattern *P) override {
3058-
TS->Patterns.insert({ P, P->hasType() ? P->getType() : Type() });
3059+
TS->Patterns.push_back(P);
30593060
return { true, P };
30603061
}
30613062

3063+
bool walkToDeclPre(Decl *D) override {
3064+
if (auto VD = dyn_cast<VarDecl>(D))
3065+
TS->Vars.push_back(VD);
3066+
3067+
return true;
3068+
}
3069+
30623070
// Don't walk into statements. This handles the BraceStmt in
30633071
// non-single-expr closures, so we don't walk into their body.
30643072
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
30653073
return { false, S };
30663074
}
30673075
};
30683076

3069-
E->walk(ExprCleanserImpl(this));
3077+
E->walk(ExprCleanerImpl(this));
30703078
}
30713079

30723080
~ExprCleaner() {
30733081
// Check each of the expression nodes to verify that there are no type
30743082
// variables hanging out. If so, just nuke the type.
30753083
for (auto E : Exprs) {
3076-
E.getFirst()->setType(E.getSecond());
3084+
if (E->getType() && E->getType()->hasTypeVariable())
3085+
E->setType(Type());
30773086
}
30783087

30793088
for (auto TL : TypeLocs) {
3080-
TL.getFirst()->setType(TL.getSecond(), false);
3089+
if (TL->getTypeRepr() && TL->getType() &&
3090+
TL->getType()->hasTypeVariable())
3091+
TL->setType(Type(), false);
30813092
}
30823093

30833094
for (auto P : Patterns) {
3084-
P.getFirst()->setType(P.getSecond());
3095+
if (P->hasType() && P->getType()->hasTypeVariable())
3096+
P->setType(Type());
3097+
}
3098+
3099+
for (auto VD : Vars) {
3100+
if (VD->hasType() && VD->getType()->hasTypeVariable()) {
3101+
VD->setType(Type());
3102+
VD->setInterfaceType(Type());
3103+
}
30853104
}
30863105
}
30873106
};

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 1 addition & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,87 +1689,6 @@ solveForExpression(Expr *&expr, DeclContext *dc, Type convertType,
16891689
return false;
16901690
}
16911691

1692-
namespace {
1693-
/// ExprCleanser - This class is used by typeCheckExpression to ensure that in
1694-
/// no situation will an expr node be left with a dangling type variable stuck
1695-
/// to it. Often type checking will create new AST nodes and replace old ones
1696-
/// (e.g. by turning an UnresolvedDotExpr into a MemberRefExpr). These nodes
1697-
/// might be left with pointers into the temporary constraint system through
1698-
/// their type variables, and we don't want pointers into the original AST to
1699-
/// dereference these now-dangling types.
1700-
class ExprCleanser {
1701-
llvm::SmallVector<Expr*,4> Exprs;
1702-
llvm::SmallVector<TypeLoc*, 4> TypeLocs;
1703-
llvm::SmallVector<Pattern*, 4> Patterns;
1704-
llvm::SmallVector<VarDecl*, 4> Vars;
1705-
public:
1706-
1707-
ExprCleanser(Expr *E) {
1708-
struct ExprCleanserImpl : public ASTWalker {
1709-
ExprCleanser *TS;
1710-
ExprCleanserImpl(ExprCleanser *TS) : TS(TS) {}
1711-
1712-
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
1713-
TS->Exprs.push_back(expr);
1714-
return { true, expr };
1715-
}
1716-
1717-
bool walkToTypeLocPre(TypeLoc &TL) override {
1718-
TS->TypeLocs.push_back(&TL);
1719-
return true;
1720-
}
1721-
1722-
std::pair<bool, Pattern*> walkToPatternPre(Pattern *P) override {
1723-
TS->Patterns.push_back(P);
1724-
return { true, P };
1725-
}
1726-
1727-
bool walkToDeclPre(Decl *D) override {
1728-
if (auto VD = dyn_cast<VarDecl>(D))
1729-
TS->Vars.push_back(VD);
1730-
1731-
return true;
1732-
}
1733-
1734-
// Don't walk into statements. This handles the BraceStmt in
1735-
// non-single-expr closures, so we don't walk into their body.
1736-
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
1737-
return { false, S };
1738-
}
1739-
};
1740-
1741-
E->walk(ExprCleanserImpl(this));
1742-
}
1743-
1744-
~ExprCleanser() {
1745-
// Check each of the expression nodes to verify that there are no type
1746-
// variables hanging out. If so, just nuke the type.
1747-
for (auto E : Exprs) {
1748-
if (E->getType() && E->getType()->hasTypeVariable())
1749-
E->setType(Type());
1750-
}
1751-
1752-
for (auto TL : TypeLocs) {
1753-
if (TL->getTypeRepr() && TL->getType() &&
1754-
TL->getType()->hasTypeVariable())
1755-
TL->setType(Type(), false);
1756-
}
1757-
1758-
for (auto P : Patterns) {
1759-
if (P->hasType() && P->getType()->hasTypeVariable())
1760-
P->setType(Type());
1761-
}
1762-
1763-
for (auto VD : Vars) {
1764-
if (VD->hasType() && VD->getType()->hasTypeVariable()) {
1765-
VD->setType(Type());
1766-
VD->setInterfaceType(Type());
1767-
}
1768-
}
1769-
}
1770-
};
1771-
} // end anonymous namespace
1772-
17731692
#pragma mark High-level entry points
17741693
Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
17751694
TypeLoc convertType,
@@ -1791,7 +1710,7 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
17911710
ConstraintSystem cs(*this, dc, csOptions);
17921711
cs.baseCS = baseCS;
17931712
CleanupIllFormedExpressionRAII cleanup(Context, expr);
1794-
ExprCleanser cleanup2(expr);
1713+
ExprCleaner cleanup2(expr);
17951714

17961715
// Verify that a purpose was specified if a convertType was. Note that it is
17971716
// ok to have a purpose without a convertType (which is used for call

0 commit comments

Comments
 (0)