18
18
#include " swift/SIL/SILUndef.h"
19
19
#include " swift/AST/ASTContext.h"
20
20
#include " swift/AST/AnyFunctionRef.h"
21
+ #include " swift/AST/ConformanceLookup.h"
21
22
#include " swift/AST/Decl.h"
22
23
#include " swift/AST/GenericEnvironment.h"
23
24
#include " swift/AST/Pattern.h"
@@ -307,18 +308,106 @@ bool SILModule::isTypeMetadataForLayoutAccessible(SILType type) {
307
308
return ::isTypeMetadataForLayoutAccessible (*this , type);
308
309
}
309
310
310
- static bool isUnsupportedKeyPathValueType (Type ty) {
311
+ // Given the type `ty`, which should be in the generic environment of the signature
312
+ // `sig`, return a generic signature with all of the requirements of `sig`,
313
+ // combined with all of the requirements necessary for `ty` to be both
314
+ // `Copyable` and `Escapable`, if possible. Returns `nullopt` if the type
315
+ // can never be both Copyable and Escapable.
316
+ static std::optional<GenericSignature>
317
+ getKeyPathSupportingGenericSignature (Type ty, GenericSignature contextSig) {
318
+ auto &C = ty->getASTContext ();
319
+
320
+ // If the type is already unconditionally Copyable and Escapable, we don't
321
+ // need any further requirements.
322
+ if (!ty->isNoncopyable () && ty->isEscapable ()) {
323
+ return contextSig;
324
+ }
325
+
326
+ ProtocolConformanceRef copyable, escapable;
327
+ auto copyableProtocol = C.getProtocol (KnownProtocolKind::Copyable);
328
+ auto escapableProtocol = C.getProtocol (KnownProtocolKind::Escapable);
329
+
330
+ // If the type is an archetype, then it just needs Copyable and Escapable
331
+ // constraints imposed.
332
+ if (ty->is <ArchetypeType>()) {
333
+ copyable = ProtocolConformanceRef::forAbstract (ty->mapTypeOutOfContext (),
334
+ copyableProtocol);
335
+ escapable = ProtocolConformanceRef::forAbstract (ty->mapTypeOutOfContext (),
336
+ escapableProtocol);
337
+ } else {
338
+ // Look for any conditional conformances.
339
+ copyable = lookupConformance (ty, copyableProtocol);
340
+ escapable = lookupConformance (ty, escapableProtocol);
341
+ }
342
+
343
+ // If the type is never copyable or escapable, that's it.
344
+ if (copyable.isInvalid () || escapable.isInvalid ()) {
345
+ return std::nullopt;
346
+ }
347
+
348
+ // Otherwise, let's see if we get a viable generic signature combining the
349
+ // requirements for those conformances with the requirements of the
350
+ // declaration context.
351
+ SmallVector<Requirement, 2 > ceRequirements;
352
+
353
+ auto getRequirementsFromConformance = [&](ProtocolConformanceRef ref) {
354
+ if (ref.isAbstract ()) {
355
+ // The only requirements are that the abstract type itself be copyable
356
+ // and escapable.
357
+ ceRequirements.push_back (Requirement (RequirementKind::Conformance,
358
+ ty->mapTypeOutOfContext (), copyableProtocol->getDeclaredType ()));
359
+ ceRequirements.push_back (Requirement (RequirementKind::Conformance,
360
+ ty->mapTypeOutOfContext (), escapableProtocol->getDeclaredType ()));
361
+ return ;
362
+ }
363
+
364
+ if (!ref.isConcrete ()) {
365
+ return ;
366
+ }
367
+ auto conformance = ref.getConcrete ();
368
+
369
+ for (auto reqt : conformance->getRootConformance ()
370
+ ->getConditionalRequirements ()) {
371
+ ceRequirements.push_back (reqt);
372
+ }
373
+ };
374
+ getRequirementsFromConformance (copyable);
375
+ getRequirementsFromConformance (escapable);
376
+
377
+ auto regularSignature = buildGenericSignatureWithError (C,
378
+ contextSig,
379
+ {},
380
+ std::move (ceRequirements),
381
+ /* allowInverses*/ false );
382
+
383
+ // If the resulting signature has conflicting requirements, then it is
384
+ // impossible for the type to be copyable and equatable.
385
+ if (regularSignature.getInt ()) {
386
+ return std::nullopt;
387
+ }
388
+
389
+ // Otherwise, we have the signature we're looking for.
390
+ return regularSignature.getPointer ();
391
+ }
392
+
393
+ static std::optional<GenericSignature>
394
+ getKeyPathSupportingGenericSignatureForValueType (Type ty,
395
+ GenericSignature sig) {
396
+ std::optional<GenericSignature> contextSig = sig;
397
+
311
398
// Visit lowered positions.
312
399
if (auto tupleTy = ty->getAs <TupleType>()) {
313
400
for (auto eltTy : tupleTy->getElementTypes ()) {
314
401
if (eltTy->is <PackExpansionType>())
315
- return true ;
402
+ return std::nullopt ;
316
403
317
- if (isUnsupportedKeyPathValueType (eltTy))
318
- return true ;
404
+ contextSig = getKeyPathSupportingGenericSignatureForValueType (
405
+ eltTy, *contextSig);
406
+ if (!contextSig)
407
+ return std::nullopt;
319
408
}
320
409
321
- return false ;
410
+ return contextSig ;
322
411
}
323
412
324
413
if (auto objTy = ty->getOptionalObjectType ())
@@ -330,66 +419,78 @@ static bool isUnsupportedKeyPathValueType(Type ty) {
330
419
for (auto param : funcTy->getParams ()) {
331
420
auto paramTy = param.getPlainType ();
332
421
if (paramTy->is <PackExpansionType>())
333
- return true ;
422
+ return std::nullopt ;
334
423
335
- if (isUnsupportedKeyPathValueType (paramTy))
336
- return true ;
424
+ contextSig = getKeyPathSupportingGenericSignatureForValueType (paramTy,
425
+ *contextSig);
426
+ if (!contextSig) {
427
+ return std::nullopt;
428
+ }
337
429
}
338
430
339
- if (isUnsupportedKeyPathValueType (funcTy->getResult ()))
340
- return true ;
431
+ contextSig = getKeyPathSupportingGenericSignatureForValueType (funcTy->getResult (),
432
+ *contextSig);
433
+
434
+ if (!contextSig) {
435
+ return std::nullopt;
436
+ }
341
437
}
342
438
343
439
// Noncopyable types aren't supported by key paths in their current form.
344
440
// They would also need a new ABI that's yet to be implemented in order to
345
441
// be properly supported, so let's suppress the descriptor for now if either
346
442
// the container or storage type of the declaration is non-copyable.
347
- if (ty->isNoncopyable ())
348
- return true ;
349
-
350
- return false ;
443
+ return getKeyPathSupportingGenericSignature (ty, *contextSig);
351
444
}
352
445
353
- bool AbstractStorageDecl::exportsPropertyDescriptor () const {
446
+ std::optional<GenericSignature>
447
+ AbstractStorageDecl::getPropertyDescriptorGenericSignature () const {
354
448
// The storage needs a descriptor if it sits at a module's ABI boundary,
355
- // meaning it has public linkage.
449
+ // meaning it has public linkage, and it is eligible to be part of a key path .
356
450
357
- if (!isStatic ()) {
358
- if (auto contextTy = getDeclContext ()->getDeclaredTypeInContext ()) {
359
- if (contextTy->isNoncopyable ()) {
360
- return false ;
361
- }
451
+ auto contextTy = getDeclContext ()->getDeclaredTypeInContext ();
452
+ auto contextSig = getInnermostDeclContext ()->getGenericSignatureOfContext ();
453
+
454
+ // If the root type is never `Copyable` or `Escapable`, then instance
455
+ // members can't be used in key paths, at least as they are implemented
456
+ // today.
457
+ if (!isStatic () && contextTy) {
458
+ auto ceContextSig = getKeyPathSupportingGenericSignature (contextTy,
459
+ contextSig);
460
+ if (!ceContextSig) {
461
+ return std::nullopt;
362
462
}
463
+ contextSig = *ceContextSig;
363
464
}
364
465
365
466
// TODO: Global properties ought to eventually be referenceable
366
467
// as key paths from ().
367
468
if (!getDeclContext ()->isTypeContext ())
368
- return false ;
469
+ return std::nullopt ;
369
470
370
471
// Protocol requirements do not need property descriptors.
371
472
if (isa<ProtocolDecl>(getDeclContext ()))
372
- return false ;
473
+ return std::nullopt ;
373
474
374
475
// Static properties declared directly in protocol do not need
375
476
// descriptors as existential Any.Type will not resolve to a value.
376
477
if (isStatic () && isa<ProtocolDecl>(getDeclContext ()))
377
- return false ;
478
+ return std::nullopt ;
378
479
379
480
// FIXME: We should support properties and subscripts with '_read' accessors;
380
481
// 'get' is not part of the opaque accessor set there.
381
482
auto *getter = getOpaqueAccessor (AccessorKind::Get);
382
483
if (!getter)
383
- return false ;
484
+ return std::nullopt ;
384
485
385
486
// If the getter is mutating, we cannot form a keypath to it at all.
386
487
if (isGetterMutating ())
387
- return false ;
488
+ return std::nullopt ;
388
489
389
490
// If the storage is an ABI-compatible override of another declaration, we're
390
491
// not going to be emitting a property descriptor either.
391
492
if (!isValidKeyPathComponent ())
392
- return false ;
493
+ return std::nullopt ;
393
494
394
495
// TODO: If previous versions of an ABI-stable binary needed the descriptor,
395
496
// then we still do.
@@ -409,27 +510,30 @@ bool AbstractStorageDecl::exportsPropertyDescriptor() const {
409
510
case SILLinkage::Private:
410
511
case SILLinkage::Hidden:
411
512
// Don't need a public descriptor.
412
- return false ;
513
+ return std::nullopt ;
413
514
414
515
case SILLinkage::HiddenExternal:
415
516
case SILLinkage::PublicExternal:
416
517
case SILLinkage::PackageExternal:
417
518
llvm_unreachable (" should be definition linkage?" );
418
519
}
419
520
420
- auto typeInContext = getInnermostDeclContext ()->mapTypeIntoContext (
521
+ auto typeInContext = contextSig. getGenericEnvironment ()->mapTypeIntoContext (
421
522
getValueInterfaceType ());
422
- if (isUnsupportedKeyPathValueType (typeInContext)) {
423
- return false ;
523
+ auto valueTypeSig = getKeyPathSupportingGenericSignatureForValueType (typeInContext, contextSig);
524
+ if (!valueTypeSig) {
525
+ return std::nullopt;
424
526
}
527
+ contextSig = *valueTypeSig;
425
528
426
529
// Subscripts with inout arguments (FIXME)and reabstracted arguments(/FIXME)
427
530
// don't have descriptors either.
428
531
if (auto sub = dyn_cast<SubscriptDecl>(this )) {
429
532
for (auto *index : *sub->getIndices ()) {
430
533
// Keypaths can't capture inout indices.
431
- if (index->isInOut ())
432
- return false ;
534
+ if (index->isInOut ()) {
535
+ return std::nullopt;
536
+ }
433
537
434
538
auto indexTy = index->getInterfaceType ()
435
539
->getReducedType (sub->getGenericSignatureOfContext ());
@@ -439,17 +543,17 @@ bool AbstractStorageDecl::exportsPropertyDescriptor() const {
439
543
// had only one abstraction level and no explosion.
440
544
441
545
if (isa<TupleType>(indexTy))
442
- return false ;
546
+ return std::nullopt ;
443
547
444
548
auto indexObjTy = indexTy;
445
549
if (auto objTy = indexObjTy.getOptionalObjectType ())
446
550
indexObjTy = objTy;
447
551
448
552
if (isa<AnyFunctionType>(indexObjTy)
449
553
|| isa<AnyMetatypeType>(indexObjTy))
450
- return false ;
554
+ return std::nullopt ;
451
555
}
452
556
}
453
557
454
- return true ;
558
+ return contextSig ;
455
559
}
0 commit comments