Skip to content

Commit ebfb3e8

Browse files
committed
[NFC] Merge ExprCleaner and ExprCleanser
The distinction was made between these two because of rdar://25341015, wherein we needed a diagnostic that could detect the shadowing of global functions by calls in protocols that don't match any of the protocol's members. This used to function by hoping that we had an argument tuple type lying around after type checking. The expr cleaner would re-write that type into the AST and we would look up based on it. Now that we write Type() into the AST on failure, we must instead type check the component parts of the argument themselves to form a tuple type to make the lookup.
1 parent adf1e2e commit ebfb3e8

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)