Skip to content

Commit f169bdb

Browse files
committed
[IDE] Call into matchWitnessStructure to check if we should inherit a comment from an overridden declaration
1 parent 3ed457a commit f169bdb

File tree

6 files changed

+94
-30
lines changed

6 files changed

+94
-30
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4684,6 +4684,24 @@ class RawCommentRequest
46844684
bool isCached() const { return true; }
46854685
};
46864686

4687+
/// Get the declaration that actually provides a doc comment for another.
4688+
class DocCommentProvidingDeclRequest
4689+
: public SimpleRequest<DocCommentProvidingDeclRequest,
4690+
const Decl *(const Decl *), RequestFlags::Cached> {
4691+
public:
4692+
using SimpleRequest::SimpleRequest;
4693+
4694+
private:
4695+
friend SimpleRequest;
4696+
4697+
// Evaluation.
4698+
const Decl *evaluate(Evaluator &evaluator, const Decl *D) const;
4699+
4700+
public:
4701+
// Separate caching.
4702+
bool isCached() const { return true; }
4703+
};
4704+
46874705
/// Retrieve the brief portion of a declaration's document comment, potentially
46884706
/// walking to find the comment providing decl if needed.
46894707
class SemanticBriefCommentRequest

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,9 @@ SWIFT_REQUEST(TypeChecker, LocalDiscriminatorsRequest,
530530
SWIFT_REQUEST(TypeChecker, RawCommentRequest,
531531
RawComment(const Decl *),
532532
Cached, NoLocationInfo)
533+
SWIFT_REQUEST(TypeChecker, DocCommentProvidingDeclRequest,
534+
const Decl *(const Decl *),
535+
Cached, NoLocationInfo)
533536
SWIFT_REQUEST(TypeChecker, SemanticBriefCommentRequest,
534537
StringRef(const Decl *),
535538
Cached, NoLocationInfo)

lib/AST/DocComment.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,17 @@ DocComment *swift::getSingleDocComment(swift::markup::MarkupContext &MC,
391391
return nullptr;
392392
return DocComment::create(D, MC, RC);
393393
}
394+
395+
const Decl *Decl::getDocCommentProvidingDecl() const {
396+
return evaluateOrDefault(getASTContext().evaluator,
397+
DocCommentProvidingDeclRequest{this}, nullptr);
398+
}
399+
400+
StringRef Decl::getSemanticBriefComment() const {
401+
if (!canHaveComment())
402+
return StringRef();
403+
404+
auto &eval = getASTContext().evaluator;
405+
return evaluateOrDefault(eval, SemanticBriefCommentRequest{this},
406+
StringRef());
407+
}

lib/Sema/Comment.cpp

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "swift/AST/Comment.h"
14+
#include "TypeChecker.h"
1415
#include "swift/AST/ASTContext.h"
1516
#include "swift/AST/Decl.h"
1617
#include "swift/AST/TypeCheckRequests.h"
@@ -80,9 +81,11 @@ class CommentProviderFinder final {
8081
}
8182

8283
for (auto *member : members) {
83-
if (isa<AbstractFunctionDecl>(member) ||
84-
isa<AbstractStorageDecl>(member)) {
85-
if (VD->isStatic() != member->isStatic()) {
84+
if (VD == member || member->isInvalid()) {
85+
continue;
86+
}
87+
if (!isa<TypeDecl>(member)) {
88+
if (!swift::TypeChecker::witnessStructureMatches(member, VD)) {
8689
continue;
8790
}
8891
Type memberComparisonTy = member->getInterfaceType();
@@ -151,7 +154,8 @@ class CommentProviderFinder final {
151154
};
152155
} // end anonymous namespace
153156

154-
const Decl *Decl::getDocCommentProvidingDecl() const {
157+
const Decl *DocCommentProvidingDeclRequest::evaluate(Evaluator &evaluator,
158+
const Decl *D) const {
155159
// Search for the first decl we see with a non-empty raw comment.
156160
auto finder = CommentProviderFinder<RawComment>(
157161
[](const Decl *D) -> std::optional<RawComment> {
@@ -161,19 +165,10 @@ const Decl *Decl::getDocCommentProvidingDecl() const {
161165
return comment;
162166
});
163167

164-
auto result = finder.findCommentProvider(this);
168+
auto result = finder.findCommentProvider(D);
165169
return result ? result->second : nullptr;
166170
}
167171

168-
StringRef swift::Decl::getSemanticBriefComment() const {
169-
if (!canHaveComment())
170-
return StringRef();
171-
172-
auto &eval = getASTContext().evaluator;
173-
return evaluateOrDefault(eval, SemanticBriefCommentRequest{this},
174-
StringRef());
175-
}
176-
177172
/// Retrieve the brief comment for a given decl \p D, without attempting to
178173
/// walk any requirements or overrides.
179174
static std::optional<StringRef> getDirectBriefComment(const Decl *D) {

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -499,15 +499,12 @@ checkEffects(AbstractStorageDecl *witness, AbstractStorageDecl *req) {
499499
return std::nullopt; // OK
500500
}
501501

502-
RequirementMatch swift::matchWitness(
503-
DeclContext *dc, ValueDecl *req, ValueDecl *witness,
504-
llvm::function_ref<
505-
std::tuple<std::optional<RequirementMatch>, Type, Type>(void)>
506-
setup,
507-
llvm::function_ref<std::optional<RequirementMatch>(Type, Type)> matchTypes,
508-
llvm::function_ref<RequirementMatch(bool, ArrayRef<OptionalAdjustment>)>
509-
finalize) {
510-
502+
/// Implementation of `matchWitnessStructure` that also sets a few out paramters
503+
/// to be used by `matchWitness`.
504+
static std::optional<RequirementMatch>
505+
matchWitnessStructureImpl(ValueDecl *req, ValueDecl *witness,
506+
bool &decomposeFunctionType, bool &ignoreReturnType,
507+
Type &reqThrownError, Type &witnessThrownError) {
511508
assert(!req->isInvalid() && "Cannot have an invalid requirement here");
512509

513510
/// Make sure the witness is of the same kind as the requirement.
@@ -530,7 +527,7 @@ RequirementMatch swift::matchWitness(
530527
if (witness->isRecursiveValidation()) {
531528
return RequirementMatch(witness, MatchKind::Circularity);
532529
}
533-
530+
534531
// If the witness is invalid, record that and stop now.
535532
if (witness->isInvalid()) {
536533
return RequirementMatch(witness, MatchKind::WitnessInvalid);
@@ -541,10 +538,6 @@ RequirementMatch swift::matchWitness(
541538
const auto &witnessAttrs = witness->getAttrs();
542539

543540
// Perform basic matching of the requirement and witness.
544-
bool decomposeFunctionType = false;
545-
bool ignoreReturnType = false;
546-
Type reqThrownError;
547-
Type witnessThrownError;
548541
if (isa<FuncDecl>(req) && isa<FuncDecl>(witness)) {
549542
auto funcReq = cast<FuncDecl>(req);
550543
auto funcWitness = cast<FuncDecl>(witness);
@@ -617,7 +610,7 @@ RequirementMatch swift::matchWitness(
617610
decomposeFunctionType = true;
618611
} else if (auto *witnessASD = dyn_cast<AbstractStorageDecl>(witness)) {
619612
auto *reqASD = cast<AbstractStorageDecl>(req);
620-
613+
621614
// Check that the static-ness matches.
622615
if (reqASD->isStatic() != witnessASD->isStatic())
623616
return RequirementMatch(witness, MatchKind::StaticNonStaticConflict);
@@ -701,8 +694,42 @@ RequirementMatch swift::matchWitness(
701694
// If the requirement is @objc, the witness must not be marked with @nonobjc.
702695
// @objc-ness will be inferred (separately) and the selector will be checked
703696
// later.
704-
if (req->isObjC() && witness->getAttrs().hasAttribute<NonObjCAttr>())
697+
if (req->isObjC() && witness->getAttrs().hasAttribute<NonObjCAttr>()) {
705698
return RequirementMatch(witness, MatchKind::NonObjC);
699+
}
700+
return std::nullopt;
701+
}
702+
703+
bool swift::TypeChecker::witnessStructureMatches(ValueDecl *req,
704+
const ValueDecl *witness) {
705+
bool decomposeFunctionType = false;
706+
bool ignoreReturnType = false;
707+
Type reqThrownError;
708+
Type witnessThrownError;
709+
return matchWitnessStructureImpl(req, const_cast<ValueDecl *>(witness),
710+
decomposeFunctionType, ignoreReturnType,
711+
reqThrownError,
712+
witnessThrownError) == std::nullopt;
713+
}
714+
715+
RequirementMatch swift::matchWitness(
716+
DeclContext *dc, ValueDecl *req, ValueDecl *witness,
717+
llvm::function_ref<
718+
std::tuple<std::optional<RequirementMatch>, Type, Type>(void)>
719+
setup,
720+
llvm::function_ref<std::optional<RequirementMatch>(Type, Type)> matchTypes,
721+
llvm::function_ref<RequirementMatch(bool, ArrayRef<OptionalAdjustment>)>
722+
finalize) {
723+
bool decomposeFunctionType = false;
724+
bool ignoreReturnType = false;
725+
Type reqThrownError;
726+
Type witnessThrownError;
727+
728+
if (auto StructuralMismatch = matchWitnessStructureImpl(
729+
req, witness, decomposeFunctionType, ignoreReturnType, reqThrownError,
730+
witnessThrownError)) {
731+
return *StructuralMismatch;
732+
}
706733

707734
// Set up the match, determining the requirement and witness types
708735
// in the process.

lib/Sema/TypeChecker.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,13 @@ void diagnoseDuplicateCaptureVars(CaptureListExpr *expr);
487487
Type checkReferenceOwnershipAttr(VarDecl *D, Type interfaceType,
488488
ReferenceOwnershipAttr *attr);
489489

490+
/// Checks if the given witness can structurally match the requirement, ie.
491+
/// whether it has a matching kind like static vs. non-static, matching decl,
492+
/// etc. It does not check if the types of the witness is able to satisfy the
493+
/// requirement.
494+
/// If there is a matching failure, returns a `false`, otherwise return `true`.
495+
bool witnessStructureMatches(ValueDecl *req, const ValueDecl *witness);
496+
490497
/// Infer default value witnesses for all requirements in the given protocol.
491498
void inferDefaultWitnesses(ProtocolDecl *proto);
492499

0 commit comments

Comments
 (0)