Skip to content

Commit 90d94c8

Browse files
authored
Merge pull request swiftlang#29086 from rintaro/ide-completion-opaqueresult-rdar57245073
[CodeCompletion] Use GenericSignature methods to get 'associatedtype' requirements
2 parents cdb4072 + b9f1e58 commit 90d94c8

File tree

4 files changed

+103
-27
lines changed

4 files changed

+103
-27
lines changed

lib/AST/ASTPrinter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3039,10 +3039,10 @@ void PrintAST::visitSubscriptDecl(SubscriptDecl *decl) {
30393039
Printer << " -> ";
30403040

30413041
TypeLoc elementTy = decl->getElementTypeLoc();
3042-
Printer.printDeclResultTypePre(decl, elementTy);
3043-
Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType);
30443042
if (!elementTy.getTypeRepr())
30453043
elementTy = TypeLoc::withoutLoc(decl->getElementInterfaceType());
3044+
Printer.printDeclResultTypePre(decl, elementTy);
3045+
Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType);
30463046

30473047
// HACK: When printing result types for subscripts with opaque result types,
30483048
// always print them using the `some` keyword instead of printing

lib/IDE/CodeCompletion.cpp

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4159,8 +4159,8 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
41594159

41604160
/// Return type if the result type if \p VD should be represented as opaque
41614161
/// result type.
4162-
TypeLoc getOpaqueResultTypeLoc(const ValueDecl *VD, DeclVisibilityKind Reason,
4163-
DynamicLookupInfo dynamicLookupInfo) {
4162+
Type getOpaqueResultType(const ValueDecl *VD, DeclVisibilityKind Reason,
4163+
DynamicLookupInfo dynamicLookupInfo) {
41644164
if (Reason !=
41654165
DeclVisibilityKind::MemberOfProtocolImplementedByCurrentNominal)
41664166
return nullptr;
@@ -4170,50 +4170,76 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
41704170
return nullptr;
41714171

41724172
Type ResultT;
4173-
if (auto *FD = dyn_cast<FuncDecl>(VD))
4173+
if (auto *FD = dyn_cast<FuncDecl>(VD)) {
4174+
if (FD->getGenericParams()) {
4175+
// Generic function cannot have opaque result type.
4176+
return nullptr;
4177+
}
41744178
ResultT = FD->getResultInterfaceType();
4175-
else if (auto *SD = dyn_cast<SubscriptDecl>(VD))
4179+
} else if (auto *SD = dyn_cast<SubscriptDecl>(VD)) {
4180+
if (SD->getGenericParams()) {
4181+
// Generic subscript cannot have opaque result type.
4182+
return nullptr;
4183+
}
41764184
ResultT = SD->getElementInterfaceType();
4177-
else if (auto *VarD = dyn_cast<VarDecl>(VD))
4185+
} else if (auto *VarD = dyn_cast<VarDecl>(VD)) {
41784186
ResultT = VarD->getInterfaceType();
4179-
else
4180-
return nullptr;
4181-
4182-
if (!ResultT->is<DependentMemberType>())
4183-
// The result is not associatedtype.
4187+
} else {
41844188
return nullptr;
4189+
}
41854190

4186-
// If associatedtype doesn't have conformance/superclass constraint, we
4187-
// can't use opaque type.
4188-
auto assocTyD = ResultT->castTo<DependentMemberType>()->getAssocType();
4189-
if (!assocTyD->getInherited().size())
4191+
if (!ResultT->is<DependentMemberType>() ||
4192+
!ResultT->castTo<DependentMemberType>()->getAssocType())
4193+
// The result is not a valid associatedtype.
41904194
return nullptr;
41914195

41924196
// Try substitution to see if the associated type is resolved to concrete
41934197
// type.
41944198
auto substMap = currTy->getMemberSubstitutionMap(
41954199
CurrDeclContext->getParentModule(), VD);
4196-
ResultT = ResultT.subst(substMap);
4197-
if (!ResultT || !ResultT->is<DependentMemberType>())
4200+
if (!ResultT.subst(substMap)->is<DependentMemberType>())
41984201
// If resolved print it.
41994202
return nullptr;
42004203

4201-
return assocTyD->getInherited()[0];
4204+
auto genericSig = VD->getDeclContext()->getGenericSignatureOfContext();
4205+
4206+
if (genericSig->isConcreteType(ResultT))
4207+
// If it has same type requrement, we will emit the concrete type.
4208+
return nullptr;
4209+
4210+
// Collect requirements on the associatedtype.
4211+
SmallVector<Type, 2> opaqueTypes;
4212+
bool hasExplicitAnyObject = false;
4213+
if (auto superTy = genericSig->getSuperclassBound(ResultT))
4214+
opaqueTypes.push_back(superTy);
4215+
for (auto proto : genericSig->getConformsTo(ResultT))
4216+
opaqueTypes.push_back(proto->getDeclaredInterfaceType());
4217+
if (auto layout = genericSig->getLayoutConstraint(ResultT))
4218+
hasExplicitAnyObject = layout->isClass();
4219+
4220+
if (!hasExplicitAnyObject) {
4221+
if (opaqueTypes.empty())
4222+
return nullptr;
4223+
if (opaqueTypes.size() == 1)
4224+
return opaqueTypes.front();
4225+
}
4226+
return ProtocolCompositionType::get(
4227+
VD->getASTContext(), opaqueTypes, hasExplicitAnyObject);
42024228
}
42034229

42044230
void addValueOverride(const ValueDecl *VD, DeclVisibilityKind Reason,
42054231
DynamicLookupInfo dynamicLookupInfo,
42064232
CodeCompletionResultBuilder &Builder,
42074233
bool hasDeclIntroducer) {
42084234
class DeclPrinter : public StreamPrinter {
4209-
TypeLoc OpaqueBaseTy;
4235+
Type OpaqueBaseTy;
42104236

42114237
public:
42124238
using StreamPrinter::StreamPrinter;
42134239

42144240
Optional<unsigned> NameOffset;
42154241

4216-
DeclPrinter(raw_ostream &OS, TypeLoc OpaqueBaseTy)
4242+
DeclPrinter(raw_ostream &OS, Type OpaqueBaseTy)
42174243
: StreamPrinter(OS), OpaqueBaseTy(OpaqueBaseTy) {}
42184244

42194245
void printDeclLoc(const Decl *D) override {
@@ -4225,7 +4251,7 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
42254251
void printDeclResultTypePre(ValueDecl *VD, TypeLoc &TL) override {
42264252
if (!OpaqueBaseTy.isNull()) {
42274253
OS << "some ";
4228-
TL = OpaqueBaseTy;
4254+
TL = TypeLoc::withoutLoc(OpaqueBaseTy);
42294255
}
42304256
}
42314257
};
@@ -4235,7 +4261,7 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
42354261
{
42364262
llvm::raw_svector_ostream OS(DeclStr);
42374263
DeclPrinter Printer(
4238-
OS, getOpaqueResultTypeLoc(VD, Reason, dynamicLookupInfo));
4264+
OS, getOpaqueResultType(VD, Reason, dynamicLookupInfo));
42394265
PrintOptions Options;
42404266
if (auto transformType = CurrDeclContext->getDeclaredTypeInContext())
42414267
Options.setBaseType(transformType);

test/IDE/complete_crossmodule.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %{python} %utils/split_file.py -o %t %s
3+
4+
// RUN: %target-swift-frontend -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift
5+
// RUN: %target-swift-ide-test -code-completion -source-filename %t/Test.swift -I %t -code-completion-token=OPAQUE_RESULT | %FileCheck --check-prefix=OPAQUE_RESULT %s
6+
7+
// BEGIN MyModule.swift
8+
9+
public protocol HasAssocWithConstraint {
10+
associatedtype AssocWithContraint: HasAssocWithConstraint
11+
var value: AssocWithContraint { get }
12+
}
13+
14+
// BEGIN Test.swift
15+
import MyModule
16+
17+
struct MyValue: HasAssocWithConstraint {
18+
var #^OPAQUE_RESULT^#
19+
// OPAQUE_RESULT: Begin completions
20+
// OPAQUE_RESULT-DAG: Decl[InstanceVar]/Super: value: some HasAssocWithConstraint;
21+
// OPAQUE_RESULT: End completions
22+
}

test/IDE/complete_opaque_result.swift

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ protocol HasAssocWithSuperClassConstraint {
9292
}
9393
protocol HasAssocWithCompositionConstraint {
9494
associatedtype AssocWithCompositionConstraint: MyClass & MyProtocol
95-
subscript<T>(idx: T) -> AssocWithCompositionConstraint where T: Comparable { get }
95+
subscript(idx: Int) -> AssocWithCompositionConstraint { get }
9696
}
9797
protocol HasAssocWithDefault {
9898
associatedtype AssocWithDefault = MyEnum
@@ -102,22 +102,46 @@ protocol HasAssocWithConstraintAndDefault {
102102
associatedtype AssocWithConstraintAndDefault: MyProtocol = ConcreteMyProtocol
103103
func returnAssocWithConstraintAndDefault() -> AssocWithConstraintAndDefault
104104
}
105+
protocol HasAssocWithAnyObjectConstraint {
106+
associatedtype AssocWithAnyObjectConstraint: AnyObject & MyProtocol
107+
func returnAssocWithAnyObjectConstraint() -> AssocWithAnyObjectConstraint
108+
}
109+
protocol HasAssocWithConstraintOnProto where Self.AssocWithConstraintOnProto : MyProtocol {
110+
associatedtype AssocWithConstraintOnProto
111+
func returnAssocWithConstraintOnProto() -> AssocWithConstraintOnProto
112+
}
113+
protocol HasAssocWithSameTypeConstraint where Self.AssocWithSameTypeConstraint == ConcreteMyProtocol {
114+
associatedtype AssocWithSameTypeConstraint : MyProtocol
115+
func returnAssocWithSameTypeConstraint() -> AssocWithSameTypeConstraint
116+
}
117+
protocol HasAssocWithConformanceConstraintGeneric {
118+
associatedtype AssocWithConformanceConstraintGeneric: MyProtocol
119+
func returnAssocWithConformanceConstraintGeneric<T>(arg: T) -> AssocWithConformanceConstraintGeneric
120+
}
105121

106122
class TestClass :
107123
HasAssocPlain,
108124
HasAssocWithConformanceConstraint,
109125
HasAssocWithSuperClassConstraint,
110126
HasAssocWithCompositionConstraint,
111127
HasAssocWithDefault,
112-
HasAssocWithConstraintAndDefault {
128+
HasAssocWithConstraintAndDefault,
129+
HasAssocWithAnyObjectConstraint,
130+
HasAssocWithConstraintOnProto,
131+
HasAssocWithSameTypeConstraint,
132+
HasAssocWithConformanceConstraintGeneric {
113133
#^OVERRIDE_TestClass^#
114134
// OVERRIDE: Begin completions
115135
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocPlain() -> AssocPlain {|};
116136
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConformanceConstraint(fn: (Int) -> Int) -> some MyProtocol {|};
117137
// OVERRIDE-DAG: Decl[InstanceVar]/Super: var valAssocWithSuperClassConstraint: some MyClass;
118-
// OVERRIDE-DAG: Decl[Subscript]/Super: subscript<T>(idx: T) -> some MyClass & MyProtocol where T : Comparable {|};
138+
// OVERRIDE-DAG: Decl[Subscript]/Super: subscript(idx: Int) -> some MyClass & MyProtocol {|};
119139
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithDefault() -> MyEnum {|};
120140
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConstraintAndDefault() -> ConcreteMyProtocol {|};
141+
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithAnyObjectConstraint() -> some MyProtocol & AnyObject {|}
142+
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConstraintOnProto() -> some MyProtocol {|}
143+
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithSameTypeConstraint() -> AssocWithSameTypeConstraint {|}
144+
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConformanceConstraintGeneric<T>(arg: T) -> AssocWithConformanceConstraintGeneric {|}
121145
// OVERRIDE: End completions
122146
}
123147

@@ -127,7 +151,11 @@ struct TestStruct :
127151
HasAssocWithSuperClassConstraint,
128152
HasAssocWithCompositionConstraint,
129153
HasAssocWithDefault,
130-
HasAssocWithConstraintAndDefault {
154+
HasAssocWithConstraintAndDefault,
155+
HasAssocWithAnyObjectConstraint,
156+
HasAssocWithConstraintOnProto,
157+
HasAssocWithSameTypeConstraint,
158+
HasAssocWithConformanceConstraintGeneric {
131159
#^OVERRIDE_TestStruct^#
132160
}
133161

0 commit comments

Comments
 (0)