@@ -1173,23 +1173,6 @@ bool WitnessChecker::findBestWitness(
11731173 }
11741174
11751175 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-
11931176 if (anyFromUnconstrainedExtension &&
11941177 conformance != nullptr &&
11951178 conformance->isInvalid ()) {
@@ -2914,6 +2897,23 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
29142897 }
29152898}
29162899
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+
29172917ResolveWitnessResult
29182918ConformanceChecker::resolveWitnessViaLookup (ValueDecl *requirement) {
29192919 assert (!isa<AssociatedTypeDecl>(requirement) && " Use resolveTypeWitnessVia*" );
@@ -2931,25 +2931,33 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
29312931 }
29322932 }
29332933
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+ }
29532961 }
29542962 }
29552963 }
@@ -2960,11 +2968,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
29602968 unsigned bestIdx = 0 ;
29612969 bool doNotDiagnoseMatches = false ;
29622970 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,
29682972 Conformance,
29692973 /* out parameters: */
29702974 matches, numViable, bestIdx, doNotDiagnoseMatches)) {
@@ -3182,19 +3186,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
31823186 // We have either no matches or an ambiguous match.
31833187
31843188 // 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) {
31983190 return ResolveWitnessResult::Missing;
31993191 }
32003192
@@ -3355,6 +3347,47 @@ CheckTypeWitnessResult swift::checkTypeWitness(TypeChecker &tc, DeclContext *dc,
33553347 return CheckTypeWitnessResult ();
33563348}
33573349
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+
33583391// / Attempt to resolve a type witness via member name lookup.
33593392ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup (
33603393 AssociatedTypeDecl *assocType) {
@@ -3625,60 +3658,14 @@ void ConformanceChecker::ensureRequirementsAreSatisfied(
36253658}
36263659
36273660#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);
36333661
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 () {
36763663 for (auto member : Proto->getMembers ()) {
36773664 auto requirement = dyn_cast<ValueDecl>(member);
36783665 if (!requirement)
36793666 continue ;
36803667
3681- // Associated type requirements handled above .
3668+ // Associated type requirements handled elsewhere .
36823669 if (isa<TypeDecl>(requirement))
36833670 continue ;
36843671
@@ -3829,9 +3816,9 @@ void ConformanceChecker::checkConformance(MissingWitnessDiagnosisKind Kind) {
38293816 // If this is an accessor for a storage decl, ignore it.
38303817 if (isa<AccessorDecl>(requirement))
38313818 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)) {
38353822 case ResolveWitnessResult::Success:
38363823 finalizeWitness ();
38373824 continue ;
@@ -3841,41 +3828,62 @@ void ConformanceChecker::checkConformance(MissingWitnessDiagnosisKind Kind) {
38413828 continue ;
38423829
38433830 case ResolveWitnessResult::Missing:
3844- // Continue trying below .
3831+ // Let it get diagnosed later .
38453832 break ;
38463833 }
3834+ }
3835+ }
38473836
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" );
38533839
3854- case ResolveWitnessResult::ExplicitFailed:
3855- Conformance->setInvalid ();
3856- continue ;
3840+ FrontendStatsTracer statsTracer (TC.Context .Stats , " check-conformance" ,
3841+ Conformance);
38573842
3858- case ResolveWitnessResult::Missing:
3859- // Continue trying below.
3860- break ;
3861- }
3843+ llvm::SaveAndRestore<bool > restoreSuppressDiagnostics (SuppressDiagnostics);
3844+ SuppressDiagnostics = false ;
38623845
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.
38683848
3869- case ResolveWitnessResult::ExplicitFailed:
3870- Conformance->setInvalid ();
3871- continue ;
3849+ // Emit known diags for this conformance.
3850+ emitDelayedDiags ();
38723851
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 ;
38773856 }
38783857
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+
38793887 emitDelayedDiags ();
38803888
38813889 // Except in specific hardcoded cases for Foundation/Swift
0 commit comments