@@ -606,6 +606,15 @@ getEnclosingSelfPropertyWrapperAccess(VarDecl *property, bool forProjected) {
606
606
return result;
607
607
}
608
608
609
+ static Optional<PropertyWrapperLValueness>
610
+ getPropertyWrapperLValueness (VarDecl *var) {
611
+ auto &ctx = var->getASTContext ();
612
+ return evaluateOrDefault (
613
+ ctx.evaluator ,
614
+ PropertyWrapperLValuenessRequest{var},
615
+ None);
616
+ }
617
+
609
618
// / Build a reference to the storage of a declaration. Returns nullptr if there
610
619
// / was an error. This should only occur if an invalid declaration was type
611
620
// / checked; another diagnostic should have been emitted already.
@@ -621,9 +630,11 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
621
630
// Local function to "finish" the expression, creating a member reference
622
631
// to the given sequence of underlying variables.
623
632
Optional<EnclosingSelfPropertyWrapperAccess> enclosingSelfAccess;
624
- llvm::TinyPtrVector< VarDecl *> underlyingVars;
633
+ llvm::SmallVector<std::pair< VarDecl *, bool >, 1 > underlyingVars;
625
634
auto finish = [&](Expr *result) -> Expr * {
626
- for (auto underlyingVar : underlyingVars) {
635
+ for (auto underlyingVarPair : underlyingVars) {
636
+ auto underlyingVar = underlyingVarPair.first ;
637
+ auto isWrapperRefLValue = underlyingVarPair.second ;
627
638
auto subs = result->getType ()
628
639
->getWithoutSpecifierType ()
629
640
->getContextSubstitutionMap (
@@ -634,7 +645,7 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
634
645
auto *memberRefExpr = new (ctx) MemberRefExpr (
635
646
result, SourceLoc (), memberRef, DeclNameLoc (), /* Implicit=*/ true );
636
647
auto type = underlyingVar->getValueInterfaceType ().subst (subs);
637
- if (isLValue )
648
+ if (isWrapperRefLValue )
638
649
type = LValueType::get (type);
639
650
memberRefExpr->setType (type);
640
651
@@ -650,6 +661,8 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
650
661
SelfAccessorKind selfAccessKind;
651
662
Type selfTypeForAccess = (selfDecl ? selfDecl->getType () : Type ());
652
663
664
+ bool isMemberLValue = isLValue;
665
+
653
666
auto *genericEnv = accessor->getGenericEnvironment ();
654
667
SubstitutionMap subs;
655
668
if (genericEnv)
@@ -714,22 +727,43 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
714
727
firstWrapperIdx = 1 ;
715
728
716
729
// Perform accesses to the wrappedValues along the composition chain.
717
- for (unsigned i : range (firstWrapperIdx, lastWrapperIdx)) {
718
- auto wrapperInfo = var->getAttachedPropertyWrapperTypeInfo (i);
719
- auto wrappedValue = wrapperInfo.valueVar ;
720
-
721
- // Check for availability of wrappedValue.
722
- if (accessor->getAccessorKind () == AccessorKind::Get ||
723
- accessor->getAccessorKind () == AccessorKind::Read) {
724
- if (auto *attr = wrappedValue->getAttrs ().getUnavailable (ctx)) {
725
- diagnoseExplicitUnavailability (
726
- wrappedValue,
727
- var->getAttachedPropertyWrappers ()[i]->getRangeWithAt (),
728
- var->getDeclContext (), nullptr );
730
+ if (firstWrapperIdx < lastWrapperIdx) {
731
+ if (auto lvalueness = getPropertyWrapperLValueness (var)) {
732
+
733
+ // Figure out if the outermost wrapper instance should be an l-value
734
+ bool isLValueForGet = lvalueness->isLValueForGetAccess [firstWrapperIdx];
735
+ bool isLValueForSet = lvalueness->isLValueForSetAccess [firstWrapperIdx];
736
+ isMemberLValue = (isLValueForGet && isUsedForGetAccess) ||
737
+ (isLValueForSet && isUsedForSetAccess);
738
+
739
+ for (unsigned i : range (firstWrapperIdx, lastWrapperIdx)) {
740
+ auto wrapperInfo = var->getAttachedPropertyWrapperTypeInfo (i);
741
+ auto wrappedValue = wrapperInfo.valueVar ;
742
+
743
+ // Figure out if the wrappedValue accesses should be l-values
744
+ bool isWrapperRefLValue = isLValue;
745
+ if (i < lastWrapperIdx - 1 ) {
746
+ bool isLValueForGet = lvalueness->isLValueForGetAccess [i+1 ];
747
+ bool isLValueForSet = lvalueness->isLValueForSetAccess [i+1 ];
748
+ isWrapperRefLValue = (isLValueForGet && isUsedForGetAccess) ||
749
+ (isLValueForSet && isUsedForSetAccess);
750
+ }
751
+
752
+ // Check for availability of wrappedValue.
753
+ if (accessor->getAccessorKind () == AccessorKind::Get ||
754
+ accessor->getAccessorKind () == AccessorKind::Read) {
755
+ if (auto *attr = wrappedValue->getAttrs ().getUnavailable (ctx)) {
756
+ diagnoseExplicitUnavailability (
757
+ wrappedValue,
758
+ var->getAttachedPropertyWrappers ()[i]->getRangeWithAt (),
759
+ var->getDeclContext (), nullptr );
760
+ }
761
+ }
762
+
763
+ underlyingVars.push_back ({ wrappedValue, isWrapperRefLValue });
764
+
729
765
}
730
766
}
731
-
732
- underlyingVars.push_back (wrappedValue);
733
767
}
734
768
semantics = AccessSemantics::DirectToStorage;
735
769
selfAccessKind = SelfAccessorKind::Peer;
@@ -750,8 +784,15 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
750
784
enclosingSelfAccess =
751
785
getEnclosingSelfPropertyWrapperAccess (var, /* forProjected=*/ true );
752
786
if (!enclosingSelfAccess) {
787
+ auto projectionVar = cast<VarDecl>(accessor->getStorage ());
788
+ if (auto lvalueness = getPropertyWrapperLValueness (projectionVar)) {
789
+ isMemberLValue =
790
+ (lvalueness->isLValueForGetAccess [0 ] && isUsedForGetAccess) ||
791
+ (lvalueness->isLValueForSetAccess [0 ] && isUsedForSetAccess);
792
+ }
753
793
underlyingVars.push_back (
754
- var->getAttachedPropertyWrapperTypeInfo (0 ).projectedValueVar );
794
+ { var->getAttachedPropertyWrapperTypeInfo (0 ).projectedValueVar ,
795
+ isLValue });
755
796
}
756
797
semantics = AccessSemantics::DirectToStorage;
757
798
selfAccessKind = SelfAccessorKind::Peer;
@@ -806,25 +847,6 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
806
847
807
848
// Build self.member or equivalent
808
849
809
- bool isMemberLValue = isLValue;
810
- if (target == TargetImpl::Wrapper || target == TargetImpl::WrapperStorage) {
811
- // If the outermost property wrapper's getter / setter is mutating,
812
- // then the reference to the backing storage should be an l-value.
813
- auto var = cast<VarDecl>(accessor->getStorage ());
814
- auto varMember = (target == TargetImpl::WrapperStorage)
815
- ? &PropertyWrapperTypeInfo::projectedValueVar
816
- : &PropertyWrapperTypeInfo::valueVar;
817
- auto wrapper = (target == TargetImpl::WrapperStorage)
818
- ? var->getOriginalWrappedProperty (
819
- PropertyWrapperSynthesizedPropertyKind::StorageWrapper)
820
- ->getAttachedPropertyWrapperTypeInfo (0 )
821
- : var->getAttachedPropertyWrapperTypeInfo (0 );
822
- bool isWrapperGetterMutating = (wrapper.*varMember)->isGetterMutating ();
823
- bool isWrapperSetterMutating = (wrapper.*varMember)->isSetterMutating ();
824
- isMemberLValue = (isWrapperGetterMutating && isUsedForGetAccess) ||
825
- (isWrapperSetterMutating && isUsedForSetAccess);
826
- }
827
-
828
850
Expr *lookupExpr;
829
851
ConcreteDeclRef memberRef (storage, subs);
830
852
auto type = storage->getValueInterfaceType ().subst (subs);
@@ -2393,6 +2415,105 @@ PropertyWrapperMutabilityRequest::evaluate(Evaluator &,
2393
2415
return result;
2394
2416
}
2395
2417
2418
+ llvm::Expected<Optional<PropertyWrapperLValueness>>
2419
+ PropertyWrapperLValuenessRequest::evaluate (Evaluator &,
2420
+ VarDecl *var) const {
2421
+ VarDecl *VD = var;
2422
+ unsigned numWrappers = var->getAttachedPropertyWrappers ().size ();
2423
+ bool isProjectedValue = false ;
2424
+ if (numWrappers < 1 ) {
2425
+ VD = var->getOriginalWrappedProperty (
2426
+ PropertyWrapperSynthesizedPropertyKind::StorageWrapper);
2427
+ numWrappers = 1 ; // Can't compose projected values
2428
+ isProjectedValue = true ;
2429
+ }
2430
+
2431
+ if (!VD)
2432
+ return None;
2433
+
2434
+ auto varMember = isProjectedValue
2435
+ ? &PropertyWrapperTypeInfo::projectedValueVar
2436
+ : &PropertyWrapperTypeInfo::valueVar;
2437
+
2438
+ // Calling the getter (or setter) on the nth property wrapper in the chain
2439
+ // is done as follows:
2440
+ // 1. call the getter on the (n-1)th property wrapper instance to get the
2441
+ // nth property wrapper instance
2442
+ // 2. call the getter (or setter) on the nth property wrapper instance
2443
+ // 3. if (2) is a mutating access, call the setter on the (n-1)th property
2444
+ // wrapper instance to write back the mutated value
2445
+
2446
+ // Below, we determine which of these property wrapper instances need to be
2447
+ // accessed mutating-ly, and therefore should be l-values.
2448
+
2449
+ // The variables used are:
2450
+ //
2451
+ // - prevWrappersMutabilityForGet:
2452
+ //
2453
+ // The mutability needed for the first (n-1) wrapper instances to be
2454
+ // able to call the getter on the (n-1)th instance, for step (1) above
2455
+ //
2456
+ // - prevWrappersMutabilityForGetAndSet:
2457
+ //
2458
+ // The mutability needed for the first (n-1) wrapper instances to be
2459
+ // able to call both the getter and setter on the (n-1)th instance, for
2460
+ // steps (1) and (3) above
2461
+ //
2462
+ // - mutability:
2463
+ //
2464
+ // The mutability needed for calling the getter / setter on the
2465
+ // nth wrapper instance, for step (2) above.
2466
+
2467
+ llvm::SmallVector<PropertyWrapperMutability::Value, 1 >
2468
+ prevWrappersMutabilityForGet, prevWrappersMutabilityForGetAndSet;
2469
+ PropertyWrapperMutability mutability;
2470
+
2471
+ auto firstWrapperInfo = VD->getAttachedPropertyWrapperTypeInfo (0 );
2472
+ mutability.Getter = getGetterMutatingness (firstWrapperInfo.*varMember);
2473
+ mutability.Setter = getSetterMutatingness (firstWrapperInfo.*varMember,
2474
+ var->getInnermostDeclContext ());
2475
+
2476
+ for (unsigned i : range (1 , numWrappers)) {
2477
+ if (mutability.Getter == PropertyWrapperMutability::Mutating) {
2478
+ prevWrappersMutabilityForGet = prevWrappersMutabilityForGetAndSet;
2479
+ }
2480
+ if (mutability.Getter != PropertyWrapperMutability::Mutating &&
2481
+ mutability.Setter != PropertyWrapperMutability::Mutating) {
2482
+ prevWrappersMutabilityForGetAndSet = prevWrappersMutabilityForGet;
2483
+ }
2484
+ prevWrappersMutabilityForGet.push_back (mutability.Getter );
2485
+ prevWrappersMutabilityForGetAndSet.push_back (
2486
+ std::max (mutability.Getter , mutability.Setter ));
2487
+ auto wrapperInfo = VD->getAttachedPropertyWrapperTypeInfo (i);
2488
+ mutability.Getter = getGetterMutatingness (wrapperInfo.*varMember);
2489
+ mutability.Setter = getSetterMutatingness (wrapperInfo.*varMember,
2490
+ var->getInnermostDeclContext ());
2491
+ }
2492
+
2493
+ auto mutabilitySequenceForLastGet =
2494
+ (mutability.Getter == PropertyWrapperMutability::Mutating)
2495
+ ? &prevWrappersMutabilityForGetAndSet
2496
+ : &prevWrappersMutabilityForGet;
2497
+ auto mutabilitySequenceForLastSet =
2498
+ (mutability.Setter == PropertyWrapperMutability::Mutating)
2499
+ ? &prevWrappersMutabilityForGetAndSet
2500
+ : &prevWrappersMutabilityForGet;
2501
+
2502
+ PropertyWrapperLValueness lvalueness;
2503
+ for (unsigned i : range (numWrappers - 1 )) {
2504
+ lvalueness.isLValueForGetAccess .push_back (
2505
+ (*mutabilitySequenceForLastGet)[i] == PropertyWrapperMutability::Mutating);
2506
+ lvalueness.isLValueForSetAccess .push_back (
2507
+ (*mutabilitySequenceForLastSet)[i] == PropertyWrapperMutability::Mutating);
2508
+ }
2509
+ lvalueness.isLValueForGetAccess .push_back (
2510
+ mutability.Getter == PropertyWrapperMutability::Mutating);
2511
+ lvalueness.isLValueForSetAccess .push_back (
2512
+ mutability.Setter == PropertyWrapperMutability::Mutating);
2513
+
2514
+ return lvalueness;
2515
+ }
2516
+
2396
2517
llvm::Expected<PropertyWrapperBackingPropertyInfo>
2397
2518
PropertyWrapperBackingPropertyInfoRequest::evaluate (Evaluator &evaluator,
2398
2519
VarDecl *var) const {
0 commit comments