1818#include " swift/SIL/SILUndef.h"
1919#include " swift/AST/ASTContext.h"
2020#include " swift/AST/AnyFunctionRef.h"
21+ #include " swift/AST/ConformanceLookup.h"
2122#include " swift/AST/Decl.h"
2223#include " swift/AST/GenericEnvironment.h"
2324#include " swift/AST/Pattern.h"
@@ -307,18 +308,106 @@ bool SILModule::isTypeMetadataForLayoutAccessible(SILType type) {
307308 return ::isTypeMetadataForLayoutAccessible (*this , type);
308309}
309310
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+
311398 // Visit lowered positions.
312399 if (auto tupleTy = ty->getAs <TupleType>()) {
313400 for (auto eltTy : tupleTy->getElementTypes ()) {
314401 if (eltTy->is <PackExpansionType>())
315- return true ;
402+ return std:: nullopt ;
316403
317- if (isUnsupportedKeyPathValueType (eltTy))
318- return true ;
404+ contextSig = getKeyPathSupportingGenericSignatureForValueType (
405+ eltTy, *contextSig);
406+ if (!contextSig)
407+ return std::nullopt ;
319408 }
320409
321- return false ;
410+ return contextSig ;
322411 }
323412
324413 if (auto objTy = ty->getOptionalObjectType ())
@@ -330,66 +419,78 @@ static bool isUnsupportedKeyPathValueType(Type ty) {
330419 for (auto param : funcTy->getParams ()) {
331420 auto paramTy = param.getPlainType ();
332421 if (paramTy->is <PackExpansionType>())
333- return true ;
422+ return std:: nullopt ;
334423
335- if (isUnsupportedKeyPathValueType (paramTy))
336- return true ;
424+ contextSig = getKeyPathSupportingGenericSignatureForValueType (paramTy,
425+ *contextSig);
426+ if (!contextSig) {
427+ return std::nullopt ;
428+ }
337429 }
338430
339- if (isUnsupportedKeyPathValueType (funcTy->getResult ()))
340- return true ;
431+ contextSig = getKeyPathSupportingGenericSignatureForValueType (funcTy->getResult (),
432+ *contextSig);
433+
434+ if (!contextSig) {
435+ return std::nullopt ;
436+ }
341437 }
342438
343439 // Noncopyable types aren't supported by key paths in their current form.
344440 // They would also need a new ABI that's yet to be implemented in order to
345441 // be properly supported, so let's suppress the descriptor for now if either
346442 // 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);
351444}
352445
353- bool AbstractStorageDecl::exportsPropertyDescriptor () const {
446+ std::optional<GenericSignature>
447+ AbstractStorageDecl::getPropertyDescriptorGenericSignature () const {
354448 // 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 .
356450
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 ;
362462 }
463+ contextSig = *ceContextSig;
363464 }
364465
365466 // TODO: Global properties ought to eventually be referenceable
366467 // as key paths from ().
367468 if (!getDeclContext ()->isTypeContext ())
368- return false ;
469+ return std:: nullopt ;
369470
370471 // Protocol requirements do not need property descriptors.
371472 if (isa<ProtocolDecl>(getDeclContext ()))
372- return false ;
473+ return std:: nullopt ;
373474
374475 // Static properties declared directly in protocol do not need
375476 // descriptors as existential Any.Type will not resolve to a value.
376477 if (isStatic () && isa<ProtocolDecl>(getDeclContext ()))
377- return false ;
478+ return std:: nullopt ;
378479
379480 // FIXME: We should support properties and subscripts with '_read' accessors;
380481 // 'get' is not part of the opaque accessor set there.
381482 auto *getter = getOpaqueAccessor (AccessorKind::Get);
382483 if (!getter)
383- return false ;
484+ return std:: nullopt ;
384485
385486 // If the getter is mutating, we cannot form a keypath to it at all.
386487 if (isGetterMutating ())
387- return false ;
488+ return std:: nullopt ;
388489
389490 // If the storage is an ABI-compatible override of another declaration, we're
390491 // not going to be emitting a property descriptor either.
391492 if (!isValidKeyPathComponent ())
392- return false ;
493+ return std:: nullopt ;
393494
394495 // TODO: If previous versions of an ABI-stable binary needed the descriptor,
395496 // then we still do.
@@ -409,27 +510,30 @@ bool AbstractStorageDecl::exportsPropertyDescriptor() const {
409510 case SILLinkage::Private:
410511 case SILLinkage::Hidden:
411512 // Don't need a public descriptor.
412- return false ;
513+ return std:: nullopt ;
413514
414515 case SILLinkage::HiddenExternal:
415516 case SILLinkage::PublicExternal:
416517 case SILLinkage::PackageExternal:
417518 llvm_unreachable (" should be definition linkage?" );
418519 }
419520
420- auto typeInContext = getInnermostDeclContext ()->mapTypeIntoContext (
521+ auto typeInContext = contextSig. getGenericEnvironment ()->mapTypeIntoContext (
421522 getValueInterfaceType ());
422- if (isUnsupportedKeyPathValueType (typeInContext)) {
423- return false ;
523+ auto valueTypeSig = getKeyPathSupportingGenericSignatureForValueType (typeInContext, contextSig);
524+ if (!valueTypeSig) {
525+ return std::nullopt ;
424526 }
527+ contextSig = *valueTypeSig;
425528
426529 // Subscripts with inout arguments (FIXME)and reabstracted arguments(/FIXME)
427530 // don't have descriptors either.
428531 if (auto sub = dyn_cast<SubscriptDecl>(this )) {
429532 for (auto *index : *sub->getIndices ()) {
430533 // Keypaths can't capture inout indices.
431- if (index->isInOut ())
432- return false ;
534+ if (index->isInOut ()) {
535+ return std::nullopt ;
536+ }
433537
434538 auto indexTy = index->getInterfaceType ()
435539 ->getReducedType (sub->getGenericSignatureOfContext ());
@@ -439,17 +543,17 @@ bool AbstractStorageDecl::exportsPropertyDescriptor() const {
439543 // had only one abstraction level and no explosion.
440544
441545 if (isa<TupleType>(indexTy))
442- return false ;
546+ return std:: nullopt ;
443547
444548 auto indexObjTy = indexTy;
445549 if (auto objTy = indexObjTy.getOptionalObjectType ())
446550 indexObjTy = objTy;
447551
448552 if (isa<AnyFunctionType>(indexObjTy)
449553 || isa<AnyMetatypeType>(indexObjTy))
450- return false ;
554+ return std:: nullopt ;
451555 }
452556 }
453557
454- return true ;
558+ return contextSig ;
455559}
0 commit comments