Skip to content

Commit 6663800

Browse files
authored
Merge pull request swiftlang#27109 from DougGregor/sr-11393
2 parents 06576e5 + 9ce12ac commit 6663800

File tree

4 files changed

+116
-14
lines changed

4 files changed

+116
-14
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,12 +1775,15 @@ static void fixItAvailableAttrRename(InFlightDiagnostic &diag,
17751775
// argumentLabelIDs = {"w", "x", "", "", "z"}
17761776
auto I = argumentLabelIDs.begin();
17771777

1778-
auto updateLabelsForArg = [&](Expr *expr) {
1778+
auto updateLabelsForArg = [&](Expr *expr) -> bool {
17791779
if (isa<DefaultArgumentExpr>(expr) ||
17801780
isa<CallerDefaultArgumentExpr>(expr)) {
17811781
// Defaulted: remove param label of it.
1782+
if (I == argumentLabelIDs.end())
1783+
return true;
1784+
17821785
I = argumentLabelIDs.erase(I);
1783-
return;
1786+
return false;
17841787
}
17851788

17861789
if (auto *varargExpr = dyn_cast<VarargExpansionExpr>(expr)) {
@@ -1800,19 +1803,26 @@ static void fixItAvailableAttrRename(InFlightDiagnostic &diag,
18001803
I = argumentLabelIDs.insert(I, variadicArgsNum, Identifier());
18011804
I += variadicArgsNum;
18021805
}
1803-
return;
1806+
return false;
18041807
}
18051808
}
18061809

18071810
// Normal: Just advance.
1811+
if (I == argumentLabelIDs.end())
1812+
return true;
1813+
18081814
++I;
1815+
return false;
18091816
};
18101817

18111818
if (auto *parenExpr = dyn_cast<ParenExpr>(argExpr)) {
1812-
updateLabelsForArg(parenExpr->getSubExpr());
1819+
if (updateLabelsForArg(parenExpr->getSubExpr()))
1820+
return;
18131821
} else {
1814-
for (auto *arg : cast<TupleExpr>(argExpr)->getElements())
1815-
updateLabelsForArg(arg);
1822+
for (auto *arg : cast<TupleExpr>(argExpr)->getElements()) {
1823+
if (updateLabelsForArg(arg))
1824+
return;
1825+
}
18161826
}
18171827

18181828
if (argumentLabelIDs.size() != argList.args.size()) {

lib/Sema/TypeCheckStorage.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2214,27 +2214,43 @@ getSetterMutatingness(VarDecl *var, DeclContext *dc) {
22142214
llvm::Expected<Optional<PropertyWrapperMutability>>
22152215
PropertyWrapperMutabilityRequest::evaluate(Evaluator &,
22162216
VarDecl *var) const {
2217-
unsigned numWrappers = var->getAttachedPropertyWrappers().size();
2218-
if (numWrappers < 1)
2219-
return None;
2217+
VarDecl *originalVar = var;
2218+
unsigned numWrappers = originalVar->getAttachedPropertyWrappers().size();
2219+
bool isProjectedValue = false;
2220+
if (numWrappers < 1) {
2221+
originalVar = var->getOriginalWrappedProperty(
2222+
PropertyWrapperSynthesizedPropertyKind::StorageWrapper);
2223+
if (!originalVar)
2224+
return None;
2225+
2226+
numWrappers = originalVar->getAttachedPropertyWrappers().size();
2227+
isProjectedValue = true;
2228+
}
2229+
22202230
if (var->getParsedAccessor(AccessorKind::Get))
22212231
return None;
22222232
if (var->getParsedAccessor(AccessorKind::Set))
22232233
return None;
22242234

2235+
// Figure out which member we're looking through.
2236+
auto varMember = isProjectedValue
2237+
? &PropertyWrapperTypeInfo::projectedValueVar
2238+
: &PropertyWrapperTypeInfo::valueVar;
2239+
22252240
// Start with the traits from the outermost wrapper.
2226-
auto firstWrapper = var->getAttachedPropertyWrapperTypeInfo(0);
2227-
if (!firstWrapper.valueVar)
2241+
auto firstWrapper = originalVar->getAttachedPropertyWrapperTypeInfo(0);
2242+
if (firstWrapper.*varMember == nullptr)
22282243
return None;
22292244

22302245
PropertyWrapperMutability result;
22312246

2232-
result.Getter = getGetterMutatingness(firstWrapper.valueVar);
2233-
result.Setter = getSetterMutatingness(firstWrapper.valueVar,
2247+
result.Getter = getGetterMutatingness(firstWrapper.*varMember);
2248+
result.Setter = getSetterMutatingness(firstWrapper.*varMember,
22342249
var->getInnermostDeclContext());
22352250

22362251
// Compose the traits of the following wrappers.
2237-
for (unsigned i = 1; i < numWrappers; ++i) {
2252+
for (unsigned i = 1; i < numWrappers && !isProjectedValue; ++i) {
2253+
assert(var == originalVar);
22382254
auto wrapper = var->getAttachedPropertyWrapperTypeInfo(i);
22392255
if (!wrapper.valueVar)
22402256
return None;

test/attr/attr_availability.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,3 +1100,16 @@ func unavailableFunc(_ arg: UnavailableProto) -> UnavailableProto {}
11001100
struct S {
11011101
var a: UnavailableProto
11021102
}
1103+
1104+
// Bad rename.
1105+
struct BadRename {
1106+
@available(*, deprecated, renamed: "init(range:step:)")
1107+
init(from: Int, to: Int, step: Int = 1) { }
1108+
1109+
init(range: Range<Int>, step: Int) { }
1110+
}
1111+
1112+
func testBadRename() {
1113+
_ = BadRename(from: 5, to: 17) // expected-warning{{'init(from:to:step:)' is deprecated: replaced by 'init(range:step:)'}}
1114+
// expected-note@-1{{use 'init(range:step:)' instead}}
1115+
}

test/decl/var/property_wrappers.swift

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,3 +1581,66 @@ protocol SR_11288_P5 {
15811581
struct SR_11288_S5<T>: SR_11288_P5 {
15821582
@SR_11288_Wrapper5 var answer = 42 // Okay
15831583
}
1584+
1585+
// SR-11393
1586+
protocol Copyable: AnyObject {
1587+
func copy() -> Self
1588+
}
1589+
1590+
@propertyWrapper
1591+
struct CopyOnWrite<Value: Copyable> {
1592+
init(wrappedValue: Value) {
1593+
self.wrappedValue = wrappedValue
1594+
}
1595+
1596+
var wrappedValue: Value
1597+
1598+
var projectedValue: Value {
1599+
mutating get {
1600+
if !isKnownUniquelyReferenced(&wrappedValue) {
1601+
wrappedValue = wrappedValue.copy()
1602+
}
1603+
return wrappedValue
1604+
}
1605+
set {
1606+
wrappedValue = newValue
1607+
}
1608+
}
1609+
}
1610+
1611+
final class CopyOnWriteTest: Copyable {
1612+
let a: Int
1613+
init(a: Int) {
1614+
self.a = a
1615+
}
1616+
1617+
func copy() -> Self {
1618+
Self.init(a: a)
1619+
}
1620+
}
1621+
1622+
struct CopyOnWriteDemo1 {
1623+
@CopyOnWrite var a = CopyOnWriteTest(a: 3)
1624+
1625+
func foo() { // expected-note{{mark method 'mutating' to make 'self' mutable}}
1626+
_ = $a // expected-error{{cannot use mutating getter on immutable value: 'self' is immutable}}
1627+
}
1628+
}
1629+
1630+
@propertyWrapper
1631+
struct NonMutatingProjectedValueSetWrapper<Value> {
1632+
var wrappedValue: Value
1633+
var projectedValue: Value {
1634+
get { wrappedValue }
1635+
nonmutating set { }
1636+
}
1637+
}
1638+
1639+
struct UseNonMutatingProjectedValueSet {
1640+
@NonMutatingProjectedValueSetWrapper var x = 17
1641+
1642+
func test() { // expected-note{{mark method 'mutating' to make 'self' mutable}}
1643+
$x = 42 // okay
1644+
x = 42 // expected-error{{cannot assign to property: 'self' is immutable}}
1645+
}
1646+
}

0 commit comments

Comments
 (0)