Skip to content

Commit 8975bf6

Browse files
committed
[Completion] Substitute base type for nested types
Ensure we call `getTypeOfMember` for nested nominals and typealiases.
1 parent be0f6f9 commit 8975bf6

File tree

4 files changed

+48
-27
lines changed

4 files changed

+48
-27
lines changed

lib/IDE/CompletionLookup.cpp

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ Type CompletionLookup::getTypeOfMember(const ValueDecl *VD,
603603
DynamicLookupInfo dynamicLookupInfo) {
604604
switch (dynamicLookupInfo.getKind()) {
605605
case DynamicLookupInfo::None:
606-
return getTypeOfMember(VD, this->ExprType);
606+
return getTypeOfMember(VD, getMemberBaseType());
607607
case DynamicLookupInfo::AnyObject:
608608
return getTypeOfMember(VD, Type());
609609
case DynamicLookupInfo::KeyPathDynamicMember: {
@@ -676,7 +676,14 @@ Type CompletionLookup::getTypeOfMember(const ValueDecl *VD,
676676
}
677677

678678
Type CompletionLookup::getTypeOfMember(const ValueDecl *VD, Type ExprType) {
679-
Type T = VD->getInterfaceType();
679+
Type T;
680+
if (auto *TD = dyn_cast<TypeDecl>(VD)) {
681+
// For a type decl we're interested in the declared interface type, i.e
682+
// we don't want a metatype.
683+
T = TD->getDeclaredInterfaceType();
684+
} else {
685+
T = VD->getInterfaceType();
686+
}
680687
assert(!T.isNull());
681688

682689
if (ExprType) {
@@ -1707,13 +1714,16 @@ void CompletionLookup::addNominalTypeRef(const NominalTypeDecl *NTD,
17071714
addLeadingDot(Builder);
17081715
Builder.addBaseName(NTD->getName().str());
17091716

1717+
// Substitute the base type for a nested type if needed.
1718+
auto nominalTy = getTypeOfMember(NTD, dynamicLookupInfo);
1719+
17101720
// "Fake" annotation for custom attribute types.
17111721
SmallVector<char, 0> stash;
17121722
StringRef customAttributeAnnotation = getTypeAnnotationString(NTD, stash);
17131723
if (!customAttributeAnnotation.empty()) {
17141724
Builder.addTypeAnnotation(customAttributeAnnotation);
17151725
} else {
1716-
addTypeAnnotation(Builder, NTD->getDeclaredInterfaceType());
1726+
addTypeAnnotation(Builder, nominalTy);
17171727
}
17181728

17191729
// Override the type relation for NominalTypes. Use the better relation
@@ -1723,8 +1733,7 @@ void CompletionLookup::addNominalTypeRef(const NominalTypeDecl *NTD,
17231733
// func receiveMetatype(_: Int.Type) {}
17241734
//
17251735
// We want to suggest 'Int' as 'Identical' for both arguments.
1726-
Builder.setResultTypes(
1727-
{NTD->getInterfaceType(), NTD->getDeclaredInterfaceType()});
1736+
Builder.setResultTypes({MetatypeType::get(nominalTy), nominalTy});
17281737
Builder.setTypeContext(expectedTypeContext, CurrDeclContext);
17291738
}
17301739

@@ -1737,13 +1746,18 @@ void CompletionLookup::addTypeAliasRef(const TypeAliasDecl *TAD,
17371746
Builder.setAssociatedDecl(TAD);
17381747
addLeadingDot(Builder);
17391748
Builder.addBaseName(TAD->getName().str());
1740-
if (auto underlyingType = TAD->getUnderlyingType()) {
1741-
if (underlyingType->hasError()) {
1742-
addTypeAnnotation(Builder, TAD->getDeclaredInterfaceType());
1743-
} else {
1744-
addTypeAnnotation(Builder, underlyingType);
1745-
}
1749+
1750+
// Substitute the base type for a nested typealias if needed.
1751+
auto ty = getTypeOfMember(TAD, dynamicLookupInfo);
1752+
1753+
// If the underlying type has an error, prefer to print the full typealias,
1754+
// otherwise get the underlying type.
1755+
if (auto *TA = dyn_cast<TypeAliasType>(ty.getPointer())) {
1756+
auto underlyingTy = TA->getSinglyDesugaredType();
1757+
if (!underlyingTy->hasError())
1758+
ty = underlyingTy;
17461759
}
1760+
addTypeAnnotation(Builder, ty);
17471761
}
17481762

17491763
void CompletionLookup::addGenericTypeParamRef(

test/IDE/complete_constrained.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func foo(s: MyStruct<Int>) {
7575
// META_MYSTRUCT_INT_DOT: Begin completions, 11 items
7676
// META_MYSTRUCT_INT_DOT-DAG: Keyword[self]/CurrNominal: self[#MyStruct<Int>.Type#]; name=self
7777
// META_MYSTRUCT_INT_DOT-DAG: Keyword/CurrNominal: Type[#MyStruct<Int>.Type#]; name=Type
78-
// META_MYSTRUCT_INT_DOT-DAG: Decl[TypeAlias]/CurrNominal: Assoc[#T#]; name=Assoc
78+
// META_MYSTRUCT_INT_DOT-DAG: Decl[TypeAlias]/CurrNominal: Assoc[#Int#]; name=Assoc
7979
// META_MYSTRUCT_INT_DOT-DAG: Decl[Constructor]/CurrNominal: init({#int: U#})[#MyStruct<Int>#]; name=init(int:)
8080
// META_MYSTRUCT_INT_DOT-DAG: Decl[Constructor]/CurrNominal: init({#withConstrainedGenericParam: SomeProto#})[#MyStruct<Int>#]; name=init(withConstrainedGenericParam:)
8181
// META_MYSTRUCT_INT_DOT-DAG: Decl[InstanceMethod]/CurrNominal: methodWithConstrainedGenericParam({#(self): MyStruct<Int>#})[#(x: SomeProto) -> Int#]; name=methodWithConstrainedGenericParam(:)

test/IDE/complete_member_type.swift

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ do {
9090
let _: Int!.#^SUGARED_IUOPTIONAL_MEMBER_DOT?check=OPTIONAL^#
9191

9292
// OPTIONAL-LABEL: Begin completions, 2 items
93-
// OPTIONAL-LABEL: Decl[TypeAlias]/CurrNominal: Wrappt[#Wrapped#]; name=Wrappt
93+
// OPTIONAL-LABEL: Decl[TypeAlias]/CurrNominal: Wrappt[#Int#]; name=Wrappt
9494
// OPTIONAL-LABEL: Keyword/None: Type[#{{Optional<Int>|Int\?}}.Type#]; name=Type
9595

9696
let _: Array<Int>.#^ARRAY_MEMBER_DOT?check=ARRAY^#
@@ -99,26 +99,26 @@ do {
9999
// ARRAY-LABEL: Begin completions, 8 items
100100
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: Index[#Int#]; name=Index
101101
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: Indices[#Range<Int>#]; name=Indices
102-
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: Iterator[#IndexingIterator<Array<Element>>#]; name=Iterator
103-
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: Element[#Element#]; name=Element
104-
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: ArrayLiteralElement[#Element#]; name=ArrayLiteralElement
105-
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: SubSequence[#ArraySlice<Element>#]; name=SubSequence
102+
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: Iterator[#IndexingIterator<Array<Int>>#]; name=Iterator
103+
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: Element[#Int#]; name=Element
104+
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: ArrayLiteralElement[#Int#]; name=ArrayLiteralElement
105+
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: SubSequence[#ArraySlice<Int>#]; name=SubSequence
106106
// ARRAY-DAG: Decl[TypeAlias]/Super/NotRecommended/IsSystem: IndexDistance[#Int#]; name=IndexDistance; diagnostics=warning:'IndexDistance' is deprecated: all index distances are now of type Int
107107
// ARRAY-DAG: Keyword/None: Type[#{{Array<Int>|\[Int\]}}.Type#]; name=Type
108108

109109
let _: Dictionary<Int, Int>.#^DICTIONARY_MEMBER_DOT?check=DICTIONARY^#
110110
let _: [Int : Int].#^SUGARED_DICTIONARY_MEMBER_DOT?check=DICTIONARY^#
111111

112112
// DICTIONARY-LABEL: Begin completions, 11 items
113-
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Element[#(key: Key, value: Value)#]; name=Element
114-
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: SubSequence[#Slice<Dictionary<Key, Value>>#]; name=SubSequence
115-
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Indices[#DefaultIndices<Dictionary<Key, Value>>#]; name=Indices
116-
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Key[#Key#]; name=Key
117-
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Value[#Value#]; name=Value
118-
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Keys[#Dictionary<Key, Value>.Keys#]; name=Keys
119-
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Values[#Dictionary<Key, Value>.Values#]; name=Values
120-
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Index[#Dictionary<Key, Value>.Index#]; name=Index
121-
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Iterator[#Dictionary<Key, Value>.Iterator#]; name=Iterator
113+
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Element[#(key: Int, value: Int)#]; name=Element
114+
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: SubSequence[#Slice<Dictionary<Int, Int>>#]; name=SubSequence
115+
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Indices[#DefaultIndices<Dictionary<Int, Int>>#]; name=Indices
116+
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Key[#Int#]; name=Key
117+
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Value[#Int#]; name=Value
118+
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Keys[#Dictionary<Int, Int>.Keys#]; name=Keys
119+
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Values[#Dictionary<Int, Int>.Values#]; name=Values
120+
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Index[#Dictionary<Int, Int>.Index#]; name=Index
121+
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Iterator[#Dictionary<Int, Int>.Iterator#]; name=Iterator
122122
// DICTIONARY-NEXT: Decl[TypeAlias]/Super/NotRecommended/IsSystem: IndexDistance[#Int#]; name=IndexDistance; diagnostics=warning
123123
// DICTIONARY-NEXT: Keyword/None: Type[#{{Dictionary<Int, Int>|\[Int : Int\]}}.Type#]; name=Type
124124
}
@@ -160,3 +160,10 @@ do {
160160
// MEMBER_EXISTENTIAL_NO_DOT-NEXT: Keyword/None: .Protocol[#(any Sequence).Type#]; name=Protocol
161161
// MEMBER_EXISTENTIAL_NO_DOT-NEXT: Keyword/None: .Type[#any Sequence.Type#]; name=Type
162162
}
163+
164+
struct TestGenericTypealias<T, U> {
165+
typealias K<V> = TestGenericTypealias<(T, U), V>
166+
}
167+
168+
let _ = TestGenericTypealias<Int, String>.K<Float>.#^GENERIC_TYPEALIAS^#
169+
// GENERIC_TYPEALIAS-DAG: Decl[TypeAlias]/CurrNominal: K[#TestGenericTypealias<((Int, String), Float), V>#]; name=K

test/IDE/complete_name_lookup.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,4 @@ extension ObservableConvertibleType {
4949
// CATCHSEQUENCE_DOT-DAG: Keyword/CurrNominal: Type[#CatchSequence<_>.Type#]; name=Type
5050
// CATCHSEQUENCE_DOT-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init()[#CatchSequence<_>#]; name=init()
5151
// CATCHSEQUENCE_DOT-DAG: Decl[StaticMethod]/Super/TypeRelation[Convertible]: catchError()[#Observable<CatchSequence<_>.T>#]; name=catchError()
52-
// CATCHSEQUENCE_DOT-DAG: Decl[TypeAlias]/Super: T[#T#]; name=T
52+
// CATCHSEQUENCE_DOT-DAG: Decl[TypeAlias]/Super: T[#Observable<_.Element.T>.T#]; name=T

0 commit comments

Comments
 (0)