Skip to content

Commit

Permalink
IDETypeChecking: Add a function to collect protocol members who have …
Browse files Browse the repository at this point in the history
…default implementations in protocol extensions. Need for rdar://25032869
  • Loading branch information
nkcsgexi committed Mar 30, 2016
1 parent 821c2cb commit b313668
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 3 deletions.
4 changes: 4 additions & 0 deletions include/swift/Sema/IDETypeChecking.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace swift {
class Expr;
class LazyResolver;
class ExtensionDecl;
class ProtocolDecl;

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

Type lookUpTypeInContext(DeclContext *DC, StringRef Name);

void collectDefaultImplementationForProtocolMembers(ProtocolDecl *PD,
llvm::SmallDenseMap<ValueDecl*, ValueDecl*> &DefaultMap);

/// \brief Given an unresolved member E and its parent P, this function tries
/// to infer the type of E.
/// \returns true on success, false on error.
Expand Down
25 changes: 24 additions & 1 deletion lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3282,7 +3282,7 @@ swift::resolveValueMember(DeclContext &DC, Type BaseTy, DeclName Name) {
Optional<Solution> OpSolution = CS.solveSingle();
if (!OpSolution.hasValue())
return Result;
SelectedOverload Selected = OpSolution.getValue().overloadChoices[Locator];
SelectedOverload Selected = OpSolution.getValue().overloadChoices[Locator];
Result.Favored = Selected.choice.getDecl();
for (OverloadChoice& Choice : LookupResult.ViableCandidates) {
ValueDecl *VD = Choice.getDecl();
Expand All @@ -3291,3 +3291,26 @@ swift::resolveValueMember(DeclContext &DC, Type BaseTy, DeclName Name) {
}
return Result;
}

void swift::collectDefaultImplementationForProtocolMembers(ProtocolDecl *PD,
llvm::SmallDenseMap<ValueDecl*, ValueDecl*> &DefaultMap) {
Type BaseTy = PD->getDeclaredTypeInContext();
DeclContext *DC = PD->getDeclContext();
auto *TC = static_cast<TypeChecker*>(DC->getASTContext().getLazyResolver());
if (!TC) {
TC = new TypeChecker(DC->getASTContext());
}
for (Decl *D : PD->getMembers()) {
ValueDecl *VD = dyn_cast<ValueDecl>(D);
if (!VD)
continue;
ResolveMemberResult Result = resolveValueMember(*DC, BaseTy,
VD->getFullName());
if (Result.OtherViables.empty())
continue;
for(ValueDecl *Other : Result.OtherViables) {
if (Other->getDeclContext()->isExtensionContext())
DefaultMap.insert({VD, Other});
}
}
}
2 changes: 2 additions & 0 deletions lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "swift/AST/TypeMatcher.h"
#include "swift/AST/TypeWalker.h"
#include "swift/Basic/Defer.h"
#include "swift/Sema/IDETypeChecking.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/SaveAndRestore.h"
Expand Down Expand Up @@ -4311,3 +4312,4 @@ bool TypeChecker::isProtocolExtensionUsable(DeclContext *dc, Type type,
// If we can solve the solution, the protocol extension is usable.
return cs.solveSingle().hasValue();
}

16 changes: 15 additions & 1 deletion test/IDE/print_synthesized_extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// RUN: FileCheck %s -check-prefix=CHECK9 < %t.syn.txt
// RUN: FileCheck %s -check-prefix=CHECK10 < %t.syn.txt
// RUN: FileCheck %s -check-prefix=CHECK11 < %t.syn.txt
// RUN: FileCheck %s -check-prefix=CHECK12 < %t.syn.txt

public protocol P1{
associatedtype T1
Expand Down Expand Up @@ -197,12 +198,20 @@ public extension P5 {
public func foo4() {}
}


public struct S12 : P5{
public typealias T1 = Int
public func foo1() {}
}

public protocol P6 {
func foo1()
func foo2()
}

public extension P6 {
public func foo1() {}
}

// CHECK1: <synthesized>extension <ref:Struct>S1</ref> where T : P2 {
// CHECK1-NEXT: <decl:Func>public func <loc>p2member()</loc></decl>
// CHECK1-NEXT: <decl:Func>public func <loc>ef1(<decl:Param>t: T</decl>)</loc></decl>
Expand Down Expand Up @@ -276,3 +285,8 @@ public struct S12 : P5{
// CHECK11-NEXT: <decl:Func>/// This is picked
// CHECK11-NEXT: public func <loc>foo4()</loc></decl>
// CHECK11-NEXT: }</synthesized>

// CHECK12: <decl:Protocol>public protocol <loc>P6</loc> {
// CHECK12-NEXT: <decl:Func(HasDefault)>public func <loc>foo1()</loc></decl>
// CHECK12-NEXT: <decl:Func>public func <loc>foo2()</loc></decl>
// CHECK12-NEXT: }</decl>
23 changes: 22 additions & 1 deletion tools/swift-ide-test/swift-ide-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "swift/IDE/SourceEntityWalker.h"
#include "swift/IDE/SyntaxModel.h"
#include "swift/IDE/Utils.h"
#include "swift/Sema/IDETypeChecking.h"
#include "swift/Markup/Markup.h"
#include "swift/Config.h"
#include "clang/APINotes/APINotesReader.h"
Expand Down Expand Up @@ -1574,11 +1575,28 @@ static int doPrintLocalTypes(const CompilerInvocation &InitInvok,

namespace {
class AnnotatingPrinter : public StreamPrinter {
llvm::SmallDenseMap<ValueDecl*, ValueDecl*> DefaultImplementationMap;
bool InProtocol = false;
public:
using StreamPrinter::StreamPrinter;

void printDeclPre(const Decl *D, Optional<BracketOptions> Bracket) override {
OS << "<decl:" << Decl::getKindName(D->getKind()) << '>';
StringRef HasDefault = "";
if (D->getKind() == DeclKind::Protocol) {
InProtocol = true;
DefaultImplementationMap.clear();
ProtocolDecl *PD = const_cast<ProtocolDecl*>(dyn_cast<ProtocolDecl>(D));
collectDefaultImplementationForProtocolMembers(PD,
DefaultImplementationMap);
}
if (InProtocol) {
if (auto *VD = const_cast<ValueDecl*>(dyn_cast<ValueDecl>(D))) {
if (DefaultImplementationMap.count(VD) != 0) {
HasDefault = "(HasDefault)";
}
}
}
OS << "<decl:" << Decl::getKindName(D->getKind()) << HasDefault << '>';
}
void printDeclLoc(const Decl *D) override {
OS << "<loc>";
Expand All @@ -1587,6 +1605,9 @@ class AnnotatingPrinter : public StreamPrinter {
OS << "</loc>";
}
void printDeclPost(const Decl *D, Optional<BracketOptions> Bracket) override {
if (D->getKind() == DeclKind::Protocol) {
InProtocol = false;
}
OS << "</decl>";
}
void printStructurePre(PrintStructureKind Kind, const Decl *D) override {
Expand Down

0 comments on commit b313668

Please sign in to comment.