Skip to content

Commit 3a2454c

Browse files
committed
[CodeCompletion] Use opaque type for override completion if preferable
rdar://problem/49354106
1 parent 8055583 commit 3a2454c

9 files changed

+217
-30
lines changed

include/swift/AST/ASTPrinter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ class ASTPrinter {
118118
/// Callers should use callPrintDeclPost().
119119
virtual void printDeclPost(const Decl *D, Optional<BracketOptions> Bracket) {}
120120

121+
/// Called before printing the result type of the declaration. Printer can
122+
/// replace \p TL to customize the input.
123+
virtual void printDeclResultTypePre(ValueDecl *VD, TypeLoc &TL) {}
124+
121125
/// Called before printing a type.
122126
virtual void printTypePre(const TypeLoc &TL) {}
123127
/// Called after printing a type.

include/swift/AST/PrintOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ struct PrintOptions {
135135
/// Whether to print *any* accessors on properties.
136136
bool PrintPropertyAccessors = true;
137137

138+
/// Whether to print *any* accessors on subscript.
139+
bool PrintSubscriptAccessors = true;
140+
138141
/// Whether to print the accessors of a property abstractly,
139142
/// i.e. always as:
140143
/// ```

include/swift/Parse/Parser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,8 @@ class Parser {
10281028
ParserResult<PrecedenceGroupDecl>
10291029
parseDeclPrecedenceGroup(ParseDeclOptions flags, DeclAttributes &attributes);
10301030

1031+
ParserResult<TypeRepr> parseDeclResultType(Diag<> MessageID);
1032+
10311033
//===--------------------------------------------------------------------===//
10321034
// Type Parsing
10331035

lib/AST/ASTPrinter.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1714,6 +1714,8 @@ void PrintAST::printMutatingModifiersIfNeeded(const AccessorDecl *accessor) {
17141714
void PrintAST::printAccessors(const AbstractStorageDecl *ASD) {
17151715
if (isa<VarDecl>(ASD) && !Options.PrintPropertyAccessors)
17161716
return;
1717+
if (isa<SubscriptDecl>(ASD) && !Options.PrintSubscriptAccessors)
1718+
return;
17171719

17181720
auto impl = ASD->getImplInfo();
17191721

@@ -2534,6 +2536,7 @@ void PrintAST::visitVarDecl(VarDecl *decl) {
25342536
if (!tyLoc.getTypeRepr())
25352537
tyLoc = TypeLoc::withoutLoc(decl->getInterfaceType());
25362538

2539+
Printer.printDeclResultTypePre(decl, tyLoc);
25372540
if (decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
25382541
printTypeLocForImplicitlyUnwrappedOptional(tyLoc);
25392542
else
@@ -2804,6 +2807,8 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) {
28042807
ResultTyLoc = TypeLoc::withoutLoc(ResultTy);
28052808
}
28062809
Printer << " -> ";
2810+
2811+
Printer.printDeclResultTypePre(decl, ResultTyLoc);
28072812
Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType);
28082813
if (decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
28092814
printTypeLocForImplicitlyUnwrappedOptional(ResultTyLoc);
@@ -2931,8 +2936,9 @@ void PrintAST::visitSubscriptDecl(SubscriptDecl *decl) {
29312936
});
29322937
Printer << " -> ";
29332938

2934-
Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType);
29352939
TypeLoc elementTy = decl->getElementTypeLoc();
2940+
Printer.printDeclResultTypePre(decl, elementTy);
2941+
Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType);
29362942
if (!elementTy.getTypeRepr())
29372943
elementTy = TypeLoc::withoutLoc(decl->getElementInterfaceType());
29382944
if (decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())

lib/IDE/CodeCompletion.cpp

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4038,27 +4038,82 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
40384038
Builder.addAccessControlKeyword(Access);
40394039
}
40404040

4041+
/// Return type if the result type if \p VD should be represented as opaque
4042+
/// result type.
4043+
TypeLoc getOpaqueResultTypeLoc(const ValueDecl *VD, DeclVisibilityKind Reason) {
4044+
if (Reason !=
4045+
DeclVisibilityKind::MemberOfProtocolImplementedByCurrentNominal)
4046+
return nullptr;
4047+
4048+
auto currTy = CurrDeclContext->getDeclaredTypeInContext();
4049+
if (!currTy)
4050+
return nullptr;
4051+
4052+
Type ResultT;
4053+
if (auto *FD = dyn_cast<FuncDecl>(VD))
4054+
ResultT = FD->getResultInterfaceType();
4055+
else if (auto *SD = dyn_cast<SubscriptDecl>(VD))
4056+
ResultT = SD->getElementInterfaceType();
4057+
else if (auto *VarD = dyn_cast<VarDecl>(VD))
4058+
ResultT = VarD->getInterfaceType();
4059+
else
4060+
return nullptr;
4061+
4062+
if (!ResultT->is<DependentMemberType>())
4063+
// The result is not associatedtype.
4064+
return nullptr;
4065+
4066+
// If associatedtype doesn't have conformance/superclass constraint, we
4067+
// can't use opaque type.
4068+
auto assocTyD = ResultT->castTo<DependentMemberType>()->getAssocType();
4069+
if (!assocTyD->getInherited().size())
4070+
return nullptr;
4071+
4072+
// Try substitution to see if the associated type is resolved to concrete
4073+
// type.
4074+
auto substMap = currTy->getMemberSubstitutionMap(
4075+
CurrDeclContext->getParentModule(), VD);
4076+
ResultT = ResultT.subst(substMap, SubstFlags::UseErrorType);
4077+
if (!ResultT || !ResultT->is<DependentMemberType>())
4078+
// If resolved print it.
4079+
return nullptr;
4080+
4081+
return assocTyD->getInherited()[0];
4082+
}
4083+
40414084
void addValueOverride(const ValueDecl *VD, DeclVisibilityKind Reason,
40424085
CodeCompletionResultBuilder &Builder,
40434086
bool hasDeclIntroducer) {
4087+
class DeclPrinter : public StreamPrinter {
4088+
TypeLoc OpaqueBaseTy;
40444089

4045-
class DeclNameOffsetLocatorPrinter : public StreamPrinter {
40464090
public:
40474091
using StreamPrinter::StreamPrinter;
40484092

40494093
Optional<unsigned> NameOffset;
40504094

4095+
DeclPrinter(raw_ostream &OS, TypeLoc OpaqueBaseTy)
4096+
: StreamPrinter(OS), OpaqueBaseTy(OpaqueBaseTy) {}
4097+
40514098
void printDeclLoc(const Decl *D) override {
40524099
if (!NameOffset.hasValue())
40534100
NameOffset = OS.tell();
40544101
}
4102+
4103+
// As for FuncDecl, SubscriptDecl, and VarDecl,
4104+
void printDeclResultTypePre(ValueDecl *VD, TypeLoc &TL) override {
4105+
if (!OpaqueBaseTy.isNull()) {
4106+
OS << "some ";
4107+
TL = OpaqueBaseTy;
4108+
}
4109+
}
40554110
};
40564111

40574112
llvm::SmallString<256> DeclStr;
40584113
unsigned NameOffset = 0;
40594114
{
40604115
llvm::raw_svector_ostream OS(DeclStr);
4061-
DeclNameOffsetLocatorPrinter Printer(OS);
4116+
DeclPrinter Printer(OS, getOpaqueResultTypeLoc(VD, Reason));
40624117
PrintOptions Options;
40634118
if (auto transformType = CurrDeclContext->getDeclaredTypeInContext())
40644119
Options.setBaseType(transformType);
@@ -4067,6 +4122,7 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
40674122
Options.ExclusiveAttrList.push_back(TAK_autoclosure);
40684123
Options.PrintOverrideKeyword = false;
40694124
Options.PrintPropertyAccessors = false;
4125+
Options.PrintSubscriptAccessors = false;
40704126
Options.PrintStaticKeyword = !hasStaticOrClass;
40714127
VD->print(Printer, Options);
40724128
NameOffset = Printer.NameOffset.getValue();
@@ -4080,7 +4136,7 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
40804136
Builder.addOverrideKeyword();
40814137
else {
40824138
auto dist = Ctx.SourceMgr.getByteDistance(
4083-
introducerLoc, Ctx.SourceMgr.getCodeCompletionLoc());
4139+
introducerLoc, Ctx.SourceMgr.getCodeCompletionLoc());
40844140
Builder.setNumBytesToErase(dist);
40854141
Builder.addOverrideKeyword();
40864142
Builder.addDeclIntroducer(DeclStr.str().substr(0, NameOffset));
@@ -4118,6 +4174,15 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
41184174
addValueOverride(VD, Reason, Builder, hasVarIntroducer);
41194175
}
41204176

4177+
void addSubscriptOverride(const SubscriptDecl *SD, DeclVisibilityKind Reason) {
4178+
CodeCompletionResultBuilder Builder(
4179+
Sink, CodeCompletionResult::ResultKind::Declaration,
4180+
SemanticContextKind::Super, {});
4181+
Builder.setAssociatedDecl(SD);
4182+
addValueOverride(SD, Reason, Builder, false);
4183+
Builder.addBraceStmtWithCursor();
4184+
}
4185+
41214186
void addTypeAlias(const AssociatedTypeDecl *ATD, DeclVisibilityKind Reason) {
41224187
CodeCompletionResultBuilder Builder(Sink,
41234188
CodeCompletionResult::ResultKind::Declaration,
@@ -4222,6 +4287,11 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
42224287
return;
42234288
}
42244289

4290+
if (auto *SD = dyn_cast<SubscriptDecl>(D)) {
4291+
if (!hasIntroducer && !hasInitializerModifier)
4292+
addSubscriptOverride(SD, Reason);
4293+
}
4294+
42254295
if (auto *CD = dyn_cast<ConstructorDecl>(D)) {
42264296
if (!isa<ProtocolDecl>(CD->getDeclContext()))
42274297
return;

test/IDE/complete_opaque_result.swift

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,21 @@
1515
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STRUCT_SUBSCRIPT | %FileCheck %s -check-prefix=BEGINNING_WITH_SOME
1616
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STRUCT_TYPEALIAS_RHS | %FileCheck %s -check-prefix=BEGINNING_WITHOUT_SOME
1717

18-
protocol MyProtocol {}
18+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERRIDE_TestClass | %FileCheck %s -check-prefix=OVERRIDE
19+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERRIDE_TestStruct | %FileCheck %s -check-prefix=OVERRIDE
20+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERRIDE_HasTypealias | %FileCheck %s -check-prefix=OVERRIDE_HasTypealias
21+
22+
protocol MyProtocol {
23+
associatedtype Mistery
24+
}
1925
struct MyStruct {}
2026
enum MyEnum {}
2127
class MyClass {}
28+
struct ConcreteMyProtocol : MyProtocol {
29+
typealias Mistery = MyStruct
30+
}
31+
32+
// MARK: 'some' keyword.
2233

2334
// BEGINNING_WITH_SOME: Begin completions
2435
// BEGINNING_WITH_SOME-DAG: Keyword/None: some[#some#]; name=some
@@ -43,8 +54,6 @@ func gloabalFunc() -> #^GLOBAL_FUNC^#
4354
var globalVar: #^GLOBAL_VAR^#
4455

4556
protocol SomeProto {
46-
associatedtype Assoc: MyProtocol
47-
4857
associatedtype protoAssocTy: #^PROTOCOL_ASSOCIATEDTYPE^#
4958
func protoMethodReq() -> #^PROTOCOL_METHOD_REQUIREMENT^#
5059
var protoVarReq: #^PROTOCOL_VAR_REQUIREMENT^#
@@ -63,3 +72,67 @@ struct SomeStruct {
6372
var structVarExt: #^STRUCT_VAR^#
6473
subscript(struct: Int) -> #^STRUCT_SUBSCRIPT^#
6574
}
75+
76+
// MARK: Conformance.
77+
78+
protocol HasAssocPlain {
79+
associatedtype AssocPlain
80+
func returnAssocPlain() -> AssocPlain
81+
}
82+
protocol HasAssocWithConformanceConstraint {
83+
associatedtype AssocWithConformanceConstraint: MyProtocol
84+
func returnAssocWithConformanceConstraint(fn: (Int) -> Int) -> AssocWithConformanceConstraint
85+
}
86+
protocol HasAssocWithSuperClassConstraint {
87+
associatedtype AssocWithSuperClassConstraint: MyClass
88+
var valAssocWithSuperClassConstraint: AssocWithSuperClassConstraint { get }
89+
}
90+
protocol HasAssocWithCompositionConstraint {
91+
associatedtype AssocWithCompositionConstraint: MyClass & MyProtocol
92+
subscript<T>(idx: T) -> AssocWithCompositionConstraint where T: Comparable { get }
93+
}
94+
protocol HasAssocWithDefault {
95+
associatedtype AssocWithDefault = MyEnum
96+
func returnAssocWithDefault() -> AssocWithDefault
97+
}
98+
protocol HasAssocWithConstraintAndDefault {
99+
associatedtype AssocWithConstraintAndDefault: MyProtocol = ConcreteMyProtocol
100+
func returnAssocWithConstraintAndDefault() -> AssocWithConstraintAndDefault
101+
}
102+
103+
class TestClass :
104+
HasAssocPlain,
105+
HasAssocWithConformanceConstraint,
106+
HasAssocWithSuperClassConstraint,
107+
HasAssocWithCompositionConstraint,
108+
HasAssocWithDefault,
109+
HasAssocWithConstraintAndDefault {
110+
#^OVERRIDE_TestClass^#
111+
// OVERRIDE: found code completion token OVERRIDE_[[BASETYPE:[A-Za-z0-9]+]] at
112+
// OVERRIDE: Begin completions
113+
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocPlain() -> [[BASETYPE]].AssocPlain {|};
114+
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConformanceConstraint(fn: (Int) -> Int) -> some MyProtocol {|};
115+
// OVERRIDE-DAG: Decl[InstanceVar]/Super: var valAssocWithSuperClassConstraint: some MyClass;
116+
// OVERRIDE-DAG: Decl[Subscript]/Super: subscript<T>(idx: T) -> some MyClass & MyProtocol where T : Comparable {|};
117+
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithDefault() -> MyEnum {|};
118+
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConstraintAndDefault() -> ConcreteMyProtocol {|};
119+
// OVERRIDE: End completions
120+
}
121+
122+
struct TestStruct :
123+
HasAssocPlain,
124+
HasAssocWithConformanceConstraint,
125+
HasAssocWithSuperClassConstraint,
126+
HasAssocWithCompositionConstraint,
127+
HasAssocWithDefault,
128+
HasAssocWithConstraintAndDefault {
129+
#^OVERRIDE_TestStruct^#
130+
}
131+
132+
class HasTypealias : HasAssocWithConformanceConstraint {
133+
typealias AssocWithConformanceConstraint = ConcreteMyProtocol
134+
#^OVERRIDE_HasTypealias^#
135+
// OVERRIDE_HasTypealias: Begin completions
136+
// OVERRIDE_HasTypealias-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConformanceConstraint(fn: (Int) -> Int) -> ConcreteMyProtocol {|};
137+
// OVERRIDE_HasTypealias: End completions
138+
}

0 commit comments

Comments
 (0)