@@ -369,6 +369,9 @@ static void maybeMarkTransparent(AccessorDecl *accessor, ASTContext &ctx) {
369
369
return ;
370
370
371
371
break ;
372
+ } else if (var->getOriginalWrappedProperty (
373
+ PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) {
374
+ break ;
372
375
}
373
376
}
374
377
@@ -613,6 +616,57 @@ namespace {
613
616
};
614
617
} // end anonymous namespace
615
618
619
+ namespace {
620
+ // / Describes the information needed to perform property wrapper access via
621
+ // / the enclosing self.
622
+ struct EnclosingSelfPropertyWrapperAccess {
623
+ // / The (genreric) subscript that will be used to perform the access.
624
+ SubscriptDecl *subscript;
625
+
626
+ // / The property being accessed.
627
+ VarDecl *accessedProperty;
628
+ };
629
+ }
630
+
631
+ // / Determine whether the given property should be accessed via the enclosing-self access pattern.
632
+ static Optional<EnclosingSelfPropertyWrapperAccess>
633
+ getEnclosingSelfPropertyWrapperAccess (VarDecl *property, bool forProjected) {
634
+ // The enclosing-self pattern only applies to instance properties of
635
+ // classes.
636
+ if (!property->isInstanceMember ())
637
+ return None;
638
+ auto classDecl = property->getDeclContext ()->getSelfClassDecl ();
639
+ if (!classDecl)
640
+ return None;
641
+
642
+ // The pattern currently only works with the outermost property wrapper.
643
+ Type outermostWrapperType = property->getAttachedPropertyWrapperType (0 );
644
+ if (!outermostWrapperType)
645
+ return None;
646
+ NominalTypeDecl *wrapperTypeDecl = outermostWrapperType->getAnyNominal ();
647
+ if (!wrapperTypeDecl)
648
+ return None;
649
+
650
+ // Look for a generic subscript that fits the general form we need.
651
+ auto wrapperInfo = wrapperTypeDecl->getPropertyWrapperTypeInfo ();
652
+ auto subscript =
653
+ forProjected ? wrapperInfo.enclosingInstanceProjectedSubscript
654
+ : wrapperInfo.enclosingInstanceWrappedSubscript ;
655
+ if (!subscript)
656
+ return None;
657
+
658
+ EnclosingSelfPropertyWrapperAccess result;
659
+ result.subscript = subscript;
660
+
661
+ if (forProjected) {
662
+ result.accessedProperty =
663
+ property->getPropertyWrapperBackingPropertyInfo ().storageWrapperVar ;
664
+ } else {
665
+ result.accessedProperty = property;
666
+ }
667
+ return result;
668
+ }
669
+
616
670
// / Build an l-value for the storage of a declaration.
617
671
static Expr *buildStorageReference (AccessorDecl *accessor,
618
672
AbstractStorageDecl *storage,
@@ -621,6 +675,7 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
621
675
ASTContext &ctx) {
622
676
// Local function to "finish" the expression, creating a member reference
623
677
// to the given sequence of underlying variables.
678
+ Optional<EnclosingSelfPropertyWrapperAccess> enclosingSelfAccess;
624
679
llvm::TinyPtrVector<VarDecl *> underlyingVars;
625
680
auto finish = [&](Expr *result) -> Expr * {
626
681
for (auto underlyingVar : underlyingVars) {
@@ -699,9 +754,20 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
699
754
case TargetImpl::Wrapper: {
700
755
auto var = cast<VarDecl>(accessor->getStorage ());
701
756
storage = var->getPropertyWrapperBackingProperty ();
702
- for (unsigned i : indices (var->getAttachedPropertyWrappers ())) {
703
- underlyingVars.push_back (
704
- var->getAttachedPropertyWrapperTypeInfo (i).valueVar );
757
+
758
+ // If the outermost property wrapper uses the enclosing self pattern,
759
+ // record that.
760
+ unsigned lastWrapperIdx = var->getAttachedPropertyWrappers ().size ();
761
+ unsigned firstWrapperIdx = 0 ;
762
+ enclosingSelfAccess =
763
+ getEnclosingSelfPropertyWrapperAccess (var, /* forProjected=*/ false );
764
+ if (enclosingSelfAccess)
765
+ firstWrapperIdx = 1 ;
766
+
767
+ // Perform accesses to the wrappedValues along the composition chain.
768
+ for (unsigned i : range (firstWrapperIdx, lastWrapperIdx)) {
769
+ auto wrapperInfo = var->getAttachedPropertyWrapperTypeInfo (i);
770
+ underlyingVars.push_back (wrapperInfo.valueVar );
705
771
}
706
772
semantics = AccessSemantics::DirectToStorage;
707
773
selfAccessKind = SelfAccessorKind::Peer;
@@ -710,9 +776,14 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
710
776
711
777
case TargetImpl::WrapperStorage: {
712
778
auto var =
713
- cast<VarDecl>(accessor->getStorage ())->getOriginalWrappedProperty ();
779
+ cast<VarDecl>(accessor->getStorage ())->getOriginalWrappedProperty ();
714
780
storage = var->getPropertyWrapperBackingProperty ();
715
- underlyingVars.push_back ( var->getAttachedPropertyWrapperTypeInfo (0 ).projectedValueVar );
781
+ enclosingSelfAccess =
782
+ getEnclosingSelfPropertyWrapperAccess (var, /* forProjected=*/ true );
783
+ if (!enclosingSelfAccess) {
784
+ underlyingVars.push_back (
785
+ var->getAttachedPropertyWrapperTypeInfo (0 ).projectedValueVar );
786
+ }
716
787
semantics = AccessSemantics::DirectToStorage;
717
788
selfAccessKind = SelfAccessorKind::Peer;
718
789
break ;
@@ -757,26 +828,82 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
757
828
selfDRE = new (ctx) DerivedToBaseExpr (selfDRE, selfTypeForAccess);
758
829
}
759
830
760
- LookupExpr *lookupExpr;
831
+ Expr *lookupExpr;
761
832
ConcreteDeclRef memberRef (storage, subs);
833
+ auto type = storage->getValueInterfaceType ()
834
+ .subst (subs, SubstFlags::UseErrorType);
835
+ if (isMemberLValue)
836
+ type = LValueType::get (type);
837
+
838
+ // When we are performing access via a property wrapper's static subscript
839
+ // that accepts the enclosing self along with key paths, form that subscript
840
+ // operation now.
841
+ if (enclosingSelfAccess) {
842
+ Type storageType = storage->getValueInterfaceType ()
843
+ .subst (subs, SubstFlags::UseErrorType);
844
+ // Metatype instance for the wrapper type itself.
845
+ TypeExpr *wrapperMetatype = TypeExpr::createImplicit (storageType, ctx);
846
+
847
+ // Key path referring to the property being accessed.
848
+ Expr *propertyKeyPath = new (ctx) KeyPathDotExpr (SourceLoc ());
849
+ propertyKeyPath = new (ctx) UnresolvedDotExpr (
850
+ propertyKeyPath, SourceLoc (),
851
+ enclosingSelfAccess->accessedProperty ->getFullName (), DeclNameLoc (),
852
+ /* Implicit=*/ true );
853
+ propertyKeyPath = new (ctx) KeyPathExpr (
854
+ SourceLoc (), nullptr , propertyKeyPath);
855
+
856
+ // Key path referring to the backing storage property.
857
+ Expr *storageKeyPath = new (ctx) KeyPathDotExpr (SourceLoc ());
858
+ storageKeyPath = new (ctx) UnresolvedDotExpr (
859
+ storageKeyPath, SourceLoc (), storage->getFullName (), DeclNameLoc (),
860
+ /* Implicit=*/ true );
861
+ storageKeyPath = new (ctx) KeyPathExpr (
862
+ SourceLoc (), nullptr , storageKeyPath);
863
+ Expr *args[3 ] = {
864
+ selfDRE,
865
+ propertyKeyPath,
866
+ storageKeyPath
867
+ };
762
868
763
- if (auto subscript = dyn_cast<SubscriptDecl>(storage)) {
869
+ SubscriptDecl *subscriptDecl = enclosingSelfAccess->subscript ;
870
+ auto &tc = static_cast <TypeChecker&>(*ctx.getLazyResolver ());
871
+ lookupExpr = SubscriptExpr::create (
872
+ ctx, wrapperMetatype, SourceLoc (), args,
873
+ subscriptDecl->getFullName ().getArgumentNames (), { }, SourceLoc (),
874
+ nullptr , subscriptDecl, /* Implicit=*/ true );
875
+ tc.typeCheckExpression (lookupExpr, accessor);
876
+
877
+ // Make sure we produce an lvalue only when desired.
878
+ if (isMemberLValue != lookupExpr->getType ()->is <LValueType>()) {
879
+ if (isMemberLValue) {
880
+ // Strip off an extraneous load.
881
+ if (auto load = dyn_cast<LoadExpr>(lookupExpr))
882
+ lookupExpr = load->getSubExpr ();
883
+ } else {
884
+ lookupExpr = new (ctx) LoadExpr (
885
+ lookupExpr, lookupExpr->getType ()->getRValueType ());
886
+ }
887
+ }
888
+ } else if (auto subscript = dyn_cast<SubscriptDecl>(storage)) {
764
889
Expr *indices = buildSubscriptIndexReference (ctx, accessor);
765
890
lookupExpr = SubscriptExpr::create (ctx, selfDRE, indices, memberRef,
766
891
IsImplicit, semantics);
892
+
893
+ if (selfAccessKind == SelfAccessorKind::Super)
894
+ cast<LookupExpr>(lookupExpr)->setIsSuper (true );
895
+
896
+ lookupExpr->setType (type);
897
+
767
898
} else {
768
899
lookupExpr = new (ctx) MemberRefExpr (selfDRE, SourceLoc (), memberRef,
769
900
DeclNameLoc (), IsImplicit, semantics);
770
- }
771
901
772
- if (selfAccessKind == SelfAccessorKind::Super)
773
- lookupExpr->setIsSuper (true );
902
+ if (selfAccessKind == SelfAccessorKind::Super)
903
+ cast<LookupExpr>( lookupExpr) ->setIsSuper (true );
774
904
775
- auto type = storage->getValueInterfaceType ()
776
- .subst (subs, SubstFlags::UseErrorType);
777
- if (isMemberLValue)
778
- type = LValueType::get (type);
779
- lookupExpr->setType (type);
905
+ lookupExpr->setType (type);
906
+ }
780
907
781
908
return finish (lookupExpr);
782
909
}
0 commit comments