Skip to content

Commit 053a4d7

Browse files
committed
[Index] Index generic parameters used inside extensions
Extensions redeclare all generic parameters of their extended type to add their additional restrictions. There are two issues with this model for indexing: - The generic paramter declarations of the extension are implicit so we wouldn't report them in the index. Any usage of the generic param in the extension references this implicit declaration so we don't include it in the index either. - The implicit re-declarations have their own USRs so any usage of a generic parameter inside an extension would use a different USR than declaration of the param in the extended type. To fix these issues, we replace the reference to the implicit generic parameter defined in the extension by a reference to the generic paramter defined in the extended type.
1 parent 5cf19e4 commit 053a4d7

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

lib/Index/Index.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/AST/Comment.h"
1717
#include "swift/AST/Decl.h"
1818
#include "swift/AST/Expr.h"
19+
#include "swift/AST/GenericParamList.h"
1920
#include "swift/AST/Module.h"
2021
#include "swift/AST/ParameterList.h"
2122
#include "swift/AST/ProtocolConformance.h"
@@ -439,6 +440,57 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
439440
return true;
440441
}
441442

443+
/// Extensions redeclare all generic parameters of their extended type to add
444+
/// their additional restrictions. There are two issues with this model for
445+
/// indexing:
446+
/// - The generic paramter declarations of the extension are implicit so we
447+
/// wouldn't report them in the index. Any usage of the generic param in
448+
/// the extension references this implicit declaration so we don't include
449+
/// it in the index either.
450+
/// - The implicit re-declarations have their own USRs so any usage of a
451+
/// generic parameter inside an extension would use a different USR than
452+
/// declaration of the param in the extended type.
453+
///
454+
/// To fix these issues, we replace the reference to the implicit generic
455+
/// parameter defined in the extension by a reference to the generic paramter
456+
/// defined in the extended type.
457+
///
458+
/// \returns the canonicalized replaced generic param decl if it can be found
459+
/// or \p GenParam otherwise.
460+
ValueDecl *
461+
canonicalizeGenericTypeParamDeclForIndex(GenericTypeParamDecl *GenParam) {
462+
auto Extension = dyn_cast_or_null<ExtensionDecl>(
463+
GenParam->getDeclContext()->getAsDecl());
464+
if (!Extension) {
465+
// We are not referencing a generic paramter defined in an extension.
466+
// Nothing to do.
467+
return GenParam;
468+
}
469+
assert(GenParam->isImplicit() &&
470+
"Generic param decls in extension should always be implicit and "
471+
"shadow a generic param in the extended type.");
472+
assert(Extension->getExtendedNominal() &&
473+
"The implict generic types on the extension should only be created "
474+
"if the extended type was found");
475+
476+
auto ExtendedTypeGenSig =
477+
Extension->getExtendedNominal()->getGenericSignature();
478+
assert(ExtendedTypeGenSig && "Extension is generic but extended type not?");
479+
480+
// The generic parameter in the extension has the same depths and index
481+
// as the one in the extended type.
482+
for (auto ExtendedTypeGenParam : ExtendedTypeGenSig->getGenericParams()) {
483+
if (ExtendedTypeGenParam->getIndex() == GenParam->getIndex() &&
484+
ExtendedTypeGenParam->getDepth() == GenParam->getDepth()) {
485+
assert(ExtendedTypeGenParam->getDecl() &&
486+
"The generic parameter defined on the extended type cannot be "
487+
"implicit.");
488+
return ExtendedTypeGenParam->getDecl();
489+
}
490+
}
491+
llvm_unreachable("Can't find the generic parameter in the extended type");
492+
}
493+
442494
bool visitDeclReference(ValueDecl *D, CharSourceRange Range,
443495
TypeDecl *CtorTyRef, ExtensionDecl *ExtTyRef, Type T,
444496
ReferenceMetaData Data) override {
@@ -455,6 +507,11 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
455507
if (CtorTyRef)
456508
if (!reportRef(CtorTyRef, Loc, Info, Data.AccKind))
457509
return false;
510+
511+
if (auto *GenParam = dyn_cast<GenericTypeParamDecl>(D)) {
512+
D = canonicalizeGenericTypeParamDeclForIndex(GenParam);
513+
}
514+
458515
if (!reportRef(D, Loc, Info, Data.AccKind))
459516
return false;
460517

test/Index/index_generic_params.swift

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// RUN: %target-swift-ide-test -print-indexed-symbols -source-filename %s | %FileCheck %s
2+
3+
// CHECK: [[@LINE+1]]:10 | protocol/Swift | P1 | s:14swift_ide_test2P1P | Def |
4+
protocol P1 {
5+
// CHECK: [[@LINE+1]]:18 | type-alias/associated-type/Swift | Assoc | s:14swift_ide_test2P1P5AssocQa | Def,RelChild |
6+
associatedtype Assoc
7+
}
8+
9+
// CHECK: [[@LINE+1]]:10 | protocol/Swift | P2 | s:14swift_ide_test2P2P | Def |
10+
protocol P2 {}
11+
12+
// MARK: - Test extening a simple generic type
13+
14+
// CHECK: [[@LINE+4]]:7 | class/Swift | Foo | s:14swift_ide_test3FooC | Def |
15+
// CHECK: [[@LINE+3]]:11 | type-alias/generic-type-param/Swift | OtherParam | s:14swift_ide_test3FooC10OtherParamxmfp | Def,RelChild |
16+
// CHECK: [[@LINE+2]]:23 | type-alias/generic-type-param/Swift | Bar | s:14swift_ide_test3FooC3Barq_mfp | Def,RelChild |
17+
// CHECK: [[@LINE+1]]:28 | protocol/Swift | P1 | s:14swift_ide_test2P1P | Ref |
18+
class Foo<OtherParam, Bar: P1> {}
19+
20+
// CHECK: [[@LINE+4]]:11 | extension/ext-class/Swift | Foo | s:e:s:14swift_ide_test3FooCA2A2P2R_rlE3foo1xyq__tF | Def |
21+
// CHECK: [[@LINE+3]]:11 | class/Swift | Foo | s:14swift_ide_test3FooC | Ref,RelExt |
22+
// CHECK: [[@LINE+2]]:21 | type-alias/generic-type-param/Swift | Bar | s:14swift_ide_test3FooC3Barq_mfp | Ref |
23+
// CHECK: [[@LINE+1]]:26 | protocol/Swift | P2 | s:14swift_ide_test2P2P | Ref |
24+
extension Foo where Bar: P2 {
25+
// CHECK: [[@LINE+1]]:15 | type-alias/generic-type-param/Swift | Bar | s:14swift_ide_test3FooC3Barq_mfp | Ref,RelCont |
26+
func foo(x: Bar) {}
27+
28+
// CHECK: [[@LINE+2]]:15 | type-alias/generic-type-param/Swift | Bar | s:14swift_ide_test3FooC3Barq_mfp | Ref,RelCont |
29+
// CHECK: [[@LINE+1]]:19 | type-alias/associated-type/Swift | Assoc | s:14swift_ide_test2P1P5AssocQa | Ref,RelCont |
30+
func bar(x: Bar.Assoc) {}
31+
}
32+
33+
// MARK: - Test extending a generic type in a generic context
34+
35+
// CHECK: [[@LINE+1]]:15 | type-alias/generic-type-param/Swift | WrapperParam | s:14swift_ide_test7WrapperC0D5Paramxmfp | Def,RelChild |
36+
class Wrapper<WrapperParam> {
37+
// CHECK: [[@LINE+2]]:9 | class/Swift | Wrapped | s:14swift_ide_test7WrapperC7WrappedC | Def,RelChild |
38+
// CHECK: [[@LINE+1]]:29 | type-alias/generic-type-param/Swift | Bar | s:14swift_ide_test7WrapperC7WrappedC3Barqd_0_mfp | Def,RelChild |
39+
class Wrapped<OtherParam, Bar: P1> {}
40+
}
41+
42+
// MARK: Extension restricted on param of inner type
43+
44+
// CHECK: [[@LINE+1]]:33 | type-alias/generic-type-param/Swift | Bar | s:14swift_ide_test7WrapperC7WrappedC3Barqd_0_mfp | Ref |
45+
extension Wrapper.Wrapped where Bar: P2 {
46+
// CHECK: [[@LINE+1]]:15 | type-alias/generic-type-param/Swift | Bar | s:14swift_ide_test7WrapperC7WrappedC3Barqd_0_mfp | Ref,RelCont |
47+
func foo(x: Bar) {}
48+
49+
// CHECK: [[@LINE+2]]:15 | type-alias/generic-type-param/Swift | Bar | s:14swift_ide_test7WrapperC7WrappedC3Barqd_0_mfp | Ref,RelCont |
50+
// CHECK: [[@LINE+1]]:19 | type-alias/associated-type/Swift | Assoc | s:14swift_ide_test2P1P5AssocQa | Ref,RelCont |
51+
func bar(x: Bar.Assoc) {}
52+
}
53+
54+
// MARK: Extension restricted on generic param of outer type
55+
56+
// CHECK: [[@LINE+1]]:33 | type-alias/generic-type-param/Swift | WrapperParam | s:14swift_ide_test7WrapperC0D5Paramxmfp | Ref |
57+
extension Wrapper.Wrapped where WrapperParam: P2 {
58+
// CHECK: [[@LINE+1]]:15 | type-alias/generic-type-param/Swift | Bar | s:14swift_ide_test7WrapperC7WrappedC3Barqd_0_mfp | Ref,RelCont |
59+
func foo(x: Bar) {}
60+
61+
// CHECK: [[@LINE+2]]:15 | type-alias/generic-type-param/Swift | Bar | s:14swift_ide_test7WrapperC7WrappedC3Barqd_0_mfp | Ref,RelCont |
62+
// CHECK: [[@LINE+1]]:19 | type-alias/associated-type/Swift | Assoc | s:14swift_ide_test2P1P5AssocQa | Ref,RelCont |
63+
func bar(x: Bar.Assoc) {}
64+
}
65+
66+
// MARK: - Test extening a non-generic type in a generic context
67+
68+
// CHECK: [[@LINE+1]]:16 | type-alias/generic-type-param/Swift | Wrapper2Param | s:14swift_ide_test8Wrapper2C0D5Paramxmfp | Def,RelChild |
69+
class Wrapper2<Wrapper2Param> {
70+
class NonGenericWrapped {}
71+
}
72+
73+
// CHECK: [[@LINE+1]]:44 | type-alias/generic-type-param/Swift | Wrapper2Param | s:14swift_ide_test8Wrapper2C0D5Paramxmfp | Ref |
74+
extension Wrapper2.NonGenericWrapped where Wrapper2Param: P1 {
75+
// CHECK: [[@LINE+1]]:15 | type-alias/generic-type-param/Swift | Wrapper2Param | s:14swift_ide_test8Wrapper2C0D5Paramxmfp | Ref,RelCont |
76+
func foo(x: Wrapper2Param) {}
77+
78+
// CHECK: [[@LINE+2]]:15 | type-alias/generic-type-param/Swift | Wrapper2Param | s:14swift_ide_test8Wrapper2C0D5Paramxmfp | Ref,RelCont |
79+
// CHECK: [[@LINE+1]]:29 | type-alias/associated-type/Swift | Assoc | s:14swift_ide_test2P1P5AssocQa | Ref,RelCont |
80+
func bar(x: Wrapper2Param.Assoc) {}
81+
}
82+
83+
// MARK: - Test extending an unkown type
84+
85+
// Check that we don't crash. We don't expect the generic params to show up in the index.
86+
extension MyUnknownType where Wrapper2Param: P1 {
87+
func foo(x: Wrapper2Param) {}
88+
}

0 commit comments

Comments
 (0)