@@ -267,49 +267,157 @@ OpaqueResultTypeRequest::evaluate(Evaluator &evaluator,
267267 return opaqueDecl;
268268}
269269
270- // / Determine whether the given type is \c Self, an associated type of \c Self,
271- // / or a concrete type.
272- static bool isSelfDerivedOrConcrete (Type protoSelf, Type type) {
273- // Check for a concrete type.
274- if (!type->hasTypeParameter ())
275- return true ;
270+ static bool checkProtocolSelfRequirementsImpl (
271+ ASTContext &ctx, ProtocolDecl *proto, ValueDecl *decl,
272+ GenericSignature originalSig,
273+ GenericSignature effectiveSig,
274+ bool downgrade,
275+ bool *hasSameTypeRequirement) {
276+ if (hasSameTypeRequirement)
277+ *hasSameTypeRequirement = false ;
278+
279+ for (auto req : effectiveSig.getRequirements ()) {
280+ if (req.getKind () == RequirementKind::SameType)
281+ if (hasSameTypeRequirement)
282+ *hasSameTypeRequirement = true ;
283+
284+ // The conformance of 'Self' to the protocol is okay.
285+ if (req.getKind () == RequirementKind::Conformance &&
286+ req.getProtocolDecl () == proto &&
287+ req.getFirstType ()->isEqual (ctx.TheSelfType ))
288+ continue ;
289+
290+ auto isSelfDerived = [&](Type t) -> bool {
291+ return t->getRootGenericParam ()->isEqual (ctx.TheSelfType );
292+ };
293+
294+ // If the requirement's subject type is rooted in an inner generic
295+ // parameter, this requirement is okay.
296+ if (!isSelfDerived (req.getFirstType ()))
297+ continue ;
298+
299+ Type firstType = req.getFirstType ();
300+ Type secondType;
301+ if (req.getKind () == RequirementKind::Layout)
302+ secondType = ctx.getAnyObjectConstraint ();
303+ else
304+ secondType = req.getSecondType ();
276305
277- if (type->isTypeParameter () &&
278- type->getRootGenericParam ()->isEqual (protoSelf))
306+ // Self.A.B == <<inner generic parameter>> is OK.
307+ if (req.getKind () == RequirementKind::SameType &&
308+ secondType->isTypeParameter () &&
309+ !isSelfDerived (secondType))
310+ continue ;
311+
312+ // Anything else is a new requirement on 'Self', which is not allowed.
313+
314+ // Downgrade even harder in this case, since the old logic always missed it.
315+ if (secondType->hasTypeParameter () && !secondType->isTypeParameter ())
316+ downgrade = true ;
317+
318+ // Re-sugar the types, since effectiveSig might be canonical.
319+ firstType = originalSig->getSugaredType (firstType);
320+ secondType = originalSig->getSugaredType (secondType);
321+ static_assert ((unsigned )RequirementKind::LAST_KIND == 4 ,
322+ " update %select in diagnostic!" );
323+
324+ ctx.Diags .diagnose (decl, diag::requirement_restricts_self, decl,
325+ firstType.getString (),
326+ static_cast <unsigned >(req.getKind ()),
327+ secondType.getString ())
328+ // FIXME: This should become an unconditional error since violating
329+ // this invariant can introduce compiler and run time crashes.
330+ .warnUntilFutureSwiftVersionIf (downgrade);
279331 return true ;
332+ }
280333
281334 return false ;
282335}
283336
284337// For a generic requirement in a protocol, make sure that the requirement
285338// set didn't add any requirements to Self or its associated types.
286339void TypeChecker::checkProtocolSelfRequirements (ValueDecl *decl) {
287- // For a generic requirement in a protocol, make sure that the requirement
288- // set didn't add any requirements to Self or its associated types.
340+ // Make sure the generic signature of a protocol method doesn't
341+ // impose any new requirements on Self or one of its member types.
289342 if (auto *proto = dyn_cast<ProtocolDecl>(decl->getDeclContext ())) {
343+ auto *genCtx = decl->getAsGenericContext ();
344+ ASSERT (genCtx != nullptr );
345+
346+ // If it's not generic and it doesn't have a where clause, there is
347+ // nothing to check.
348+ if (!genCtx->getGenericParams () && !genCtx->getTrailingWhereClause ())
349+ return ;
350+
290351 auto &ctx = proto->getASTContext ();
291- auto protoSelf = proto->getSelfInterfaceType ();
292- auto sig = decl->getInnermostDeclContext ()->getGenericSignatureOfContext ();
352+ auto sig = genCtx->getGenericSignature ();
353+
354+ bool hasSameTypeRequirement = false ;
355+
356+ // Perform the check as it was formerly implemented first, by looking at
357+ // the syntactic requirements of the original generic signature.
358+ if (checkProtocolSelfRequirementsImpl (ctx, proto, decl, sig, sig,
359+ /* downgrade=*/ false ,
360+ &hasSameTypeRequirement)) {
361+ return ;
362+ }
363+
364+ // If the generic signature was sufficiently simple, we're done.
365+ if (!hasSameTypeRequirement)
366+ return ;
367+
368+ // The quick check doesn't catch everything when same-type requirements
369+ // are involved, so the correct thing is to build a new signature where
370+ // the innermost generic parameters added by the protocol method now have
371+ // a non-zero weight. In this signature, any type that can be made
372+ // equivalent to a member type of Self will have a reduced type rooted
373+ // in Self.
374+ SmallVector<GenericTypeParamType *, 2 > params;
375+ SmallVector<Requirement, 2 > reqs;
376+
377+ auto transformParam = [&](GenericTypeParamType *paramTy)
378+ -> GenericTypeParamType * {
379+ if (paramTy->getDepth () == sig->getMaxDepth ()) {
380+ return GenericTypeParamType::get (
381+ paramTy->getParamKind (),
382+ paramTy->getDepth (),
383+ paramTy->getIndex (),
384+ /* weight=*/ 1 ,
385+ paramTy->getValueType (), ctx);
386+ }
387+
388+ return cast<GenericTypeParamType>(paramTy->getCanonicalType ());
389+ };
390+
391+ for (auto *paramTy : sig.getGenericParams ())
392+ params.push_back (transformParam (paramTy));
393+
394+ auto transformType = [&](Type t) -> Type {
395+ return t.transformRec ([&](TypeBase *t) -> std::optional<Type> {
396+ if (auto *paramTy = dyn_cast<GenericTypeParamType>(t))
397+ return transformParam (paramTy);
398+
399+ return std::nullopt ;
400+ })->getCanonicalType ();
401+ };
402+
293403 for (auto req : sig.getRequirements ()) {
294- // If one of the types in the requirement is dependent on a non-Self
295- // type parameter, this requirement is okay.
296- if (!isSelfDerivedOrConcrete (protoSelf, req.getFirstType ()) ||
297- !isSelfDerivedOrConcrete (protoSelf, req.getSecondType ()))
298- continue ;
299-
300- // The conformance of 'Self' to the protocol is okay.
301- if (req.getKind () == RequirementKind::Conformance &&
302- req.getProtocolDecl () == proto &&
303- req.getFirstType ()->is <GenericTypeParamType>())
304- continue ;
305-
306- static_assert ((unsigned )RequirementKind::LAST_KIND == 4 ,
307- " update %select in diagnostic!" );
308- ctx.Diags .diagnose (decl, diag::requirement_restricts_self, decl,
309- req.getFirstType ().getString (),
310- static_cast <unsigned >(req.getKind ()),
311- req.getSecondType ().getString ());
404+ if (req.getKind () != RequirementKind::Layout) {
405+ reqs.emplace_back (req.getKind (),
406+ transformType (req.getFirstType ()),
407+ transformType (req.getSecondType ()));
408+ } else {
409+ reqs.emplace_back (req.getKind (),
410+ transformType (req.getFirstType ()),
411+ req.getLayoutConstraint ());
412+ }
312413 }
414+
415+ auto weightedSig = buildGenericSignature (
416+ ctx, GenericSignature (), params, reqs, /* allowInverses=*/ false );
417+
418+ // Repeat the check with the new signature.
419+ checkProtocolSelfRequirementsImpl (ctx, proto, decl, sig, weightedSig,
420+ /* downgrade=*/ true , nullptr );
313421 }
314422}
315423
0 commit comments