Skip to content

Commit 7976162

Browse files
authored
Merge pull request #32567 from slavapestov/sink-sanitize-expr
Sink SanitizeExpr down into code completion
2 parents 0a48a39 + 0232cd0 commit 7976162

12 files changed

+368
-401
lines changed

lib/Sema/CSGen.cpp

Lines changed: 0 additions & 319 deletions
Original file line numberDiff line numberDiff line change
@@ -36,26 +36,6 @@
3636
using namespace swift;
3737
using namespace swift::constraints;
3838

39-
/// Find the declaration directly referenced by this expression.
40-
static std::pair<ValueDecl *, FunctionRefKind>
41-
findReferencedDecl(Expr *expr, DeclNameLoc &loc) {
42-
do {
43-
expr = expr->getSemanticsProvidingExpr();
44-
45-
if (auto ice = dyn_cast<ImplicitConversionExpr>(expr)) {
46-
expr = ice->getSubExpr();
47-
continue;
48-
}
49-
50-
if (auto dre = dyn_cast<DeclRefExpr>(expr)) {
51-
loc = dre->getNameLoc();
52-
return { dre->getDecl(), dre->getFunctionRefKind() };
53-
}
54-
55-
return { nullptr, FunctionRefKind::Unapplied };
56-
} while (true);
57-
}
58-
5939
static bool isArithmeticOperatorDecl(ValueDecl *vd) {
6040
return vd &&
6141
(vd->getBaseName() == "+" ||
@@ -915,35 +895,6 @@ namespace {
915895
};
916896
} // end anonymous namespace
917897

918-
namespace {
919-
// Check if \p E is a call expression to curried thunk of "KeyPath as function".
920-
// i.e. '{ `$kp$` in { $0[keyPath: $kp$] } }(keypath)'
921-
static bool isKeyPathCurriedThunkCallExpr(Expr *E) {
922-
auto CE = dyn_cast<CallExpr>(E);
923-
if (!CE)
924-
return false;
925-
auto thunk = dyn_cast<AutoClosureExpr>(CE->getFn());
926-
if (!thunk)
927-
return false;
928-
if (thunk->getParameters()->size() != 1 ||
929-
thunk->getParameters()->get(0)->getParameterName().str() != "$kp$")
930-
return false;
931-
932-
auto PE = dyn_cast<ParenExpr>(CE->getArg());
933-
if (!PE)
934-
return false;
935-
return isa<KeyPathExpr>(PE->getSubExpr());
936-
}
937-
938-
// Extract the keypath expression from the curried thunk expression.
939-
static Expr *extractKeyPathFromCurryThunkCall(Expr *E) {
940-
assert(isKeyPathCurriedThunkCallExpr(E));
941-
auto call = cast<CallExpr>(E);
942-
auto arg = cast<ParenExpr>(call->getArg());
943-
return arg->getSubExpr();
944-
}
945-
} // end anonymous namespace
946-
947898
namespace {
948899

949900
class ConstraintGenerator : public ExprVisitor<ConstraintGenerator, Type> {
@@ -3776,272 +3727,6 @@ namespace {
37763727
}
37773728
};
37783729

3779-
/// AST walker that "sanitizes" an expression for re-typechecking during
3780-
/// code completion.
3781-
///
3782-
/// FIXME: Remove this.
3783-
class SanitizeExpr : public ASTWalker {
3784-
ASTContext &C;
3785-
bool ShouldReusePrecheckedType;
3786-
llvm::SmallDenseMap<OpaqueValueExpr *, Expr *, 4> OpenExistentials;
3787-
3788-
public:
3789-
SanitizeExpr(ASTContext &C,
3790-
bool shouldReusePrecheckedType)
3791-
: C(C), ShouldReusePrecheckedType(shouldReusePrecheckedType) { }
3792-
3793-
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
3794-
while (true) {
3795-
3796-
// If we should reuse pre-checked types, don't sanitize the expression
3797-
// if it's already type-checked.
3798-
if (ShouldReusePrecheckedType && expr->getType())
3799-
return { false, expr };
3800-
3801-
// OpenExistentialExpr contains OpaqueValueExpr in its sub expression.
3802-
if (auto OOE = dyn_cast<OpenExistentialExpr>(expr)) {
3803-
auto archetypeVal = OOE->getOpaqueValue();
3804-
auto base = OOE->getExistentialValue();
3805-
3806-
bool inserted = OpenExistentials.insert({archetypeVal, base}).second;
3807-
assert(inserted && "OpaqueValue appears multiple times?");
3808-
(void)inserted;
3809-
SWIFT_DEFER { OpenExistentials.erase(archetypeVal); };
3810-
3811-
// Walk to and return the base expression to erase any existentials
3812-
// within it.
3813-
return { false, OOE->getSubExpr()->walk(*this) };
3814-
}
3815-
3816-
// Hacky, this behaves just like an OpenedExistential in that it changes
3817-
// the expr tree.
3818-
if (auto ISLE = dyn_cast<InterpolatedStringLiteralExpr>(expr)) {
3819-
if (auto subExpr = ISLE->getAppendingExpr()->getSubExpr()) {
3820-
if (auto opaqueValue = dyn_cast<OpaqueValueExpr>(subExpr)) {
3821-
ISLE->getAppendingExpr()->setSubExpr(nullptr);
3822-
}
3823-
}
3824-
}
3825-
3826-
// Substitute OpaqueValue with its representing existental.
3827-
if (auto OVE = dyn_cast<OpaqueValueExpr>(expr)) {
3828-
auto value = OpenExistentials.find(OVE);
3829-
3830-
if (value != OpenExistentials.end()) {
3831-
expr = value->second;
3832-
continue;
3833-
} else {
3834-
assert(OVE->isPlaceholder() &&
3835-
"Didn't see this OVE in a containing OpenExistentialExpr?");
3836-
}
3837-
}
3838-
3839-
// Skip any implicit conversions applied to this expression.
3840-
if (auto ICE = dyn_cast<ImplicitConversionExpr>(expr)) {
3841-
expr = ICE->getSubExpr();
3842-
continue;
3843-
}
3844-
3845-
// MakeTemporarilyEscapableExpr is typechecked expression.
3846-
if (auto MTEE = dyn_cast<MakeTemporarilyEscapableExpr>(expr)) {
3847-
expr = MTEE->getOriginalExpr();
3848-
continue;
3849-
}
3850-
3851-
// Extract keypath from '{ `$kp$` in { $0[keyPath: $kp$] } }(keypath)'
3852-
if (isKeyPathCurriedThunkCallExpr(expr)) {
3853-
expr = extractKeyPathFromCurryThunkCall(expr);
3854-
continue;
3855-
}
3856-
3857-
// Restore '@autoclosure'd value.
3858-
if (auto ACE = dyn_cast<AutoClosureExpr>(expr)) {
3859-
// This is only valid if the closure doesn't have parameters.
3860-
if (ACE->getParameters()->size() == 0) {
3861-
expr = ACE->getSingleExpressionBody();
3862-
continue;
3863-
}
3864-
llvm_unreachable("other AutoClosureExpr must be handled specially");
3865-
}
3866-
3867-
// Remove any semantic expression injected by typechecking.
3868-
if (auto EPE = dyn_cast<EditorPlaceholderExpr>(expr)) {
3869-
EPE->setSemanticExpr(nullptr);
3870-
}
3871-
3872-
// Strip default arguments and varargs from type-checked call
3873-
// argument lists.
3874-
if (isa<ParenExpr>(expr) || isa<TupleExpr>(expr)) {
3875-
if (shouldSanitizeArgumentList(expr))
3876-
expr = sanitizeArgumentList(expr);
3877-
}
3878-
3879-
// If this expression represents keypath based dynamic member
3880-
// lookup, let's convert it back to the original form of
3881-
// member or subscript reference.
3882-
if (auto *SE = dyn_cast<SubscriptExpr>(expr)) {
3883-
if (auto *TE = dyn_cast<TupleExpr>(SE->getIndex())) {
3884-
auto isImplicitKeyPathExpr = [](Expr *argExpr) -> bool {
3885-
if (auto *KP = dyn_cast<KeyPathExpr>(argExpr))
3886-
return KP->isImplicit();
3887-
return false;
3888-
};
3889-
3890-
if (TE->isImplicit() && TE->getNumElements() == 1 &&
3891-
TE->getElementName(0) == C.Id_dynamicMember &&
3892-
isImplicitKeyPathExpr(TE->getElement(0))) {
3893-
auto *keyPathExpr = cast<KeyPathExpr>(TE->getElement(0));
3894-
auto *componentExpr = keyPathExpr->getParsedPath();
3895-
3896-
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(componentExpr)) {
3897-
UDE->setBase(SE->getBase());
3898-
return {true, UDE};
3899-
}
3900-
3901-
if (auto *subscript = dyn_cast<SubscriptExpr>(componentExpr)) {
3902-
subscript->setBase(SE->getBase());
3903-
return {true, subscript};
3904-
}
3905-
3906-
llvm_unreachable("unknown keypath component type");
3907-
}
3908-
}
3909-
}
3910-
3911-
// If this is a closure, only walk into its children if they
3912-
// are type-checked in the context of the enclosing expression.
3913-
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
3914-
if (!shouldTypeCheckInEnclosingExpression(closure))
3915-
return { false, expr };
3916-
}
3917-
3918-
// Now, we're ready to walk into sub expressions.
3919-
return {true, expr};
3920-
}
3921-
}
3922-
3923-
bool isSyntheticArgumentExpr(const Expr *expr) {
3924-
if (isa<DefaultArgumentExpr>(expr))
3925-
return true;
3926-
3927-
if (auto *varargExpr = dyn_cast<VarargExpansionExpr>(expr))
3928-
if (isa<ArrayExpr>(varargExpr->getSubExpr()))
3929-
return true;
3930-
3931-
return false;
3932-
}
3933-
3934-
bool shouldSanitizeArgumentList(const Expr *expr) {
3935-
if (auto *parenExpr = dyn_cast<ParenExpr>(expr)) {
3936-
return isSyntheticArgumentExpr(parenExpr->getSubExpr());
3937-
} else if (auto *tupleExpr = dyn_cast<TupleExpr>(expr)) {
3938-
for (auto *arg : tupleExpr->getElements()) {
3939-
if (isSyntheticArgumentExpr(arg))
3940-
return true;
3941-
}
3942-
3943-
return false;
3944-
} else {
3945-
return isSyntheticArgumentExpr(expr);
3946-
}
3947-
}
3948-
3949-
Expr *sanitizeArgumentList(Expr *original) {
3950-
auto argList = getOriginalArgumentList(original);
3951-
3952-
if (argList.args.size() == 1 &&
3953-
argList.labels[0].empty() &&
3954-
!isa<VarargExpansionExpr>(argList.args[0])) {
3955-
auto *result =
3956-
new (C) ParenExpr(argList.lParenLoc,
3957-
argList.args[0],
3958-
argList.rParenLoc,
3959-
argList.hasTrailingClosure);
3960-
result->setImplicit();
3961-
return result;
3962-
}
3963-
3964-
return TupleExpr::create(C,
3965-
argList.lParenLoc,
3966-
argList.args,
3967-
argList.labels,
3968-
argList.labelLocs,
3969-
argList.rParenLoc,
3970-
argList.hasTrailingClosure,
3971-
/*implicit=*/true);
3972-
}
3973-
3974-
Expr *walkToExprPost(Expr *expr) override {
3975-
assert(!isa<ImplicitConversionExpr>(expr) &&
3976-
"ImplicitConversionExpr should be eliminated in walkToExprPre");
3977-
3978-
auto buildMemberRef = [&](Type memberType, Expr *base, SourceLoc dotLoc,
3979-
ConcreteDeclRef member, DeclNameLoc memberLoc,
3980-
bool implicit) -> Expr * {
3981-
auto *memberRef = new (C)
3982-
MemberRefExpr(base, dotLoc, member, memberLoc, implicit);
3983-
3984-
if (memberType) {
3985-
memberRef->setType(memberType);
3986-
return memberRef;
3987-
}
3988-
3989-
return memberRef;
3990-
};
3991-
3992-
// A DotSyntaxCallExpr is a member reference that has already been
3993-
// type-checked down to a call; turn it back into an overloaded
3994-
// member reference expression.
3995-
if (auto dotCall = dyn_cast<DotSyntaxCallExpr>(expr)) {
3996-
DeclNameLoc memberLoc;
3997-
auto memberAndFunctionRef = findReferencedDecl(dotCall->getFn(),
3998-
memberLoc);
3999-
if (memberAndFunctionRef.first) {
4000-
assert(!isa<ImplicitConversionExpr>(dotCall->getBase()));
4001-
return buildMemberRef(dotCall->getType(),
4002-
dotCall->getBase(),
4003-
dotCall->getDotLoc(),
4004-
memberAndFunctionRef.first,
4005-
memberLoc, expr->isImplicit());
4006-
}
4007-
}
4008-
4009-
if (auto *dynamicMember = dyn_cast<DynamicMemberRefExpr>(expr)) {
4010-
if (auto memberRef = dynamicMember->getMember()) {
4011-
assert(!isa<ImplicitConversionExpr>(dynamicMember->getBase()));
4012-
return buildMemberRef(dynamicMember->getType(),
4013-
dynamicMember->getBase(),
4014-
dynamicMember->getDotLoc(),
4015-
memberRef,
4016-
dynamicMember->getNameLoc(),
4017-
expr->isImplicit());
4018-
}
4019-
}
4020-
4021-
// A DotSyntaxBaseIgnoredExpr is a static member reference that has
4022-
// already been type-checked down to a call where the argument doesn't
4023-
// actually matter; turn it back into an overloaded member reference
4024-
// expression.
4025-
if (auto dotIgnored = dyn_cast<DotSyntaxBaseIgnoredExpr>(expr)) {
4026-
DeclNameLoc memberLoc;
4027-
auto memberAndFunctionRef = findReferencedDecl(dotIgnored->getRHS(),
4028-
memberLoc);
4029-
if (memberAndFunctionRef.first) {
4030-
assert(!isa<ImplicitConversionExpr>(dotIgnored->getLHS()));
4031-
return buildMemberRef(dotIgnored->getType(),
4032-
dotIgnored->getLHS(),
4033-
dotIgnored->getDotLoc(),
4034-
memberAndFunctionRef.first,
4035-
memberLoc, expr->isImplicit());
4036-
}
4037-
}
4038-
return expr;
4039-
}
4040-
4041-
/// Ignore declarations.
4042-
bool walkToDeclPre(Decl *decl) override { return false; }
4043-
};
4044-
40453730
class ConstraintWalker : public ASTWalker {
40463731
ConstraintGenerator &CG;
40473732

@@ -4169,10 +3854,6 @@ namespace {
41693854

41703855
static Expr *generateConstraintsFor(ConstraintSystem &cs, Expr *expr,
41713856
DeclContext *DC) {
4172-
// Remove implicit conversions from the expression.
4173-
expr = expr->walk(SanitizeExpr(cs.getASTContext(),
4174-
cs.shouldReusePrecheckedType()));
4175-
41763857
// Walk the expression, generating constraints.
41773858
ConstraintGenerator cg(cs, DC);
41783859
ConstraintWalker cw(cg);

lib/Sema/DerivedConformanceAdditiveArithmetic.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,10 @@ deriveBodyMathOperator(AbstractFunctionDecl *funcDecl, MathOperator op) {
126126
confRef.getConcrete()->getWitnessDecl(operatorReq))
127127
memberOpDecl = concreteMemberMethodDecl;
128128
assert(memberOpDecl && "Member operator declaration must exist");
129-
auto memberOpDRE =
130-
new (C) DeclRefExpr(memberOpDecl, DeclNameLoc(), /*Implicit*/ true);
131129
auto *memberTypeExpr = TypeExpr::createImplicit(memberType, C);
132130
auto memberOpExpr =
133-
new (C) DotSyntaxCallExpr(memberOpDRE, SourceLoc(), memberTypeExpr);
131+
new (C) MemberRefExpr(memberTypeExpr, SourceLoc(), memberOpDecl,
132+
DeclNameLoc(), /*Implicit*/ true);
134133

135134
// Create expression `lhs.member <op> rhs.member`.
136135
// NOTE(TF-1054): create new `DeclRefExpr`s per loop iteration to avoid

lib/Sema/DerivedConformanceCaseIterable.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ deriveCaseIterable_enum_getter(AbstractFunctionDecl *funcDecl, void *) {
4848

4949
SmallVector<Expr *, 8> elExprs;
5050
for (EnumElementDecl *elt : parentEnum->getAllElements()) {
51-
auto *ref = new (C) DeclRefExpr(elt, DeclNameLoc(), /*implicit*/true);
5251
auto *base = TypeExpr::createImplicit(enumTy, C);
53-
auto *apply = new (C) DotSyntaxCallExpr(ref, SourceLoc(), base);
52+
auto *apply = new (C) MemberRefExpr(base, SourceLoc(),
53+
elt, DeclNameLoc(), /*implicit*/true);
5454
elExprs.push_back(apply);
5555
}
5656
auto *arrayExpr = ArrayExpr::create(C, SourceLoc(), elExprs, {}, SourceLoc());

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -619,9 +619,9 @@ deriveBodyEncodable_encode(AbstractFunctionDecl *encodeDecl, void *) {
619619
DeclNameLoc(), /*Implicit=*/true);
620620

621621
// CodingKeys.x
622-
auto *eltRef = new (C) DeclRefExpr(elt, DeclNameLoc(), /*implicit=*/true);
623622
auto *metaTyRef = TypeExpr::createImplicit(codingKeysType, C);
624-
auto *keyExpr = new (C) DotSyntaxCallExpr(eltRef, SourceLoc(), metaTyRef);
623+
auto *keyExpr = new (C) MemberRefExpr(metaTyRef, SourceLoc(), elt,
624+
DeclNameLoc(), /*Implicit=*/true);
625625

626626
// encode(_:forKey:)/encodeIfPresent(_:forKey:)
627627
auto methodName = useIfPresentVariant ? C.Id_encodeIfPresent : C.Id_encode;
@@ -901,9 +901,9 @@ deriveBodyDecodable_init(AbstractFunctionDecl *initDecl, void *) {
901901
SourceLoc(), varType);
902902

903903
// CodingKeys.x
904-
auto *eltRef = new (C) DeclRefExpr(elt, DeclNameLoc(), /*implicit=*/true);
905904
metaTyRef = TypeExpr::createImplicit(codingKeysType, C);
906-
auto *keyExpr = new (C) DotSyntaxCallExpr(eltRef, SourceLoc(), metaTyRef);
905+
auto *keyExpr = new (C) MemberRefExpr(metaTyRef, SourceLoc(),
906+
elt, DeclNameLoc(), /*Implicit=*/true);
907907

908908
// decode(_:forKey:)/decodeIfPresent(_:forKey:)
909909
SmallVector<Identifier, 2> argNames{Identifier(), C.Id_forKey};

0 commit comments

Comments
 (0)