@@ -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
@@ -3357,10 +3349,29 @@ CheckTypeWitnessResult swift::checkTypeWitness(TypeChecker &tc, DeclContext *dc,
3357
3349
3358
3350
ResolveWitnessResult
3359
3351
ConformanceChecker::resolveWitnessTryingAllStrategies (ValueDecl *requirement) {
3360
- decltype (&ConformanceChecker::resolveWitnessViaLookup) strategies[] = {
3352
+ using ResolveWitnessStrategy =
3353
+ decltype (&ConformanceChecker::resolveWitnessViaLookup);
3354
+ static const constexpr ResolveWitnessStrategy defaultStrategies[] = {
3361
3355
&ConformanceChecker::resolveWitnessViaLookup,
3362
3356
&ConformanceChecker::resolveWitnessViaDerivation,
3363
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
+ }
3364
3375
3365
3376
for (auto strategy : strategies) {
3366
3377
ResolveWitnessResult result = (this ->*strategy)(requirement);
0 commit comments