Skip to content

Commit ae3f35d

Browse files
committed
[AST] Bring 'mutating' and 'inout self' in sync.
- 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 2b415a3 commit ae3f35d

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
@@ -2700,6 +2700,28 @@ class Verifier : public ASTWalker {
27002700
}
27012701
}
27022702

2703+
if (FD->isMutating()) {
2704+
if (!FD->isInstanceMember()) {
2705+
Out << "mutating function is not an instance member\n";
2706+
abort();
2707+
}
2708+
if (FD->getDeclContext()->getAsClassOrClassExtensionContext()) {
2709+
Out << "mutating function in a class\n";
2710+
abort();
2711+
}
2712+
const ParamDecl *selfParam = FD->getImplicitSelfDecl();
2713+
if (!selfParam->getInterfaceType()->is<InOutType>()) {
2714+
Out << "mutating function does not have inout 'self'\n";
2715+
abort();
2716+
}
2717+
} else {
2718+
const ParamDecl *selfParam = FD->getImplicitSelfDecl();
2719+
if (selfParam && selfParam->getInterfaceType()->is<InOutType>()) {
2720+
Out << "non-mutating function has inout 'self'\n";
2721+
abort();
2722+
}
2723+
}
2724+
27032725
verifyCheckedBase(FD);
27042726
}
27052727

lib/AST/Decl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3395,7 +3395,9 @@ bool AbstractStorageDecl::isSetterNonMutating() const {
33953395
switch (getStorageKind()) {
33963396
case AbstractStorageDecl::Stored:
33973397
case AbstractStorageDecl::StoredWithTrivialAccessors:
3398-
return false;
3398+
// Instance member setters are mutating; static property setters and
3399+
// top-level setters are not.
3400+
return !isInstanceMember();
33993401

34003402
case AbstractStorageDecl::StoredWithObservers:
34013403
case AbstractStorageDecl::InheritedWithObservers:

lib/Parse/ParseDecl.cpp

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3418,29 +3418,28 @@ static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, ParameterList *param,
34183418
// Non-static set/willSet/didSet/materializeForSet/mutableAddress
34193419
// default to mutating. get/address default to
34203420
// non-mutating.
3421-
if (!D->isStatic()) {
3422-
switch (Kind) {
3423-
case AccessorKind::IsAddressor:
3424-
D->setAddressorKind(addressorKind);
3425-
break;
3421+
switch (Kind) {
3422+
case AccessorKind::IsAddressor:
3423+
D->setAddressorKind(addressorKind);
3424+
break;
34263425

3427-
case AccessorKind::IsGetter:
3428-
break;
3426+
case AccessorKind::IsGetter:
3427+
break;
34293428

3430-
case AccessorKind::IsMutableAddressor:
3431-
D->setAddressorKind(addressorKind);
3432-
LLVM_FALLTHROUGH;
3429+
case AccessorKind::IsMutableAddressor:
3430+
D->setAddressorKind(addressorKind);
3431+
LLVM_FALLTHROUGH;
34333432

3434-
case AccessorKind::IsSetter:
3435-
case AccessorKind::IsWillSet:
3436-
case AccessorKind::IsDidSet:
3433+
case AccessorKind::IsSetter:
3434+
case AccessorKind::IsWillSet:
3435+
case AccessorKind::IsDidSet:
3436+
if (D->isInstanceMember())
34373437
D->setMutating();
3438-
break;
3438+
break;
34393439

3440-
case AccessorKind::IsMaterializeForSet:
3441-
case AccessorKind::NotAccessor:
3442-
llvm_unreachable("not parseable accessors");
3443-
}
3440+
case AccessorKind::IsMaterializeForSet:
3441+
case AccessorKind::NotAccessor:
3442+
llvm_unreachable("not parseable accessors");
34443443
}
34453444

34463445
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
@@ -5037,6 +5037,12 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
50375037
else if (FD->getAttrs().hasAttribute<NonMutatingAttr>())
50385038
FD->setMutating(false);
50395039

5040+
if (FD->isMutating()) {
5041+
Type contextTy = FD->getDeclContext()->getDeclaredInterfaceType();
5042+
if (contextTy->hasReferenceSemantics())
5043+
FD->setMutating(false);
5044+
}
5045+
50405046
// Check whether the return type is dynamic 'Self'.
50415047
if (checkDynamicSelfReturn(FD))
50425048
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)