Skip to content

Commit b313668

Browse files
committed
IDETypeChecking: Add a function to collect protocol members who have default implementations in protocol extensions. Need for rdar://25032869
1 parent 821c2cb commit b313668

File tree

5 files changed

+67
-3
lines changed

5 files changed

+67
-3
lines changed

include/swift/Sema/IDETypeChecking.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace swift {
2828
class Expr;
2929
class LazyResolver;
3030
class ExtensionDecl;
31+
class ProtocolDecl;
3132

3233
/// \brief Typecheck a declaration parsed during code completion.
3334
///
@@ -47,6 +48,9 @@ namespace swift {
4748

4849
Type lookUpTypeInContext(DeclContext *DC, StringRef Name);
4950

51+
void collectDefaultImplementationForProtocolMembers(ProtocolDecl *PD,
52+
llvm::SmallDenseMap<ValueDecl*, ValueDecl*> &DefaultMap);
53+
5054
/// \brief Given an unresolved member E and its parent P, this function tries
5155
/// to infer the type of E.
5256
/// \returns true on success, false on error.

lib/Sema/CSGen.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3282,7 +3282,7 @@ swift::resolveValueMember(DeclContext &DC, Type BaseTy, DeclName Name) {
32823282
Optional<Solution> OpSolution = CS.solveSingle();
32833283
if (!OpSolution.hasValue())
32843284
return Result;
3285-
SelectedOverload Selected = OpSolution.getValue().overloadChoices[Locator];
3285+
SelectedOverload Selected = OpSolution.getValue().overloadChoices[Locator];
32863286
Result.Favored = Selected.choice.getDecl();
32873287
for (OverloadChoice& Choice : LookupResult.ViableCandidates) {
32883288
ValueDecl *VD = Choice.getDecl();
@@ -3291,3 +3291,26 @@ swift::resolveValueMember(DeclContext &DC, Type BaseTy, DeclName Name) {
32913291
}
32923292
return Result;
32933293
}
3294+
3295+
void swift::collectDefaultImplementationForProtocolMembers(ProtocolDecl *PD,
3296+
llvm::SmallDenseMap<ValueDecl*, ValueDecl*> &DefaultMap) {
3297+
Type BaseTy = PD->getDeclaredTypeInContext();
3298+
DeclContext *DC = PD->getDeclContext();
3299+
auto *TC = static_cast<TypeChecker*>(DC->getASTContext().getLazyResolver());
3300+
if (!TC) {
3301+
TC = new TypeChecker(DC->getASTContext());
3302+
}
3303+
for (Decl *D : PD->getMembers()) {
3304+
ValueDecl *VD = dyn_cast<ValueDecl>(D);
3305+
if (!VD)
3306+
continue;
3307+
ResolveMemberResult Result = resolveValueMember(*DC, BaseTy,
3308+
VD->getFullName());
3309+
if (Result.OtherViables.empty())
3310+
continue;
3311+
for(ValueDecl *Other : Result.OtherViables) {
3312+
if (Other->getDeclContext()->isExtensionContext())
3313+
DefaultMap.insert({VD, Other});
3314+
}
3315+
}
3316+
}

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "swift/AST/TypeMatcher.h"
2828
#include "swift/AST/TypeWalker.h"
2929
#include "swift/Basic/Defer.h"
30+
#include "swift/Sema/IDETypeChecking.h"
3031
#include "llvm/ADT/ScopedHashTable.h"
3132
#include "llvm/ADT/SmallString.h"
3233
#include "llvm/Support/SaveAndRestore.h"
@@ -4311,3 +4312,4 @@ bool TypeChecker::isProtocolExtensionUsable(DeclContext *dc, Type type,
43114312
// If we can solve the solution, the protocol extension is usable.
43124313
return cs.solveSingle().hasValue();
43134314
}
4315+

test/IDE/print_synthesized_extensions.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// RUN: FileCheck %s -check-prefix=CHECK9 < %t.syn.txt
1313
// RUN: FileCheck %s -check-prefix=CHECK10 < %t.syn.txt
1414
// RUN: FileCheck %s -check-prefix=CHECK11 < %t.syn.txt
15+
// RUN: FileCheck %s -check-prefix=CHECK12 < %t.syn.txt
1516

1617
public protocol P1{
1718
associatedtype T1
@@ -197,12 +198,20 @@ public extension P5 {
197198
public func foo4() {}
198199
}
199200

200-
201201
public struct S12 : P5{
202202
public typealias T1 = Int
203203
public func foo1() {}
204204
}
205205

206+
public protocol P6 {
207+
func foo1()
208+
func foo2()
209+
}
210+
211+
public extension P6 {
212+
public func foo1() {}
213+
}
214+
206215
// CHECK1: <synthesized>extension <ref:Struct>S1</ref> where T : P2 {
207216
// CHECK1-NEXT: <decl:Func>public func <loc>p2member()</loc></decl>
208217
// CHECK1-NEXT: <decl:Func>public func <loc>ef1(<decl:Param>t: T</decl>)</loc></decl>
@@ -276,3 +285,8 @@ public struct S12 : P5{
276285
// CHECK11-NEXT: <decl:Func>/// This is picked
277286
// CHECK11-NEXT: public func <loc>foo4()</loc></decl>
278287
// CHECK11-NEXT: }</synthesized>
288+
289+
// CHECK12: <decl:Protocol>public protocol <loc>P6</loc> {
290+
// CHECK12-NEXT: <decl:Func(HasDefault)>public func <loc>foo1()</loc></decl>
291+
// CHECK12-NEXT: <decl:Func>public func <loc>foo2()</loc></decl>
292+
// CHECK12-NEXT: }</decl>

tools/swift-ide-test/swift-ide-test.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "swift/IDE/SourceEntityWalker.h"
3939
#include "swift/IDE/SyntaxModel.h"
4040
#include "swift/IDE/Utils.h"
41+
#include "swift/Sema/IDETypeChecking.h"
4142
#include "swift/Markup/Markup.h"
4243
#include "swift/Config.h"
4344
#include "clang/APINotes/APINotesReader.h"
@@ -1574,11 +1575,28 @@ static int doPrintLocalTypes(const CompilerInvocation &InitInvok,
15741575

15751576
namespace {
15761577
class AnnotatingPrinter : public StreamPrinter {
1578+
llvm::SmallDenseMap<ValueDecl*, ValueDecl*> DefaultImplementationMap;
1579+
bool InProtocol = false;
15771580
public:
15781581
using StreamPrinter::StreamPrinter;
15791582

15801583
void printDeclPre(const Decl *D, Optional<BracketOptions> Bracket) override {
1581-
OS << "<decl:" << Decl::getKindName(D->getKind()) << '>';
1584+
StringRef HasDefault = "";
1585+
if (D->getKind() == DeclKind::Protocol) {
1586+
InProtocol = true;
1587+
DefaultImplementationMap.clear();
1588+
ProtocolDecl *PD = const_cast<ProtocolDecl*>(dyn_cast<ProtocolDecl>(D));
1589+
collectDefaultImplementationForProtocolMembers(PD,
1590+
DefaultImplementationMap);
1591+
}
1592+
if (InProtocol) {
1593+
if (auto *VD = const_cast<ValueDecl*>(dyn_cast<ValueDecl>(D))) {
1594+
if (DefaultImplementationMap.count(VD) != 0) {
1595+
HasDefault = "(HasDefault)";
1596+
}
1597+
}
1598+
}
1599+
OS << "<decl:" << Decl::getKindName(D->getKind()) << HasDefault << '>';
15821600
}
15831601
void printDeclLoc(const Decl *D) override {
15841602
OS << "<loc>";
@@ -1587,6 +1605,9 @@ class AnnotatingPrinter : public StreamPrinter {
15871605
OS << "</loc>";
15881606
}
15891607
void printDeclPost(const Decl *D, Optional<BracketOptions> Bracket) override {
1608+
if (D->getKind() == DeclKind::Protocol) {
1609+
InProtocol = false;
1610+
}
15901611
OS << "</decl>";
15911612
}
15921613
void printStructurePre(PrintStructureKind Kind, const Decl *D) override {

0 commit comments

Comments
 (0)