mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Completion] Substitute base type for nested types
Ensure we call `getTypeOfMember` for nested nominals and typealiases.
This commit is contained in:
@@ -603,7 +603,7 @@ Type CompletionLookup::getTypeOfMember(const ValueDecl *VD,
|
||||
DynamicLookupInfo dynamicLookupInfo) {
|
||||
switch (dynamicLookupInfo.getKind()) {
|
||||
case DynamicLookupInfo::None:
|
||||
return getTypeOfMember(VD, this->ExprType);
|
||||
return getTypeOfMember(VD, getMemberBaseType());
|
||||
case DynamicLookupInfo::AnyObject:
|
||||
return getTypeOfMember(VD, Type());
|
||||
case DynamicLookupInfo::KeyPathDynamicMember: {
|
||||
@@ -676,7 +676,14 @@ Type CompletionLookup::getTypeOfMember(const ValueDecl *VD,
|
||||
}
|
||||
|
||||
Type CompletionLookup::getTypeOfMember(const ValueDecl *VD, Type ExprType) {
|
||||
Type T = VD->getInterfaceType();
|
||||
Type T;
|
||||
if (auto *TD = dyn_cast<TypeDecl>(VD)) {
|
||||
// For a type decl we're interested in the declared interface type, i.e
|
||||
// we don't want a metatype.
|
||||
T = TD->getDeclaredInterfaceType();
|
||||
} else {
|
||||
T = VD->getInterfaceType();
|
||||
}
|
||||
assert(!T.isNull());
|
||||
|
||||
if (ExprType) {
|
||||
@@ -1707,13 +1714,16 @@ void CompletionLookup::addNominalTypeRef(const NominalTypeDecl *NTD,
|
||||
addLeadingDot(Builder);
|
||||
Builder.addBaseName(NTD->getName().str());
|
||||
|
||||
// Substitute the base type for a nested type if needed.
|
||||
auto nominalTy = getTypeOfMember(NTD, dynamicLookupInfo);
|
||||
|
||||
// "Fake" annotation for custom attribute types.
|
||||
SmallVector<char, 0> stash;
|
||||
StringRef customAttributeAnnotation = getTypeAnnotationString(NTD, stash);
|
||||
if (!customAttributeAnnotation.empty()) {
|
||||
Builder.addTypeAnnotation(customAttributeAnnotation);
|
||||
} else {
|
||||
addTypeAnnotation(Builder, NTD->getDeclaredInterfaceType());
|
||||
addTypeAnnotation(Builder, nominalTy);
|
||||
}
|
||||
|
||||
// Override the type relation for NominalTypes. Use the better relation
|
||||
@@ -1723,8 +1733,7 @@ void CompletionLookup::addNominalTypeRef(const NominalTypeDecl *NTD,
|
||||
// func receiveMetatype(_: Int.Type) {}
|
||||
//
|
||||
// We want to suggest 'Int' as 'Identical' for both arguments.
|
||||
Builder.setResultTypes(
|
||||
{NTD->getInterfaceType(), NTD->getDeclaredInterfaceType()});
|
||||
Builder.setResultTypes({MetatypeType::get(nominalTy), nominalTy});
|
||||
Builder.setTypeContext(expectedTypeContext, CurrDeclContext);
|
||||
}
|
||||
|
||||
@@ -1737,13 +1746,18 @@ void CompletionLookup::addTypeAliasRef(const TypeAliasDecl *TAD,
|
||||
Builder.setAssociatedDecl(TAD);
|
||||
addLeadingDot(Builder);
|
||||
Builder.addBaseName(TAD->getName().str());
|
||||
if (auto underlyingType = TAD->getUnderlyingType()) {
|
||||
if (underlyingType->hasError()) {
|
||||
addTypeAnnotation(Builder, TAD->getDeclaredInterfaceType());
|
||||
} else {
|
||||
addTypeAnnotation(Builder, underlyingType);
|
||||
}
|
||||
|
||||
// Substitute the base type for a nested typealias if needed.
|
||||
auto ty = getTypeOfMember(TAD, dynamicLookupInfo);
|
||||
|
||||
// If the underlying type has an error, prefer to print the full typealias,
|
||||
// otherwise get the underlying type.
|
||||
if (auto *TA = dyn_cast<TypeAliasType>(ty.getPointer())) {
|
||||
auto underlyingTy = TA->getSinglyDesugaredType();
|
||||
if (!underlyingTy->hasError())
|
||||
ty = underlyingTy;
|
||||
}
|
||||
addTypeAnnotation(Builder, ty);
|
||||
}
|
||||
|
||||
void CompletionLookup::addGenericTypeParamRef(
|
||||
|
||||
@@ -75,7 +75,7 @@ func foo(s: MyStruct<Int>) {
|
||||
// META_MYSTRUCT_INT_DOT: Begin completions, 11 items
|
||||
// META_MYSTRUCT_INT_DOT-DAG: Keyword[self]/CurrNominal: self[#MyStruct<Int>.Type#]; name=self
|
||||
// META_MYSTRUCT_INT_DOT-DAG: Keyword/CurrNominal: Type[#MyStruct<Int>.Type#]; name=Type
|
||||
// META_MYSTRUCT_INT_DOT-DAG: Decl[TypeAlias]/CurrNominal: Assoc[#T#]; name=Assoc
|
||||
// META_MYSTRUCT_INT_DOT-DAG: Decl[TypeAlias]/CurrNominal: Assoc[#Int#]; name=Assoc
|
||||
// META_MYSTRUCT_INT_DOT-DAG: Decl[Constructor]/CurrNominal: init({#int: U#})[#MyStruct<Int>#]; name=init(int:)
|
||||
// META_MYSTRUCT_INT_DOT-DAG: Decl[Constructor]/CurrNominal: init({#withConstrainedGenericParam: SomeProto#})[#MyStruct<Int>#]; name=init(withConstrainedGenericParam:)
|
||||
// META_MYSTRUCT_INT_DOT-DAG: Decl[InstanceMethod]/CurrNominal: methodWithConstrainedGenericParam({#(self): MyStruct<Int>#})[#(x: SomeProto) -> Int#]; name=methodWithConstrainedGenericParam(:)
|
||||
|
||||
@@ -90,7 +90,7 @@ do {
|
||||
let _: Int!.#^SUGARED_IUOPTIONAL_MEMBER_DOT?check=OPTIONAL^#
|
||||
|
||||
// OPTIONAL-LABEL: Begin completions, 2 items
|
||||
// OPTIONAL-LABEL: Decl[TypeAlias]/CurrNominal: Wrappt[#Wrapped#]; name=Wrappt
|
||||
// OPTIONAL-LABEL: Decl[TypeAlias]/CurrNominal: Wrappt[#Int#]; name=Wrappt
|
||||
// OPTIONAL-LABEL: Keyword/None: Type[#{{Optional<Int>|Int\?}}.Type#]; name=Type
|
||||
|
||||
let _: Array<Int>.#^ARRAY_MEMBER_DOT?check=ARRAY^#
|
||||
@@ -99,10 +99,10 @@ do {
|
||||
// ARRAY-LABEL: Begin completions, 8 items
|
||||
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: Index[#Int#]; name=Index
|
||||
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: Indices[#Range<Int>#]; name=Indices
|
||||
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: Iterator[#IndexingIterator<Array<Element>>#]; name=Iterator
|
||||
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: Element[#Element#]; name=Element
|
||||
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: ArrayLiteralElement[#Element#]; name=ArrayLiteralElement
|
||||
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: SubSequence[#ArraySlice<Element>#]; name=SubSequence
|
||||
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: Iterator[#IndexingIterator<Array<Int>>#]; name=Iterator
|
||||
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: Element[#Int#]; name=Element
|
||||
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: ArrayLiteralElement[#Int#]; name=ArrayLiteralElement
|
||||
// ARRAY-DAG: Decl[TypeAlias]/CurrNominal/IsSystem: SubSequence[#ArraySlice<Int>#]; name=SubSequence
|
||||
// ARRAY-DAG: Decl[TypeAlias]/Super/NotRecommended/IsSystem: IndexDistance[#Int#]; name=IndexDistance; diagnostics=warning:'IndexDistance' is deprecated: all index distances are now of type Int
|
||||
// ARRAY-DAG: Keyword/None: Type[#{{Array<Int>|\[Int\]}}.Type#]; name=Type
|
||||
|
||||
@@ -110,15 +110,15 @@ do {
|
||||
let _: [Int : Int].#^SUGARED_DICTIONARY_MEMBER_DOT?check=DICTIONARY^#
|
||||
|
||||
// DICTIONARY-LABEL: Begin completions, 11 items
|
||||
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Element[#(key: Key, value: Value)#]; name=Element
|
||||
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: SubSequence[#Slice<Dictionary<Key, Value>>#]; name=SubSequence
|
||||
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Indices[#DefaultIndices<Dictionary<Key, Value>>#]; name=Indices
|
||||
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Key[#Key#]; name=Key
|
||||
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Value[#Value#]; name=Value
|
||||
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Keys[#Dictionary<Key, Value>.Keys#]; name=Keys
|
||||
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Values[#Dictionary<Key, Value>.Values#]; name=Values
|
||||
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Index[#Dictionary<Key, Value>.Index#]; name=Index
|
||||
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Iterator[#Dictionary<Key, Value>.Iterator#]; name=Iterator
|
||||
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Element[#(key: Int, value: Int)#]; name=Element
|
||||
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: SubSequence[#Slice<Dictionary<Int, Int>>#]; name=SubSequence
|
||||
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Indices[#DefaultIndices<Dictionary<Int, Int>>#]; name=Indices
|
||||
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Key[#Int#]; name=Key
|
||||
// DICTIONARY-NEXT: Decl[TypeAlias]/CurrNominal/IsSystem: Value[#Int#]; name=Value
|
||||
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Keys[#Dictionary<Int, Int>.Keys#]; name=Keys
|
||||
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Values[#Dictionary<Int, Int>.Values#]; name=Values
|
||||
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Index[#Dictionary<Int, Int>.Index#]; name=Index
|
||||
// DICTIONARY-NEXT: Decl[Struct]/CurrNominal/IsSystem: Iterator[#Dictionary<Int, Int>.Iterator#]; name=Iterator
|
||||
// DICTIONARY-NEXT: Decl[TypeAlias]/Super/NotRecommended/IsSystem: IndexDistance[#Int#]; name=IndexDistance; diagnostics=warning
|
||||
// DICTIONARY-NEXT: Keyword/None: Type[#{{Dictionary<Int, Int>|\[Int : Int\]}}.Type#]; name=Type
|
||||
}
|
||||
@@ -160,3 +160,10 @@ do {
|
||||
// MEMBER_EXISTENTIAL_NO_DOT-NEXT: Keyword/None: .Protocol[#(any Sequence).Type#]; name=Protocol
|
||||
// MEMBER_EXISTENTIAL_NO_DOT-NEXT: Keyword/None: .Type[#any Sequence.Type#]; name=Type
|
||||
}
|
||||
|
||||
struct TestGenericTypealias<T, U> {
|
||||
typealias K<V> = TestGenericTypealias<(T, U), V>
|
||||
}
|
||||
|
||||
let _ = TestGenericTypealias<Int, String>.K<Float>.#^GENERIC_TYPEALIAS^#
|
||||
// GENERIC_TYPEALIAS-DAG: Decl[TypeAlias]/CurrNominal: K[#TestGenericTypealias<((Int, String), Float), V>#]; name=K
|
||||
|
||||
@@ -49,4 +49,4 @@ extension ObservableConvertibleType {
|
||||
// CATCHSEQUENCE_DOT-DAG: Keyword/CurrNominal: Type[#CatchSequence<_>.Type#]; name=Type
|
||||
// CATCHSEQUENCE_DOT-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init()[#CatchSequence<_>#]; name=init()
|
||||
// CATCHSEQUENCE_DOT-DAG: Decl[StaticMethod]/Super/TypeRelation[Convertible]: catchError()[#Observable<CatchSequence<_>.T>#]; name=catchError()
|
||||
// CATCHSEQUENCE_DOT-DAG: Decl[TypeAlias]/Super: T[#T#]; name=T
|
||||
// CATCHSEQUENCE_DOT-DAG: Decl[TypeAlias]/Super: T[#Observable<_.Element.T>.T#]; name=T
|
||||
|
||||
Reference in New Issue
Block a user