@@ -1173,23 +1173,6 @@ bool WitnessChecker::findBestWitness(
1173
1173
}
1174
1174
1175
1175
if (numViable == 0 ) {
1176
- // Assume any missing value witnesses for a conformance in a parseable
1177
- // interface can be treated as opaque.
1178
- // FIXME: ...but we should do something better about types.
1179
- if (conformance && !conformance->isInvalid ()) {
1180
- if (auto *SF = DC->getParentSourceFile ()) {
1181
- if (SF->Kind == SourceFileKind::Interface) {
1182
- auto match = matchWitness (TC, ReqEnvironmentCache, Proto,
1183
- conformance, DC, requirement, requirement);
1184
- assert (match.isViable ());
1185
- numViable = 1 ;
1186
- bestIdx = matches.size ();
1187
- matches.push_back (std::move (match));
1188
- return true ;
1189
- }
1190
- }
1191
- }
1192
-
1193
1176
if (anyFromUnconstrainedExtension &&
1194
1177
conformance != nullptr &&
1195
1178
conformance->isInvalid ()) {
@@ -2914,6 +2897,23 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
2914
2897
}
2915
2898
}
2916
2899
2900
+ ResolveWitnessResult
2901
+ ConformanceChecker::resolveWitnessAsOpaque (ValueDecl *requirement) {
2902
+ assert (!isa<AssociatedTypeDecl>(requirement) && " Use resolveTypeWitnessVia*" );
2903
+ auto match = matchWitness (TC, ReqEnvironmentCache, Proto,
2904
+ Conformance, DC, requirement, requirement);
2905
+ recordWitness (requirement, match);
2906
+ return ResolveWitnessResult::Success;
2907
+ }
2908
+
2909
+ static bool isConformanceFromParseableInterface (
2910
+ const NormalProtocolConformance *conformance) {
2911
+ auto *containingSF = conformance->getDeclContext ()->getParentSourceFile ();
2912
+ if (!containingSF)
2913
+ return false ;
2914
+ return containingSF->Kind == SourceFileKind::Interface;
2915
+ }
2916
+
2917
2917
ResolveWitnessResult
2918
2918
ConformanceChecker::resolveWitnessViaLookup (ValueDecl *requirement) {
2919
2919
assert (!isa<AssociatedTypeDecl>(requirement) && " Use resolveTypeWitnessVia*" );
@@ -2931,25 +2931,33 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
2931
2931
}
2932
2932
}
2933
2933
2934
- // Determine whether we can derive a witness for this requirement.
2935
- bool canDerive = false ;
2936
-
2937
- // Can a witness for this requirement be derived for this nominal type?
2938
- if (auto derivable = DerivedConformance::getDerivableRequirement (
2939
- TC,
2940
- nominal,
2941
- requirement)) {
2942
- if (derivable == requirement) {
2943
- // If it's the same requirement, we can derive it here.
2944
- canDerive = true ;
2945
- } else {
2946
- // Otherwise, go satisfy the derivable requirement, which can introduce
2947
- // a member that could in turn satisfy *this* requirement.
2948
- auto derivableProto = cast<ProtocolDecl>(derivable->getDeclContext ());
2949
- if (auto conformance =
2950
- TC.conformsToProtocol (Adoptee, derivableProto, DC, None)) {
2951
- if (conformance->isConcrete ())
2952
- (void )conformance->getConcrete ()->getWitnessDecl (derivable, &TC);
2934
+ // Determine whether we can get a witness for this requirement some other way.
2935
+ bool hasFallbacks = false ;
2936
+ if (!hasFallbacks)
2937
+ hasFallbacks = requirement->getAttrs ().hasAttribute <OptionalAttr>();
2938
+ if (!hasFallbacks)
2939
+ hasFallbacks = requirement->getAttrs ().isUnavailable (TC.Context );
2940
+ if (!hasFallbacks)
2941
+ hasFallbacks = isConformanceFromParseableInterface (Conformance);
2942
+
2943
+ if (!hasFallbacks) {
2944
+ // Can a witness for this requirement be derived for this nominal type?
2945
+ if (auto derivable = DerivedConformance::getDerivableRequirement (
2946
+ TC,
2947
+ nominal,
2948
+ requirement)) {
2949
+ if (derivable == requirement) {
2950
+ // If it's the same requirement, we can derive it here.
2951
+ hasFallbacks = true ;
2952
+ } else {
2953
+ // Otherwise, go satisfy the derivable requirement, which can introduce
2954
+ // a member that could in turn satisfy *this* requirement.
2955
+ auto derivableProto = cast<ProtocolDecl>(derivable->getDeclContext ());
2956
+ if (auto conformance =
2957
+ TC.conformsToProtocol (Adoptee, derivableProto, DC, None)) {
2958
+ if (conformance->isConcrete ())
2959
+ (void )conformance->getConcrete ()->getWitnessDecl (derivable, &TC);
2960
+ }
2953
2961
}
2954
2962
}
2955
2963
}
@@ -2960,11 +2968,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
2960
2968
unsigned bestIdx = 0 ;
2961
2969
bool doNotDiagnoseMatches = false ;
2962
2970
bool ignoringNames = false ;
2963
- bool considerRenames =
2964
- !canDerive && !requirement->getAttrs ().hasAttribute <OptionalAttr>() &&
2965
- !requirement->getAttrs ().isUnavailable (TC.Context );
2966
- if (findBestWitness (requirement,
2967
- considerRenames ? &ignoringNames : nullptr ,
2971
+ if (findBestWitness (requirement, hasFallbacks ? nullptr : &ignoringNames,
2968
2972
Conformance,
2969
2973
/* out parameters: */
2970
2974
matches, numViable, bestIdx, doNotDiagnoseMatches)) {
@@ -3182,19 +3186,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
3182
3186
// We have either no matches or an ambiguous match.
3183
3187
3184
3188
// If we can derive a definition for this requirement, just call it missing.
3185
- if (canDerive) {
3186
- return ResolveWitnessResult::Missing;
3187
- }
3188
-
3189
- // If the requirement is optional, it's okay. We'll satisfy this via
3190
- // our handling of default definitions.
3191
- //
3192
- // FIXME: revisit this once we get default definitions in protocol bodies.
3193
- //
3194
- // Treat 'unavailable' implicitly as if it were 'optional'.
3195
- // The compiler will reject actual uses.
3196
- auto Attrs = requirement->getAttrs ();
3197
- if (Attrs.hasAttribute <OptionalAttr>() || Attrs.isUnavailable (TC.Context )) {
3189
+ if (hasFallbacks) {
3198
3190
return ResolveWitnessResult::Missing;
3199
3191
}
3200
3192
@@ -3355,6 +3347,47 @@ CheckTypeWitnessResult swift::checkTypeWitness(TypeChecker &tc, DeclContext *dc,
3355
3347
return CheckTypeWitnessResult ();
3356
3348
}
3357
3349
3350
+ ResolveWitnessResult
3351
+ ConformanceChecker::resolveWitnessTryingAllStrategies (ValueDecl *requirement) {
3352
+ using ResolveWitnessStrategy =
3353
+ decltype (&ConformanceChecker::resolveWitnessViaLookup);
3354
+ static const constexpr ResolveWitnessStrategy defaultStrategies[] = {
3355
+ &ConformanceChecker::resolveWitnessViaLookup,
3356
+ &ConformanceChecker::resolveWitnessViaDerivation,
3357
+ &ConformanceChecker::resolveWitnessViaDefault};
3358
+ ArrayRef<ResolveWitnessStrategy> strategies = defaultStrategies;
3359
+
3360
+ // Don't try any sort of derivation when processing a parseable interface.
3361
+ if (isConformanceFromParseableInterface (Conformance)) {
3362
+ if (Conformance->isResilient ()) {
3363
+ // Resilient conformances don't allow any sort of devirtualization, so
3364
+ // don't bother looking up witnesses at all.
3365
+ static const constexpr ResolveWitnessStrategy resilientStrategies[] = {
3366
+ &ConformanceChecker::resolveWitnessAsOpaque};
3367
+ strategies = resilientStrategies;
3368
+ } else {
3369
+ static const constexpr ResolveWitnessStrategy interfaceStrategies[] = {
3370
+ &ConformanceChecker::resolveWitnessViaLookup,
3371
+ &ConformanceChecker::resolveWitnessAsOpaque};
3372
+ strategies = interfaceStrategies;
3373
+ }
3374
+ }
3375
+
3376
+ for (auto strategy : strategies) {
3377
+ ResolveWitnessResult result = (this ->*strategy)(requirement);
3378
+ switch (result) {
3379
+ case ResolveWitnessResult::Success:
3380
+ case ResolveWitnessResult::ExplicitFailed:
3381
+ return result;
3382
+ case ResolveWitnessResult::Missing:
3383
+ // Continue trying.
3384
+ break ;
3385
+ }
3386
+ }
3387
+
3388
+ return ResolveWitnessResult::Missing;
3389
+ }
3390
+
3358
3391
// / Attempt to resolve a type witness via member name lookup.
3359
3392
ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup (
3360
3393
AssociatedTypeDecl *assocType) {
@@ -3625,60 +3658,14 @@ void ConformanceChecker::ensureRequirementsAreSatisfied(
3625
3658
}
3626
3659
3627
3660
#pragma mark Protocol conformance checking
3628
- void ConformanceChecker::checkConformance (MissingWitnessDiagnosisKind Kind) {
3629
- assert (!Conformance->isComplete () && " Conformance is already complete" );
3630
-
3631
- FrontendStatsTracer statsTracer (TC.Context .Stats , " check-conformance" ,
3632
- Conformance);
3633
3661
3634
- llvm::SaveAndRestore<bool > restoreSuppressDiagnostics (SuppressDiagnostics);
3635
- SuppressDiagnostics = false ;
3636
-
3637
- // FIXME: Caller checks that this type conforms to all of the
3638
- // inherited protocols.
3639
-
3640
- // Emit known diags for this conformance.
3641
- emitDelayedDiags ();
3642
-
3643
- // If delayed diags have already complained, return.
3644
- if (AlreadyComplained) {
3645
- Conformance->setInvalid ();
3646
- return ;
3647
- }
3648
-
3649
- // Resolve all of the type witnesses.
3650
- resolveTypeWitnesses ();
3651
-
3652
- // Diagnose missing type witnesses for now.
3653
- diagnoseMissingWitnesses (Kind);
3654
-
3655
- // Ensure the conforming type is used.
3656
- //
3657
- // FIXME: This feels like the wrong place for this, but if we don't put
3658
- // it here, extensions don't end up depending on the extended type.
3659
- recordConformanceDependency (DC, Adoptee->getAnyNominal (), Conformance, false );
3660
-
3661
- // If we complain about any associated types, there is no point in continuing.
3662
- // FIXME: Not really true. We could check witnesses that don't involve the
3663
- // failed associated types.
3664
- if (AlreadyComplained) {
3665
- Conformance->setInvalid ();
3666
- return ;
3667
- }
3668
-
3669
- // Diagnose missing value witnesses later.
3670
- SWIFT_DEFER { diagnoseMissingWitnesses (Kind); };
3671
-
3672
- // Ensure the associated type conformances are used.
3673
- addUsedConformances (Conformance);
3674
-
3675
- // Check non-type requirements.
3662
+ void ConformanceChecker::resolveValueWitnesses () {
3676
3663
for (auto member : Proto->getMembers ()) {
3677
3664
auto requirement = dyn_cast<ValueDecl>(member);
3678
3665
if (!requirement)
3679
3666
continue ;
3680
3667
3681
- // Associated type requirements handled above .
3668
+ // Associated type requirements handled elsewhere .
3682
3669
if (isa<TypeDecl>(requirement))
3683
3670
continue ;
3684
3671
@@ -3829,9 +3816,9 @@ void ConformanceChecker::checkConformance(MissingWitnessDiagnosisKind Kind) {
3829
3816
// If this is an accessor for a storage decl, ignore it.
3830
3817
if (isa<AccessorDecl>(requirement))
3831
3818
continue ;
3832
-
3833
- // Try to resolve the witness via explicit definitions .
3834
- switch (resolveWitnessViaLookup (requirement)) {
3819
+
3820
+ // Try to resolve the witness.
3821
+ switch (resolveWitnessTryingAllStrategies (requirement)) {
3835
3822
case ResolveWitnessResult::Success:
3836
3823
finalizeWitness ();
3837
3824
continue ;
@@ -3841,41 +3828,62 @@ void ConformanceChecker::checkConformance(MissingWitnessDiagnosisKind Kind) {
3841
3828
continue ;
3842
3829
3843
3830
case ResolveWitnessResult::Missing:
3844
- // Continue trying below .
3831
+ // Let it get diagnosed later .
3845
3832
break ;
3846
3833
}
3834
+ }
3835
+ }
3847
3836
3848
- // Try to resolve the witness via derivation.
3849
- switch (resolveWitnessViaDerivation (requirement)) {
3850
- case ResolveWitnessResult::Success:
3851
- finalizeWitness ();
3852
- continue ;
3837
+ void ConformanceChecker::checkConformance (MissingWitnessDiagnosisKind Kind) {
3838
+ assert (!Conformance->isComplete () && " Conformance is already complete" );
3853
3839
3854
- case ResolveWitnessResult::ExplicitFailed:
3855
- Conformance->setInvalid ();
3856
- continue ;
3840
+ FrontendStatsTracer statsTracer (TC.Context .Stats , " check-conformance" ,
3841
+ Conformance);
3857
3842
3858
- case ResolveWitnessResult::Missing:
3859
- // Continue trying below.
3860
- break ;
3861
- }
3843
+ llvm::SaveAndRestore<bool > restoreSuppressDiagnostics (SuppressDiagnostics);
3844
+ SuppressDiagnostics = false ;
3862
3845
3863
- // Try to resolve the witness via defaults.
3864
- switch (resolveWitnessViaDefault (requirement)) {
3865
- case ResolveWitnessResult::Success:
3866
- finalizeWitness ();
3867
- continue ;
3846
+ // FIXME: Caller checks that this type conforms to all of the
3847
+ // inherited protocols.
3868
3848
3869
- case ResolveWitnessResult::ExplicitFailed:
3870
- Conformance->setInvalid ();
3871
- continue ;
3849
+ // Emit known diags for this conformance.
3850
+ emitDelayedDiags ();
3872
3851
3873
- case ResolveWitnessResult::Missing:
3874
- // Continue trying below.
3875
- break ;
3876
- }
3852
+ // If delayed diags have already complained, return.
3853
+ if (AlreadyComplained) {
3854
+ Conformance-> setInvalid () ;
3855
+ return ;
3877
3856
}
3878
3857
3858
+ // Resolve all of the type witnesses.
3859
+ resolveTypeWitnesses ();
3860
+
3861
+ // Diagnose missing type witnesses for now.
3862
+ diagnoseMissingWitnesses (Kind);
3863
+
3864
+ // Ensure the conforming type is used.
3865
+ //
3866
+ // FIXME: This feels like the wrong place for this, but if we don't put
3867
+ // it here, extensions don't end up depending on the extended type.
3868
+ recordConformanceDependency (DC, Adoptee->getAnyNominal (), Conformance, false );
3869
+
3870
+ // If we complain about any associated types, there is no point in continuing.
3871
+ // FIXME: Not really true. We could check witnesses that don't involve the
3872
+ // failed associated types.
3873
+ if (AlreadyComplained) {
3874
+ Conformance->setInvalid ();
3875
+ return ;
3876
+ }
3877
+
3878
+ // Diagnose missing value witnesses later.
3879
+ SWIFT_DEFER { diagnoseMissingWitnesses (Kind); };
3880
+
3881
+ // Ensure the associated type conformances are used.
3882
+ addUsedConformances (Conformance);
3883
+
3884
+ // Check non-type requirements.
3885
+ resolveValueWitnesses ();
3886
+
3879
3887
emitDelayedDiags ();
3880
3888
3881
3889
// Except in specific hardcoded cases for Foundation/Swift
0 commit comments