@@ -1173,6 +1173,23 @@ 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
+
1176
1193
if (anyFromUnconstrainedExtension &&
1177
1194
conformance != nullptr &&
1178
1195
conformance->isInvalid ()) {
@@ -2899,23 +2916,6 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
2899
2916
}
2900
2917
}
2901
2918
2902
- ResolveWitnessResult
2903
- ConformanceChecker::resolveWitnessAsOpaque (ValueDecl *requirement) {
2904
- assert (!isa<AssociatedTypeDecl>(requirement) && " Use resolveTypeWitnessVia*" );
2905
- auto match = matchWitness (TC, ReqEnvironmentCache, Proto,
2906
- Conformance, DC, requirement, requirement);
2907
- recordWitness (requirement, match);
2908
- return ResolveWitnessResult::Success;
2909
- }
2910
-
2911
- static bool isConformanceFromParseableInterface (
2912
- const NormalProtocolConformance *conformance) {
2913
- auto *containingSF = conformance->getDeclContext ()->getParentSourceFile ();
2914
- if (!containingSF)
2915
- return false ;
2916
- return containingSF->Kind == SourceFileKind::Interface;
2917
- }
2918
-
2919
2919
ResolveWitnessResult
2920
2920
ConformanceChecker::resolveWitnessViaLookup (ValueDecl *requirement) {
2921
2921
assert (!isa<AssociatedTypeDecl>(requirement) && " Use resolveTypeWitnessVia*" );
@@ -2933,33 +2933,25 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
2933
2933
}
2934
2934
}
2935
2935
2936
- // Determine whether we can get a witness for this requirement some other way.
2937
- bool hasFallbacks = false ;
2938
- if (!hasFallbacks)
2939
- hasFallbacks = requirement->getAttrs ().hasAttribute <OptionalAttr>();
2940
- if (!hasFallbacks)
2941
- hasFallbacks = requirement->getAttrs ().isUnavailable (TC.Context );
2942
- if (!hasFallbacks)
2943
- hasFallbacks = isConformanceFromParseableInterface (Conformance);
2944
-
2945
- if (!hasFallbacks) {
2946
- // Can a witness for this requirement be derived for this nominal type?
2947
- if (auto derivable = DerivedConformance::getDerivableRequirement (
2948
- TC,
2949
- nominal,
2950
- requirement)) {
2951
- if (derivable == requirement) {
2952
- // If it's the same requirement, we can derive it here.
2953
- hasFallbacks = true ;
2954
- } else {
2955
- // Otherwise, go satisfy the derivable requirement, which can introduce
2956
- // a member that could in turn satisfy *this* requirement.
2957
- auto derivableProto = cast<ProtocolDecl>(derivable->getDeclContext ());
2958
- if (auto conformance =
2959
- TC.conformsToProtocol (Adoptee, derivableProto, DC, None)) {
2960
- if (conformance->isConcrete ())
2961
- (void )conformance->getConcrete ()->getWitnessDecl (derivable, &TC);
2962
- }
2936
+ // Determine whether we can derive a witness for this requirement.
2937
+ bool canDerive = false ;
2938
+
2939
+ // Can a witness for this requirement be derived for this nominal type?
2940
+ if (auto derivable = DerivedConformance::getDerivableRequirement (
2941
+ TC,
2942
+ nominal,
2943
+ requirement)) {
2944
+ if (derivable == requirement) {
2945
+ // If it's the same requirement, we can derive it here.
2946
+ canDerive = true ;
2947
+ } else {
2948
+ // Otherwise, go satisfy the derivable requirement, which can introduce
2949
+ // a member that could in turn satisfy *this* requirement.
2950
+ auto derivableProto = cast<ProtocolDecl>(derivable->getDeclContext ());
2951
+ if (auto conformance =
2952
+ TC.conformsToProtocol (Adoptee, derivableProto, DC, None)) {
2953
+ if (conformance->isConcrete ())
2954
+ (void )conformance->getConcrete ()->getWitnessDecl (derivable, &TC);
2963
2955
}
2964
2956
}
2965
2957
}
@@ -2970,7 +2962,11 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
2970
2962
unsigned bestIdx = 0 ;
2971
2963
bool doNotDiagnoseMatches = false ;
2972
2964
bool ignoringNames = false ;
2973
- if (findBestWitness (requirement, hasFallbacks ? nullptr : &ignoringNames,
2965
+ bool considerRenames =
2966
+ !canDerive && !requirement->getAttrs ().hasAttribute <OptionalAttr>() &&
2967
+ !requirement->getAttrs ().isUnavailable (TC.Context );
2968
+ if (findBestWitness (requirement,
2969
+ considerRenames ? &ignoringNames : nullptr ,
2974
2970
Conformance,
2975
2971
/* out parameters: */
2976
2972
matches, numViable, bestIdx, doNotDiagnoseMatches)) {
@@ -3192,7 +3188,19 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
3192
3188
// We have either no matches or an ambiguous match.
3193
3189
3194
3190
// If we can derive a definition for this requirement, just call it missing.
3195
- if (hasFallbacks) {
3191
+ if (canDerive) {
3192
+ return ResolveWitnessResult::Missing;
3193
+ }
3194
+
3195
+ // If the requirement is optional, it's okay. We'll satisfy this via
3196
+ // our handling of default definitions.
3197
+ //
3198
+ // FIXME: revisit this once we get default definitions in protocol bodies.
3199
+ //
3200
+ // Treat 'unavailable' implicitly as if it were 'optional'.
3201
+ // The compiler will reject actual uses.
3202
+ auto Attrs = requirement->getAttrs ();
3203
+ if (Attrs.hasAttribute <OptionalAttr>() || Attrs.isUnavailable (TC.Context )) {
3196
3204
return ResolveWitnessResult::Missing;
3197
3205
}
3198
3206
@@ -3355,29 +3363,10 @@ CheckTypeWitnessResult swift::checkTypeWitness(TypeChecker &tc, DeclContext *dc,
3355
3363
3356
3364
ResolveWitnessResult
3357
3365
ConformanceChecker::resolveWitnessTryingAllStrategies (ValueDecl *requirement) {
3358
- using ResolveWitnessStrategy =
3359
- decltype (&ConformanceChecker::resolveWitnessViaLookup);
3360
- static const constexpr ResolveWitnessStrategy defaultStrategies[] = {
3366
+ decltype (&ConformanceChecker::resolveWitnessViaLookup) strategies[] = {
3361
3367
&ConformanceChecker::resolveWitnessViaLookup,
3362
3368
&ConformanceChecker::resolveWitnessViaDerivation,
3363
3369
&ConformanceChecker::resolveWitnessViaDefault};
3364
- ArrayRef<ResolveWitnessStrategy> strategies = defaultStrategies;
3365
-
3366
- // Don't try any sort of derivation when processing a parseable interface.
3367
- if (isConformanceFromParseableInterface (Conformance)) {
3368
- if (Conformance->isResilient ()) {
3369
- // Resilient conformances don't allow any sort of devirtualization, so
3370
- // don't bother looking up witnesses at all.
3371
- static const constexpr ResolveWitnessStrategy resilientStrategies[] = {
3372
- &ConformanceChecker::resolveWitnessAsOpaque};
3373
- strategies = resilientStrategies;
3374
- } else {
3375
- static const constexpr ResolveWitnessStrategy interfaceStrategies[] = {
3376
- &ConformanceChecker::resolveWitnessViaLookup,
3377
- &ConformanceChecker::resolveWitnessAsOpaque};
3378
- strategies = interfaceStrategies;
3379
- }
3380
- }
3381
3370
3382
3371
for (auto strategy : strategies) {
3383
3372
ResolveWitnessResult result = (this ->*strategy)(requirement);
0 commit comments