@@ -1706,6 +1706,10 @@ namespace {
1706
1706
// / Whether we've already complained about problems with this conformance.
1707
1707
bool AlreadyComplained = false ;
1708
1708
1709
+ // / Keep track of missing witnesses, either type or value, for later
1710
+ // / diagnosis emits.
1711
+ llvm::SetVector<ValueDecl*> MissingWitnesses;
1712
+
1709
1713
// / Retrieve the associated types that are referenced by the given
1710
1714
// / requirement with a base of 'Self'.
1711
1715
ArrayRef<AssociatedTypeDecl *> getReferencedAssociatedTypes (ValueDecl *req);
@@ -1779,6 +1783,8 @@ namespace {
1779
1783
llvm::SmallPtrSetImpl<ProtocolConformance *> &visited);
1780
1784
void addUsedConformances (ProtocolConformance *conformance);
1781
1785
1786
+ // / Call this to diagnose currently known missing witnesses.
1787
+ void diagnoseMissingWitnesses ();
1782
1788
public:
1783
1789
// / Emit any diagnostics that have been delayed.
1784
1790
void emitDelayedDiags ();
@@ -2397,50 +2403,77 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
2397
2403
return true ;
2398
2404
}
2399
2405
2400
-
2401
- // / Generates a note for a protocol requirement for which no witness was found
2402
- // / and provides a fixit to add a stub to the adopter
2403
- static void diagnoseNoWitness (ValueDecl *Requirement, Type RequirementType,
2404
- NormalProtocolConformance *Conformance) {
2405
- // FIXME: Try an ignore-access lookup?
2406
-
2407
- DeclContext *Adopter = Conformance->getDeclContext ();
2408
-
2409
- SourceLoc FixitLocation;
2410
- SourceLoc TypeLoc;
2411
- if (auto Extension = dyn_cast<ExtensionDecl>(Adopter)) {
2412
- FixitLocation = Extension->getBraces ().Start ;
2413
- TypeLoc = Extension->getStartLoc ();
2414
- } else if (auto Nominal = dyn_cast<NominalTypeDecl>(Adopter)) {
2415
- FixitLocation = Nominal->getBraces ().Start ;
2416
- TypeLoc = Nominal->getStartLoc ();
2417
- } else {
2418
- llvm_unreachable (" Unknown adopter kind" );
2419
- }
2420
-
2421
- ASTContext &Ctx = Requirement->getASTContext ();
2422
- auto &Diags = Ctx.Diags ;
2423
- std::string FixitString;
2406
+ // / Print the stubs for an array of witnesses, either type or value, to
2407
+ // / FixitString. If for a witness we cannot have stub printed, insert it to
2408
+ // / NoStubRequirements.
2409
+ static void
2410
+ printProtocolStubFixitString (SourceLoc TypeLoc, ProtocolConformance *Conf,
2411
+ ArrayRef<ValueDecl*> MissingWitnesses,
2412
+ std::string &FixitString,
2413
+ llvm::SetVector<ValueDecl*> &NoStubRequirements) {
2424
2414
llvm::raw_string_ostream FixitStream (FixitString);
2415
+ std::for_each (MissingWitnesses.begin (), MissingWitnesses.end (),
2416
+ [&](ValueDecl* VD) {
2417
+ if (!printRequirementStub (VD, Conf->getDeclContext (), Conf->getType (),
2418
+ TypeLoc, FixitStream)) {
2419
+ NoStubRequirements.insert (VD);
2420
+ }
2421
+ });
2422
+ }
2425
2423
2426
- bool AddFixit = printRequirementStub (Requirement, Adopter,
2427
- Conformance-> getType (), TypeLoc,
2428
- FixitStream) ;
2424
+ void ConformanceChecker::diagnoseMissingWitnesses () {
2425
+ if (MissingWitnesses. empty ())
2426
+ return ;
2429
2427
2430
- if (auto MissingTypeWitness = dyn_cast<AssociatedTypeDecl>(Requirement)) {
2431
- Diags.diagnose (MissingTypeWitness, diag::no_witnesses_type,
2432
- MissingTypeWitness->getName ())
2433
- .fixItInsertAfter (FixitLocation, FixitStream.str ());
2434
- } else {
2435
- // Point out the requirement that wasn't met.
2436
- auto diag = Diags.diagnose (Requirement, diag::no_witnesses,
2437
- getRequirementKind (Requirement),
2438
- Requirement->getFullName (),
2439
- RequirementType, AddFixit);
2440
- if (AddFixit) {
2441
- diag.fixItInsertAfter (FixitLocation, FixitStream.str ());
2442
- }
2443
- }
2428
+ // Make sure we clear the missing witness bucket when exiting.
2429
+ SWIFT_DEFER { MissingWitnesses.clear (); };
2430
+ llvm::SetVector<ValueDecl*> MissingWitnesses = this ->MissingWitnesses ;
2431
+ diagnoseOrDefer (MissingWitnesses[0 ], true ,
2432
+ [MissingWitnesses](NormalProtocolConformance *Conf) {
2433
+ DeclContext *DC = Conf->getDeclContext ();
2434
+ // The location where to insert stubs.
2435
+ SourceLoc FixitLocation;
2436
+
2437
+ // The location where the type starts.
2438
+ SourceLoc TypeLoc;
2439
+ if (auto Extension = dyn_cast<ExtensionDecl>(DC)) {
2440
+ FixitLocation = Extension->getBraces ().Start ;
2441
+ TypeLoc = Extension->getStartLoc ();
2442
+ } else if (auto Nominal = dyn_cast<NominalTypeDecl>(DC)) {
2443
+ FixitLocation = Nominal->getBraces ().Start ;
2444
+ TypeLoc = Nominal->getStartLoc ();
2445
+ } else {
2446
+ llvm_unreachable (" Unknown adopter kind" );
2447
+ }
2448
+ std::string FixIt;
2449
+ llvm::SetVector<ValueDecl*> NoStubRequirements;
2450
+
2451
+ // Print stubs for all known missing witnesses.
2452
+ printProtocolStubFixitString (TypeLoc, Conf,
2453
+ MissingWitnesses.getArrayRef (),
2454
+ FixIt, NoStubRequirements);
2455
+ auto &Diags = DC->getASTContext ().Diags ;
2456
+ for (auto VD : MissingWitnesses) {
2457
+ // Whether this VD has a stub printed.
2458
+ bool AddFixit = !NoStubRequirements.count (VD);
2459
+
2460
+ // Issue diagnostics for witness types.
2461
+ if (auto MissingTypeWitness = dyn_cast<AssociatedTypeDecl>(VD)) {
2462
+ Diags.diagnose (MissingTypeWitness, diag::no_witnesses_type,
2463
+ MissingTypeWitness->getName ()).
2464
+ fixItInsertAfter (FixitLocation, FixIt);
2465
+ continue ;
2466
+ }
2467
+ // Issue diagnostics for witness values.
2468
+ Type RequirementType =
2469
+ getRequirementTypeForDisplay (DC->getParentModule (), Conf, VD);
2470
+ auto Diag = Diags.diagnose (VD, diag::no_witnesses,
2471
+ getRequirementKind (VD), VD->getFullName (),
2472
+ RequirementType, AddFixit);
2473
+ if (AddFixit)
2474
+ Diag.fixItInsertAfter (FixitLocation, FixIt);
2475
+ }
2476
+ });
2444
2477
}
2445
2478
2446
2479
ResolveWitnessResult
@@ -2754,30 +2787,36 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
2754
2787
return ResolveWitnessResult::ExplicitFailed;
2755
2788
}
2756
2789
2790
+
2791
+ if (!numViable) {
2792
+ // Save the missing requirement for later diagnosis.
2793
+ MissingWitnesses.insert (requirement);
2794
+ diagnoseOrDefer (requirement, true ,
2795
+ [requirement, matches](NormalProtocolConformance *conformance) {
2796
+ auto dc = conformance->getDeclContext ();
2797
+ // Diagnose each of the matches.
2798
+ for (const auto &match : matches)
2799
+ diagnoseMatch (dc->getParentModule (), conformance, requirement, match);
2800
+ });
2801
+ return ResolveWitnessResult::ExplicitFailed;
2802
+ }
2803
+
2757
2804
diagnoseOrDefer (requirement, true ,
2758
- [requirement, matches, ignoringNames, numViable ](
2805
+ [requirement, matches, ignoringNames](
2759
2806
NormalProtocolConformance *conformance) {
2760
2807
auto dc = conformance->getDeclContext ();
2761
- auto &diags = dc->getASTContext ().Diags ;
2762
-
2763
2808
// Determine the type that the requirement is expected to have.
2764
2809
Type reqType = getRequirementTypeForDisplay (dc->getParentModule (),
2765
2810
conformance, requirement);
2766
-
2767
- if (numViable > 0 ) {
2768
- auto diagnosticMessage = diag::ambiguous_witnesses;
2769
- if (ignoringNames) {
2770
- diagnosticMessage = diag::ambiguous_witnesses_wrong_name;
2771
- }
2772
- diags.diagnose (requirement, diagnosticMessage,
2773
- getRequirementKind (requirement),
2774
- requirement->getFullName (),
2775
- reqType);
2776
- } else {
2777
- // Generate diagnostics for the missing requirement and a fixit to add
2778
- // it
2779
- diagnoseNoWitness (requirement, reqType, conformance);
2811
+ auto &diags = dc->getASTContext ().Diags ;
2812
+ auto diagnosticMessage = diag::ambiguous_witnesses;
2813
+ if (ignoringNames) {
2814
+ diagnosticMessage = diag::ambiguous_witnesses_wrong_name;
2780
2815
}
2816
+ diags.diagnose (requirement, diagnosticMessage,
2817
+ getRequirementKind (requirement),
2818
+ requirement->getFullName (),
2819
+ reqType);
2781
2820
2782
2821
// Diagnose each of the matches.
2783
2822
for (const auto &match : matches)
@@ -2841,21 +2880,8 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDefault(
2841
2880
recordOptionalWitness (requirement);
2842
2881
return ResolveWitnessResult::Success;
2843
2882
}
2844
-
2845
- diagnoseOrDefer (requirement, true ,
2846
- [requirement](NormalProtocolConformance *conformance) {
2847
- auto dc = conformance->getDeclContext ();
2848
- auto &diags = dc->getASTContext ().Diags ;
2849
- // Determine the type that the requirement is expected to have.
2850
- Type reqType = getRequirementTypeForDisplay (dc->getParentModule (),
2851
- conformance, requirement);
2852
-
2853
- // Point out the requirement that wasn't met.
2854
- diags.diagnose (requirement, diag::no_witnesses,
2855
- getRequirementKind (requirement), requirement->getName (),
2856
- reqType, false );
2857
- });
2858
-
2883
+ // Save the missing requirement for later diagnosis.
2884
+ MissingWitnesses.insert (requirement);
2859
2885
return ResolveWitnessResult::ExplicitFailed;
2860
2886
}
2861
2887
@@ -2949,13 +2975,13 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
2949
2975
2950
2976
return ResolveWitnessResult::ExplicitFailed;
2951
2977
}
2978
+ // Save the missing type witness for later diagnosis.
2979
+ MissingWitnesses.insert (assocType);
2952
2980
2953
2981
// None of the candidates were viable.
2954
2982
diagnoseOrDefer (assocType, true ,
2955
- [assocType, nonViable](NormalProtocolConformance *conformance) {
2956
- auto &diags = assocType->getASTContext ().Diags ;
2957
- diags.diagnose (assocType, diag::no_witnesses_type, assocType->getName ());
2958
-
2983
+ [nonViable](NormalProtocolConformance *conformance) {
2984
+ auto &diags = conformance->getDeclContext ()->getASTContext ().Diags ;
2959
2985
for (auto candidate : nonViable) {
2960
2986
if (candidate.first ->getDeclaredInterfaceType ()->hasError ())
2961
2987
continue ;
@@ -4224,12 +4250,9 @@ void ConformanceChecker::resolveTypeWitnesses() {
4224
4250
return ;
4225
4251
}
4226
4252
4227
- for (auto missingTypeWitness : unresolvedAssocTypes) {
4228
- diagnoseOrDefer (missingTypeWitness, true ,
4229
- [missingTypeWitness](NormalProtocolConformance *conformance) {
4230
- diagnoseNoWitness (missingTypeWitness, Type (), conformance);
4231
- });
4232
- }
4253
+ // Save the missing type witnesses for later diagnosis.
4254
+ MissingWitnesses.insert (unresolvedAssocTypes.begin (),
4255
+ unresolvedAssocTypes.end ());
4233
4256
4234
4257
return ;
4235
4258
}
@@ -4303,6 +4326,8 @@ void ConformanceChecker::resolveTypeWitnesses() {
4303
4326
4304
4327
void ConformanceChecker::resolveSingleTypeWitness (
4305
4328
AssociatedTypeDecl *assocType) {
4329
+ // Ensure we diagnose if the witness is missing.
4330
+ SWIFT_DEFER { diagnoseMissingWitnesses (); };
4306
4331
switch (resolveTypeWitnessViaLookup (assocType)) {
4307
4332
case ResolveWitnessResult::Success:
4308
4333
case ResolveWitnessResult::ExplicitFailed:
@@ -4510,6 +4535,11 @@ void ConformanceChecker::checkConformance() {
4510
4535
// Resolve all of the type witnesses.
4511
4536
resolveTypeWitnesses ();
4512
4537
4538
+ // Diagnose missing type witnesses for now.
4539
+ diagnoseMissingWitnesses ();
4540
+ // Diagnose missing value witnesses later.
4541
+ SWIFT_DEFER { diagnoseMissingWitnesses (); };
4542
+
4513
4543
// Resolution attempts to have the witnesses be correct by construction, but
4514
4544
// this isn't guaranteed, so let's double check.
4515
4545
ensureRequirementsAreSatisfied ();
0 commit comments