Skip to content

Commit cbeffb6

Browse files
committed
[CodeCompletion] Don't ignore CovariantReturnConversionExpr
in typechecked AST. This is needed to correctly get the type of the parsed expression when the expression is a calling to a method in super class returning 'Self'. rdar://problem/51504896
1 parent f4fee7a commit cbeffb6

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,35 @@ class ExprFinder : public ASTWalker {
138138
return SM.rangeContains(Node->getSourceRange(), TargetRange);
139139
}
140140

141+
bool shouldIgnore(Expr *E) {
142+
// E.g. instanceOfDerived.methodInBaseReturningSelf().#^HERE^#'
143+
// When calling a method in a base class returning 'Self', the call
144+
// expression itself has the type of the base class. That is wrapped with
145+
// CovariantReturnConversionExpr which downcasts it to the derived class.
146+
if (isa<CovariantReturnConversionExpr>(E))
147+
return false;
148+
149+
// E.g. TypeName(#^HERE^#
150+
// In this case, we want the type expression instead of a reference to the
151+
// initializer.
152+
if (isa<ConstructorRefCallExpr>(E))
153+
return true;
154+
155+
// Ignore other implicit expression.
156+
if (E->isImplicit())
157+
return true;
158+
159+
return false;
160+
}
161+
141162
public:
142163
ExprFinder(SourceManager &SM, SourceRange TargetRange)
143164
: SM(SM), TargetRange(TargetRange) {}
144165

145166
Expr *get() const { return FoundExpr; }
146167

147168
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
148-
if (TargetRange == E->getSourceRange() && !E->isImplicit() &&
149-
!isa<ConstructorRefCallExpr>(E)) {
169+
if (TargetRange == E->getSourceRange() && !shouldIgnore(E)) {
150170
assert(!FoundExpr && "non-nullptr for found expr");
151171
FoundExpr = E;
152172
return {false, nullptr};

test/IDE/complete_super_self.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COVARIANT_RETURN_CONV | %FileCheck %s --check-prefix=COVARIANT_RETURN_CONV
2+
3+
class BaseClass {
4+
func returnSelf() -> Self {}
5+
}
6+
7+
class DerivedClass: BaseClass {
8+
var value: Int
9+
func foo() {}
10+
}
11+
12+
func test(value: DerivedClass) {
13+
value.returnSelf().#^COVARIANT_RETURN_CONV^#
14+
// COVARIANT_RETURN_CONV: Begin completions, 4 items
15+
// COVARIANT_RETURN_CONV-DAG: Keyword[self]/CurrNominal: self[#DerivedClass#];
16+
// COVARIANT_RETURN_CONV-DAG: Decl[InstanceVar]/CurrNominal: value[#Int#];
17+
// COVARIANT_RETURN_CONV-DAG: Decl[InstanceMethod]/CurrNominal: foo()[#Void#];
18+
// COVARIANT_RETURN_CONV-DAG: Decl[InstanceMethod]/Super: returnSelf()[#Self#];
19+
// COVARIANT_RETURN_CONV: End completions
20+
}

0 commit comments

Comments
 (0)