[IDE] Teach type checker about conditional conformance extensions.

Before conditional conformances, the archetypes in conformance
extensions (i.e. extension Foo: SomeProtocol) were equivalent to those
in the type decl, with the same protocol bounds and so on. The code for
printing "synthesized" members relied on this fact. This commit teaches
that code to deal with archetypes in the conditional conformance
extension when required.

Fixes rdar://problem/36553066 and SR-6930.
This commit is contained in:
Huon Wilson
2018-02-13 01:32:24 +11:00
parent 715ca9d27d
commit cb60dbeee2
14 changed files with 870 additions and 437 deletions

View File

@@ -62,7 +62,7 @@ struct TextRange {
struct TextEntity {
const Decl *Dcl = nullptr;
const Decl *SynthesizeTarget = nullptr;
TypeOrExtensionDecl SynthesizeTarget;
const Decl *DefaultImplementationOf = nullptr;
StringRef Argument;
TextRange Range;
@@ -70,26 +70,26 @@ struct TextEntity {
std::vector<TextEntity> SubEntities;
const bool IsSynthesizedExtension;
TextEntity(const Decl *D, const Decl *SynthesizeTarget,
const Decl* DefaultImplementationOf,
unsigned StartOffset, bool IsSynthesizedExtension)
: Dcl(D), SynthesizeTarget(SynthesizeTarget),
DefaultImplementationOf(DefaultImplementationOf), Range{StartOffset, 0},
IsSynthesizedExtension(IsSynthesizedExtension) {}
TextEntity(const Decl *D, TypeOrExtensionDecl SynthesizeTarget,
const Decl *DefaultImplementationOf, unsigned StartOffset,
bool IsSynthesizedExtension)
: Dcl(D), SynthesizeTarget(SynthesizeTarget),
DefaultImplementationOf(DefaultImplementationOf), Range{StartOffset, 0},
IsSynthesizedExtension(IsSynthesizedExtension) {}
TextEntity(const Decl *D, const Decl *SynthesizeTarget,
const Decl* DefaultImplementationOf, TextRange TR,
unsigned LocOffset, bool IsSynthesizedExtension) : Dcl(D),
DefaultImplementationOf(DefaultImplementationOf), Range(TR),
LocOffset(LocOffset),
IsSynthesizedExtension(IsSynthesizedExtension) {}
TextEntity(const Decl *D, TypeOrExtensionDecl SynthesizeTarget,
const Decl *DefaultImplementationOf, TextRange TR,
unsigned LocOffset, bool IsSynthesizedExtension)
: Dcl(D), DefaultImplementationOf(DefaultImplementationOf), Range(TR),
LocOffset(LocOffset), IsSynthesizedExtension(IsSynthesizedExtension) {}
TextEntity(const Decl *D, const Decl *SynthesizeTarget,
const Decl* DefaultImplementationOf, StringRef Arg,
TextRange TR, unsigned LocOffset, bool IsSynthesizedExtension)
: Dcl(D), SynthesizeTarget(SynthesizeTarget),
DefaultImplementationOf(DefaultImplementationOf), Argument(Arg), Range(TR),
LocOffset(LocOffset), IsSynthesizedExtension(IsSynthesizedExtension) {}
TextEntity(const Decl *D, TypeOrExtensionDecl SynthesizeTarget,
const Decl *DefaultImplementationOf, StringRef Arg, TextRange TR,
unsigned LocOffset, bool IsSynthesizedExtension)
: Dcl(D), SynthesizeTarget(SynthesizeTarget),
DefaultImplementationOf(DefaultImplementationOf), Argument(Arg),
Range(TR), LocOffset(LocOffset),
IsSynthesizedExtension(IsSynthesizedExtension) {}
};
struct TextReference {
@@ -103,8 +103,8 @@ struct TextReference {
class AnnotatingPrinter : public StreamPrinter {
std::pair<const ExtensionDecl *, const NominalTypeDecl *>
SynthesizedExtensionInfo = {nullptr, nullptr};
std::pair<const ExtensionDecl *, TypeOrExtensionDecl>
SynthesizedExtensionInfo = {nullptr, {}};
typedef llvm::SmallDenseMap<ValueDecl*, ValueDecl*> DefaultImplementMap;
llvm::SmallDenseMap<ProtocolDecl*, DefaultImplementMap> AllDefaultMaps;
@@ -175,22 +175,22 @@ public:
}
void printSynthesizedExtensionPre(const ExtensionDecl *ED,
const NominalTypeDecl *NTD,
TypeOrExtensionDecl Target,
Optional<BracketOptions> Bracket) override {
assert(!SynthesizedExtensionInfo.first);
SynthesizedExtensionInfo = {ED, NTD};
SynthesizedExtensionInfo = {ED, Target};
if (!shouldContinuePre(ED, Bracket))
return;
unsigned StartOffset = OS.tell();
EntitiesStack.emplace_back(ED, SynthesizedExtensionInfo.second, nullptr,
StartOffset, true);
EntitiesStack.emplace_back(ED, Target, nullptr, StartOffset, true);
}
void printSynthesizedExtensionPost(const ExtensionDecl *ED,
const NominalTypeDecl *NTD,
Optional<BracketOptions> Bracket) override {
void
printSynthesizedExtensionPost(const ExtensionDecl *ED,
TypeOrExtensionDecl Target,
Optional<BracketOptions> Bracket) override {
assert(SynthesizedExtensionInfo.first);
SynthesizedExtensionInfo = {nullptr, nullptr};
SynthesizedExtensionInfo = {nullptr, {}};
if (!shouldContinuePost(ED, Bracket))
return;
TextEntity Entity = std::move(EntitiesStack.back());
@@ -207,8 +207,8 @@ public:
return;
unsigned StartOffset = OS.tell();
initDefaultMapToUse(D);
const NominalTypeDecl *SynthesizedTarget = nullptr;
// If D is declared in the extension, then the synthesized target is valid.
TypeOrExtensionDecl SynthesizedTarget;
if (D->getDeclContext() == SynthesizedExtensionInfo.first)
SynthesizedTarget = SynthesizedExtensionInfo.second;
EntitiesStack.emplace_back(D, SynthesizedTarget,
@@ -297,10 +297,10 @@ static void initDocGenericParams(const Decl *D, DocEntityInfo &Info) {
}
}
static bool initDocEntityInfo(const Decl *D, const Decl *SynthesizedTarget,
const Decl *DefaultImplementationOf,
bool IsRef, bool IsSynthesizedExtension,
DocEntityInfo &Info,
static bool initDocEntityInfo(const Decl *D,
TypeOrExtensionDecl SynthesizedTarget,
const Decl *DefaultImplementationOf, bool IsRef,
bool IsSynthesizedExtension, DocEntityInfo &Info,
StringRef Arg = StringRef()) {
if (!IsRef && D->isImplicit())
return true;
@@ -320,9 +320,13 @@ static bool initDocEntityInfo(const Decl *D, const Decl *SynthesizedTarget,
return false;
}
if (IsSynthesizedExtension)
Info.Kind = SwiftLangSupport::getUIDForExtensionOfDecl(SynthesizedTarget);
else
auto SynthesizedTargetNTD =
SynthesizedTarget ? SynthesizedTarget.getBaseNominal() : nullptr;
if (IsSynthesizedExtension) {
Info.Kind =
SwiftLangSupport::getUIDForExtensionOfDecl(SynthesizedTargetNTD);
} else
Info.Kind = SwiftLangSupport::getUIDForDecl(D, IsRef);
if (Info.Kind.isInvalid())
@@ -335,7 +339,7 @@ static bool initDocEntityInfo(const Decl *D, const Decl *SynthesizedTarget,
SwiftLangSupport::printUSR(VD, OS);
if (SynthesizedTarget) {
OS << SwiftLangSupport::SynthesizedUSRSeparator;
SwiftLangSupport::printUSR(dyn_cast<ValueDecl>(SynthesizedTarget), OS);
SwiftLangSupport::printUSR(SynthesizedTargetNTD, OS);
{
llvm::raw_svector_ostream OS(Info.OriginalUSR);
SwiftLangSupport::printUSR(VD, OS);
@@ -375,8 +379,7 @@ static bool initDocEntityInfo(const Decl *D, const Decl *SynthesizedTarget,
SecondPart = SecondPart.substr(ExtendedName.size());
llvm::SmallString<128> UpdatedDocBuffer;
UpdatedDocBuffer.append(FirstPart);
UpdatedDocBuffer.append(((const NominalTypeDecl*)SynthesizedTarget)->getName().
str());
UpdatedDocBuffer.append(SynthesizedTargetNTD->getName().str());
UpdatedDocBuffer.append(SecondPart);
OS << UpdatedDocBuffer;
} else
@@ -392,9 +395,7 @@ static bool initDocEntityInfo(const Decl *D, const Decl *SynthesizedTarget,
llvm::raw_svector_ostream OS(Info.FullyAnnotatedDecl);
if (SynthesizedTarget)
SwiftLangSupport::printFullyAnnotatedSynthesizedDeclaration(
VD, const_cast<NominalTypeDecl *>(
static_cast<const NominalTypeDecl *>(SynthesizedTarget)),
OS);
VD, SynthesizedTarget, OS);
else
SwiftLangSupport::printFullyAnnotatedDeclaration(VD, Type(), OS);
}
@@ -461,13 +462,13 @@ static const TypeDecl *getTypeDeclFromType(Type Ty) {
static void passInherits(const ValueDecl *D, DocInfoConsumer &Consumer) {
DocEntityInfo EntInfo;
if (initDocEntityInfo(D, nullptr, nullptr, /*IsRef=*/true, false, EntInfo))
if (initDocEntityInfo(D, {}, nullptr, /*IsRef=*/true, false, EntInfo))
return;
Consumer.handleInheritsEntity(EntInfo);
}
static void passConforms(const ValueDecl *D, DocInfoConsumer &Consumer) {
DocEntityInfo EntInfo;
if (initDocEntityInfo(D, nullptr, nullptr, /*IsRef=*/true, false, EntInfo))
if (initDocEntityInfo(D, {}, nullptr, /*IsRef=*/true, false, EntInfo))
return;
Consumer.handleConformsToEntity(EntInfo);
}
@@ -503,7 +504,7 @@ static void passConforms(ArrayRef<ValueDecl *> Dcls,
}
static void passExtends(const ValueDecl *D, DocInfoConsumer &Consumer) {
DocEntityInfo EntInfo;
if (initDocEntityInfo(D, nullptr, nullptr, /*IsRef=*/true, false, EntInfo))
if (initDocEntityInfo(D, {}, nullptr, /*IsRef=*/true, false, EntInfo))
return;
Consumer.handleExtendsEntity(EntInfo);
}
@@ -516,15 +517,15 @@ static void passInheritsAndConformancesForValueDecl(const ValueDecl *VD,
Consumer);
}
static void reportRelated(ASTContext &Ctx,
const Decl *D,
const Decl* SynthesizedTarget,
static void reportRelated(ASTContext &Ctx, const Decl *D,
TypeOrExtensionDecl SynthesizedTarget,
DocInfoConsumer &Consumer) {
if (!D || isa<ParamDecl>(D))
return;
if (const auto *ED = dyn_cast<ExtensionDecl>(D)) {
if (SynthesizedTarget) {
passExtends((const ValueDecl*)SynthesizedTarget, Consumer);
auto Extends = SynthesizedTarget.getBaseNominal();
passExtends(Extends, Consumer);
} else if (Type T = ED->getExtendedType()) {
if (auto TD = getTypeDeclFromType(T))
passExtends(TD, Consumer);
@@ -645,7 +646,8 @@ static void reportDocEntities(ASTContext &Ctx,
continue;
Consumer.startSourceEntity(EntInfo);
reportRelated(Ctx, Entity.Dcl,
Entity.IsSynthesizedExtension ? Entity.SynthesizeTarget : nullptr,
Entity.IsSynthesizedExtension ? Entity.SynthesizeTarget
: TypeOrExtensionDecl(),
Consumer);
reportDocEntities(Ctx, Entity.SubEntities, Consumer);
reportAttributes(Ctx, Entity.Dcl, Consumer);
@@ -759,8 +761,7 @@ private:
const TextReference &Ref = References.front();
References = References.slice(1);
DocEntityInfo Info;
if (initDocEntityInfo(Ref.Dcl, nullptr, nullptr, /*IsRef=*/true, false,
Info))
if (initDocEntityInfo(Ref.Dcl, {}, nullptr, /*IsRef=*/true, false, Info))
continue;
Info.Offset = Ref.Range.Offset;
Info.Length = Ref.Range.Length;
@@ -826,7 +827,7 @@ static void addParameters(ArrayRef<Identifier> &ArgNames,
SM.getLocOffsetInBuffer(Lexer::getLocForEndOfToken(SM, TypeRange.End),
BufferID);
TextRange TR{ StartOffs, EndOffs-StartOffs };
TextEntity Param(param, nullptr, nullptr, Arg, TR, StartOffs, false);
TextEntity Param(param, {}, nullptr, Arg, TR, StartOffs, false);
Ent.SubEntities.push_back(std::move(Param));
}
}
@@ -1020,7 +1021,8 @@ public:
return true;
TextRange TR = getTextRange(D->getSourceRange());
unsigned LocOffset = getOffset(Range.getStart());
EntitiesStack.emplace_back(D, nullptr, nullptr, TR, LocOffset, false);
EntitiesStack.emplace_back(D, TypeOrExtensionDecl(), nullptr, TR, LocOffset,
false);
return true;
}