38
38
#include " llvm/Support/Compiler.h"
39
39
#include " llvm/Support/SaveAndRestore.h"
40
40
41
+ #define DEBUG_TYPE " protocol-conformance-checking"
42
+ #include " llvm/Support/Debug.h"
43
+
41
44
using namespace swift ;
42
45
43
46
namespace {
@@ -3029,6 +3032,9 @@ ConformanceChecker::inferTypeWitnessesViaValueWitnesses(
3029
3032
};
3030
3033
3031
3034
for (auto witness : lookupValueWitnesses (req, /* ignoringNames=*/ nullptr )) {
3035
+ DEBUG (llvm::dbgs () << " Inferring associated types from decl:\n " ;
3036
+ witness->dump (llvm::dbgs ()));
3037
+
3032
3038
// If the potential witness came from an extension, and our `Self`
3033
3039
// type can't use it regardless of what associated types we end up
3034
3040
// inferring, skip the witness.
@@ -3049,18 +3055,27 @@ ConformanceChecker::inferTypeWitnessesViaValueWitnesses(
3049
3055
}
3050
3056
auto &result = witnessResult.Inferred [i];
3051
3057
3058
+ DEBUG (llvm::dbgs () << " Considering whether " << result.first ->getName ()
3059
+ << " can infer to:\n " ;
3060
+ result.second ->dump (llvm::dbgs ()));
3061
+
3052
3062
// Filter out errors.
3053
- if (result.second ->hasError ())
3063
+ if (result.second ->hasError ()) {
3064
+ DEBUG (llvm::dbgs () << " -- has error type\n " );
3054
3065
REJECT;
3066
+ }
3055
3067
3056
3068
// Filter out duplicates.
3057
3069
if (!known.insert ({result.first , result.second ->getCanonicalType ()})
3058
- .second )
3070
+ .second ) {
3071
+ DEBUG (llvm::dbgs () << " -- duplicate\n " );
3059
3072
REJECT;
3073
+ }
3060
3074
3061
3075
// Filter out circular possibilities, e.g. that
3062
3076
// AssocType == S.AssocType or
3063
3077
// AssocType == Foo<S.AssocType>.
3078
+ bool canInferFromOtherAssociatedType = false ;
3064
3079
bool containsTautologicalType =
3065
3080
result.second .findIf ([&](Type t) -> bool {
3066
3081
auto dmt = t->getAs <DependentMemberType>();
@@ -3072,11 +3087,63 @@ ConformanceChecker::inferTypeWitnessesViaValueWitnesses(
3072
3087
if (!dmt->getBase ()->isEqual (Conformance->getType ()))
3073
3088
return false ;
3074
3089
3090
+ // If this associated type is same-typed to another associated type
3091
+ // on `Self`, then it may still be an interesting candidate if we find
3092
+ // an answer for that other type.
3093
+ auto witnessContext = witness->getDeclContext ();
3094
+ if (witnessContext->getAsProtocolExtensionContext ()
3095
+ && witnessContext->getGenericSignatureOfContext ()) {
3096
+ auto selfTy = witnessContext->getSelfInterfaceType ();
3097
+ auto selfAssocTy = DependentMemberType::get (selfTy,
3098
+ dmt->getAssocType ());
3099
+ for (auto &reqt : witnessContext->getGenericSignatureOfContext ()
3100
+ ->getRequirements ()) {
3101
+ switch (reqt.getKind ()) {
3102
+ case RequirementKind::Conformance:
3103
+ case RequirementKind::Superclass:
3104
+ case RequirementKind::Layout:
3105
+ break ;
3106
+
3107
+ case RequirementKind::SameType:
3108
+ Type other;
3109
+ if (reqt.getFirstType ()->isEqual (selfAssocTy)) {
3110
+ other = reqt.getSecondType ();
3111
+ } else if (reqt.getSecondType ()->isEqual (selfAssocTy)) {
3112
+ other = reqt.getFirstType ();
3113
+ } else {
3114
+ break ;
3115
+ }
3116
+
3117
+ if (auto otherAssoc = other->getAs <DependentMemberType>()) {
3118
+ if (otherAssoc->getBase ()->isEqual (selfTy)) {
3119
+ auto otherDMT = DependentMemberType::get (dmt->getBase (),
3120
+ otherAssoc->getAssocType ());
3121
+
3122
+ // We may be able to infer one associated type from the
3123
+ // other.
3124
+ result.second = result.second .transform ([&](Type t) -> Type{
3125
+ if (t->isEqual (dmt))
3126
+ return otherDMT;
3127
+ return t;
3128
+ });
3129
+ canInferFromOtherAssociatedType = true ;
3130
+ DEBUG (llvm::dbgs () << " ++ we can same-type to:\n " ;
3131
+ result.second ->dump (llvm::dbgs ()));
3132
+ return false ;
3133
+ }
3134
+ }
3135
+ break ;
3136
+ }
3137
+ }
3138
+ }
3139
+
3075
3140
return true ;
3076
3141
});
3077
3142
3078
- if (containsTautologicalType)
3143
+ if (containsTautologicalType) {
3144
+ DEBUG (llvm::dbgs () << " -- tautological\n " );
3079
3145
REJECT;
3146
+ }
3080
3147
3081
3148
// Check that the type witness doesn't contradict an
3082
3149
// explicitly-given type witness. If it does contradict, throw out the
@@ -3093,19 +3160,27 @@ ConformanceChecker::inferTypeWitnessesViaValueWitnesses(
3093
3160
auto newWitness = result.second ->getCanonicalType ();
3094
3161
if (!newWitness->hasTypeParameter ()
3095
3162
&& !existingWitness->isEqual (newWitness)) {
3163
+ DEBUG (llvm::dbgs () << " ** contradicts explicit type witness, "
3164
+ " rejecting inference from this decl\n " );
3096
3165
goto next_witness;
3097
3166
}
3098
3167
}
3099
3168
3100
- // Check that the type witness meets the
3101
- // requirements on the associated type.
3102
- if (auto failed = checkTypeWitness (TC, DC, result.first ,
3103
- result.second )) {
3104
- witnessResult.NonViable .push_back (
3105
- std::make_tuple (result.first ,result.second ,failed));
3106
- REJECT;
3169
+ // If we same-typed to another unresolved associated type, we won't
3170
+ // be able to check conformances yet.
3171
+ if (!canInferFromOtherAssociatedType) {
3172
+ // Check that the type witness meets the
3173
+ // requirements on the associated type.
3174
+ if (auto failed = checkTypeWitness (TC, DC, result.first ,
3175
+ result.second )) {
3176
+ witnessResult.NonViable .push_back (
3177
+ std::make_tuple (result.first ,result.second ,failed));
3178
+ DEBUG (llvm::dbgs () << " -- doesn't fulfill requirements\n " );
3179
+ REJECT;
3180
+ }
3107
3181
}
3108
3182
3183
+ DEBUG (llvm::dbgs () << " ++ seems legit\n " );
3109
3184
++i;
3110
3185
}
3111
3186
#undef REJECT
@@ -3622,6 +3697,8 @@ void ConformanceChecker::resolveTypeWitnesses() {
3622
3697
3623
3698
// Infer type witnesses from value witnesses.
3624
3699
auto inferred = inferTypeWitnessesViaValueWitnesses (unresolvedAssocTypes);
3700
+ DEBUG (llvm::dbgs () << " Candidates for inference:\n " ;
3701
+ dumpInferredAssociatedTypes (inferred));
3625
3702
3626
3703
// Compute the set of solutions.
3627
3704
SmallVector<std::pair<ValueDecl *, ValueDecl *>, 4 > valueWitnesses;
@@ -3812,6 +3889,9 @@ void ConformanceChecker::resolveTypeWitnesses() {
3812
3889
Type replaced = known->first .transform (foldDependentMemberTypes);
3813
3890
if (replaced.isNull ())
3814
3891
return true ;
3892
+
3893
+ if (checkTypeWitness (TC, DC, assocType, replaced))
3894
+ return true ;
3815
3895
3816
3896
known->first = replaced;
3817
3897
}
0 commit comments