Skip to content

Commit 77de3dc

Browse files
authored
[AST] Bring 'mutating' and 'inout self' in sync. (#10375)
- A mutating method or accessor always has 'inout self'. - A nonmutating method or accessor never has 'inout self'. - Only instance members can be mutating. - Addressors are still addressors even when on static members. Came up after reviewing another patch that confused the two as possibly distinct concepts.
1 parent 23e86cf commit 77de3dc

File tree

7 files changed

+68
-31
lines changed

7 files changed

+68
-31
lines changed

lib/AST/ASTVerifier.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2690,6 +2690,28 @@ class Verifier : public ASTWalker {
26902690
}
26912691
}
26922692

2693+
if (FD->isMutating()) {
2694+
if (!FD->isInstanceMember()) {
2695+
Out << "mutating function is not an instance member\n";
2696+
abort();
2697+
}
2698+
if (FD->getDeclContext()->getAsClassOrClassExtensionContext()) {
2699+
Out << "mutating function in a class\n";
2700+
abort();
2701+
}
2702+
const ParamDecl *selfParam = FD->getImplicitSelfDecl();
2703+
if (!selfParam->getInterfaceType()->is<InOutType>()) {
2704+
Out << "mutating function does not have inout 'self'\n";
2705+
abort();
2706+
}
2707+
} else {
2708+
const ParamDecl *selfParam = FD->getImplicitSelfDecl();
2709+
if (selfParam && selfParam->getInterfaceType()->is<InOutType>()) {
2710+
Out << "non-mutating function has inout 'self'\n";
2711+
abort();
2712+
}
2713+
}
2714+
26932715
verifyCheckedBase(FD);
26942716
}
26952717

lib/AST/Decl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3398,7 +3398,9 @@ bool AbstractStorageDecl::isSetterNonMutating() const {
33983398
switch (getStorageKind()) {
33993399
case AbstractStorageDecl::Stored:
34003400
case AbstractStorageDecl::StoredWithTrivialAccessors:
3401-
return false;
3401+
// Instance member setters are mutating; static property setters and
3402+
// top-level setters are not.
3403+
return !isInstanceMember();
34023404

34033405
case AbstractStorageDecl::StoredWithObservers:
34043406
case AbstractStorageDecl::InheritedWithObservers:

lib/Parse/ParseDecl.cpp

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3445,29 +3445,28 @@ static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, ParameterList *param,
34453445
// Non-static set/willSet/didSet/materializeForSet/mutableAddress
34463446
// default to mutating. get/address default to
34473447
// non-mutating.
3448-
if (!D->isStatic()) {
3449-
switch (Kind) {
3450-
case AccessorKind::IsAddressor:
3451-
D->setAddressorKind(addressorKind);
3452-
break;
3448+
switch (Kind) {
3449+
case AccessorKind::IsAddressor:
3450+
D->setAddressorKind(addressorKind);
3451+
break;
34533452

3454-
case AccessorKind::IsGetter:
3455-
break;
3453+
case AccessorKind::IsGetter:
3454+
break;
34563455

3457-
case AccessorKind::IsMutableAddressor:
3458-
D->setAddressorKind(addressorKind);
3459-
LLVM_FALLTHROUGH;
3456+
case AccessorKind::IsMutableAddressor:
3457+
D->setAddressorKind(addressorKind);
3458+
LLVM_FALLTHROUGH;
34603459

3461-
case AccessorKind::IsSetter:
3462-
case AccessorKind::IsWillSet:
3463-
case AccessorKind::IsDidSet:
3460+
case AccessorKind::IsSetter:
3461+
case AccessorKind::IsWillSet:
3462+
case AccessorKind::IsDidSet:
3463+
if (D->isInstanceMember())
34643464
D->setMutating();
3465-
break;
3465+
break;
34663466

3467-
case AccessorKind::IsMaterializeForSet:
3468-
case AccessorKind::NotAccessor:
3469-
llvm_unreachable("not parseable accessors");
3470-
}
3467+
case AccessorKind::IsMaterializeForSet:
3468+
case AccessorKind::NotAccessor:
3469+
llvm_unreachable("not parseable accessors");
34713470
}
34723471

34733472
return D;

lib/Sema/CodeSynthesis.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -352,18 +352,15 @@ static FuncDecl *createMaterializeForSetPrototype(AbstractStorageDecl *storage,
352352
params, TypeLoc::withoutLoc(retTy), DC);
353353
materializeForSet->setImplicit();
354354

355-
bool isStatic = storage->isStatic();
356-
357355
// Open-code the setMutating() calculation since we might run before
358-
// the setter has been type checked. Also as a hack, always mark the
359-
// setter mutating if we're inside a protocol, because it seems some
360-
// things break otherwise -- the root cause should be fixed eventually.
356+
// the setter has been type checked.
357+
Type contextTy = DC->getDeclaredInterfaceType();
361358
materializeForSet->setMutating(
362-
storage->getDeclContext()->getAsProtocolOrProtocolExtensionContext() ||
363-
(!setter->getAttrs().hasAttribute<NonMutatingAttr>() &&
364-
!storage->isSetterNonMutating()));
359+
contextTy && !contextTy->hasReferenceSemantics() &&
360+
!setter->getAttrs().hasAttribute<NonMutatingAttr>() &&
361+
!storage->isSetterNonMutating());
365362

366-
materializeForSet->setStatic(isStatic);
363+
materializeForSet->setStatic(storage->isStatic());
367364

368365
// materializeForSet is final if the storage is.
369366
if (storage->isFinal())

lib/Sema/TypeCheckDecl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5038,6 +5038,12 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
50385038
else if (FD->getAttrs().hasAttribute<NonMutatingAttr>())
50395039
FD->setMutating(false);
50405040

5041+
if (FD->isMutating()) {
5042+
Type contextTy = FD->getDeclContext()->getDeclaredInterfaceType();
5043+
if (contextTy->hasReferenceSemantics())
5044+
FD->setMutating(false);
5045+
}
5046+
50415047
// Check whether the return type is dynamic 'Self'.
50425048
if (checkDynamicSelfReturn(FD))
50435049
FD->setInvalid();

test/SILGen/addressors.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ struct A {
2222
return base
2323
}
2424
}
25+
26+
static var staticProp: Int32 {
27+
unsafeAddress {
28+
// Just don't trip up the verifier.
29+
fatalError()
30+
}
31+
}
2532
}
2633

2734
// CHECK-LABEL: sil hidden @_T010addressors1AV9subscripts5Int32VAFcflu : $@convention(method) (Int32, A) -> UnsafePointer<Int32>

test/SILGen/guaranteed_self.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,16 @@ struct S: Fooable {
188188
// CHECK-NOT: destroy_addr [[SELF_ADDR]]
189189

190190
// Witness thunk for prop3 nonmutating materializeForSet
191-
// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop3SifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
191+
// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop3SifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
192192
// CHECK: bb0({{.*}} [[SELF_ADDR:%.*]] : $*S):
193-
// CHECK: [[SELF:%.*]] = load [copy] [[SELF_ADDR]]
193+
// CHECK: [[SELF_COPY:%.*]] = alloc_stack $S
194+
// CHECK: copy_addr [[SELF_ADDR]] to [initialization] [[SELF_COPY]]
195+
// CHECK: [[SELF:%.*]] = load [take] [[SELF_COPY]]
194196
// CHECK: destroy_value [[SELF]]
195197
// CHECK-NOT: destroy_value [[SELF]]
196-
// CHECK: }
198+
// CHECK-NOT: destroy_addr [[SELF_COPY]]
199+
// CHECK-NOT: destroy_addr [[SELF_ADDR]]
200+
// CHECK: } // end sil function '_T015guaranteed_self1SVAA7FooableA2aDP5prop3SifmTW'
197201

198202
//
199203
// TODO: Expected output for the other cases

0 commit comments

Comments
 (0)