Skip to content

[SR-7268] [SILGen/exclusivity] call to nonmutating setter is not a mutation. #49816

@atrick

Description

@atrick
Previous ID SR-7268
Radar rdar://problem/38817096
Original Reporter @atrick
Type Improvement
Status Closed
Resolution Done
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Improvement
Assignee @jckarter
Priority Medium

md5: e48aca74fdd947f40063a338b94cec45

relates to:

  • SR-7248 Simultaneous access when using non-class-bound protocol

Issue Description:

Currently, SILGen emits a nonmutating setter call as a mutation of the underlying access path. Enough jargon. This is what happens to an innocent fruit basket:

public protocol Fruit {
  var seeds: Int { get nonmutating set }
}

class Apple: Fruit {
  init() {}
  
  var seeds: Int = 0
}

public class Basket {
  var fruit: Fruit = Apple()
}

public func foo(basket: Basket) {
  basket.fruit.seeds = 3
}

foo will begin an exclusive modify of `fruit`, call materializeForSet, execute the writeback, and end the exlusive access.

However, the fruit isn't actually being modified (according to this silly class-based model, the seeds aren't part of the value). So, we should not need exclusive access to fruit, and we shouldn't need to materializeForSet or writeback. Just getting a reference to its seeds and calling the setter should be fine.

In addition to performance, this actually affects semantics. Fixing this is backward source compatible though, so this is a good improvement to make any time.

protocol P {
  var s: String? { get nonmutating set }
}

class C: P {
  init() {}
  var s: String? {
    didSet {
      foo()
    }
  }
  static var shared: P = C()
}

func foo() {
  print(C.shared.s ?? "")
}

C.shared.s = "boo"

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions