39
39
#include " llvm/Support/Compiler.h"
40
40
#include " llvm/Support/SaveAndRestore.h"
41
41
42
+ #define DEBUG_TYPE " protocol-conformance-checking"
43
+ #include " llvm/Support/Debug.h"
44
+
42
45
using namespace swift ;
43
46
44
47
namespace {
@@ -3064,6 +3067,9 @@ ConformanceChecker::inferTypeWitnessesViaValueWitnesses(
3064
3067
};
3065
3068
3066
3069
for (auto witness : lookupValueWitnesses (req, /* ignoringNames=*/ nullptr )) {
3070
+ DEBUG (llvm::dbgs () << " Inferring associated types from decl:\n " ;
3071
+ witness->dump (llvm::dbgs ()));
3072
+
3067
3073
// If the potential witness came from an extension, and our `Self`
3068
3074
// type can't use it regardless of what associated types we end up
3069
3075
// inferring, skip the witness.
@@ -3084,18 +3090,27 @@ ConformanceChecker::inferTypeWitnessesViaValueWitnesses(
3084
3090
}
3085
3091
auto &result = witnessResult.Inferred [i];
3086
3092
3093
+ DEBUG (llvm::dbgs () << " Considering whether " << result.first ->getName ()
3094
+ << " can infer to:\n " ;
3095
+ result.second ->dump (llvm::dbgs ()));
3096
+
3087
3097
// Filter out errors.
3088
- if (result.second ->hasError ())
3098
+ if (result.second ->hasError ()) {
3099
+ DEBUG (llvm::dbgs () << " -- has error type\n " );
3089
3100
REJECT;
3101
+ }
3090
3102
3091
3103
// Filter out duplicates.
3092
3104
if (!known.insert ({result.first , result.second ->getCanonicalType ()})
3093
- .second )
3105
+ .second ) {
3106
+ DEBUG (llvm::dbgs () << " -- duplicate\n " );
3094
3107
REJECT;
3108
+ }
3095
3109
3096
3110
// Filter out circular possibilities, e.g. that
3097
3111
// AssocType == S.AssocType or
3098
3112
// AssocType == Foo<S.AssocType>.
3113
+ bool canInferFromOtherAssociatedType = false ;
3099
3114
bool containsTautologicalType =
3100
3115
result.second .findIf ([&](Type t) -> bool {
3101
3116
auto dmt = t->getAs <DependentMemberType>();
@@ -3107,11 +3122,63 @@ ConformanceChecker::inferTypeWitnessesViaValueWitnesses(
3107
3122
if (!dmt->getBase ()->isEqual (Conformance->getType ()))
3108
3123
return false ;
3109
3124
3125
+ // If this associated type is same-typed to another associated type
3126
+ // on `Self`, then it may still be an interesting candidate if we find
3127
+ // an answer for that other type.
3128
+ auto witnessContext = witness->getDeclContext ();
3129
+ if (witnessContext->getAsProtocolExtensionContext ()
3130
+ && witnessContext->getGenericSignatureOfContext ()) {
3131
+ auto selfTy = witnessContext->getSelfInterfaceType ();
3132
+ auto selfAssocTy = DependentMemberType::get (selfTy,
3133
+ dmt->getAssocType ());
3134
+ for (auto &reqt : witnessContext->getGenericSignatureOfContext ()
3135
+ ->getRequirements ()) {
3136
+ switch (reqt.getKind ()) {
3137
+ case RequirementKind::Conformance:
3138
+ case RequirementKind::Superclass:
3139
+ case RequirementKind::Layout:
3140
+ break ;
3141
+
3142
+ case RequirementKind::SameType:
3143
+ Type other;
3144
+ if (reqt.getFirstType ()->isEqual (selfAssocTy)) {
3145
+ other = reqt.getSecondType ();
3146
+ } else if (reqt.getSecondType ()->isEqual (selfAssocTy)) {
3147
+ other = reqt.getFirstType ();
3148
+ } else {
3149
+ break ;
3150
+ }
3151
+
3152
+ if (auto otherAssoc = other->getAs <DependentMemberType>()) {
3153
+ if (otherAssoc->getBase ()->isEqual (selfTy)) {
3154
+ auto otherDMT = DependentMemberType::get (dmt->getBase (),
3155
+ otherAssoc->getAssocType ());
3156
+
3157
+ // We may be able to infer one associated type from the
3158
+ // other.
3159
+ result.second = result.second .transform ([&](Type t) -> Type{
3160
+ if (t->isEqual (dmt))
3161
+ return otherDMT;
3162
+ return t;
3163
+ });
3164
+ canInferFromOtherAssociatedType = true ;
3165
+ DEBUG (llvm::dbgs () << " ++ we can same-type to:\n " ;
3166
+ result.second ->dump (llvm::dbgs ()));
3167
+ return false ;
3168
+ }
3169
+ }
3170
+ break ;
3171
+ }
3172
+ }
3173
+ }
3174
+
3110
3175
return true ;
3111
3176
});
3112
3177
3113
- if (containsTautologicalType)
3178
+ if (containsTautologicalType) {
3179
+ DEBUG (llvm::dbgs () << " -- tautological\n " );
3114
3180
REJECT;
3181
+ }
3115
3182
3116
3183
// Check that the type witness doesn't contradict an
3117
3184
// explicitly-given type witness. If it does contradict, throw out the
@@ -3128,19 +3195,27 @@ ConformanceChecker::inferTypeWitnessesViaValueWitnesses(
3128
3195
auto newWitness = result.second ->getCanonicalType ();
3129
3196
if (!newWitness->hasTypeParameter ()
3130
3197
&& !existingWitness->isEqual (newWitness)) {
3198
+ DEBUG (llvm::dbgs () << " ** contradicts explicit type witness, "
3199
+ " rejecting inference from this decl\n " );
3131
3200
goto next_witness;
3132
3201
}
3133
3202
}
3134
3203
3135
- // Check that the type witness meets the
3136
- // requirements on the associated type.
3137
- if (auto failed = checkTypeWitness (TC, DC, result.first ,
3138
- result.second )) {
3139
- witnessResult.NonViable .push_back (
3140
- std::make_tuple (result.first ,result.second ,failed));
3141
- REJECT;
3204
+ // If we same-typed to another unresolved associated type, we won't
3205
+ // be able to check conformances yet.
3206
+ if (!canInferFromOtherAssociatedType) {
3207
+ // Check that the type witness meets the
3208
+ // requirements on the associated type.
3209
+ if (auto failed = checkTypeWitness (TC, DC, result.first ,
3210
+ result.second )) {
3211
+ witnessResult.NonViable .push_back (
3212
+ std::make_tuple (result.first ,result.second ,failed));
3213
+ DEBUG (llvm::dbgs () << " -- doesn't fulfill requirements\n " );
3214
+ REJECT;
3215
+ }
3142
3216
}
3143
3217
3218
+ DEBUG (llvm::dbgs () << " ++ seems legit\n " );
3144
3219
++i;
3145
3220
}
3146
3221
#undef REJECT
@@ -3657,6 +3732,8 @@ void ConformanceChecker::resolveTypeWitnesses() {
3657
3732
3658
3733
// Infer type witnesses from value witnesses.
3659
3734
auto inferred = inferTypeWitnessesViaValueWitnesses (unresolvedAssocTypes);
3735
+ DEBUG (llvm::dbgs () << " Candidates for inference:\n " ;
3736
+ dumpInferredAssociatedTypes (inferred));
3660
3737
3661
3738
// Compute the set of solutions.
3662
3739
SmallVector<std::pair<ValueDecl *, ValueDecl *>, 4 > valueWitnesses;
@@ -3847,6 +3924,9 @@ void ConformanceChecker::resolveTypeWitnesses() {
3847
3924
Type replaced = known->first .transform (foldDependentMemberTypes);
3848
3925
if (replaced.isNull ())
3849
3926
return true ;
3927
+
3928
+ if (checkTypeWitness (TC, DC, assocType, replaced))
3929
+ return true ;
3850
3930
3851
3931
known->first = replaced;
3852
3932
}
0 commit comments