Skip to content

Commit e22fc3e

Browse files
authored
Merge pull request #60345 from xedin/type-wrappers
[TypeChecker] Type wrappers (experimental feature)
2 parents a21984e + 491defb commit e22fc3e

22 files changed

+2131
-73
lines changed

include/swift/AST/Attr.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,11 @@ DECL_ATTR(_expose, Expose,
763763
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
764764
133)
765765

766+
SIMPLE_DECL_ATTR(typeWrapper, TypeWrapper,
767+
OnStruct | OnClass | OnEnum |
768+
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
769+
134)
770+
766771
// If you're adding a new underscored attribute here, please document it in
767772
// docs/ReferenceGuides/UnderscoredAttributes.md.
768773

include/swift/AST/Decl.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3754,6 +3754,21 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
37543754
return getGlobalActorInstance() != nullptr;
37553755
}
37563756

3757+
/// Returns true if this type has a type wrapper custom attribute.
3758+
bool hasTypeWrapper() const { return bool(getTypeWrapper()); }
3759+
3760+
/// Return a type wrapper (if any) associated with this type.
3761+
NominalTypeDecl *getTypeWrapper() const;
3762+
3763+
/// If this declaration has a type wrapper return a property that
3764+
/// is used for all type wrapper related operations (mainly for
3765+
/// applicable property access routing).
3766+
VarDecl *getTypeWrapperProperty() const;
3767+
3768+
/// Get an initializer that could be used to instantiate a
3769+
/// type wrapped type.
3770+
ConstructorDecl *getTypeWrapperInitializer() const;
3771+
37573772
// Implement isa/cast/dyncast/etc.
37583773
static bool classof(const Decl *D) {
37593774
return D->getKind() >= DeclKind::First_NominalTypeDecl &&
@@ -5549,7 +5564,18 @@ class VarDecl : public AbstractStorageDecl {
55495564
/// Return true if this property either has storage or has an attached property
55505565
/// wrapper that has storage.
55515566
bool hasStorageOrWrapsStorage() const;
5552-
5567+
5568+
/// Whether this property belongs to a type wrapped type and has
5569+
/// all access to it routed through a type wrapper.
5570+
bool isAccessedViaTypeWrapper() const;
5571+
5572+
/// For type wrapped properties (see \c isAccessedViaTypeWrapper)
5573+
/// all access is routed through a type wrapper.
5574+
///
5575+
/// \returns an underlying type wrapper property which is a
5576+
/// storage endpoint for all access to this property.
5577+
VarDecl *getUnderlyingTypeWrapperStorage() const;
5578+
55535579
/// Visit all auxiliary declarations to this VarDecl.
55545580
///
55555581
/// An auxiliary declaration is a declaration synthesized by the compiler to support

include/swift/AST/DiagnosticsSema.def

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6479,5 +6479,46 @@ ERROR(moveOnly_not_allowed_here,none,
64796479
ERROR(move_expression_not_passed_lvalue,none,
64806480
"'move' can only be applied to lvalues", ())
64816481

6482+
//------------------------------------------------------------------------------
6483+
// MARK: Type Wrappers
6484+
//------------------------------------------------------------------------------
6485+
6486+
ERROR(type_wrappers_are_experimental,none,
6487+
"type wrappers are an experimental feature", ())
6488+
6489+
ERROR(type_wrapper_attribute_not_allowed_here,none,
6490+
"type wrapper attribute %0 can only be applied to a class, struct",
6491+
(Identifier))
6492+
6493+
ERROR(type_wrapper_requires_a_single_generic_param,none,
6494+
"type wrapper has to declare a single generic parameter "
6495+
"for underlying storage type", ())
6496+
6497+
ERROR(cannot_use_multiple_type_wrappers,none,
6498+
"type %0 cannot use more than one type wrapper", ())
6499+
6500+
ERROR(type_wrapper_requires_memberwise_init,none,
6501+
"type wrapper type %0 does not contain a required initializer"
6502+
" - init(memberwise:)",
6503+
(DeclName))
6504+
6505+
ERROR(type_wrapper_requires_subscript,none,
6506+
"type wrapper type %0 does not contain a required subscript"
6507+
" - subscript(storedKeyPath:)",
6508+
(DeclName))
6509+
6510+
ERROR(type_wrapper_failable_init,none,
6511+
"type wrapper initializer %0 cannot be failable", (DeclName))
6512+
6513+
ERROR(type_wrapper_invalid_subscript_param_type, none,
6514+
"type wrapper subscript expects a key path parameter type (got: %0)",
6515+
(Type))
6516+
6517+
ERROR(type_wrapper_type_requirement_not_accessible,none,
6518+
"%select{private|fileprivate|internal|public|open}0 %1 %2 cannot have "
6519+
"more restrictive access than its enclosing type wrapper type %3 "
6520+
"(which is %select{private|fileprivate|internal|public|open}4)",
6521+
(AccessLevel, DescriptiveDeclKind, DeclName, Type, AccessLevel))
6522+
64826523
#define UNDEFINE_DIAGNOSTIC_MACROS
64836524
#include "DefineDiagnosticMacros.h"

include/swift/AST/KnownIdentifiers.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,12 @@ IDENTIFIER(decodeNextArgument)
307307
IDENTIFIER(SerializationRequirement)
308308
IDENTIFIER_WITH_NAME(builderSelf, "$builderSelf")
309309

310+
// Type wrappers
311+
IDENTIFIER_WITH_NAME(TypeWrapperStorage, "$Storage")
312+
IDENTIFIER_WITH_NAME(TypeWrapperProperty, "$_storage")
313+
IDENTIFIER(storageKeyPath)
314+
IDENTIFIER(memberwise)
315+
310316
#undef IDENTIFIER
311317
#undef IDENTIFIER_
312318
#undef IDENTIFIER_WITH_NAME

include/swift/AST/TypeCheckRequests.h

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3364,6 +3364,10 @@ enum class CustomAttrTypeKind {
33643364
/// unbound generic types.
33653365
PropertyWrapper,
33663366

3367+
/// Just like property wrappers, type wrappers are represented
3368+
/// as custom type attributes and allow unbound generic types.
3369+
TypeWrapper,
3370+
33673371
/// Global actors are represented as custom type attributes. They don't
33683372
/// have any particularly interesting semantics.
33693373
GlobalActor,
@@ -3499,6 +3503,174 @@ class GetSourceFileAsyncNode
34993503
bool isCached() const { return true; }
35003504
};
35013505

3506+
/// Return a type wrapper (if any) associated with the given declaration.
3507+
class GetTypeWrapper
3508+
: public SimpleRequest<GetTypeWrapper, NominalTypeDecl *(NominalTypeDecl *),
3509+
RequestFlags::Cached> {
3510+
public:
3511+
using SimpleRequest::SimpleRequest;
3512+
3513+
private:
3514+
friend SimpleRequest;
3515+
3516+
NominalTypeDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *) const;
3517+
3518+
public:
3519+
bool isCached() const { return true; }
3520+
};
3521+
3522+
/// Return a type of the type wrapper (if any) associated with the given
3523+
/// declaration.
3524+
class GetTypeWrapperType
3525+
: public SimpleRequest<GetTypeWrapperType, Type(NominalTypeDecl *),
3526+
RequestFlags::Cached> {
3527+
public:
3528+
using SimpleRequest::SimpleRequest;
3529+
3530+
private:
3531+
friend SimpleRequest;
3532+
3533+
Type evaluate(Evaluator &evaluator, NominalTypeDecl *) const;
3534+
3535+
public:
3536+
bool isCached() const { return true; }
3537+
};
3538+
3539+
/// Inject or get `$Storage` type which has all of the stored properties
3540+
/// of the given type with a type wrapper.
3541+
class GetTypeWrapperStorage
3542+
: public SimpleRequest<GetTypeWrapperStorage,
3543+
NominalTypeDecl *(NominalTypeDecl *),
3544+
RequestFlags::Cached> {
3545+
public:
3546+
using SimpleRequest::SimpleRequest;
3547+
3548+
private:
3549+
friend SimpleRequest;
3550+
3551+
NominalTypeDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *) const;
3552+
3553+
public:
3554+
bool isCached() const { return true; }
3555+
};
3556+
3557+
/// Inject or get `$_storage` property which is used to route accesses through
3558+
/// to all stored properties of a type that has a type wrapper.
3559+
class GetTypeWrapperProperty
3560+
: public SimpleRequest<GetTypeWrapperProperty, VarDecl *(NominalTypeDecl *),
3561+
RequestFlags::Cached> {
3562+
public:
3563+
using SimpleRequest::SimpleRequest;
3564+
3565+
private:
3566+
friend SimpleRequest;
3567+
3568+
VarDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *) const;
3569+
3570+
public:
3571+
bool isCached() const { return true; }
3572+
};
3573+
3574+
/// Given a stored property associated with a type wrapped type,
3575+
/// produce a property that mirrors it in the type wrapper context.
3576+
class GetTypeWrapperStorageForProperty
3577+
: public SimpleRequest<GetTypeWrapperStorageForProperty,
3578+
VarDecl *(VarDecl *), RequestFlags::Cached> {
3579+
public:
3580+
using SimpleRequest::SimpleRequest;
3581+
3582+
private:
3583+
friend SimpleRequest;
3584+
3585+
VarDecl *evaluate(Evaluator &evaluator, VarDecl *) const;
3586+
3587+
public:
3588+
bool isCached() const { return true; }
3589+
};
3590+
3591+
/// Synthesize the body of a getter for a stored property that belongs to
3592+
/// a type wrapped type.
3593+
class SynthesizeTypeWrappedPropertyGetterBody
3594+
: public SimpleRequest<SynthesizeTypeWrappedPropertyGetterBody,
3595+
BraceStmt *(AccessorDecl *), RequestFlags::Cached> {
3596+
public:
3597+
using SimpleRequest::SimpleRequest;
3598+
3599+
private:
3600+
friend SimpleRequest;
3601+
3602+
BraceStmt *evaluate(Evaluator &evaluator, AccessorDecl *) const;
3603+
3604+
public:
3605+
bool isCached() const { return true; }
3606+
};
3607+
3608+
/// Synthesize the body of a setter for a stored property that belongs to
3609+
/// a type wrapped type.
3610+
class SynthesizeTypeWrappedPropertySetterBody
3611+
: public SimpleRequest<SynthesizeTypeWrappedPropertySetterBody,
3612+
BraceStmt *(AccessorDecl *), RequestFlags::Cached> {
3613+
public:
3614+
using SimpleRequest::SimpleRequest;
3615+
3616+
private:
3617+
friend SimpleRequest;
3618+
3619+
BraceStmt *evaluate(Evaluator &evaluator, AccessorDecl *) const;
3620+
3621+
public:
3622+
bool isCached() const { return true; }
3623+
};
3624+
3625+
/// Inject or get `$Storage` type which has all of the stored properties
3626+
/// of the given type with a type wrapper.
3627+
class IsPropertyAccessedViaTypeWrapper
3628+
: public SimpleRequest<IsPropertyAccessedViaTypeWrapper, bool(VarDecl *),
3629+
RequestFlags::Cached> {
3630+
public:
3631+
using SimpleRequest::SimpleRequest;
3632+
3633+
private:
3634+
friend SimpleRequest;
3635+
3636+
bool evaluate(Evaluator &evaluator, VarDecl *) const;
3637+
3638+
public:
3639+
bool isCached() const { return true; }
3640+
};
3641+
3642+
class SynthesizeTypeWrapperInitializer
3643+
: public SimpleRequest<SynthesizeTypeWrapperInitializer,
3644+
ConstructorDecl *(NominalTypeDecl *),
3645+
RequestFlags::Cached> {
3646+
public:
3647+
using SimpleRequest::SimpleRequest;
3648+
3649+
private:
3650+
friend SimpleRequest;
3651+
3652+
ConstructorDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *) const;
3653+
3654+
public:
3655+
bool isCached() const { return true; }
3656+
};
3657+
3658+
class SynthesizeTypeWrapperInitializerBody
3659+
: public SimpleRequest<SynthesizeTypeWrapperInitializerBody,
3660+
BraceStmt *(ConstructorDecl *),
3661+
RequestFlags::Cached> {
3662+
public:
3663+
using SimpleRequest::SimpleRequest;
3664+
3665+
private:
3666+
friend SimpleRequest;
3667+
3668+
BraceStmt *evaluate(Evaluator &evaluator, ConstructorDecl *) const;
3669+
3670+
public:
3671+
bool isCached() const { return true; }
3672+
};
3673+
35023674
void simple_display(llvm::raw_ostream &out, ASTNode node);
35033675
void simple_display(llvm::raw_ostream &out, Type value);
35043676
void simple_display(llvm::raw_ostream &out, const TypeRepr *TyR);

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,3 +399,33 @@ SWIFT_REQUEST(TypeChecker, ClosureEffectsRequest,
399399
SWIFT_REQUEST(TypeChecker, GetSourceFileAsyncNode,
400400
AwaitExpr *(const SourceFile *),
401401
Cached, NoLocationInfo)
402+
SWIFT_REQUEST(TypeChecker, GetTypeWrapper,
403+
NominalTypeDecl *(NominalTypeDecl *),
404+
Cached, NoLocationInfo)
405+
SWIFT_REQUEST(TypeChecker, GetTypeWrapperType,
406+
Type(NominalTypeDecl *),
407+
Cached, NoLocationInfo)
408+
SWIFT_REQUEST(TypeChecker, GetTypeWrapperStorage,
409+
NominalTypeDecl *(NominalTypeDecl *),
410+
Cached, NoLocationInfo)
411+
SWIFT_REQUEST(TypeChecker, GetTypeWrapperProperty,
412+
VarDecl *(NominalTypeDecl *),
413+
Cached, NoLocationInfo)
414+
SWIFT_REQUEST(TypeChecker, GetTypeWrapperStorageForProperty,
415+
VarDecl *(VarDecl *),
416+
Cached, NoLocationInfo)
417+
SWIFT_REQUEST(TypeChecker, SynthesizeTypeWrappedPropertyGetterBody,
418+
BraceStmt *(AccessorDecl *),
419+
Cached, NoLocationInfo)
420+
SWIFT_REQUEST(TypeChecker, SynthesizeTypeWrappedPropertySetterBody,
421+
BraceStmt *(AccessorDecl *),
422+
Cached, NoLocationInfo)
423+
SWIFT_REQUEST(TypeChecker, IsPropertyAccessedViaTypeWrapper,
424+
bool(VarDecl *),
425+
Cached, NoLocationInfo)
426+
SWIFT_REQUEST(TypeChecker, SynthesizeTypeWrapperInitializer,
427+
ConstructorDecl *(NominalTypeDecl *),
428+
Cached, NoLocationInfo)
429+
SWIFT_REQUEST(TypeChecker, SynthesizeTypeWrapperInitializerBody,
430+
BraceStmt *(ConstructorDecl *),
431+
Cached, NoLocationInfo)

include/swift/Basic/Features.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ EXPERIMENTAL_FEATURE(SendableCompletionHandlers)
122122
/// Enables opaque type erasure without also enabling implict dynamic
123123
EXPERIMENTAL_FEATURE(OpaqueTypeErasure)
124124

125+
/// Whether to enable experimental @typeWrapper feature which allows to
126+
/// declare a type that controls access to all stored properties of the
127+
/// wrapped type.
128+
EXPERIMENTAL_FEATURE(TypeWrappers)
129+
125130
#undef EXPERIMENTAL_FEATURE
126131
#undef UPCOMING_FEATURE
127132
#undef SUPPRESSIBLE_LANGUAGE_FEATURE

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2935,6 +2935,10 @@ static bool usesFeatureSpecializeAttributeWithAvailability(Decl *decl) {
29352935
return false;
29362936
}
29372937

2938+
static bool usesFeatureTypeWrappers(Decl *decl) {
2939+
return decl->getAttrs().hasAttribute<TypeWrapperAttr>();
2940+
}
2941+
29382942
static void suppressingFeatureSpecializeAttributeWithAvailability(
29392943
PrintOptions &options,
29402944
llvm::function_ref<void()> action) {

lib/AST/Decl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6733,7 +6733,8 @@ bool VarDecl::hasStorageOrWrapsStorage() const {
67336733
}
67346734

67356735
void VarDecl::visitAuxiliaryDecls(llvm::function_ref<void(VarDecl *)> visit) const {
6736-
if (getDeclContext()->isTypeContext() || isImplicit())
6736+
if (getDeclContext()->isTypeContext() ||
6737+
(isImplicit() && !isa<ParamDecl>(this)))
67376738
return;
67386739

67396740
if (getAttrs().hasAttribute<LazyAttr>()) {

lib/AST/TypeCheckRequests.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,6 +1531,10 @@ void swift::simple_display(llvm::raw_ostream &out, CustomAttrTypeKind value) {
15311531
out << "property-wrapper";
15321532
return;
15331533

1534+
case CustomAttrTypeKind::TypeWrapper:
1535+
out << "type-wrapper";
1536+
return;
1537+
15341538
case CustomAttrTypeKind::GlobalActor:
15351539
out << "global-actor";
15361540
return;

0 commit comments

Comments
 (0)