@@ -267,49 +267,157 @@ OpaqueResultTypeRequest::evaluate(Evaluator &evaluator,
267
267
return opaqueDecl;
268
268
}
269
269
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 ();
276
305
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);
279
331
return true ;
332
+ }
280
333
281
334
return false ;
282
335
}
283
336
284
337
// For a generic requirement in a protocol, make sure that the requirement
285
338
// set didn't add any requirements to Self or its associated types.
286
339
void 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.
289
342
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
+
290
351
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
+
293
403
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
+ }
312
413
}
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 );
313
421
}
314
422
}
315
423
0 commit comments