Skip to content

Commit 341b870

Browse files
authored
Merge pull request #36909 from ahoppen/pr/index-generic-params-in-extensions
[Index] Index generic parameters used inside extensions
2 parents f53f80f + 053a4d7 commit 341b870

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)