{"action":"created","issue":{"url":"https://api.github.com/repos/apple/swift/issues/4578","repository_url":"https://api.github.com/repos/apple/swift","labels_url":"https://api.github.com/repos/apple/swift/issues/4578/labels{/name}","comments_url":"https://api.github.com/repos/apple/swift/issues/4578/comments","events_url":"https://api.github.com/repos/apple/swift/issues/4578/events","html_url":"https://github.com/apple/swift/pull/4578","id":174394913,"number":4578,"title":"[SILOptimizer] Fix let constant of non-class protocol type being mutable","user":{"login":"timbodeit","id":4222754,"avatar_url":"https://avatars.githubusercontent.com/u/4222754?v=3","gravatar_id":"","url":"https://api.github.com/users/timbodeit","html_url":"https://github.com/timbodeit","followers_url":"https://api.github.com/users/timbodeit/followers","following_url":"https://api.github.com/users/timbodeit/following{/other_user}","gists_url":"https://api.github.com/users/timbodeit/gists{/gist_id}","starred_url":"https://api.github.com/users/timbodeit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/timbodeit/subscriptions","organizations_url":"https://api.github.com/users/timbodeit/orgs","repos_url":"https://api.github.com/users/timbodeit/repos","events_url":"https://api.github.com/users/timbodeit/events{/privacy}","received_events_url":"https://api.github.com/users/timbodeit/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":1,"created_at":"2016-08-31T22:31:51Z","updated_at":"2016-08-31T23:21:21Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/apple/swift/pulls/4578","html_url":"https://github.com/apple/swift/pull/4578","diff_url":"https://github.com/apple/swift/pull/4578.diff","patch_url":"https://github.com/apple/swift/pull/4578.patch"},"body":"In certain cases the Swift compiler currently allows mutating a let constant containing structs and enums.\r\n\r\nThis pull requests extends the checks in `LifetimeChecker` in `SILOptimizer/Mandatory/DefiniteInitialization.cpp` to catch when the memory object corresponding to a let constant is used as an inout parameter in a protocol witness method.\r\n\r\n### Code examples\r\n\r\n```swift\r\nprotocol TestProtocol {\r\n    var foo: Int { get set }\r\n}\r\n\r\nstruct TestStruct: TestProtocol {\r\n    var foo: Int\r\n}\r\n\r\nlet testObject: TestProtocol\r\ntestObject = TestStruct(foo: 42)\r\n\r\ntestObject.foo = 666       // No compile time error despite mutating\r\n                           // a struct assigned to let constant.\r\n\r\nprint(testObject)          // Output: TestStruct(foo: 666)\r\n```\r\n\r\nThe code example above should produce a compile time error in line 12. Instead of failing, the above example behaves as if `testObject` had been defined as a `var`.\r\n\r\n### Reproducability\r\n\r\n* the constant must be of protocol type  \r\n  _`let testObject: TestStruct` behaves as expected (compile time error)_\r\n* constant declaration and initialization must happen in two different lines / instructions  \r\n  _`let testObject: TestProtocol = TestStruct(foo: 42)` behaves as expected_\r\n* illegal access must occur within either \r\n\t* global scope, if constant was defined in global scope [(Main example)](http://swiftlang.ng.bluemix.net/#/repl/57a3ba35a7e343a94179b85b)  \r\n\t  _Defining constant in global scope, but attempting mutating action within a function behaves as expected_\r\n\t* the function where a local constant is defined [(Example)](http://swiftlang.ng.bluemix.net/#/repl/57a3ba35a7e343a94179b85b)\r\n\t* a designated initializer of the class, in which a let property is defined [(Example)](http://swiftlang.ng.bluemix.net/#/repl/57a3c183a7e343a94179b860)  \r\n\t  _Attempted mutation outside of designated initializer or in subclass initializer behaves as expected_\r\n\t  \r\n* mutation can happen through\r\n\t* variable setters [(Main example)](http://swiftlang.ng.bluemix.net/#/repl/57a3ba35a7e343a94179b85b)\r\n\t* calls to `mutating func`s [(Struct Example)](http://swiftlang.ng.bluemix.net/#/repl/57a3b8bca7e343a94179b859) [(Enum Example)](http://swiftlang.ng.bluemix.net/#/repl/57a3b75ba7e343a94179b858)\r\n\t* passing a reference to struct's property as an inout parameter to a function [(Example)](http://swiftlang.ng.bluemix.net/#/repl/57c744d7acbc649256bab974)\r\n\r\n### Issue description\r\n\r\nInitializing the constant separate from its declaration requires write access. Therefore it is treated as `@lvalue TestProtocol` in the AST for a certain scope.  \r\nChecking that the constant is not written to after being initialized is supposed to happen in the Mandatory SILOptimizer phase instead.\r\n\r\nOn loads, the Optimizer checks, that a variable is fully initialized, but currently does not validate what happens to it after it is loaded.  \r\nThis allows loading the memory object (or the named element of a reference type) through an [`open_existential_addr`](https://github.com/apple/swift/blob/master/docs/SIL.rst#open-existential-addr) instruction and applying the result as an Operand to a mutating witness method.\r\n\r\n--\r\n\r\nNote: I currently do not fully understand what an archetype refers to in the Swift compiler internals. The change is written in a way that is not specific to `witness_method`s, but still only checks apply instructions. If you can think of another way the result of an `open_existential_addr` instruction could be used in a mutating fashion, please leave a comment."},"comment":{"url":"https://api.github.com/repos/apple/swift/issues/comments/243931966","html_url":"https://github.com/apple/swift/pull/4578#issuecomment-243931966","issue_url":"https://api.github.com/repos/apple/swift/issues/4578","id":243931966,"user":{"login":"jckarter","id":147281,"avatar_url":"https://avatars.githubusercontent.com/u/147281?v=3","gravatar_id":"","url":"https://api.github.com/users/jckarter","html_url":"https://github.com/jckarter","followers_url":"https://api.github.com/users/jckarter/followers","following_url":"https://api.github.com/users/jckarter/following{/other_user}","gists_url":"https://api.github.com/users/jckarter/gists{/gist_id}","starred_url":"https://api.github.com/users/jckarter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jckarter/subscriptions","organizations_url":"https://api.github.com/users/jckarter/orgs","repos_url":"https://api.github.com/users/jckarter/repos","events_url":"https://api.github.com/users/jckarter/events{/privacy}","received_events_url":"https://api.github.com/users/jckarter/received_events","type":"User","site_admin":false},"created_at":"2016-08-31T23:21:21Z","updated_at":"2016-08-31T23:21:21Z","body":"Nice catch!"}}
{"actor":{"display_login":"jckarter"}}