Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion lib/IDE/SourceEntityWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,11 +362,24 @@ ASTWalker::PreWalkResult<Expr *> SemaAnnotator::walkToExprPre(Expr *E) {
}
}

// Check if this is an implicit DeclRefExpr to a constructor - we should
// NOT skip these as they need to be indexed for Self.NestedType() calls.
// However, only do this when we're NOT inside a ConstructorRefCallExpr
// (tracked by CtorRefs), as that case is already handled and we'd create
// duplicate references.
bool isImplicitCtorRef = false;
if (CtorRefs.empty()) {
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
if (isa<ConstructorDecl>(DRE->getDecl()))
isImplicitCtorRef = true;
}
}

if (!isa<InOutExpr>(E) && !isa<LoadExpr>(E) && !isa<OpenExistentialExpr>(E) &&
!isa<MakeTemporarilyEscapableExpr>(E) &&
!isa<CollectionUpcastConversionExpr>(E) && !isa<OpaqueValueExpr>(E) &&
!isa<SubscriptExpr>(E) && !isa<KeyPathExpr>(E) && !isa<LiteralExpr>(E) &&
!isa<CollectionExpr>(E) && E->isImplicit())
!isa<CollectionExpr>(E) && E->isImplicit() && !isImplicitCtorRef)
return Action::Continue(E);

if (auto LE = dyn_cast<LiteralExpr>(E)) {
Expand Down
17 changes: 16 additions & 1 deletion lib/IDE/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -963,7 +963,22 @@ bool swift::ide::isBeingCalled(ArrayRef<Expr *> ExprStack) {
}
if (isa<SelfApplyExpr>(AE))
continue;
if (getReferencedDecl(AE->getFn()).second == UnderlyingDecl)
Expr *Fn = AE->getFn();
// Unwrap AutoClosureExpr and nested CallExpr to get the actual function
// expression. This handles cases like Self.NestedType() where the
// constructor call is wrapped in an autoclosure containing another call.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bug that these calls are wrapped in an autoclosure. We can land this as a workaround, but do you want to investigate and fix the underlying issue?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the problem is somewhere in shouldBuildCurryThunk() in CSApply.cpp. It has this weird bit of code in it which suggests something is not being modeled properly with constructors:

        // FIXME: Representational gunk because "T(...)" is really
        // "T.init(...)" -- pretend it has two argument lists like
        // a real '.' call.
        if (isa<ConstructorDecl>(member) &&
            isa<CallExpr>(prev) &&
            isa<TypeExpr>(cast<CallExpr>(prev)->getFn())) {
          assert(maxArgCount == 2);
          return 2;
        }

Or maybe the problem is even further upstream. Really, Self.NestedType should be identical to Container.NestedType, because the special meaning of Self inside a class type should not have any effect for a nested type reference.

Nice discovery, by the way, this is really bizarre.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked into this and there are two issues:

  • We don't fold Self.NestedType in the same way as Container.NestedType
  • We form an autoclosure erroneously in other cases

I have a fix for the first problem coming up, which eliminates the autoclosure. I'll see if I can fix the second as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the fix for the underlying problem: #86146

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the proper fix @slavapestov!

while (true) {
if (auto *ACE = dyn_cast<AutoClosureExpr>(Fn)) {
Fn = ACE->getSingleExpressionBody();
continue;
}
if (auto *InnerCall = dyn_cast<CallExpr>(Fn)) {
Fn = InnerCall->getFn();
continue;
}
break;
}
if (getReferencedDecl(Fn).second == UnderlyingDecl)
return true;
}
return false;
Expand Down
17 changes: 17 additions & 0 deletions test/Index/expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,20 @@ func castExpr(x: Any) {
// CHECK: [[@LINE+1]]:15 | struct/Swift | S1 | [[S1_USR]] | Ref
_ = x as? S1
}

// Test that initializers are indexed when called through Self.NestedType
// CHECK: [[@LINE+1]]:7 | class(internal)/Swift | Container | [[Container_USR:.*]] | Def
class Container {
// CHECK: [[@LINE+1]]:11 | class(internal)/Swift | NestedType | [[NestedType_USR:.*]] | Def
class NestedType {
// CHECK: [[@LINE+1]]:9 | constructor(internal)/Swift | init(value:) | [[NestedType_init_USR:.*]] | Def
init(value: Int) {}
}

func someFunc() {
// CHECK: [[@LINE+3]]:13 | class/Swift | Container | [[Container_USR]] | Ref
// CHECK: [[@LINE+2]]:18 | class/Swift | NestedType | [[NestedType_USR]] | Ref
// CHECK: [[@LINE+1]]:18 | constructor/Swift | init(value:) | [[NestedType_init_USR]] | Ref,Call
_ = Self.NestedType(value: 1)
}
}