@@ -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 ()) {
@@ -2892,23 +2909,6 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
2892
2909
}
2893
2910
}
2894
2911
2895
- ResolveWitnessResult
2896
- ConformanceChecker::resolveWitnessAsOpaque (ValueDecl *requirement) {
2897
- assert (!isa<AssociatedTypeDecl>(requirement) && " Use resolveTypeWitnessVia*" );
2898
- auto match = matchWitness (TC, ReqEnvironmentCache, Proto,
2899
- Conformance, DC, requirement, requirement);
2900
- recordWitness (requirement, match);
2901
- return ResolveWitnessResult::Success;
2902
- }
2903
-
2904
- static bool isConformanceFromParseableInterface (
2905
- const NormalProtocolConformance *conformance) {
2906
- auto *containingSF = conformance->getDeclContext ()->getParentSourceFile ();
2907
- if (!containingSF)
2908
- return false ;
2909
- return containingSF->Kind == SourceFileKind::Interface;
2910
- }
2911
-
2912
2912
ResolveWitnessResult
2913
2913
ConformanceChecker::resolveWitnessViaLookup (ValueDecl *requirement) {
2914
2914
assert (!isa<AssociatedTypeDecl>(requirement) && " Use resolveTypeWitnessVia*" );
@@ -2926,33 +2926,25 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
2926
2926
}
2927
2927
}
2928
2928
2929
- // Determine whether we can get a witness for this requirement some other way.
2930
- bool hasFallbacks = false ;
2931
- if (!hasFallbacks)
2932
- hasFallbacks = requirement->getAttrs ().hasAttribute <OptionalAttr>();
2933
- if (!hasFallbacks)
2934
- hasFallbacks = requirement->getAttrs ().isUnavailable (TC.Context );
2935
- if (!hasFallbacks)
2936
- hasFallbacks = isConformanceFromParseableInterface (Conformance);
2937
-
2938
- if (!hasFallbacks) {
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
- hasFallbacks = 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);
2955
- }
2929
+ // Determine whether we can derive a witness for this requirement.
2930
+ bool canDerive = false ;
2931
+
2932
+ // Can a witness for this requirement be derived for this nominal type?
2933
+ if (auto derivable = DerivedConformance::getDerivableRequirement (
2934
+ TC,
2935
+ nominal,
2936
+ requirement)) {
2937
+ if (derivable == requirement) {
2938
+ // If it's the same requirement, we can derive it here.
2939
+ canDerive = true ;
2940
+ } else {
2941
+ // Otherwise, go satisfy the derivable requirement, which can introduce
2942
+ // a member that could in turn satisfy *this* requirement.
2943
+ auto derivableProto = cast<ProtocolDecl>(derivable->getDeclContext ());
2944
+ if (auto conformance =
2945
+ TC.conformsToProtocol (Adoptee, derivableProto, DC, None)) {
2946
+ if (conformance->isConcrete ())
2947
+ (void )conformance->getConcrete ()->getWitnessDecl (derivable, &TC);
2956
2948
}
2957
2949
}
2958
2950
}
@@ -2963,7 +2955,11 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
2963
2955
unsigned bestIdx = 0 ;
2964
2956
bool doNotDiagnoseMatches = false ;
2965
2957
bool ignoringNames = false ;
2966
- if (findBestWitness (requirement, hasFallbacks ? nullptr : &ignoringNames,
2958
+ bool considerRenames =
2959
+ !canDerive && !requirement->getAttrs ().hasAttribute <OptionalAttr>() &&
2960
+ !requirement->getAttrs ().isUnavailable (TC.Context );
2961
+ if (findBestWitness (requirement,
2962
+ considerRenames ? &ignoringNames : nullptr ,
2967
2963
Conformance,
2968
2964
/* out parameters: */
2969
2965
matches, numViable, bestIdx, doNotDiagnoseMatches)) {
@@ -3181,7 +3177,19 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
3181
3177
// We have either no matches or an ambiguous match.
3182
3178
3183
3179
// If we can derive a definition for this requirement, just call it missing.
3184
- if (hasFallbacks) {
3180
+ if (canDerive) {
3181
+ return ResolveWitnessResult::Missing;
3182
+ }
3183
+
3184
+ // If the requirement is optional, it's okay. We'll satisfy this via
3185
+ // our handling of default definitions.
3186
+ //
3187
+ // FIXME: revisit this once we get default definitions in protocol bodies.
3188
+ //
3189
+ // Treat 'unavailable' implicitly as if it were 'optional'.
3190
+ // The compiler will reject actual uses.
3191
+ auto Attrs = requirement->getAttrs ();
3192
+ if (Attrs.hasAttribute <OptionalAttr>() || Attrs.isUnavailable (TC.Context )) {
3185
3193
return ResolveWitnessResult::Missing;
3186
3194
}
3187
3195
@@ -3344,29 +3352,10 @@ CheckTypeWitnessResult swift::checkTypeWitness(TypeChecker &tc, DeclContext *dc,
3344
3352
3345
3353
ResolveWitnessResult
3346
3354
ConformanceChecker::resolveWitnessTryingAllStrategies (ValueDecl *requirement) {
3347
- using ResolveWitnessStrategy =
3348
- decltype (&ConformanceChecker::resolveWitnessViaLookup);
3349
- static const constexpr ResolveWitnessStrategy defaultStrategies[] = {
3355
+ decltype (&ConformanceChecker::resolveWitnessViaLookup) strategies[] = {
3350
3356
&ConformanceChecker::resolveWitnessViaLookup,
3351
3357
&ConformanceChecker::resolveWitnessViaDerivation,
3352
3358
&ConformanceChecker::resolveWitnessViaDefault};
3353
- ArrayRef<ResolveWitnessStrategy> strategies = defaultStrategies;
3354
-
3355
- // Don't try any sort of derivation when processing a parseable interface.
3356
- if (isConformanceFromParseableInterface (Conformance)) {
3357
- if (Conformance->isResilient ()) {
3358
- // Resilient conformances don't allow any sort of devirtualization, so
3359
- // don't bother looking up witnesses at all.
3360
- static const constexpr ResolveWitnessStrategy resilientStrategies[] = {
3361
- &ConformanceChecker::resolveWitnessAsOpaque};
3362
- strategies = resilientStrategies;
3363
- } else {
3364
- static const constexpr ResolveWitnessStrategy interfaceStrategies[] = {
3365
- &ConformanceChecker::resolveWitnessViaLookup,
3366
- &ConformanceChecker::resolveWitnessAsOpaque};
3367
- strategies = interfaceStrategies;
3368
- }
3369
- }
3370
3359
3371
3360
for (auto strategy : strategies) {
3372
3361
ResolveWitnessResult result = (this ->*strategy)(requirement);
0 commit comments