Skip to content

Commit d2751bf

Browse files
committed
TypeChecker: Introduce an alternative 'checkGenericArguments' for out-of-place diagnostics
1 parent 0b3ac2b commit d2751bf

File tree

2 files changed

+132
-1
lines changed

2 files changed

+132
-1
lines changed

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,76 @@ RequirementCheckResult TypeChecker::checkGenericArguments(
930930
return RequirementCheckResult::SubstitutionFailure;
931931
}
932932

933+
CheckGenericArgumentsResult TypeChecker::checkGenericArgumentsForDiagnostics(
934+
ModuleDecl *module, ArrayRef<Requirement> requirements,
935+
TypeSubstitutionFn substitutions) {
936+
using ParentConditionalConformances =
937+
SmallVector<ParentConditionalConformance, 2>;
938+
939+
struct WorklistItem {
940+
/// The set of requirements to check. These are either the primary set
941+
/// of requirements, or the conditional requirements of the last conformance
942+
/// in \c ReqsPath (if any).
943+
ArrayRef<Requirement> Requirements;
944+
945+
/// The chain of conditional conformances that leads to the above
946+
/// requirement set.
947+
ParentConditionalConformances ReqsPath;
948+
949+
WorklistItem(ArrayRef<Requirement> Requirements,
950+
ParentConditionalConformances ReqsPath)
951+
: Requirements(Requirements), ReqsPath(ReqsPath) {}
952+
};
953+
954+
bool hadSubstFailure = false;
955+
SmallVector<WorklistItem, 4> worklist;
956+
957+
worklist.emplace_back(requirements, ParentConditionalConformances{});
958+
while (!worklist.empty()) {
959+
const auto item = worklist.pop_back_val();
960+
961+
const bool isPrimaryReq = item.ReqsPath.empty();
962+
for (const auto &req : item.Requirements) {
963+
Requirement substReq = req;
964+
if (isPrimaryReq) {
965+
// Primary requirements do not have substitutions applied.
966+
if (auto resolved =
967+
req.subst(substitutions, LookUpConformanceInModule(module))) {
968+
substReq = *resolved;
969+
} else {
970+
// Another requirement might fail later; just continue.
971+
hadSubstFailure = true;
972+
continue;
973+
}
974+
}
975+
976+
ArrayRef<Requirement> conditionalRequirements;
977+
if (!substReq.isSatisfied(conditionalRequirements,
978+
/*allowMissing=*/true)) {
979+
return CheckGenericArgumentsResult::createRequirementFailure(
980+
req, substReq, std::move(item.ReqsPath));
981+
}
982+
983+
if (conditionalRequirements.empty()) {
984+
continue;
985+
}
986+
987+
assert(req.getKind() == RequirementKind::Conformance);
988+
989+
auto reqsPath = item.ReqsPath;
990+
reqsPath.push_back({substReq.getFirstType(), substReq.getProtocolDecl()});
991+
992+
worklist.emplace_back(conditionalRequirements, std::move(reqsPath));
993+
}
994+
}
995+
996+
if (hadSubstFailure) {
997+
return CheckGenericArgumentsResult::createSubstitutionFailure();
998+
}
999+
1000+
return CheckGenericArgumentsResult::createSuccess();
1001+
}
1002+
9331003
RequirementCheckResult
9341004
TypeChecker::checkGenericArguments(ModuleDecl *module,
9351005
ArrayRef<Requirement> requirements,

lib/Sema/TypeChecker.h

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,56 @@ enum class RequirementCheckResult {
214214
Success, Failure, SubstitutionFailure
215215
};
216216

217+
class CheckGenericArgumentsResult {
218+
public:
219+
enum Kind { Success, RequirementFailure, SubstitutionFailure };
220+
221+
struct RequirementFailureInfo {
222+
/// The failed requirement.
223+
Requirement Req;
224+
225+
/// The failed requirement with substitutions applied.
226+
Requirement SubstReq;
227+
228+
/// The chain of conditional conformances that leads to the failed
229+
/// requirement \c Req. Accordingly, \c Req is a conditional requirement of
230+
/// the last conformance in the chain (if any).
231+
SmallVector<ParentConditionalConformance, 2> ReqPath;
232+
};
233+
234+
private:
235+
Kind Knd;
236+
Optional<RequirementFailureInfo> ReqFailureInfo;
237+
238+
CheckGenericArgumentsResult(Kind Knd,
239+
Optional<RequirementFailureInfo> ReqFailureInfo)
240+
: Knd(Knd), ReqFailureInfo(ReqFailureInfo) {}
241+
242+
public:
243+
static CheckGenericArgumentsResult createSuccess() {
244+
return CheckGenericArgumentsResult(Success, None);
245+
}
246+
247+
static CheckGenericArgumentsResult createSubstitutionFailure() {
248+
return CheckGenericArgumentsResult(SubstitutionFailure, None);
249+
}
250+
251+
static CheckGenericArgumentsResult createRequirementFailure(
252+
Requirement Req, Requirement SubstReq,
253+
SmallVector<ParentConditionalConformance, 2> ReqPath) {
254+
return CheckGenericArgumentsResult(
255+
RequirementFailure, RequirementFailureInfo{Req, SubstReq, ReqPath});
256+
}
257+
258+
const RequirementFailureInfo &getRequirementFailureInfo() const {
259+
assert(Knd == RequirementFailure);
260+
261+
return ReqFailureInfo.getValue();
262+
}
263+
264+
operator Kind() const { return Knd; }
265+
};
266+
217267
/// Describes the kind of checked cast operation being performed.
218268
enum class CheckedCastContextKind {
219269
/// None: we're just establishing how to perform the checked cast. This
@@ -480,7 +530,18 @@ RequirementCheckResult checkGenericArguments(
480530
ArrayRef<Requirement> requirements, TypeSubstitutionFn substitutions,
481531
SubstOptions options = None);
482532

483-
/// A lower-level version of the above without diagnostic emission.
533+
/// Check the given generic parameter substitutions against the given
534+
/// requirements and report on any requirement failures in detail for
535+
/// diagnostic needs.
536+
CheckGenericArgumentsResult
537+
checkGenericArgumentsForDiagnostics(ModuleDecl *module,
538+
ArrayRef<Requirement> requirements,
539+
TypeSubstitutionFn substitutions);
540+
541+
/// Check the given generic parameter substitutions against the given
542+
/// requirements. Unlike \c checkAndDiagnoseGenericArguments, this version
543+
/// reports just the result of the check and doesn't provide additional
544+
/// information on requirement failures that is warranted for diagnostics.
484545
RequirementCheckResult checkGenericArguments(
485546
ModuleDecl *module,
486547
ArrayRef<Requirement> requirements,

0 commit comments

Comments
 (0)