@@ -2418,10 +2418,17 @@ TypeEraserHasViableInitRequest::evaluate(Evaluator &evaluator,
2418
2418
// 3. The type eraser must have an init of the form init<T: Protocol>(erasing: T)
2419
2419
auto lookupResult = TypeChecker::lookupMember (dc, typeEraser,
2420
2420
DeclNameRef::createConstructor ());
2421
+
2422
+ // Keep track of unviable init candidates for diagnostics
2423
+ enum class UnviableReason {
2424
+ Failable,
2425
+ UnsatisfiedRequirements,
2426
+ };
2427
+ SmallVector<std::pair<ConstructorDecl *, UnviableReason>, 2 > unviable;
2428
+
2421
2429
bool foundMatch = llvm::any_of (lookupResult, [&](const LookupResultEntry &entry) {
2422
2430
auto *init = cast<ConstructorDecl>(entry.getValueDecl ());
2423
- if (init->isFailable () || !init->isGeneric () ||
2424
- init->getGenericParams ()->size () != 1 )
2431
+ if (!init->isGeneric () || init->getGenericParams ()->size () != 1 )
2425
2432
return false ;
2426
2433
2427
2434
auto genericSignature = init->getGenericSignature ();
@@ -2455,31 +2462,49 @@ TypeEraserHasViableInitRequest::evaluate(Evaluator &evaluator,
2455
2462
return getSubstitution (type);
2456
2463
}, TypeChecker::LookUpConformance (dc));
2457
2464
2458
- // Listener to suppress diagnostics while checking if the generic
2459
- // requirements are satisfied.
2460
- class Listener : public GenericRequirementsCheckListener {
2461
- bool diagnoseUnsatisfiedRequirement (
2462
- const Requirement &req, Type first, Type second,
2463
- ArrayRef<ParentConditionalConformance> parents) override {
2464
- return true ;
2465
- }
2466
- } listener;
2467
-
2468
- auto loc = attr->getLocation ();
2465
+ // Use invalid 'SourceLoc's to suppress diagnostics.
2469
2466
auto result = TypeChecker::checkGenericArguments (
2470
- protocol, loc, loc , typeEraser,
2467
+ protocol, SourceLoc (), SourceLoc () , typeEraser,
2471
2468
genericSignature->getGenericParams (),
2472
2469
genericSignature->getRequirements (),
2473
2470
QuerySubstitutionMap{subMap},
2474
2471
TypeChecker::LookUpConformance (dc),
2475
- None, &listener);
2476
- return result == RequirementCheckResult::Success;
2472
+ None);
2473
+
2474
+ if (result != RequirementCheckResult::Success) {
2475
+ unviable.push_back ({init, UnviableReason::UnsatisfiedRequirements});
2476
+ return false ;
2477
+ }
2478
+
2479
+ if (init->isFailable ()) {
2480
+ unviable.push_back ({init, UnviableReason::Failable});
2481
+ return false ;
2482
+ }
2483
+
2484
+ return true ;
2477
2485
});
2478
2486
2479
2487
if (!foundMatch) {
2480
2488
diags.diagnose (attr->getLocation (), diag::type_eraser_missing_init,
2481
2489
typeEraser, protocolType);
2482
- diags.diagnose (nominalTypeDecl->getLoc (), diag::type_eraser_declared_here);
2490
+ if (unviable.empty ())
2491
+ diags.diagnose (nominalTypeDecl->getLoc (),
2492
+ diag::type_eraser_declared_here);
2493
+
2494
+ for (auto &candidate: unviable) {
2495
+ auto init = candidate.first ;
2496
+ auto reason = candidate.second ;
2497
+
2498
+ switch (reason) {
2499
+ case UnviableReason::Failable:
2500
+ diags.diagnose (init->getLoc (), diag::type_eraser_failable_init);
2501
+ break ;
2502
+ case UnviableReason::UnsatisfiedRequirements:
2503
+ diags.diagnose (init->getLoc (),
2504
+ diag::type_eraser_init_unsatisfied_requirements);
2505
+ break ;
2506
+ }
2507
+ }
2483
2508
return false ;
2484
2509
}
2485
2510
0 commit comments