@@ -192,6 +192,28 @@ template <> struct DenseMapInfo<OverrideSignatureKey> {
192192};
193193} // namespace llvm
194194
195+ namespace {
196+
197+ // / If the conformance is in a primary file, we might diagnose some failures
198+ // / early via request evaluation, with all remaining failures diagnosed when
199+ // / we completely force the conformance from typeCheckDecl(). To emit the
200+ // / diagnostics together, we batch them up in the Diags vector.
201+ // /
202+ // / If the conformance is in a secondary file, we instead just diagnose a
203+ // / generic "T does not conform to P" error the first time we hit an error
204+ // / via request evaluation. The detailed delayed conformance diagnostics
205+ // / are discarded, since we'll emit them again when we compile the file as
206+ // / a primary file.
207+ struct DelayedConformanceDiags {
208+ // / We set this if we've ever seen an error diagnostic here.
209+ bool HadError = false ;
210+
211+ // / The delayed conformance diagnostics that have not been emitted yet.
212+ // / Never actually emitted for a secondary file.
213+ std::vector<ASTContext::DelayedConformanceDiag> Diags;
214+ };
215+
216+ }
195217struct ASTContext ::Implementation {
196218 Implementation ();
197219 ~Implementation ();
@@ -354,8 +376,7 @@ struct ASTContext::Implementation {
354376
355377 // / Map from normal protocol conformances to diagnostics that have
356378 // / been delayed until the conformance is fully checked.
357- llvm::DenseMap<NormalProtocolConformance *,
358- std::vector<ASTContext::DelayedConformanceDiag>>
379+ llvm::DenseMap<NormalProtocolConformance *, ::DelayedConformanceDiags>
359380 DelayedConformanceDiags;
360381
361382 // / Map from normal protocol conformances to missing witnesses that have
@@ -2733,25 +2754,18 @@ LazyIterableDeclContextData *ASTContext::getOrCreateLazyIterableContextData(
27332754bool ASTContext::hasDelayedConformanceErrors (
27342755 NormalProtocolConformance const * conformance) const {
27352756
2736- auto hasDelayedErrors = [](std::vector<DelayedConformanceDiag> const & diags) {
2737- return std::any_of (diags.begin (), diags.end (),
2738- [](ASTContext::DelayedConformanceDiag const & diag) {
2739- return diag.IsError ;
2740- });
2741- };
2742-
27432757 if (conformance) {
27442758 auto entry = getImpl ().DelayedConformanceDiags .find (conformance);
27452759 if (entry != getImpl ().DelayedConformanceDiags .end ())
2746- return hasDelayedErrors ( entry->second ) ;
2760+ return entry->second . HadError ;
27472761
27482762 return false ; // unknown conformance, so no delayed diags either.
27492763 }
27502764
27512765 // check all conformances for any delayed errors
27522766 for (const auto &entry : getImpl ().DelayedConformanceDiags ) {
27532767 auto const & diagnostics = entry.getSecond ();
2754- if (hasDelayedErrors ( diagnostics) )
2768+ if (diagnostics. HadError )
27552769 return true ;
27562770 }
27572771
@@ -2763,7 +2777,44 @@ MissingWitnessesBase::~MissingWitnessesBase() { }
27632777void ASTContext::addDelayedConformanceDiag (
27642778 NormalProtocolConformance *conformance,
27652779 DelayedConformanceDiag fn) {
2766- getImpl ().DelayedConformanceDiags [conformance].push_back (std::move (fn));
2780+ auto &diagnostics = getImpl ().DelayedConformanceDiags [conformance];
2781+
2782+ if (fn.IsError && !diagnostics.HadError ) {
2783+ diagnostics.HadError = true ;
2784+
2785+ auto *proto = conformance->getProtocol ();
2786+ auto *dc = conformance->getDeclContext ();
2787+ auto *sf = dc->getParentSourceFile ();
2788+ auto *mod = sf->getParentModule ();
2789+ assert (mod->isMainModule ());
2790+
2791+ // If we have at least one primary file and the conformance is declared in a
2792+ // non-primary file, emit a fallback diagnostic.
2793+ if ((!sf->isPrimary () && !mod->getPrimarySourceFiles ().empty ()) ||
2794+ TypeCheckerOpts.EnableLazyTypecheck ) {
2795+ auto complainLoc = evaluator.getInnermostSourceLoc ([&](SourceLoc loc) {
2796+ if (loc.isInvalid ())
2797+ return false ;
2798+
2799+ auto *otherSF = mod->getSourceFileContainingLocation (loc);
2800+ if (otherSF == nullptr )
2801+ return false ;
2802+
2803+ return otherSF->isPrimary ();
2804+ });
2805+
2806+ if (complainLoc.isInvalid ()) {
2807+ complainLoc = conformance->getLoc ();
2808+ }
2809+
2810+ Diags.diagnose (complainLoc,
2811+ diag::type_does_not_conform,
2812+ dc->getSelfInterfaceType (),
2813+ proto->getDeclaredInterfaceType ());
2814+ }
2815+ }
2816+
2817+ diagnostics.Diags .push_back (std::move (fn));
27672818}
27682819
27692820void ASTContext::addDelayedMissingWitnesses (
@@ -2789,8 +2840,7 @@ ASTContext::takeDelayedConformanceDiags(NormalProtocolConformance const* cnfrm){
27892840 std::vector<ASTContext::DelayedConformanceDiag> result;
27902841 auto known = getImpl ().DelayedConformanceDiags .find (cnfrm);
27912842 if (known != getImpl ().DelayedConformanceDiags .end ()) {
2792- result = std::move (known->second );
2793- getImpl ().DelayedConformanceDiags .erase (known);
2843+ std::swap (result, known->second .Diags );
27942844 }
27952845 return result;
27962846}
0 commit comments