@@ -87,11 +87,7 @@ class CheckTypeWitnessResult {
87
87
88
88
// / Type witness does not satisfy a layout requirement on
89
89
// / the associated type.
90
- Layout,
91
-
92
- // / Type witness of a tuple conformance does not have the form
93
- // / (repeat (each Element).A).
94
- Tuple
90
+ Layout
95
91
} kind;
96
92
97
93
private:
@@ -125,25 +121,36 @@ class CheckTypeWitnessResult {
125
121
return CheckTypeWitnessResult (Layout, reqt);
126
122
}
127
123
128
- static CheckTypeWitnessResult forTuple (Type reqt) {
129
- return CheckTypeWitnessResult (Tuple, reqt);
130
- }
131
-
132
124
Kind getKind () const { return kind; }
133
125
Type getRequirement () const { return reqt; }
134
126
135
127
explicit operator bool () const { return kind != Success; }
136
128
};
137
129
130
+ // / Checks a potential witness for an associated type A against the "local"
131
+ // / requirements of the type parameter Self.[P]A. We call this to check
132
+ // / type witnesses found by name lookup, as well as candidate witnesses during
133
+ // / inference.
134
+ // /
135
+ // / This does not completely check the witness; we check the entire requirement
136
+ // / signature at the end. However, rejecting witnesses that are definitely
137
+ // / invalid here can cut down the search space.
138
138
static CheckTypeWitnessResult
139
139
checkTypeWitness (Type type, AssociatedTypeDecl *assocType,
140
140
const NormalProtocolConformance *Conf,
141
141
SubstOptions options) {
142
+ assert (!type->hasTypeParameter ());
143
+
142
144
auto &ctx = assocType->getASTContext ();
143
145
144
146
if (type->hasError ())
145
147
return CheckTypeWitnessResult::forError ();
146
148
149
+ // If the type witness is equivalent to some other unresolved witness,
150
+ // we cannot check anything, so accept the witness.
151
+ if (type->is <DependentMemberType>())
152
+ return CheckTypeWitnessResult::forSuccess ();
153
+
147
154
const auto proto = Conf->getProtocol ();
148
155
const auto dc = Conf->getDeclContext ();
149
156
const auto sig = proto->getGenericSignature ();
@@ -167,53 +174,43 @@ checkTypeWitness(Type type, AssociatedTypeDecl *assocType,
167
174
const auto depTy = DependentMemberType::get (proto->getSelfInterfaceType (),
168
175
assocType);
169
176
170
- Type contextType = type->hasTypeParameter () ? dc->mapTypeIntoContext (type)
171
- : type;
172
-
173
177
if (auto superclass = sig->getSuperclassBound (depTy)) {
174
- if (superclass->hasTypeParameter ()) {
175
- // Replace type parameters with other known or tentative type witnesses.
176
- superclass = superclass.subst (
177
- [&](SubstitutableType *type) {
178
- if (type->isEqual (proto->getSelfInterfaceType ()))
179
- return Conf->getType ();
180
-
181
- return Type ();
182
- },
183
- LookUpConformanceInModule (dc->getParentModule ()), options);
184
-
185
- if (superclass->hasTypeParameter ())
186
- superclass = dc->mapTypeIntoContext (superclass);
178
+ // We only check that the type's superclass declaration is correct.
179
+ // If the superclass bound is generic, we may not have resolved all of
180
+ // the type witnesses that appear in generic arguments yet, and doing so
181
+ // here might run into a request cycle.
182
+ auto superclassDecl = superclass->getClassOrBoundGenericClass ();
183
+ assert (superclassDecl);
184
+
185
+ // Fish a class declaration out of the type witness.
186
+ auto classDecl = type->getClassOrBoundGenericClass ();
187
+ if (!classDecl) {
188
+ if (auto archetype = type->getAs <ArchetypeType>()) {
189
+ if (auto superclassType = archetype->getSuperclass ())
190
+ classDecl = superclassType->getClassOrBoundGenericClass ();
191
+ }
187
192
}
188
- if (!superclass->isExactSuperclassOf (contextType))
193
+
194
+ if (!classDecl || !superclassDecl->isSuperclassOf (classDecl))
189
195
return CheckTypeWitnessResult::forSuperclass (superclass);
190
196
}
191
197
192
198
auto *module = dc->getParentModule ();
193
199
194
- // Check protocol conformances.
200
+ // Check protocol conformances. We don't check conditional requirements here.
195
201
for (const auto reqProto : sig->getRequiredProtocols (depTy)) {
196
202
if (module ->lookupConformance (
197
- contextType , reqProto,
203
+ type , reqProto,
198
204
/* allowMissing=*/ reqProto->isSpecificProtocol (
199
205
KnownProtocolKind::Sendable))
200
206
.isInvalid ())
201
207
return CheckTypeWitnessResult::forConformance (reqProto);
202
208
}
203
209
210
+ // We can completely check an AnyObject layout constraint.
204
211
if (sig->requiresClass (depTy) &&
205
- !contextType->satisfiesClassConstraint ()) {
206
- return CheckTypeWitnessResult::forLayout (
207
- module ->getASTContext ().getAnyObjectType ());
208
- }
209
-
210
- // Tuple conformances can only witness associated types by projecting them
211
- // element-wise.
212
- if (isa<BuiltinTupleDecl>(dc->getSelfNominalTypeDecl ())) {
213
- auto expectedTy = getTupleConformanceTypeWitness (dc, assocType);
214
- if (!expectedTy->isEqual (type)) {
215
- return CheckTypeWitnessResult::forTuple (expectedTy);
216
- }
212
+ !type->satisfiesClassConstraint ()) {
213
+ return CheckTypeWitnessResult::forLayout (ctx.getAnyObjectType ());
217
214
}
218
215
219
216
// Success!
@@ -222,10 +219,21 @@ checkTypeWitness(Type type, AssociatedTypeDecl *assocType,
222
219
223
220
}
224
221
222
+ static bool containsConcreteDependentMemberType (Type ty) {
223
+ return ty.findIf ([](Type t) -> bool {
224
+ if (auto *dmt = t->getAs <DependentMemberType>())
225
+ return !dmt->isTypeParameter ();
226
+
227
+ return false ;
228
+ });
229
+ }
230
+
225
231
static void recordTypeWitness (NormalProtocolConformance *conformance,
226
232
AssociatedTypeDecl *assocType,
227
233
Type type,
228
234
TypeDecl *typeDecl) {
235
+ assert (!containsConcreteDependentMemberType (type));
236
+
229
237
// If we already recoded this type witness, there's nothing to do.
230
238
if (conformance->hasTypeWitness (assocType)) {
231
239
assert (conformance->getTypeWitnessUncached (assocType)
@@ -473,9 +481,12 @@ static ResolveWitnessResult resolveTypeWitnessViaLookup(
473
481
if (!viableTypes.insert (memberType->getCanonicalType ()).second )
474
482
continue ;
475
483
484
+ auto memberTypeInContext = dc->mapTypeIntoContext (memberType);
485
+
476
486
// Check this type against the protocol requirements.
477
487
if (auto checkResult =
478
- checkTypeWitness (memberType, assocType, conformance, llvm::None)) {
488
+ checkTypeWitness (memberTypeInContext, assocType,
489
+ conformance, llvm::None)) {
479
490
nonViable.push_back ({typeDecl, checkResult});
480
491
} else {
481
492
viable.push_back ({typeDecl, memberType, nullptr });
@@ -551,14 +562,6 @@ static ResolveWitnessResult resolveTypeWitnessViaLookup(
551
562
candidate.first ->getDeclaredInterfaceType (),
552
563
candidate.second .getRequirement ());
553
564
break ;
554
-
555
- case CheckTypeWitnessResult::Tuple:
556
- diags.diagnose (
557
- candidate.first ,
558
- diag::protocol_type_witness_tuple,
559
- candidate.first ->getDeclaredInterfaceType (),
560
- candidate.second .getRequirement ());
561
- break ;
562
565
}
563
566
}
564
567
});
@@ -1353,7 +1356,6 @@ enum class InferenceCandidateKind {
1353
1356
1354
1357
static InferenceCandidateKind checkInferenceCandidate (
1355
1358
std::pair<AssociatedTypeDecl *, Type> *result,
1356
- bool *canInferFromOtherAssociatedType,
1357
1359
NormalProtocolConformance *conformance,
1358
1360
ValueDecl *witness) {
1359
1361
auto isTautological = [&](Type t) -> bool {
@@ -1418,7 +1420,6 @@ static InferenceCandidateKind checkInferenceCandidate(
1418
1420
return otherDMT;
1419
1421
return t;
1420
1422
});
1421
- *canInferFromOtherAssociatedType = true ;
1422
1423
LLVM_DEBUG (llvm::dbgs () << " ++ we can same-type to:\n " ;
1423
1424
result->second ->dump (llvm::dbgs ()));
1424
1425
return InferenceCandidateKind::Good;
@@ -1543,11 +1544,7 @@ AssociatedTypeInference::getPotentialTypeWitnessesFromRequirement(
1543
1544
// Filter out circular possibilities, e.g. that
1544
1545
// AssocType == S.AssocType or
1545
1546
// AssocType == Foo<S.AssocType>.
1546
- bool canInferFromOtherAssociatedType = false ;
1547
-
1548
- switch (checkInferenceCandidate (&result,
1549
- &canInferFromOtherAssociatedType,
1550
- conformance, witness)) {
1547
+ switch (checkInferenceCandidate (&result, conformance, witness)) {
1551
1548
case InferenceCandidateKind::Good:
1552
1549
// Continued below.
1553
1550
break ;
@@ -1588,23 +1585,19 @@ AssociatedTypeInference::getPotentialTypeWitnessesFromRequirement(
1588
1585
}
1589
1586
}
1590
1587
1591
- // If we same-typed to another unresolved associated type, we won't
1592
- // be able to check conformances yet.
1593
- if (!canInferFromOtherAssociatedType) {
1594
- // Check that the type witness meets the
1595
- // requirements on the associated type.
1596
- if (auto failed =
1597
- checkTypeWitness (result.second , result.first , conformance,
1598
- llvm::None)) {
1599
- witnessResult.NonViable .push_back (
1600
- std::make_tuple (result.first ,result.second ,failed));
1601
- LLVM_DEBUG (llvm::dbgs () << " -- doesn't fulfill requirements\n " );
1602
-
1603
- // By adding an element to NonViable we ensure the witness is rejected
1604
- // below, so we continue to consider other bindings to generate better
1605
- // diagnostics later.
1606
- REJECT;
1607
- }
1588
+ // Check that the type witness meets the requirements on the
1589
+ // associated type.
1590
+ if (auto failed =
1591
+ checkTypeWitness (result.second , result.first , conformance,
1592
+ llvm::None)) {
1593
+ witnessResult.NonViable .push_back (
1594
+ std::make_tuple (result.first ,result.second ,failed));
1595
+ LLVM_DEBUG (llvm::dbgs () << " -- doesn't fulfill requirements\n " );
1596
+
1597
+ // By adding an element to NonViable we ensure the witness is rejected
1598
+ // below, so we continue to consider other bindings to generate better
1599
+ // diagnostics later.
1600
+ REJECT;
1608
1601
}
1609
1602
1610
1603
LLVM_DEBUG (llvm::dbgs () << " ++ seems legit\n " );
@@ -2286,6 +2279,8 @@ AssociatedTypeInference::computeDerivedTypeWitness(
2286
2279
if (!result.first )
2287
2280
return std::make_pair (Type (), nullptr );
2288
2281
2282
+ assert (!containsConcreteDependentMemberType (result.first ));
2283
+
2289
2284
// Make sure that the derived type satisfies requirements.
2290
2285
if (checkTypeWitness (result.first , assocType, conformance, llvm::None)) {
2291
2286
// / FIXME: Diagnose based on this.
@@ -2649,15 +2644,6 @@ bool AssociatedTypeInference::checkConstrainedExtension(ExtensionDecl *ext) {
2649
2644
llvm_unreachable (" unhandled result" );
2650
2645
}
2651
2646
2652
- static bool containsConcreteDependentMemberType (Type ty) {
2653
- return ty.findIf ([](Type t) -> bool {
2654
- if (auto *dmt = t->getAs <DependentMemberType>())
2655
- return !dmt->isTypeParameter ();
2656
-
2657
- return false ;
2658
- });
2659
- }
2660
-
2661
2647
AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses (
2662
2648
ArrayRef<AssociatedTypeDecl *> unresolvedAssocTypes, unsigned reqDepth) {
2663
2649
if (unresolvedAssocTypes.empty ()) {
@@ -3560,16 +3546,6 @@ bool AssociatedTypeInference::diagnoseNoSolutions(
3560
3546
proto->getDeclaredInterfaceType (),
3561
3547
failedDefaultedResult.getRequirement ());
3562
3548
break ;
3563
-
3564
- case CheckTypeWitnessResult::Tuple:
3565
- diags.diagnose (
3566
- failedDefaultedAssocType,
3567
- diag::default_associated_type_tuple,
3568
- failedDefaultedWitness,
3569
- failedDefaultedAssocType,
3570
- proto->getDeclaredInterfaceType (),
3571
- failedDefaultedResult.getRequirement ());
3572
- break ;
3573
3549
}
3574
3550
});
3575
3551
@@ -3675,14 +3651,6 @@ bool AssociatedTypeInference::diagnoseNoSolutions(
3675
3651
assocType, failed.TypeWitness ,
3676
3652
failed.Result .getRequirement ());
3677
3653
break ;
3678
-
3679
- case CheckTypeWitnessResult::Tuple:
3680
- diags.diagnose (
3681
- failed.Witness ,
3682
- diag::associated_type_deduction_tuple,
3683
- assocType, failed.TypeWitness ,
3684
- failed.Result .getRequirement ());
3685
- break ;
3686
3654
}
3687
3655
}
3688
3656
});
0 commit comments