@@ -592,6 +592,15 @@ getEnclosingSelfPropertyWrapperAccess(VarDecl *property, bool forProjected) {
592
592
return result;
593
593
}
594
594
595
+ static Optional<PropertyWrapperLValueness>
596
+ getPropertyWrapperLValueness (VarDecl *var) {
597
+ auto &ctx = var->getASTContext ();
598
+ return evaluateOrDefault (
599
+ ctx.evaluator ,
600
+ PropertyWrapperLValuenessRequest{var},
601
+ None);
602
+ }
603
+
595
604
// / Build a reference to the storage of a declaration. Returns nullptr if there
596
605
// / was an error. This should only occur if an invalid declaration was type
597
606
// / checked; another diagnostic should have been emitted already.
@@ -606,9 +615,11 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
606
615
// Local function to "finish" the expression, creating a member reference
607
616
// to the given sequence of underlying variables.
608
617
Optional<EnclosingSelfPropertyWrapperAccess> enclosingSelfAccess;
609
- llvm::TinyPtrVector< VarDecl *> underlyingVars;
618
+ llvm::SmallVector<std::pair< VarDecl *, bool >, 1 > underlyingVars;
610
619
auto finish = [&](Expr *result) -> Expr * {
611
- for (auto underlyingVar : underlyingVars) {
620
+ for (auto underlyingVarPair : underlyingVars) {
621
+ auto underlyingVar = underlyingVarPair.first ;
622
+ auto isWrapperRefLValue = underlyingVarPair.second ;
612
623
auto subs = result->getType ()
613
624
->getWithoutSpecifierType ()
614
625
->getContextSubstitutionMap (
@@ -619,7 +630,7 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
619
630
auto *memberRefExpr = new (ctx) MemberRefExpr (
620
631
result, SourceLoc (), memberRef, DeclNameLoc (), /* Implicit=*/ true );
621
632
auto type = underlyingVar->getValueInterfaceType ().subst (subs);
622
- if (isLValue )
633
+ if (isWrapperRefLValue )
623
634
type = LValueType::get (type);
624
635
memberRefExpr->setType (type);
625
636
@@ -635,6 +646,8 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
635
646
SelfAccessorKind selfAccessKind;
636
647
Type selfTypeForAccess = (selfDecl ? selfDecl->getType () : Type ());
637
648
649
+ bool isMemberLValue = isLValue;
650
+
638
651
auto *genericEnv = accessor->getGenericEnvironment ();
639
652
SubstitutionMap subs;
640
653
if (genericEnv)
@@ -709,22 +722,42 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
709
722
firstWrapperIdx = 1 ;
710
723
711
724
// Perform accesses to the wrappedValues along the composition chain.
712
- for (unsigned i : range (firstWrapperIdx, lastWrapperIdx)) {
713
- auto wrapperInfo = var->getAttachedPropertyWrapperTypeInfo (i);
714
- auto wrappedValue = wrapperInfo.valueVar ;
715
-
716
- // Check for availability of wrappedValue.
717
- if (accessor->getAccessorKind () == AccessorKind::Get ||
718
- accessor->getAccessorKind () == AccessorKind::Read) {
719
- if (wrappedValue->getAttrs ().getUnavailable (ctx)) {
720
- diagnoseExplicitUnavailability (
721
- wrappedValue,
722
- var->getAttachedPropertyWrappers ()[i]->getRangeWithAt (),
723
- var->getDeclContext (), nullptr );
725
+ if (firstWrapperIdx < lastWrapperIdx) {
726
+ if (auto lvalueness = getPropertyWrapperLValueness (var)) {
727
+
728
+ // Figure out if the outermost wrapper instance should be an l-value
729
+ bool isLValueForGet = lvalueness->isLValueForGetAccess [firstWrapperIdx];
730
+ bool isLValueForSet = lvalueness->isLValueForSetAccess [firstWrapperIdx];
731
+ isMemberLValue = (isLValueForGet && isUsedForGetAccess) ||
732
+ (isLValueForSet && isUsedForSetAccess);
733
+
734
+ for (unsigned i : range (firstWrapperIdx, lastWrapperIdx)) {
735
+ auto wrapperInfo = var->getAttachedPropertyWrapperTypeInfo (i);
736
+ auto wrappedValue = wrapperInfo.valueVar ;
737
+
738
+ // Figure out if the wrappedValue accesses should be l-values
739
+ bool isWrapperRefLValue = isLValue;
740
+ if (i < lastWrapperIdx - 1 ) {
741
+ bool isLValueForGet = lvalueness->isLValueForGetAccess [i+1 ];
742
+ bool isLValueForSet = lvalueness->isLValueForSetAccess [i+1 ];
743
+ isWrapperRefLValue = (isLValueForGet && isUsedForGetAccess) ||
744
+ (isLValueForSet && isUsedForSetAccess);
745
+ }
746
+
747
+ // Check for availability of wrappedValue.
748
+ if (accessor->getAccessorKind () == AccessorKind::Get ||
749
+ accessor->getAccessorKind () == AccessorKind::Read) {
750
+ if (wrappedValue->getAttrs ().getUnavailable (ctx)) {
751
+ diagnoseExplicitUnavailability (
752
+ wrappedValue,
753
+ var->getAttachedPropertyWrappers ()[i]->getRangeWithAt (),
754
+ var->getDeclContext (), nullptr );
755
+ }
756
+ }
757
+
758
+ underlyingVars.push_back ({ wrappedValue, isWrapperRefLValue });
724
759
}
725
760
}
726
-
727
- underlyingVars.push_back (wrappedValue);
728
761
}
729
762
semantics = AccessSemantics::DirectToStorage;
730
763
selfAccessKind = SelfAccessorKind::Peer;
@@ -745,8 +778,15 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
745
778
enclosingSelfAccess =
746
779
getEnclosingSelfPropertyWrapperAccess (var, /* forProjected=*/ true );
747
780
if (!enclosingSelfAccess) {
781
+ auto projectionVar = cast<VarDecl>(accessor->getStorage ());
782
+ if (auto lvalueness = getPropertyWrapperLValueness (projectionVar)) {
783
+ isMemberLValue =
784
+ (lvalueness->isLValueForGetAccess [0 ] && isUsedForGetAccess) ||
785
+ (lvalueness->isLValueForSetAccess [0 ] && isUsedForSetAccess);
786
+ }
748
787
underlyingVars.push_back (
749
- var->getAttachedPropertyWrapperTypeInfo (0 ).projectedValueVar );
788
+ { var->getAttachedPropertyWrapperTypeInfo (0 ).projectedValueVar ,
789
+ isLValue });
750
790
}
751
791
semantics = AccessSemantics::DirectToStorage;
752
792
selfAccessKind = SelfAccessorKind::Peer;
@@ -802,25 +842,6 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
802
842
803
843
// Build self.member or equivalent
804
844
805
- bool isMemberLValue = isLValue;
806
- if (target == TargetImpl::Wrapper || target == TargetImpl::WrapperStorage) {
807
- // If the outermost property wrapper's getter / setter is mutating,
808
- // then the reference to the backing storage should be an l-value.
809
- auto var = cast<VarDecl>(accessor->getStorage ());
810
- auto varMember = (target == TargetImpl::WrapperStorage)
811
- ? &PropertyWrapperTypeInfo::projectedValueVar
812
- : &PropertyWrapperTypeInfo::valueVar;
813
- auto wrapper = (target == TargetImpl::WrapperStorage)
814
- ? var->getOriginalWrappedProperty (
815
- PropertyWrapperSynthesizedPropertyKind::StorageWrapper)
816
- ->getAttachedPropertyWrapperTypeInfo (0 )
817
- : var->getAttachedPropertyWrapperTypeInfo (0 );
818
- bool isWrapperGetterMutating = (wrapper.*varMember)->isGetterMutating ();
819
- bool isWrapperSetterMutating = (wrapper.*varMember)->isSetterMutating ();
820
- isMemberLValue = (isWrapperGetterMutating && isUsedForGetAccess) ||
821
- (isWrapperSetterMutating && isUsedForSetAccess);
822
- }
823
-
824
845
Expr *lookupExpr;
825
846
ConcreteDeclRef memberRef (storage, subs);
826
847
auto type = storage->getValueInterfaceType ().subst (subs);
@@ -2473,6 +2494,105 @@ PropertyWrapperMutabilityRequest::evaluate(Evaluator &,
2473
2494
return result;
2474
2495
}
2475
2496
2497
+ Optional<PropertyWrapperLValueness>
2498
+ PropertyWrapperLValuenessRequest::evaluate (Evaluator &,
2499
+ VarDecl *var) const {
2500
+ VarDecl *VD = var;
2501
+ unsigned numWrappers = var->getAttachedPropertyWrappers ().size ();
2502
+ bool isProjectedValue = false ;
2503
+ if (numWrappers < 1 ) {
2504
+ VD = var->getOriginalWrappedProperty (
2505
+ PropertyWrapperSynthesizedPropertyKind::StorageWrapper);
2506
+ numWrappers = 1 ; // Can't compose projected values
2507
+ isProjectedValue = true ;
2508
+ }
2509
+
2510
+ if (!VD)
2511
+ return None;
2512
+
2513
+ auto varMember = isProjectedValue
2514
+ ? &PropertyWrapperTypeInfo::projectedValueVar
2515
+ : &PropertyWrapperTypeInfo::valueVar;
2516
+
2517
+ // Calling the getter (or setter) on the nth property wrapper in the chain
2518
+ // is done as follows:
2519
+ // 1. call the getter on the (n-1)th property wrapper instance to get the
2520
+ // nth property wrapper instance
2521
+ // 2. call the getter (or setter) on the nth property wrapper instance
2522
+ // 3. if (2) is a mutating access, call the setter on the (n-1)th property
2523
+ // wrapper instance to write back the mutated value
2524
+
2525
+ // Below, we determine which of these property wrapper instances need to be
2526
+ // accessed mutating-ly, and therefore should be l-values.
2527
+
2528
+ // The variables used are:
2529
+ //
2530
+ // - prevWrappersMutabilityForGet:
2531
+ //
2532
+ // The mutability needed for the first (n-1) wrapper instances to be
2533
+ // able to call the getter on the (n-1)th instance, for step (1) above
2534
+ //
2535
+ // - prevWrappersMutabilityForGetAndSet:
2536
+ //
2537
+ // The mutability needed for the first (n-1) wrapper instances to be
2538
+ // able to call both the getter and setter on the (n-1)th instance, for
2539
+ // steps (1) and (3) above
2540
+ //
2541
+ // - mutability:
2542
+ //
2543
+ // The mutability needed for calling the getter / setter on the
2544
+ // nth wrapper instance, for step (2) above.
2545
+
2546
+ llvm::SmallVector<PropertyWrapperMutability::Value, 1 >
2547
+ prevWrappersMutabilityForGet, prevWrappersMutabilityForGetAndSet;
2548
+ PropertyWrapperMutability mutability;
2549
+
2550
+ auto firstWrapperInfo = VD->getAttachedPropertyWrapperTypeInfo (0 );
2551
+ mutability.Getter = getGetterMutatingness (firstWrapperInfo.*varMember);
2552
+ mutability.Setter = getSetterMutatingness (firstWrapperInfo.*varMember,
2553
+ var->getInnermostDeclContext ());
2554
+
2555
+ for (unsigned i : range (1 , numWrappers)) {
2556
+ if (mutability.Getter == PropertyWrapperMutability::Mutating) {
2557
+ prevWrappersMutabilityForGet = prevWrappersMutabilityForGetAndSet;
2558
+ }
2559
+ if (mutability.Getter != PropertyWrapperMutability::Mutating &&
2560
+ mutability.Setter != PropertyWrapperMutability::Mutating) {
2561
+ prevWrappersMutabilityForGetAndSet = prevWrappersMutabilityForGet;
2562
+ }
2563
+ prevWrappersMutabilityForGet.push_back (mutability.Getter );
2564
+ prevWrappersMutabilityForGetAndSet.push_back (
2565
+ std::max (mutability.Getter , mutability.Setter ));
2566
+ auto wrapperInfo = VD->getAttachedPropertyWrapperTypeInfo (i);
2567
+ mutability.Getter = getGetterMutatingness (wrapperInfo.*varMember);
2568
+ mutability.Setter = getSetterMutatingness (wrapperInfo.*varMember,
2569
+ var->getInnermostDeclContext ());
2570
+ }
2571
+
2572
+ auto mutabilitySequenceForLastGet =
2573
+ (mutability.Getter == PropertyWrapperMutability::Mutating)
2574
+ ? &prevWrappersMutabilityForGetAndSet
2575
+ : &prevWrappersMutabilityForGet;
2576
+ auto mutabilitySequenceForLastSet =
2577
+ (mutability.Setter == PropertyWrapperMutability::Mutating)
2578
+ ? &prevWrappersMutabilityForGetAndSet
2579
+ : &prevWrappersMutabilityForGet;
2580
+
2581
+ PropertyWrapperLValueness lvalueness;
2582
+ for (unsigned i : range (numWrappers - 1 )) {
2583
+ lvalueness.isLValueForGetAccess .push_back (
2584
+ (*mutabilitySequenceForLastGet)[i] == PropertyWrapperMutability::Mutating);
2585
+ lvalueness.isLValueForSetAccess .push_back (
2586
+ (*mutabilitySequenceForLastSet)[i] == PropertyWrapperMutability::Mutating);
2587
+ }
2588
+ lvalueness.isLValueForGetAccess .push_back (
2589
+ mutability.Getter == PropertyWrapperMutability::Mutating);
2590
+ lvalueness.isLValueForSetAccess .push_back (
2591
+ mutability.Setter == PropertyWrapperMutability::Mutating);
2592
+
2593
+ return lvalueness;
2594
+ }
2595
+
2476
2596
PropertyWrapperBackingPropertyInfo
2477
2597
PropertyWrapperBackingPropertyInfoRequest::evaluate (Evaluator &evaluator,
2478
2598
VarDecl *var) const {
0 commit comments