profile
viewpoint

filip-sakel/swift-evolution 0

This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.

hborla/swift 0

The Swift Programming Language

pull request commentapple/swift

[Constraint System] Implement heuristics for linked operator expressions in the solver proper.

@swift-ci please test compiler performance

hborla

comment created time in 2 days

pull request commentapple/swift

[Constraint System] Implement heuristics for linked operator expressions in the solver proper.

@swift-ci please smoke test compiler performance

hborla

comment created time in 2 days

PR opened apple/swift

[Constraint System] Implement heuristics for linked operator expressions in the solver proper.

This PR contains the first handful of commits from @gregomni in https://github.com/apple/swift/pull/26140, with some adjustments and an additional heuristic for pruning generic search space. Specifically:

  • Remove operator type variable merging in CSGen.
  • Favor operator overload choices that are either already bound elsewhere in the expression, or have the same type as an existing operator binding.
  • Consider the number of favored choices when choosing which disjunction to try first in selectDisjunction
  • If the solver already found an unadjusted solution, check generic requirements early in order to filter out generic operator overloads that obviously won't work. This prunes a lot of the search space for some obvious cases that use generic operators such as collection + collection + collection ....

Thank you to Greg for the initial work in this PR!!

Note: This isn't ready for review yet, but I want to see the initial results of a compiler performance test

+226 -137

0 comment

17 changed files

pr created time in 2 days

push eventhborla/swift

Holly Borla

commit sha 75dc82f45b52d3371faede75d25eddca5d691a45

[ConstraintSystem] Allow the solver to find other solutions after successfully finding a solution by favoring operators already bound elsewhere. Favoring existing operator bindings often lets the solver find a solution fast, but it's not necessarily the best solution.

view details

Holly Borla

commit sha ffff44b83aba9caa35bb83880713c3b26d94f9b1

[ConstraintSystem] If the solver has already found an unadjusted solution, check to see if known argument types satisfy generic operator requirements early, and skip the overload choice if any requirements fail. This helps the solver avoid exploring way too much search space when the right solution involves a generic operator overload, but the argument types are known up front, such as `collection + collection + collection`.

view details

Holly Borla

commit sha 2967fe86b1c98512204bcaec0019db16825481a5

[Test] Adjust type checker performance tests

view details

push time in 2 days

PullRequestReviewEvent

push eventhborla/swift

Holly Borla

commit sha 30d4b26073eb0d5423cedc6262c357c6dd3c78b2

[ConstraintSystem] If the solver has already found an unadjusted solution, check to see if known argument types satisfy generic operator requirements early, and skip the overload choice if any requirements fail. This helps the solver avoid exploring way too much search space when the right solution involves a generic operator overload, but the argument types are known up front, such as `collection + collection + collection`.

view details

push time in 2 days

PullRequestReviewEvent

Pull request review commentapple/swift

[ConstraintSystem] Record trailing choice match choice when arguments…

 ConstraintSystem::simplifyApplicableFnConstraint(   ConstraintLocatorBuilder outerLocator =     getConstraintLocator(anchor, parts, locator.getSummaryFlags()); +  // If the types are obviously equivalent, we're done. This optimization+  // is not valid for operators though, where an inout parameter does not+  // have an explicit inout argument.+  if (type1.getPointer() == desugar2) {+    if (!isOperator || !hasInOut()) {+      recordTrailingClosureMatch(+          getConstraintLocator(+              outerLocator.withPathElement(ConstraintLocator::ApplyArgument)),+          TrailingClosureMatching::Forward);

Gotcha, thanks!

xedin

comment created time in 5 days

PullRequestReviewEvent

Pull request review commentapple/swift

[ConstraintSystem] Record trailing choice match choice when arguments…

 ConstraintSystem::simplifyApplicableFnConstraint(   ConstraintLocatorBuilder outerLocator =     getConstraintLocator(anchor, parts, locator.getSummaryFlags()); +  // If the types are obviously equivalent, we're done. This optimization+  // is not valid for operators though, where an inout parameter does not+  // have an explicit inout argument.+  if (type1.getPointer() == desugar2) {+    if (!isOperator || !hasInOut()) {+      recordTrailingClosureMatch(+          getConstraintLocator(+              outerLocator.withPathElement(ConstraintLocator::ApplyArgument)),+          TrailingClosureMatching::Forward);

I'm not super familiar with the trailing closure implementation - does recordTrailingClosureMatch just record which trailing closure matching strategy was used for the call?

xedin

comment created time in 5 days

PullRequestReviewEvent
PullRequestReviewEvent

push eventhborla/swift

Alexey Komnin

commit sha 4fa17bf59774ae6543a33b1a29f01320705f4dfe

SR-12022: refactor LiteralExpr to combine common initializer code

view details

Michael Gottesman

commit sha d3e6ffdbad9ed2af857508891a4530b7f11d4c6e

[lldb-toolbox] Add the ability to disassemble-to-file a specific function from a target without running the target. The routine already supports dumping the assembly to file if we are at a breakpoint using the current frame. This adds a -n option so one can without running just dump the assembly to a file of a specific function in a binary.

view details

Dave Lee

commit sha 27330f169df5d2dcb018ab2c6615d66be91d04e2

[build] Remove unused lldb cmake

view details

Mike Ash

commit sha 630aff7b19b80f29445b645424e20fd1bb6bd551

[Runtime] Change SimpleGlobalCache to use ConcurrentReadableHashMap instead of ConcurrentMap. This gives us faster lookups and a small advantage in memory usage. Most of these maps need stable addresses for their entries, so we add a level of indirection to ConcurrentReadableHashMap for these cases to accommodate that. This costs some extra memory, but it's still a net win. A new StableAddressConcurrentReadableHashMap type handles this indirection and adds a convenience getOrInsert to take advantage of it. ConcurrentReadableHashMap is tweaked to avoid any global constructors or destructors when using it as a global variable. ForeignWitnessTables does not need stable addresses and it now uses ConcurrentReadableHashMap directly. rdar://problem/70056398

view details

Alexis Laferrière

commit sha e61ffea42c943044fe4fc8c35d5040bc8815e420

[Sema] Check availability in inlinable code using the explicit version Inlinable functions can be inlined in clients with a lower OS target version than the framework defining the function. For this reason, the availability in inlinable functions should always be checked using the explicit introduction OS version as lower bound and not the minimum deployment version. rdar://problem/67975153

view details

Alexis Laferrière

commit sha 53e04cb39db86d890ff674b775a5dbda47e9d599

[Sema] Test explicit versions in TypeRefinementContext

view details

Alexis Laferrière

commit sha 2f182c2b785f5f7b68ee756d1474f21f3050ba67

[Sema] Consider unavailable functions as being unreachable This has the effect of rejecting unavailable overrides to available methods in a similar way as overrides that are less available than the introduction are rejected.

view details

Alexis Laferrière

commit sha 39ee5916bd656cf56c75ddf45a47e628d0ff1db1

[SIL] Don't print availability for unreachable/unavailable functions

view details

Alexis Laferrière

commit sha c79d5cfbd6952c5dc141a24db10a87d548bc5f4f

[Sema] Still use the current minimum deployment target as fallback

view details

Alexis Laferrière

commit sha 25c9ddd7c817d4dee5a1643cc0fc32f3cf833af2

[Sema] Prioritize unavailability check for protocol witnesses The errors on explicit unavailability are more precise than those on availablity version. Make sure we prioritize the unavailability ones first.

view details

Alexis Laferrière

commit sha f536a581082633e33ea8849b7f1d2f9b0d816c6c

[Sema] Silence an inconsistent availability error for the stdlib Don't raise the error availability_decl_more_than_enclosing in the context is unavailable and if read in a swiftinterface file. This error was present in the stdlib in 5.3 without side effects so we still want to accept it.

view details

Alexis Laferrière

commit sha 429017fc7acc303d70c6251eec7c59c97255fa96

[ClangImporter] Import unavailable decls as unavailable

view details

Alexis Laferrière

commit sha d2343f23a4d14b37f1f603ae13e3421fb5455df4

[Sema] Create a new TypeRefinementContext only for explicit inlinables

view details

Alexis Laferrière

commit sha 1ca852e77a00bf8323494d7445d054ea28466b99

[Sema] Accept unavailable constructors override in unavailable types Preserve the old behavior of accepted unavailable override of constructors as this change would be source breaking.

view details

Alexis Laferrière

commit sha fca7d36cb42b044b1179254d6e38f2b8a263eeed

[Sema] Use the deployment target as minimum OS version in swiftinterfaces Preserve the previous behavior when parsing swiftinterfaces as the Swift stdlib for Swift 5.3 and a few other swiftinterfaces in Xcode 12.0 had issues that would now be reported as errors.

view details

Erik Eckstein

commit sha aced5c74df5804b7c567a1ae9cf68b7e9cb336ee

SILOptimizer: Remove InspectionMode from MemBehehaviorVisitor The InspectionMode was never set to anything else than "IgnoreRetains"

view details

Erik Eckstein

commit sha d4a6bd39b686307028b850d25a2a2fbc337160a3

SILOptimizer: improve MemBehavior for apply instructions. 1. Do a better alias analysis for "function-local" objects, like alloc_stack and inout parameters 2. Fully support try_apply and begin/end/abort_apply So far we fully relied on escape analysis. But escape analysis has some shortcomings with SIL address-types. Therefore, handle two common cases, alloc_stack and inout parameters, with alias analysis. This gives better results. The biggest change here is to do a quick check if the address escapes via an address_to_pointer instructions.

view details

Erik Eckstein

commit sha 9f85cb8576becac281397e967e67ec44e5aabc5b

TempRValueElimination: handle potential modifications of the copy-source in a called functions correctly. This fixes a miscompile in case the source of the optimized copy_addr is modified in a called function with to a not visible alias. This can happen with class properties or global variables. This fix removes the special handling of function parameters, which was just wrong. Instead it simply uses the alias analysis API to check for modifications of the source object. The fix makes TempRValueElimination more conservative and this can cause some performance regressions, but this is unavoidable. rdar://problem/69605657

view details

Erik Eckstein

commit sha 68f485424c2b655075c77877acc9ed05756c5d08

SILOptimizer: add an additional TempRValueOpt pass later in the pipeline. This can compensate the performance regression of the more conservative handling of function calls in TempRValueOpt (see previous commit). The pass runs after the inlining passes and can therefore optimize in some cases where it's not possible before inlining.

view details

Mishal Shah

commit sha 2324aceec85904e20c5a5fd6ca097c87b854673e

Update the Apple Watch Simulator to Series 5

view details

push time in 9 days

push eventhborla/swift

Doug Gregor

commit sha 21a0696e165747248ac5f4532feeb942e13e326b

[Concurrency] Clean up inference logic for @asyncHandler.

view details

Doug Gregor

commit sha dee5356021f49ea31954e3ecc2170d285d47804c

[Concurrency] Add inferred actor-isolation attributes. When we infer an actor-isolation attribute on a declaration, add an implicit attribute that will show up in the printed interface and get serialized. ... and clean up the type resolution logic for global actor attributes to make it use CustomAttrTypeRequest, so the result gets appropriately cached in CustomAttr for serialization.

view details

Doug Gregor

commit sha 4032cd8e7d4857dad9e07782212e30848580ca56

Rename CustomAttrTypeKind::PropertyDelegate to PropertyWrapper.

view details

Alexis Laferrière

commit sha e509d6883a068334df96f34ade141d8c38dfd1f0

Revert "[Sema] Fix availability checking in inlinable code"

view details

Arnold Schwaighofer

commit sha d6d921d7fafcfa67e500e6013f93ac30f6248b79

IRGen: Fix fixLifetime emission of enums rdar://70270724

view details

Robert Widmann

commit sha 6125d25cb4f5059f455b3c6f4bde70f6aa79f59e

[NFC] Silence Non-Exhaustive Switch Warnings on Windows

view details

Robert Widmann

commit sha 9c879c008e642278b2bce557db19b78ca391caad

Resolve Virtual Inheritance By Dominance By Being Explicit Since the alternative is name lookup selecting members from a pure virtual base, it's probably best to be explicit here.

view details

Alexis Laferrière

commit sha 0d8f689d1c50121c13980eadf7ee58917a930aef

Merge pull request #34306 from apple/revert-33855-availability-inlinable Revert "[Sema] Fix availability checking in inlinable code"

view details

Robert Widmann

commit sha ba737b563154e2e5261c57c482699d6ee8f4abf3

[NFC] Use an Explicit 64-Bit Shift

view details

Robert Widmann

commit sha 0d6a16258a1519b59644618be1ae2280476878ba

Silence a Deprecation Warning with FixedVectorType

view details

Saleem Abdulrasool

commit sha 78bc6aae363ff8e82d28aa7725c562ecf7e66ab2

Platform: link against Pathcch.lib when using pathcch.h The MSDN documentation indicates that you should link against the `Pathcch.lib` import library when using functions from `pathcch.h` which can also be verified by use functions failing to link due to unresolved symbols. Add the missing linking to enable autolinking for `WinSDK`.

view details

Arnold Schwaighofer

commit sha 1c85d201921abcedbd3a693229f597a6d015f81d

Try to appease 32bit tests

view details

Holly Borla

commit sha 1e0038c3be0f6f2fbe1ba6ccb7fa394b7320aa22

[ConstraintSystem] Remove implementation of operator designated types in the solver.

view details

Robert Widmann

commit sha 476890cac5224f1c9a2fcfee5a2267bd44d24466

Merge pull request #34312 from CodaFi/just-keep-passing-the-open-windows Silence a Raft of Warnings from the Windows Build

view details

Holly Borla

commit sha 4c0f49f7a6a7a642cd57aeec70e8b392f3296cf1

[ConstraintSystem] Remove selectApplyDisjunction, which was only used by the operator designated types implementation.

view details

Mishal Shah

commit sha 1d4fd87ee603a954ec078be88bf0d64962c001c8

[update-checkout] Add scheme to test a branch

view details

Saleem Abdulrasool

commit sha d3108db2429b29b96f452374a70fe74b08678fd6

Merge pull request #34314 from compnerd/autolinking-pathcch Platform: link against Pathcch.lib when using pathcch.h

view details

swift-ci

commit sha f9609079161420e152c325ba67e36d992bcdc2c0

Merge pull request #34316 from apple/shahmishal/test/update-checkout-scheme

view details

Slava Pestov

commit sha 3d0e35e082c5f18da4a6eff30fe08706f26695fa

Sema: Remove a bit of dead code

view details

Slava Pestov

commit sha 94e999a1b55dd14284d96b60e1b67de7aae71dac

Sema: Pull availability checking out of resolveType() We used to diagnose references to unavailable declarations in two places: - inside Exprs, right after type checking the expression - inside TypeReprs, from resolveType() In broad terms, resolveType() is called with TypeReprs stored inside both Stmts and Decls. To handle the first case, I added a new overload of diagAvailability() that takes a Stmt, to be called from typeCheckStmt(). This doesn't actually walk into any Exprs stored inside the statement; this means it only walks Patterns and such. For the second case, a new DeclAvailabilityChecker is now defined in TypeCheckAccess.cpp. It's structure is analogous to the other three walkers there: - AccessControlChecker - UsableFromInlineChecker - ExportabilityChecker The new implementation of availability checking for types introduces a lot more code than the old online logic it replaces. However, I hope to consolidate some of the code duplication among the four checkers that are defined in TypeCheckAccess.cpp, and do some other cleanups that will make the benefit of the new approach apparent.

view details

push time in 10 days

push eventapple/swift

Holly Borla

commit sha 1e0038c3be0f6f2fbe1ba6ccb7fa394b7320aa22

[ConstraintSystem] Remove implementation of operator designated types in the solver.

view details

Holly Borla

commit sha 4c0f49f7a6a7a642cd57aeec70e8b392f3296cf1

[ConstraintSystem] Remove selectApplyDisjunction, which was only used by the operator designated types implementation.

view details

Holly Borla

commit sha 529660d2c96f04c8abba187923d913c5dbd31e75

Merge pull request #34315 from hborla/remove-operator-designated-types [ConstraintSystem] Remove implementation of operator designated types in the solver.

view details

push time in 10 days

delete branch hborla/swift

delete branch : remove-operator-designated-types

delete time in 10 days

PR merged apple/swift

[ConstraintSystem] Remove implementation of operator designated types in the solver.

Remove the -solver-enable-operator-designated-types flag and implementation in the solver. This experimental feature is no longer being explored, and we're implementing other approaches to improving constraint solver performance that break this feature.

There's a little more to remove (the -enable-operator-designated-types flag enables designated types in the parser, and designated type syntax is adopted in the standard library) but this lets me make more progress on chipping away at solver performance hacks.

+55 -254

2 comments

22 changed files

hborla

pr closed time in 10 days

pull request commentapple/swift

[ConstraintSystem] Remove implementation of operator designated types in the solver.

@swift-ci please smoke test

hborla

comment created time in 10 days

push eventhborla/swift

Holly Borla

commit sha 4c0f49f7a6a7a642cd57aeec70e8b392f3296cf1

[ConstraintSystem] Remove selectApplyDisjunction, which was only used by the operator designated types implementation.

view details

push time in 10 days

Pull request review commentapple/swift

[ConstraintSystem] Remove implementation of operator designated types in the solver.

 Constraint *ConstraintSystem::selectDisjunction() {   if (disjunctions.empty())     return nullptr; -  // Attempt apply disjunctions first. When we have operators with-  // designated types, this is important, because it allows us to-  // select all the preferred operator overloads prior to other-  // disjunctions that we may not be able to short-circuit, allowing-  // us to eliminate behavior that is exponential in the number of-  // operators in the expression.-  if (getASTContext().TypeCheckerOpts.SolverEnableOperatorDesignatedTypes) {-    if (auto *disjunction = selectApplyDisjunction())

Ah you're right, thanks for catching that!

hborla

comment created time in 10 days

PullRequestReviewEvent

Pull request review commentapple/swift-evolution

[Proposal] Extend Property Wrappers to Function and Closure Parameters

+# Extend Property Wrappers to Function and Closure Parameters++* Proposal: [SE-NNNN](NNNN-extend-property-wrappers-to-function-and-closure-parameters.md)+* Authors: [Holly Borla](https://github.com/hborla), [Filip Sakel](https://github.com/filip-sakel)+* Review Manager: TBD+* Status: **Awaiting implementation**+++## Introduction++Property Wrappers were [introduced in Swift 5.1](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md), and have since become a popular feature abstracting away common accessor patterns for properties. Currently, applying a property wrapper is solely permitted on properties inside of a type context. However, with increasing adoption demand for extending _where_ property wrappers can be applied has emerged. This proposal aims to extend property wrappers to function and closure parameters.+++## Motivation++Property wrappers have undoubtably been very successful. Applying a property wrapper to a property is enabled by an incredibly lightweight and expressive syntax. Therefore, library authors can expose complex behavior through easily understandable property-wrapper types in an efficient manner. For instance, frameworks such as [SwiftUI](https://developer.apple.com/documentation/swiftui/) and [Combine](https://developer.apple.com/documentation/combine) introduce property wrappers such as [`State`](https://developer.apple.com/documentation/swiftui/state), [`Binding`](https://developer.apple.com/documentation/swiftui/binding) and [`Published`](https://developer.apple.com/documentation/combine/published) respectively to expose elaborate behavior through a succint interface, helping craft expressive yet simple APIs. However, property wrappers are only applicable to type properties, shattering the illusion that they helped realize in the first place:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {++  init(+    wrappedValue: Value,+    to range: Range<Value>+  ) { ... }+  +  +  var wrappedValue: Value { +    get { ... }+    set { ... }+  }+  +}+++struct Percentage {++  @Clamped(to: 0 ... 100)+  var percent = 0+     +     +  mutating func increment() {+    percent += 1+    // Great!+  }++  mutating func adding(_ offset: Int) {+    percent += min(100, max(0, offset))+    //         ^~~~~~~~~~~~~~~~~~~~~~~~+    // We are forced to manually adjust 'percent' +    // instead of utilizing the abstraction +    // property wrappers offer.+  }++  mutating func adding(_ offset: Clamped<Int>) {+    //                   ^~~~~~~~~~~~~~~~~~~~+    // Unfortunately, we can't use +    // '@Clamped(to: 0 ... 100)' here.+    +    percent += offset.wrappedValue+    //               ^~~~~~~~~~~~~+    // We must access 'wrappedValue' manually.+  }+  +}+```++As seen in the above example, it is quite awkward and unintuitive that property wrappers cannot be applied to function parameters. In this case, a property wrapper parameter would be useful for expressing and enforcing invariants about the `offset` argument to the `adding` method on `Percentage`. Inability to allow the property wrapper attribute on the `offset` parameter causes the API author to choose between making invariant checking an implementation detail, or forcing the invariant checking on every caller of the API.++This limitation in expressivity is emphasized by the fact that property wrappers were originally sought out to abstract away such patterns.  As a result, elegant APIs are undermined by this limitation. Not only is this limiting users by forcing them to carefully read documentation, which may not cover a specific use case, to make sure no invariants have been violated, but it also limits API authors in what they can create. That is, API authors can't use property-wrapper types in closure parameters nor can code be seperated into functions that accept property wrapper syntax:++```swift+extension Percentage {++  func modify(+    inSeconds seconds: Int,+    block: @escaping (inout Clamped<Int>) -> Void+  ) { ... }+  +}+++let myPercentage = Percentage(percent: 50)++myPercentage+  .modify(inSeconds: 3) { percent in+    percent.wrappedValue = 100+    //    ^~~~~~~~~~~~ +    // Again, we have to access+    // count through 'wrappedValue'.+  }+```++In fact, establishing custom behavior on closure parameters is really powerful. For example, if such a feature were supported, it could be used in conjunction with [Function Builders](https://github.com/apple/swift-evolution/blob/master/proposals/0289-function-builders.md) to expose data managed by a 'component' type. For instance, in SwiftUI [`ForEach`](https://developer.apple.com/documentation/swiftui/foreach) could leverage this feature to expose the mutable state of its data source to its 'content' closure. This would enable users to more easily work with the data source itself inside the closure instead of accessing the original property, which is particularly painful when working with collections, as shown in this example:++```swift+struct MyView: View {++  // A simple Shopping Item that includes+  // a 'quantity' and a 'name' property.+  @State +  private var shoppingItems: [Item]+++  var body: some View {+    ForEach(0 ..< shoppingItems.count) { index in+  +      TextField("Enter the item's name...", $shoppingItems[index].name)+      +    }+  }+  +}+```++we would – with an appropriate initializer – be able to simplify the above code, reducing boilerplate as a result:++```swift+struct MyView: View {++  @State +  private var shoppingItems: [Item]+++  var body: some View {+    ForEach($shoppingItems) { @Binding shoppingItem in+    +      TextField("Enter the item's name...", $shoppingItem.name)+      +    }+  }+  +}+```+++## Proposed solution++We propose to extend the contexts were application of property-wrapper types is permitted. Namely, application of such types will be allowed on function and closure parameters:+++## Detailed design++Property wrappers are essentially sugar wrapping a given property with compiler synthesized code. This proposal retains this principle employing the following rules for transformation.++### Property Wrappers on Function Parameters++Function parameters marked with a set of compatible property-wrapper custom attributes must conform to the following rules:++1. Property wrapper function parameters must support initialization through their `wrappedValue` type. Therefore, all property-wrapper types must provide a suitable `init(wrappedValue:)`.+2. Each `wrappedValue` getter shall be `nonmutating`.+3. Default values for such parameters must be expressed in terms of the innermost `wrappedValue` type.++Transformation of property-wrapper parameters will be performed as such:++1. The external parameter name will remain unchanged.+2. The internal parameter name will be prefixed with an underscore.+3. The parameter will be bound to the backing property wrapper type.+4. A local computed property representing  `wrappedValue` will be synthesized by the compiler and named per the original (non-prefixed) parameter name. The accessors will mirror the `wrappedValue` accessors. A setter will only be synthesized for the local property if the `wrappedValue` setter is `nonmutating`, or if the wrapper is a reference type.+5. If the property wrapper defines a `projectedValue`, a local computed property representing  `projectedValue` will be synthesized by the compiler and named per the original parameter name prefixed with a dollar sign (`$`). The same accessor rules for `wrappedValue` apply to `projectedValue`.+6. When passing an argument to a property wrapper parameter, the compiler will wrap the argument in the appropriate `init(wrappedValue:)` call.++#### Transformation Example:++```swift+@propertyWrapper+struct Percentage {++  init(wrappedValue: Int) { ... }+    +    +  var wrappedValue: Int {+    get { ... }+    set { ... }+  }+  +}++func reportProgress(+  @Percentage of progress: Int+) { ... }+++reportProgress(of: 50)+```++In the above code, the `reportProgress(of:)` function and its caller are equivalent to:++```swift+func reportProgress(of _progress: Percentage) {++  var progress: Int {+    get { _progress.wrappedValue }+    // The setter accessor is not synthesized+    // because the setter of Percentage's  +    // 'wrappedValue' is mutating.+  }+++  ...+  +}+++reportProgress(of: Percentage(wrappedValue: 50))+```++#### Restrictions on Property Wrapper Function Parameters++##### `@autoclosure`++Function parameters with a property wrapper custom attribute cannot have an `@autoclosure` type. `@autoclosure` is unnecessary for the wrapped value itself because the wrapped value argument at the call-site will always be wrapped in a call to `init(wrappedValue:)`, which already can support `@autoclosure` arguments. Using `@autoclosure` for the backing wrapper type would be misleading, because the type spelled out for the parameter would not be the true autoclosure type. Consider the `reportProgress` example from above with an `@autoclosure` parameter:++```swift+func reportProgress(+  @Percentage progress: @autoclosure () -> Int+) { ... }+++reportProgress(of: 50)+```+The above code would be transformed to:+```swift+func reportProgress(+  progress _progress: @autoclosure () -> Percentage<Int>+) { ... }+++reportProgress(of: Percentage(wrappedValue: 50))+```+The changing type of the `@autoclosure` is incredibly misleading, as it's not obvious that `@autoclosure` applies to the backing wrapper rather than the wrapped value. Therefore, using `@autoclosure` for a property wrapper function parameter will be a compiler error.+++### Property Wrappers on Closure Parameters++Since a property wrapper custom attribute is applied directly to the declaration that will be wrapped, application of a property wrapper type is only available within a closure expression. That is, the signature of a function that contains a closure cannot include the property wrapper attibute. Instead the application of the attrbute will be up to the caller of the function, which supplies the closure argument.++Closure parameters marked with a set of property wrapper custom attributes must conform to the following rules:++1. Each wrapper attribute must not specify any arguments.+2. Each `wrappedValue` getter shall be `nonmutating`.+3. Any contextual type for the parameter must match the outermost backing wrapper type.++The transformation of a property wrapper closure parameter will take place as follows:++1. The parameter name will be prefixed with an underscore.+2. The parameter will be bound to the backing property wrapper type.+3. A local computed property representing  `wrappedValue` will be synthesized by the compiler and named per the original (non-prefixed) parameter name. The accessors will mirror the `wrappedValue` accessors. A setter will only be synthesized for the local property if the `wrappedValue` setter is `nonmutating`, or if the wrapper is a reference type.+4. If the property wrapper defines a `projectedValue`, a local computed property representing  `projectedValue` will be synthesized by the compiler and named per the original parameter name prefixed with a dollar sign (`$`). The same accessor rules for `wrappedValue` apply to `projectedValue`.++#### Transformation Example:++```swift+@propertyWrapper+struct Reference<Value> {++  init(+    getter: @escaping () -> Value,+    setter: @escaping (Value) -> Void+  ) { ... }+    +    +  var wrappedValue: Value {+    get +    nonmutating set+  }+    +  var projectedValue: Self {+    self+  }+  +}++typealias A = (Reference<Int>) -> Void++let a: A = { @Reference reference in+  ...+}+```++In the above example, the closure `a` is equivalent to:++```swift+let a: A = { (_reference: Reference<Int>) in++  var reference: Int {+    get { +      _reference.wrappedValue+    }+    set { +      _reference.wrappedValue = newValue+    }+  }++  var $reference: Int {+    get { +      _reference.projectedValue+    }+  }+    +    +  ...+  +}+```++## Source compatibility++This is an additive change with _no_ impact on **source compatibility**.+++## Effect on ABI stability++This is an additive change with _no_ impact on **ABI stability**.+++## Effect on API resilience++This is an additive change with _no_ impact on **API resilience**.+++## Alternatives Considered++### Allow Property Wrapper Attributes as Type Attributes++One approach for marking closure parameters as property wrappers is to allow property wrapper custom attributes to be applied to types, such as:++```swift+func useReference(+  _ closure: (@Reference reference: Int) -> Void+) { ... }+++useReference { reference in+  ...+}+```++This approach enables inference of the wrapper attribute on the closure parameter from context. However, this breaks the property wrapper declaration model, and it would force callers into the property wrapper syntax. This approach also raises questions about anonymous closure parameters that have an inferred property wrapper custom attribute. If an anonymous closure parameter `$0` has the `wrappedValue` type, accessing the backing wrapper and projected value would naturally use `_$0` and `$$0`, which are far from readable. If `$0` has the backing wrapper type, this would mean that naming the parameter would cause the value to change types, which is very unexpected for the user. Finally, the property wrapper syntax is purely implementation detail for the closure body, which does not belong in the API signature.+++## Future Directions++### Support Property Wrapper Initialization from a Projected Value++Today, a property wrapper can be initialized from an instance of its `wrappedValue` type if the wrapper provides a suitable `init(wrappedValue:)`. The same initialization strategy is used in this proposal for property wrapper parameters to allow users to pass a wrapped value as a property wrapper argument. We could extend this model to support initializing a property wrapper from an instance of its `projectedValue` type by allowing property wrappers to define an `init(projectedValue:)` that follows the same rules as `init(wrappedValue:)`. This could allow users to additionally pass a projected value as a property wrapper argument, like so:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {++  ...+  ++  init(projectedValue: Self) { ... }+  +}++func distanceFromUpperBound(+  @Clamped clamped: Int+) { ... }+++distanceFromUpperBound(+  $clamped: Clamped(to: 0 ... 100, wrappedValue: 30)+) // returns: 70+```+++### Add Support for `inout` Wrapped Parameters is Functions++This proposal doesn't currently support marking function parameters to which wrapper types have been applied `inout`. We deemed that this functionality would be better tackled by another proposal due to its implementation complexity. However, such a feature would be really useful for wrapper types with value semantics and it would simplify the mental model. Furthermore, it could alleviate some confusion for users that don't understand the difference between a setter with value semantics and one with reference semantics.+++### Accessing Enclosing Self from Wrapper Types++There's currently no public feature that allows a wrapper to access its enclosing `Self` type:++```swift+@propertyWrapper+struct Mirror<EnclosingSelf, Value, Path>+  where Path : KeyPath<EnclosingSelf, Value> { +  +  let keyPath: Path +++  init(of keyPath: Path) { ... }+  +}+++struct Point {++  private var _vector: SIMD2<Double>+  +  +  init(x: Double, y: Double) {+    self._vector = SIMD2(x: x, y: y)+  }+  +  +  @Mirror(of: \._vector.x)+  var x+  +  @Mirror(of: \._vector.y)+  var y+  +} ❌+// In the above use, we'd access the enclosing+// type's '_vector' property through the provided+// keyPath. However, today that's invalid.+```++Furthermore, extending this feature's availability to function and closure parameters be really powerful:++```swift+func valueAndIdPair<Value>(+  @Mirror of property: Value+) -> (value: Value, id: Int) {+  (value: property, id: $property.keyPath.hashValue)+}+```++It's important to note that allowing use of such a feature in function parameters would entail some limitations. For example, a parameter marked with a wrapper type referencing enclosing `self` would be an error for a non-instance method, as the accessors for the `wrappedValue` and `projectedValue` need an enclosing `self` instance.++### Add Wrapper Types in the Standard Library++Adding wrapper types to the Standard Library has been discussed for types [such as `@Atomic`] and [`@Weak`](https://forums.swift.org/t/should-weak-be-a-type/34032), which would facilitate certain APIs. Another interesting Standard Library wrapper type could be `@UnsafePointer`, which would be quite useful, as access of the `pointee` property is quite common:++```swift+let myPointer: UnsafePointer<UInt8> = ...++myPointer.pointee +//        ^~~~~~~ +// This is the accessor pattern property +// wrappers were devised to tackle.+```++Instead of writing the above, in the future one might be able to write this:++```swift+let myInt = 0++withUnsafePointer(to: ...) { @UnsafePointer value in++  print(value) // 0+  +  $value.withMemoryRebound(to: UInt64.self {+    ... +  }+  +}+```++As a result, unsafe code is not dominated by visually displeasing accesses to `pointee` members; rather, more natural and clear code is enabled. ++What's more, a `@Lazy` type could be added so as to alleviate the need for custom behavior built into the compiler. Instead, `@Lazy` would act as more comprehensible, easy to maintain type, that would also allow for a more streamlined way of resetting its storage:

That's fair - it's not worth raising a bunch of questions just for a future direction. I think we should find another example or just remove the section. Somebody on the pitch thread had suggested creating a "manifesto" document for all of the future directions for property wrappers that have been floating around, and we could put all the work you've done for this section in there so it doesn't get lost!

filip-sakel

comment created time in 10 days

PullRequestReviewEvent

pull request commentapple/swift

[ConstraintSystem] Remove implementation of operator designated types in the solver.

@swift-ci please smoke test

hborla

comment created time in 10 days

PR opened apple/swift

Reviewers
[ConstraintSystem] Remove implementation of operator designated types in the solver.

Remove the -solver-enable-operator-designated-types flag and implementation in the solver. This experimental feature is no longer being explored, and we're implementing other approaches to improving constraint solver performance that break this feature.

There's a little more to remove (the -enable-operator-designated-types flag enables designated types in the parser, and designated type syntax is adopted in the standard library) but this lets me make more progress on chipping away at solver performance hacks.

+55 -228

0 comment

22 changed files

pr created time in 10 days

create barnchhborla/swift

branch : remove-operator-designated-types

created branch time in 10 days

create barnchhborla/swift

branch : main

created branch time in 11 days

create barnchhborla/swift

branch : optimize-linked-operator-solving

created branch time in 11 days

push eventfilip-sakel/swift-evolution

Holly Borla

commit sha 6defa9ab2eb64e04f5406d5fda04ae0e18ad6506

[Property Wrapper Parameters] Fix a typo in code example

view details

Holly Borla

commit sha 74cf5b363ced1492f14409d0a4dbb44acc4dedac

[Property Wrapper Parameters] Clarify API Resilience section.

view details

Holly Borla

commit sha 26b80034d704147cf22fdc6222cfe0c0d9147e6b

[Property Wrapper Parameters] Add implementation PR link

view details

push time in 11 days

push eventhborla/swift

Mike Ash

commit sha ece0399d601eec1069131f465bdbe7e16f4c6a50

[Runtime] Have ConcurrentReadableHashMap use 1-byte or 2-byte indices when possible.

view details

Doug Gregor

commit sha e36011def493dceec79381f2e4a051f1f1e610fe

[Type checker] Delay the diagnosis of missing witnesses further. The handling of "global" missing witnesses would diagnose a missing witness (showing "almost" matches) and then, later, provide the Fix-It to add the declaration if the user wants it. Delay the diagnostic part until later, when we add the missing witness. While here, correct an existing issue with memory corruption that occurs because we would diagnose some of these witnesses, then clear a "global" witness list, while still iterating through parts of that list.

view details

Doug Gregor

commit sha fe4a8bb9f926684d2621fba13cc326580380bcbc

[Clang importer] Allow both sync and async imports with the same name. The Clang importer was filtering out cases where the same declaration is imported twice under the same name, which can now happen when one is synchronous and one is asynchronous. This happens when, e.g., an Objective-C class provides both a completion-hander-based asynchronous version and a synchronous version, and the Swift names line up after the completion-handler parameter is dropped. Stop filtering these out. Overload resolution is capable of handling synchronous/asynchronous overloading based on context.

view details

Doug Gregor

commit sha 50f870566a1a35b4073adb1bce078451790b74a5

Handle conformance with multiple protocol requirements with the same selector. When concurrency is enabled, the same Objective-C method on a protocol can be imported as two different protocol requirements, both of which have the same selector. When performing conformance checking, only treat a given @objc protocol requirement as "unsatisfied" by a conformance if none of the requirements with the same Objective-C selector (+ instance/class designation) are satisfied.

view details

Doug Gregor

commit sha 591e6e89e259818a8dd56bbba41057e776d92c8a

[Concurrency] Only infer @asyncHandler for witnesses within actor classes. Actor classes are by definition new code, so only perform inference of @asyncHandler from a protocol requirement to witnesses when those witnesses are within an actor class. This is partly because @asyncHandler might not have reasonable semantics outside of actor classes anywhere (where would you execute the detached task?), and partly because it is a source-compatibility problem due to the combination of... 1) Inferring @asyncHandler on imported Objective-C protocol methods for existing protocols, 2) Inferring @asyncHandler from those protocol methods to an existing method in a class that conforms to that protocol, and 3) Using an API that is now overloaded for both synchronous and asynchronous callers will end up preferring the asynchronous version, then fail due to a missing "await". The individual steps here are all reasonable, but the result is a source break, so back off on @asyncHandler inference for witnesses outside of actor classes. New code gets the more-asynchronous behavior for free.

view details

Doug Gregor

commit sha bb066b6fa68f06885c84838be7f7e264d70bc0e6

[Concurrency] Make actor-isolated protocol witnesses an error. With actor isolation checking for protocol witnesses moved out of the witness-matching phase, move the corresponding diagnostics from notes (that would have been on the "type does not conform" error) to freestanding errors.

view details

Simon Evans

commit sha 960d0e30ee2b70ba3bb7ec076c16045afab01589

Linux: Fix -static-executable and remove swiftImageInspectionShared - Remove references to swiftImageInspectionShared on Linux and dont have split libraries between static/non-static linked executables. - -static-executable now links correctly Linux. Note: swift::lookupSymbol() will not work on statically linked executables but this can be worked around by using the https://github.com/swift-server/swift-backtrace package.

view details

Cassie Jones

commit sha 8ffaf79ec2e106a58dff2402a06210bf9ca97357

[build] Support installing swift-driver without swiftpm The install-swift-driver phase knows how to build swift-driver using CMake. Allowing only install-swift-driver without plain swift-driver allows installing it without requiring swiftpm.

view details

Michael Gottesman

commit sha e7761cf997897aaa38af0d0969ca9acd7e504fbf

[DebuggingTheCompiler] Document a few flags for dumping llvm-ir. I needed to use these and realized they were not documented here. I had them in my brain, but others may not, so seemed good to do.

view details

Xi Ge

commit sha 00eb2e9db2140d7a7acdd9aa3176e12df9012a7d

Frontend: add a frontend flag to disable building module from textual interface This is for testing purposes to ensure prebuilt modules are up to date. rdar://68770805

view details

Cassie Jones

commit sha 20995ae0bbf765d39cb28c63318e301c27cc2157

[build] Add FILES_MATCHING to CMakeLists.txt The bare "PATTERN" argument by default does nothing, you need either "EXCLUDE" or "FILES_MATCHING" to make it do something. This likely wasn't previously a problem because clang is only installing headers, but it should be fixed for robustness.

view details

Robert Widmann

commit sha 82e9935885bed95b0091476bfda95f4fdae14e9b

Correct the Serialization of Embedded Swift Dependencies llvm-bcanalyzer does *not* like it when there are multiple block info metadata blocks in the same bitstream file. This patch will skip the emission of that and just jump straight to the metadata block when we're not reading a "standalone" incremental dependency file. While I'm here, also add the right block abbreviation info so we can get a decent dump from llvm-bcanalyzer

view details

Robert Widmann

commit sha d7cd605c3129bd567f5be18b57eec33135dc439e

Adjust the Registration of the Pseudo-Job for External Incremental Dependencies Register the module the external dependencies ride in with the pseudo-job in the Driver. This is a hack.

view details

Robert Widmann

commit sha a77f059c8292c157f07a4de9a2d1ee9597c5b57d

Turn on Cross-Module Incremental Dependencies! Cross-Module incremental dependencies are a new experimental mode of the Swift driver and frontend. Through a tight partnership between the two, we enable the driver to have far greater visibility into the dependency structure of a Swift module. Rather than invent a new model, we have chosen to extend the existing incremental compilation model that works for a single module to multiple modules. To do this, we need the frontend to emit Swift dependencies in a form the driver can consume. We could emit these metadata in the form of an extra supplementary output that summarizes the contents of a generated module. However, this approach comes with a number of downsides: - It requires additional integration with the build system - It assumes swiftmodule files will be consumed directly from the build directory; they are not - It incorrectly assumes a swiftmodule has but one interface. Taken in aggregate, a swiftmodule directory has one interface *per triple* Given this, the approach we take here is to encode these dependencies directly into the swiftmodule file itself. When frontends load these souped-up incremental swiftmodule files, they record in their own swiftdeps files that they depend on an incremental swiftmodule. Upon the next build, the driver is then able to read that module file, extract the swiftdeps information from it, and use it to influence the way it schedules jobs. The sum total is that we neatly extend the intra-module case of incremental builds to the inter-module case by treating swiftmodule inputs not as opaque entities, but as "big ol' flat Swift files" that just export an interface like any other Swift file within the module. As a further optimization, and because clients literally cannot observe this aspect of the incremental build, we only serialize the provides (the "defs" side of a "use-def" edge) when emitting swiftdeps metadata into swiftmodule files. rdar://69595010

view details

Doug Gregor

commit sha 147f9e6c90f66068f567b5b7a14e7eb7abdafa29

Generalize test

view details

Pavel Yaskevich

commit sha f26bce350d41ec1ffefa8cae61f759985244b055

[Sema] NFC: Move `ContextualTypePurpose` to constraint system header

view details

Pavel Yaskevich

commit sha 588d42c56440db5e6166c1e979c13c8ae3343a60

[Sema] NFC: Move `FreeTypeVariableBinding` to constraint system header

view details

Meghana Gupta

commit sha 141b032e7c6ad24133905b35a6080f872feb7dac

Enable --build-sil-debugging-stdlib for all of swift/stdlib/public (#34197) Previously it was enable only for swift/stdlib/public/core

view details

Alexis Laferrière

commit sha c6fc53e844ac4fd542adb0669ac7038c2919d283

[Sema] Define availability via compiler flag Introduce availability macros defined by a frontend flag. This feature makes it possible to set the availability versions at the moment of compilation instead of having it hard coded in the sources. It can be used by projects with a need to change the availability depending on the compilation context while using the same sources. The availability macro is defined with the `-define-availability` flag: swift MyLib.swift -define-availability "_iOS8Aligned:macOS 10.10, iOS 8.0" .. The macro can be used in code instead of a platform name and version: @available(_iOS8Aligned, *) public func foo() {} rdar://problem/65612624

view details

Alexis Laferrière

commit sha 5ed261683d5973ef4dd45922b5ac77ba7cefcf43

[Sema] Report availability macros in inlinable code Availability macros can’t be used in inlinable code as inlinable is copied textually in the generated swiftinterface files. Further would could lift this limitation.

view details

push time in 12 days

pull request commentapple/swift

[Property Wrappers] Support property wrappers on function and closure parameters

@swift-ci please build toolchain

hborla

comment created time in 12 days

push eventhborla/swift

Holly Borla

commit sha ec28ed15e01e91735b173fcc975d57b2aee5646f

[ConstraintSystem] Use a wrapped value placeholder when matching property wrapper arguments in the constraint system in order to avoid generating constraints for the argument multiple times.

view details

push time in 13 days

Pull request review commentapple/swift-evolution

[Proposal] Extend Property Wrappers to Function and Closure Parameters

+# Extend Property Wrappers to Function and Closure Parameters++* Proposal: [SE-NNNN](NNNN-extend-property-wrappers-to-function-and-closure-parameters.md)+* Authors: [Holly Borla](https://github.com/hborla), [Filip Sakel](https://github.com/filip-sakel)+* Review Manager: TBD+* Status: **Awaiting implementation**+++## Introduction++Property Wrappers were [introduced in Swift 5.1](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md), and have since become a popular feature abstracting away common accessor patterns for properties. Currently, applying a property wrapper is solely permitted on properties inside of a type context. However, with increasing adoption demand for extending _where_ property wrappers can be applied has emerged. This proposal aims to extend property wrappers to function and closure parameters.+++## Motivation++Property wrappers have undoubtably been very successful. Applying a property wrapper to a property is enabled by an incredibly lightweight and expressive syntax. Therefore, library authors can expose complex behavior through easily understandable property-wrapper types in an efficient manner. For instance, frameworks such as [SwiftUI](https://developer.apple.com/documentation/swiftui/) and [Combine](https://developer.apple.com/documentation/combine) introduce property wrappers such as [`State`](https://developer.apple.com/documentation/swiftui/state), [`Binding`](https://developer.apple.com/documentation/swiftui/binding) and [`Published`](https://developer.apple.com/documentation/combine/published) respectively to expose elaborate behavior through a succint interface, helping craft expressive yet simple APIs. However, property wrappers are only applicable to type properties, shattering the illusion that they helped realize in the first place:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {++  init(+    wrappedValue: Value,+    to range: Range<Value>+  ) { ... }+  +  +  var wrappedValue: Value { +    get { ... }+    set { ... }+  }+  +}+++struct Percentage {++  @Clamped(to: 0 ... 100)+  var percent = 0+     +     +  mutating func increment() {+    percent += 1+    // Great!+  }++  mutating func adding(_ offset: Int) {+    percent += min(100, max(0, offset))+    //         ^~~~~~~~~~~~~~~~~~~~~~~~+    // We are forced to manually adjust 'percent' +    // instead of utilizing the abstraction +    // property wrappers offer.+  }++  mutating func adding(_ offset: Clamped<Int>) {+    //                   ^~~~~~~~~~~~~~~~~~~~+    // Unfortunately, we can't use +    // '@Clamped(to: 0 ... 100)' here.+    +    percent += offset.wrappedValue+    //               ^~~~~~~~~~~~~+    // We must access 'wrappedValue' manually.+  }+  +}+```++As seen in the above example, it is quite awkward and unintuitive that property wrappers cannot be applied to function parameters. In this case, a property wrapper parameter would be useful for expressing and enforcing invariants about the `offset` argument to the `adding` method on `Percentage`. Inability to allow the property wrapper attribute on the `offset` parameter causes the API author to choose between making invariant checking an implementation detail, or forcing the invariant checking on every caller of the API.++This limitation in expressivity is emphasized by the fact that property wrappers were originally sought out to abstract away such patterns.  As a result, elegant APIs are undermined by this limitation. Not only is this limiting users by forcing them to carefully read documentation, which may not cover a specific use case, to make sure no invariants have been violated, but it also limits API authors in what they can create. That is, API authors can't use property-wrapper types in closure parameters nor can code be seperated into functions that accept property wrapper syntax:++```swift+extension Percentage {++  func modify(+    inSeconds seconds: Int,+    block: @escaping (inout Clamped<Int>) -> Void+  ) { ... }+  +}+++let myPercentage = Percentage(percent: 50)++myPercentage+  .modify(inSeconds: 3) { percent in+    percent.wrappedValue = 100+    //    ^~~~~~~~~~~~ +    // Again, we have to access+    // count through 'wrappedValue'.+  }+```++In fact, establishing custom behavior on closure parameters is really powerful. For example, if such a feature were supported, it could be used in conjunction with [Function Builders](https://github.com/apple/swift-evolution/blob/master/proposals/0289-function-builders.md) to expose data managed by a 'component' type. For instance, in SwiftUI [`ForEach`](https://developer.apple.com/documentation/swiftui/foreach) could leverage this feature to expose the mutable state of its data source to its 'content' closure. This would enable users to more easily work with the data source itself inside the closure instead of accessing the original property, which is particularly painful when working with collections, as shown in this example:++```swift+struct MyView: View {++  // A simple Shopping Item that includes+  // a 'quantity' and a 'name' property.+  @State +  private var shoppingItems: [Item]+++  var body: some View {+    ForEach(0 ..< shoppingItems.count) { index in+  +      TextField("Enter the item's name...", $shoppingItems[index].name)+      +    }+  }+  +}+```++we would – with an appropriate initializer – be able to simplify the above code, reducing boilerplate as a result:++```swift+struct MyView: View {++  @State +  private var shoppingItems: [Item]+++  var body: some View {+    ForEach($shoppingItems) { @Binding shoppingItem in+    +      TextField("Enter the item's name...", $shoppingItem.name)+      +    }+  }+  +}+```+++## Proposed solution++We propose to extend the contexts were application of property-wrapper types is permitted. Namely, application of such types will be allowed on function and closure parameters:+++## Detailed design++Property wrappers are essentially sugar wrapping a given property with compiler synthesized code. This proposal retains this principle employing the following rules for transformation.++### Property Wrappers on Function Parameters++Function parameters marked with a set of compatible property-wrapper custom attributes must conform to the following rules:++1. Property wrapper function parameters must support initialization through their `wrappedValue` type. Therefore, all property-wrapper types must provide a suitable `init(wrappedValue:)`.+2. Each `wrappedValue` getter shall be `nonmutating`.+3. Default values for such parameters must be expressed in terms of the innermost `wrappedValue` type.++Transformation of property-wrapper parameters will be performed as such:++1. The external parameter name will remain unchanged.+2. The internal parameter name will be prefixed with an underscore.+3. The parameter will be bound to the backing property wrapper type.+4. A local computed property representing  `wrappedValue` will be synthesized by the compiler and named per the original (non-prefixed) parameter name. The accessors will mirror the `wrappedValue` accessors. A setter will only be synthesized for the local property if the `wrappedValue` setter is `nonmutating`, or if the wrapper is a reference type.+5. If the property wrapper defines a `projectedValue`, a local computed property representing  `projectedValue` will be synthesized by the compiler and named per the original parameter name prefixed with a dollar sign (`$`). The same accessor rules for `wrappedValue` apply to `projectedValue`.+6. When passing an argument to a property wrapper parameter, the compiler will wrap the argument in the appropriate `init(wrappedValue:)` call.++#### Transformation Example:++```swift+@propertyWrapper+struct Percentage {++  init(wrappedValue: Int) { ... }+    +    +  var wrappedValue: Int {+    get { ... }+    set { ... }+  }+  +}++func reportProgress(+  @Percentage of progress: Int+) { ... }+++reportProgress(of: 50)+```++In the above code, the `reportProgress(of:)` function and its caller are equivalent to:++```swift+func reportProgress(of _progress: Percentage) {++  var progress: Int {+    get { _progress.wrappedValue }+    // The setter accessor is not synthesized+    // because the setter of Percentage's  +    // 'wrappedValue' is mutating.+  }+++  ...+  +}+++reportProgress(of: Percentage(wrappedValue: 50))+```++#### Restrictions on Property Wrapper Function Parameters++##### `@autoclosure`++Function parameters with a property wrapper custom attribute cannot have an `@autoclosure` type. `@autoclosure` is unnecessary for the wrapped value itself because the wrapped value argument at the call-site will always be wrapped in a call to `init(wrappedValue:)`, which already can support `@autoclosure` arguments. Using `@autoclosure` for the backing wrapper type would be misleading, because the type spelled out for the parameter would not be the true autoclosure type. Consider the `reportProgress` example from above with an `@autoclosure` parameter:++```swift+func reportProgress(+  @Percentage progress: @autoclosure () -> Int+) { ... }+++reportProgress(of: 50)+```+The above code would be transformed to:+```swift+func reportProgress(+  progress _progress: @autoclosure () -> Percentage<Int>+) { ... }+++reportProgress(of: Percentage(wrappedValue: 50))+```+The changing type of the `@autoclosure` is incredibly misleading, as it's not obvious that `@autoclosure` applies to the backing wrapper rather than the wrapped value. Therefore, using `@autoclosure` for a property wrapper function parameter will be a compiler error.+++### Property Wrappers on Closure Parameters++Since a property wrapper custom attribute is applied directly to the declaration that will be wrapped, application of a property wrapper type is only available within a closure expression. That is, the signature of a function that contains a closure cannot include the property wrapper attibute. Instead the application of the attrbute will be up to the caller of the function, which supplies the closure argument.++Closure parameters marked with a set of property wrapper custom attributes must conform to the following rules:++1. Each wrapper attribute must not specify any arguments.+2. Each `wrappedValue` getter shall be `nonmutating`.+3. Any contextual type for the parameter must match the outermost backing wrapper type.++The transformation of a property wrapper closure parameter will take place as follows:++1. The parameter name will be prefixed with an underscore.+2. The parameter will be bound to the backing property wrapper type.+3. A local computed property representing  `wrappedValue` will be synthesized by the compiler and named per the original (non-prefixed) parameter name. The accessors will mirror the `wrappedValue` accessors. A setter will only be synthesized for the local property if the `wrappedValue` setter is `nonmutating`, or if the wrapper is a reference type.+4. If the property wrapper defines a `projectedValue`, a local computed property representing  `projectedValue` will be synthesized by the compiler and named per the original parameter name prefixed with a dollar sign (`$`). The same accessor rules for `wrappedValue` apply to `projectedValue`.++#### Transformation Example:++```swift+@propertyWrapper+struct Reference<Value> {++  init(+    getter: @escaping () -> Value,+    setter: @escaping (Value) -> Void+  ) { ... }+    +    +  var wrappedValue: Value {+    get +    nonmutating set+  }+    +  var projectedValue: Self {+    self+  }+  +}++typealias A = (Reference<Int>) -> Void++let a: A = { @Reference reference in+  ...+}+```++In the above example, the closure `a` is equivalent to:++```swift+let a: A = { (_reference: Reference<Int>) in++  var reference: Int {+    get { +      _reference.wrappedValue+    }+    set { +      _reference.wrappedValue = newValue+    }+  }++  var $reference: Int {+    get { +      _reference.projectedValue+    }+  }+    +    +  ...+  +}+```++## Source compatibility++This is an additive change with _no_ impact on **source compatibility**.+++## Effect on ABI stability++This is an additive change with _no_ impact on **ABI stability**.+++## Effect on API resilience++This is an additive change with _no_ impact on **API resilience**.+++## Alternatives Considered++### Allow Property Wrapper Attributes as Type Attributes++One approach for marking closure parameters as property wrappers is to allow property wrapper custom attributes to be applied to types, such as:++```swift+func useReference(+  _ closure: (@Reference reference: Int) -> Void+) { ... }+++useReference { reference in+  ...+}+```++This approach enables inference of the wrapper attribute on the closure parameter from context. However, this breaks the property wrapper declaration model, and it would force callers into the property wrapper syntax. This approach also raises questions about anonymous closure parameters that have an inferred property wrapper custom attribute. If an anonymous closure parameter `$0` has the `wrappedValue` type, accessing the backing wrapper and projected value would naturally use `_$0` and `$$0`, which are far from readable. If `$0` has the backing wrapper type, this would mean that naming the parameter would cause the value to change types, which is very unexpected for the user. Finally, the property wrapper syntax is purely implementation detail for the closure body, which does not belong in the API signature.+++## Future Directions++### Support Property Wrapper Initialization from a Projected Value++Today, a property wrapper can be initialized from an instance of its `wrappedValue` type if the wrapper provides a suitable `init(wrappedValue:)`. The same initialization strategy is used in this proposal for property wrapper parameters to allow users to pass a wrapped value as a property wrapper argument. We could extend this model to support initializing a property wrapper from an instance of its `projectedValue` type by allowing property wrappers to define an `init(projectedValue:)` that follows the same rules as `init(wrappedValue:)`. This could allow users to additionally pass a projected value as a property wrapper argument, like so:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {++  ...+  ++  init(projectedValue: Self) { ... }+  +}++func distanceFromUpperBound(+  @Clamped clamped: Int+) { ... }+++distanceFromUpperBound(+  $clamped: Clamped(to: 0 ... 100, wrappedValue: 30)+) // returns: 70+```+++### Add Support for `inout` Wrapped Parameters is Functions++This proposal doesn't currently support marking function parameters to which wrapper types have been applied `inout`. We deemed that this functionality would be better tackled by another proposal due to its implementation complexity. However, such a feature would be really useful for wrapper types with value semantics and it would simplify the mental model. Furthermore, it could alleviate some confusion for users that don't understand the difference between a setter with value semantics and one with reference semantics.+++### Accessing Enclosing Self from Wrapper Types++There's currently no public feature that allows a wrapper to access its enclosing `Self` type:++```swift+@propertyWrapper+struct Mirror<EnclosingSelf, Value, Path>+  where Path : KeyPath<EnclosingSelf, Value> { +  +  let keyPath: Path +++  init(of keyPath: Path) { ... }+  +}+++struct Point {++  private var _vector: SIMD2<Double>+  +  +  init(x: Double, y: Double) {+    self._vector = SIMD2(x: x, y: y)+  }+  +  +  @Mirror(of: \._vector.x)+  var x+  +  @Mirror(of: \._vector.y)+  var y+  +} ❌+// In the above use, we'd access the enclosing+// type's '_vector' property through the provided+// keyPath. However, today that's invalid.+```++Furthermore, extending this feature's availability to function and closure parameters be really powerful:++```swift+func valueAndIdPair<Value>(+  @Mirror of property: Value+) -> (value: Value, id: Int) {+  (value: property, id: $property.keyPath.hashValue)+}+```++It's important to note that allowing use of such a feature in function parameters would entail some limitations. For example, a parameter marked with a wrapper type referencing enclosing `self` would be an error for a non-instance method, as the accessors for the `wrappedValue` and `projectedValue` need an enclosing `self` instance.++### Add Wrapper Types in the Standard Library++Adding wrapper types to the Standard Library has been discussed for types [such as `@Atomic`] and [`@Weak`](https://forums.swift.org/t/should-weak-be-a-type/34032), which would facilitate certain APIs. Another interesting Standard Library wrapper type could be `@UnsafePointer`, which would be quite useful, as access of the `pointee` property is quite common:++```swift+let myPointer: UnsafePointer<UInt8> = ...++myPointer.pointee +//        ^~~~~~~ +// This is the accessor pattern property +// wrappers were devised to tackle.+```++Instead of writing the above, in the future one might be able to write this:++```swift+let myInt = 0++withUnsafePointer(to: ...) { @UnsafePointer value in++  print(value) // 0+  +  $value.withMemoryRebound(to: UInt64.self {+    ... +  }+  +}+```++As a result, unsafe code is not dominated by visually displeasing accesses to `pointee` members; rather, more natural and clear code is enabled. ++What's more, a `@Lazy` type could be added so as to alleviate the need for custom behavior built into the compiler. Instead, `@Lazy` would act as more comprehensible, easy to maintain type, that would also allow for a more streamlined way of resetting its storage:

You're right that if we want to use @Lazy on a parameter, it can't have a mutating getter. If we want to use this example, we'd have to implement Lazy differently than in the original property wrapper proposal. Using reference types is the way to do this, either by making Lazy itself a reference type, or making it store an instance of some reference type that represents the initialization state.

filip-sakel

comment created time in 13 days

PullRequestReviewEvent

Pull request review commentapple/swift-evolution

[Proposal] Extend Property Wrappers to Function and Closure Parameters

+# Extend Property Wrappers to Function and Closure Parameters++* Proposal: [SE-NNNN](NNNN-extend-property-wrappers-to-function-and-closure-parameters.md)+* Authors: [Holly Borla](https://github.com/hborla), [Filip Sakel](https://github.com/filip-sakel)+* Review Manager: TBD+* Status: **Awaiting implementation**+++## Introduction++Property Wrappers were [introduced in Swift 5.1](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md), and have since become a popular feature abstracting away common accessor patterns for properties. Currently, applying a property wrapper is solely permitted on properties inside of a type context. However, with increasing adoption demand for extending _where_ property wrappers can be applied has emerged. This proposal describes extending property wrappers to function and closure parameters.+++## Motivation++Property wrappers have undoubtably been very successful. Applying a property wrapper to a property is enabled by an incredibly lightweight and expressive syntax. Therefore, library authors can expose complex behavior through easily understandable property-wrapper types in an efficient manner. For instance, frameworks such as [SwiftUI](https://developer.apple.com/documentation/swiftui/) and [Combine](https://developer.apple.com/documentation/combine) introduce property wrappers such as [`State`](https://developer.apple.com/documentation/swiftui/state), [`Binding`](https://developer.apple.com/documentation/swiftui/binding) and [`Published`](https://developer.apple.com/documentation/combine/published) respectively to expose elaborate behavior through a succint interface, helping craft expressive yet simple APIs. However, property wrappers are only applicable to type properties, shattering the illusion that they helped realize in the first place:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {+  init(+    wrappedValue: Value,+    to range: Range<Value>+  ) { ... }+  +  var wrappedValue: Value { +    get { ... }+    set { ... }+  }+}++struct Percentage {+  @Clamped(to: 0 ... 100)+  var percent = 0+     +  mutating func increment() {+    percent += 1+    // Great!+  }++  mutating func adding(_ offset: Int) {+    percent += min(100, max(0, offset))+    //         ^~~~~~~~~~~~~~~~~~~~~~~~+    // Manual adjustment instead of using the Clamped abstraction.+  }++  mutating func adding(_ offset: Clamped<Int>) {+    //                   ^~~~~~~~~~~~~~~~~~~~+    // Unfortunately, we can't use @Clamped(to: 0 ... 100) here+    percent += offset.wrappedValue+    //               ^~~~~~~~~~~~~+    // We must access wrappedValue manually.+  }+}+```++As seen in the above example, it is quite awkward and unintuitive that property wrappers cannot be applied to function parameters. In this case, a property wrapper parameter would be useful for expressing and enforcing invariants about the `offset` argument to the `adding` method on `Percentage`. Disallowing the property wrapper attribute on the `offset` parameter causes the API author to choose between making invariant checking implementation detail, or forcing the invariant checking on every caller of the API.++This limitation in expressivity is emphasized by the fact that property wrappers were originally sought out to abstract away such patterns.  As a result, elegant APIs are undermined by this limitation. Not only is this limiting users by forcing them to carefully read documentation, which may not cover a specific use case, to make sure no invariants have been violated, but it also limits API authors in what they can create. That is, API authors can't use property-wrapper types in closure parameters nor can code be seperated into functions that accept property wrapper syntax:++```swift+extension Percentage {+  func modify(+    inSeconds seconds: Int,+    block: @escaping (Clamped<Int>) -> Void+  ) { ... }+}++let myPercentage = Percentage(percent: 50)++myPercentage+  .modify(inSeconds: 3) { percent in+    percent.wrappedValue = 100+    //    ^~~~~~~~~~~~ +    // Again, we have to +    // access count through+    // `wrappedValue`.+  }+```++In fact, establishing custom behavior on closure parameters is really powerful. For example, if such a feature were supported, it could be used in conjunction with [Function Builders](https://github.com/apple/swift-evolution/blob/master/proposals/0289-function-builders.md) to expose data managed by a 'component' type. For instance, in SwiftUI [`ForEach`](https://developer.apple.com/documentation/swiftui/foreach) could utilize this feature to expose the mutable state of its data source to its 'content' closure. Thus, instead of manually mutating the data source, as is done here:++```swift+struct MyView: View {+  // A simple Shopping Item that includes+  // a 'quantity' and a 'name' property.+  @State +  private var shoppingItems: [Item]++  var body: some View {+    ForEach(0 ..< shoppingItems.count) { index in+  +      Text(shoppingItems[index].name)+        .onTapGesture {+          // We increase the item's quantity +          // when the user taps the item. +          // Unfortunately, to mutate the item+          // we have to manually index our+          // data source.+          shoppingItems[index].quanity += 1+        }+      +    }+  }+}+```++With an appropriate initializer we would be able to simplify the above code, therefore reducing boilerplate:++```swift+struct MyView: View {+  @State +  private var shoppingItems: [Item]++  var body: some View {+    ForEach($shoppingItems) { @Binding shoppingItem in+    +      Text(shoppingItem.name)+        .onTapGesture {+          shoppingItem.quanity += 1+        }+      +    }+  }+}+```+++## Proposed solution++We propose to extend the contexts were application of property-wrapper types is allowed. Namely, application of such types will be allowed on function and closure parameters:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {+  ...+    +  var projectedValue: Self {+    self+  }+}++func increment(+  @Clamped(to: 0 ... 100) percent: Int = 100+) { ... }++myPercentage+  .modify(inSeconds: 3) { @Clamped percent in+    percent = 100 +  }+```+++## Detailed design++Property wrappers are essentially sugar wrapping a given property with compiler synthesized code. This proposal retains this principle employing the following rules for transformation.++### Property Wrappers on Function Parameters++Function parameters marked with a set of property wrapper custom attributes must conform to the following rules:++1. Each property wrapper type must have a suitable `init(wrappedValue:)` for initializing the property wrapper from an instance of its `wrappedValue` type.+2. Each `wrappedValue` getter must be `nonmutating`.+3. Default values must be expressed in terms of the innermost `wrappedValue` type.++The transformation of a property wrapper parameter will take place is as follows:++1. The external parameter name will remain unchanged.+2. The internal parameter name will be prefixed with an underscore, and the type of this parameter is the backing property wrapper type.+3. A local computed property representing  `wrappedValue` will be synthesized by the compiler and named per the original (non-prefixed) parameter name. The accessors will mirror the `wrappedValue` accessors. A setter will only be synthesized for the local property if the `wrappedValue` setter is `nonmutating`, or if the wrapper is a reference type.+4. If the property wrapper defines a `projectedValue`, a local computed property representing  `projectedValue` will be synthesized by the compiler and named per the original parameter name prefixed with a dollar sign (`$`). The same accessor rules for `wrappedValue` apply to `projectedValue`.+5. When passing an argument to a property wrapper parameter, the compiler will wrap the argument in the appropriate `init(wrappedValue:)` call.++#### Transformation Example:++```swift+@propertyWrapper+struct Percentage {

I like that example!

filip-sakel

comment created time in 13 days

PullRequestReviewEvent

pull request commentapple/swift

[Property Wrappers] Support property wrappers on function and closure parameters

@swift-ci please build toolchain macOS platform

hborla

comment created time in 13 days

pull request commentapple/swift

[Property Wrappers] Support property wrappers on function and closure parameters

@swift-ci please build toolchain

hborla

comment created time in 13 days

push eventhborla/swift

Holly Borla

commit sha 452d1a323ef804b6e263938ff726269cfad9f337

[Sema] Visit auxiliary decls on parameters in the decl checker.

view details

Holly Borla

commit sha 02c633b3ecb94aa1c5cfc71c71e2f8047f40d914

[SILGen] Teach SILGen to emit property wrapper parameters.

view details

Holly Borla

commit sha dbd53bf215fff6f6234532aab3f49ab88c5723d3

[Property Wrappers] Allow property wrapper attributes to be applied to parameters.

view details

push time in 13 days

push eventhborla/swift

Mike Ash

commit sha ece0399d601eec1069131f465bdbe7e16f4c6a50

[Runtime] Have ConcurrentReadableHashMap use 1-byte or 2-byte indices when possible.

view details

Doug Gregor

commit sha e36011def493dceec79381f2e4a051f1f1e610fe

[Type checker] Delay the diagnosis of missing witnesses further. The handling of "global" missing witnesses would diagnose a missing witness (showing "almost" matches) and then, later, provide the Fix-It to add the declaration if the user wants it. Delay the diagnostic part until later, when we add the missing witness. While here, correct an existing issue with memory corruption that occurs because we would diagnose some of these witnesses, then clear a "global" witness list, while still iterating through parts of that list.

view details

Doug Gregor

commit sha fe4a8bb9f926684d2621fba13cc326580380bcbc

[Clang importer] Allow both sync and async imports with the same name. The Clang importer was filtering out cases where the same declaration is imported twice under the same name, which can now happen when one is synchronous and one is asynchronous. This happens when, e.g., an Objective-C class provides both a completion-hander-based asynchronous version and a synchronous version, and the Swift names line up after the completion-handler parameter is dropped. Stop filtering these out. Overload resolution is capable of handling synchronous/asynchronous overloading based on context.

view details

Doug Gregor

commit sha 50f870566a1a35b4073adb1bce078451790b74a5

Handle conformance with multiple protocol requirements with the same selector. When concurrency is enabled, the same Objective-C method on a protocol can be imported as two different protocol requirements, both of which have the same selector. When performing conformance checking, only treat a given @objc protocol requirement as "unsatisfied" by a conformance if none of the requirements with the same Objective-C selector (+ instance/class designation) are satisfied.

view details

Doug Gregor

commit sha 591e6e89e259818a8dd56bbba41057e776d92c8a

[Concurrency] Only infer @asyncHandler for witnesses within actor classes. Actor classes are by definition new code, so only perform inference of @asyncHandler from a protocol requirement to witnesses when those witnesses are within an actor class. This is partly because @asyncHandler might not have reasonable semantics outside of actor classes anywhere (where would you execute the detached task?), and partly because it is a source-compatibility problem due to the combination of... 1) Inferring @asyncHandler on imported Objective-C protocol methods for existing protocols, 2) Inferring @asyncHandler from those protocol methods to an existing method in a class that conforms to that protocol, and 3) Using an API that is now overloaded for both synchronous and asynchronous callers will end up preferring the asynchronous version, then fail due to a missing "await". The individual steps here are all reasonable, but the result is a source break, so back off on @asyncHandler inference for witnesses outside of actor classes. New code gets the more-asynchronous behavior for free.

view details

Doug Gregor

commit sha bb066b6fa68f06885c84838be7f7e264d70bc0e6

[Concurrency] Make actor-isolated protocol witnesses an error. With actor isolation checking for protocol witnesses moved out of the witness-matching phase, move the corresponding diagnostics from notes (that would have been on the "type does not conform" error) to freestanding errors.

view details

Simon Evans

commit sha 960d0e30ee2b70ba3bb7ec076c16045afab01589

Linux: Fix -static-executable and remove swiftImageInspectionShared - Remove references to swiftImageInspectionShared on Linux and dont have split libraries between static/non-static linked executables. - -static-executable now links correctly Linux. Note: swift::lookupSymbol() will not work on statically linked executables but this can be worked around by using the https://github.com/swift-server/swift-backtrace package.

view details

Cassie Jones

commit sha 8ffaf79ec2e106a58dff2402a06210bf9ca97357

[build] Support installing swift-driver without swiftpm The install-swift-driver phase knows how to build swift-driver using CMake. Allowing only install-swift-driver without plain swift-driver allows installing it without requiring swiftpm.

view details

Michael Gottesman

commit sha e7761cf997897aaa38af0d0969ca9acd7e504fbf

[DebuggingTheCompiler] Document a few flags for dumping llvm-ir. I needed to use these and realized they were not documented here. I had them in my brain, but others may not, so seemed good to do.

view details

Xi Ge

commit sha 00eb2e9db2140d7a7acdd9aa3176e12df9012a7d

Frontend: add a frontend flag to disable building module from textual interface This is for testing purposes to ensure prebuilt modules are up to date. rdar://68770805

view details

Cassie Jones

commit sha 20995ae0bbf765d39cb28c63318e301c27cc2157

[build] Add FILES_MATCHING to CMakeLists.txt The bare "PATTERN" argument by default does nothing, you need either "EXCLUDE" or "FILES_MATCHING" to make it do something. This likely wasn't previously a problem because clang is only installing headers, but it should be fixed for robustness.

view details

Robert Widmann

commit sha 82e9935885bed95b0091476bfda95f4fdae14e9b

Correct the Serialization of Embedded Swift Dependencies llvm-bcanalyzer does *not* like it when there are multiple block info metadata blocks in the same bitstream file. This patch will skip the emission of that and just jump straight to the metadata block when we're not reading a "standalone" incremental dependency file. While I'm here, also add the right block abbreviation info so we can get a decent dump from llvm-bcanalyzer

view details

Robert Widmann

commit sha d7cd605c3129bd567f5be18b57eec33135dc439e

Adjust the Registration of the Pseudo-Job for External Incremental Dependencies Register the module the external dependencies ride in with the pseudo-job in the Driver. This is a hack.

view details

Robert Widmann

commit sha a77f059c8292c157f07a4de9a2d1ee9597c5b57d

Turn on Cross-Module Incremental Dependencies! Cross-Module incremental dependencies are a new experimental mode of the Swift driver and frontend. Through a tight partnership between the two, we enable the driver to have far greater visibility into the dependency structure of a Swift module. Rather than invent a new model, we have chosen to extend the existing incremental compilation model that works for a single module to multiple modules. To do this, we need the frontend to emit Swift dependencies in a form the driver can consume. We could emit these metadata in the form of an extra supplementary output that summarizes the contents of a generated module. However, this approach comes with a number of downsides: - It requires additional integration with the build system - It assumes swiftmodule files will be consumed directly from the build directory; they are not - It incorrectly assumes a swiftmodule has but one interface. Taken in aggregate, a swiftmodule directory has one interface *per triple* Given this, the approach we take here is to encode these dependencies directly into the swiftmodule file itself. When frontends load these souped-up incremental swiftmodule files, they record in their own swiftdeps files that they depend on an incremental swiftmodule. Upon the next build, the driver is then able to read that module file, extract the swiftdeps information from it, and use it to influence the way it schedules jobs. The sum total is that we neatly extend the intra-module case of incremental builds to the inter-module case by treating swiftmodule inputs not as opaque entities, but as "big ol' flat Swift files" that just export an interface like any other Swift file within the module. As a further optimization, and because clients literally cannot observe this aspect of the incremental build, we only serialize the provides (the "defs" side of a "use-def" edge) when emitting swiftdeps metadata into swiftmodule files. rdar://69595010

view details

Doug Gregor

commit sha 147f9e6c90f66068f567b5b7a14e7eb7abdafa29

Generalize test

view details

Pavel Yaskevich

commit sha f26bce350d41ec1ffefa8cae61f759985244b055

[Sema] NFC: Move `ContextualTypePurpose` to constraint system header

view details

Pavel Yaskevich

commit sha 588d42c56440db5e6166c1e979c13c8ae3343a60

[Sema] NFC: Move `FreeTypeVariableBinding` to constraint system header

view details

Meghana Gupta

commit sha 141b032e7c6ad24133905b35a6080f872feb7dac

Enable --build-sil-debugging-stdlib for all of swift/stdlib/public (#34197) Previously it was enable only for swift/stdlib/public/core

view details

Alexis Laferrière

commit sha c6fc53e844ac4fd542adb0669ac7038c2919d283

[Sema] Define availability via compiler flag Introduce availability macros defined by a frontend flag. This feature makes it possible to set the availability versions at the moment of compilation instead of having it hard coded in the sources. It can be used by projects with a need to change the availability depending on the compilation context while using the same sources. The availability macro is defined with the `-define-availability` flag: swift MyLib.swift -define-availability "_iOS8Aligned:macOS 10.10, iOS 8.0" .. The macro can be used in code instead of a platform name and version: @available(_iOS8Aligned, *) public func foo() {} rdar://problem/65612624

view details

Alexis Laferrière

commit sha 5ed261683d5973ef4dd45922b5ac77ba7cefcf43

[Sema] Report availability macros in inlinable code Availability macros can’t be used in inlinable code as inlinable is copied textually in the generated swiftinterface files. Further would could lift this limitation.

view details

push time in 13 days

push eventhborla/swift

Holly Borla

commit sha bf4f52db71e3fcf963a9a57f7f1aa766fdec349f

[Property Wrappers] Handle property wrappers on parameters in PropertyWrapperBackingPropertyInfoRequest.

view details

Holly Borla

commit sha c6c07312fd4ebf06dcf2392bfcd5b2061fd3dd16

[ConstraintSystem] Teach the constraint system to apply property wrappers to arguments passed to a property wrapper parameters.

view details

Holly Borla

commit sha d357e6ed82ead89c7040dcd3ed33680b9b76eaea

[Property Wrappers] Don't allow property wrapper attributes to have arguments when applied to parameters.

view details

Holly Borla

commit sha 4b7cf22c7908f06d4dcfdfd8a283ec7bd5cec998

[Property Wrappers] Add a request to synthesize the local wrapped value variable for a parameter with an attached property wrapper.

view details

Holly Borla

commit sha 2f6b033065729b892b336d34207e35d603b4db6b

[Sema] Visit auxiliary decls on parameters in the decl checker.

view details

Holly Borla

commit sha 3cb539c415e4dd562a4732a416f1cb8f897bf0f0

[SILGen] Teach SILGen to emit property wrapper parameters.

view details

Holly Borla

commit sha bf68f239a39069f95193a6c87db297332ca4f51b

[Property Wrappers] Allow property wrapper attributes to be applied to parameters.

view details

push time in 13 days

push eventhborla/swift

Holly Borla

commit sha 2dddaa00130a0dd4868f179c50d5fb35d474ccf7

fix

view details

Holly Borla

commit sha 102ebbba0472baa7bda34fa688918208208d7529

[ConstraintSystem] Teach the constraint system to apply property wrappers to arguments passed to a property wrapper parameters.

view details

Holly Borla

commit sha 3cf184c77951ab523353030e0fe35d086670c674

[Property Wrappers] Don't allow property wrapper attributes to have arguments when applied to parameters.

view details

Holly Borla

commit sha 4011b977809b50d4c9ec883ff8a4a69894205b63

[Property Wrappers] Add a request to synthesize the local wrapped value variable for a parameter with an attached property wrapper.

view details

Holly Borla

commit sha 42f62d357b67e5302d0affd28605b2dd5d21d088

[Sema] Visit auxiliary decls on parameters in the decl checker.

view details

Holly Borla

commit sha 4aa8ef3c4092a1fcba9a784a1ac6501f73b8c35b

[SILGen] Teach SILGen to emit property wrapper parameters.

view details

Holly Borla

commit sha 4e1057f94298427c53e9ad16f885850362f8468e

[Property Wrappers] Allow property wrapper attributes to be applied to parameters.

view details

push time in 13 days

push eventhborla/swift

Holly Borla

commit sha 15fc0ceb53ff4bf0e8e07b13b28eb1f935a9186c

[ConstraintSystem] Teach the constraint system about property wrapper parameters.

view details

Holly Borla

commit sha 93a9f7604c3c609e775c8a61f27995146ada67a2

[Property Wrappers] Handle property wrappers on parameters in PropertyWrapperBackingPropertyInfoRequest.

view details

Holly Borla

commit sha e1b8b539862a39136f86d57522df16fa8d157a99

[ConstraintSystem] Teach the constraint system to apply property wrappers to arguments passed to a property wrapper parameters.

view details

Holly Borla

commit sha 118d8a9e434f84cd6aa34d818dbdc6583c364f9d

[Property Wrappers] Don't allow property wrapper attributes to have arguments when applied to parameters.

view details

Holly Borla

commit sha 8d60edded53bb60e06acb498cf056a0e036d7426

[Property Wrappers] Add a request to synthesize the local wrapped value variable for a parameter with an attached property wrapper.

view details

Holly Borla

commit sha acb54ad61c3ac87a6352ec680a00776564027bae

[Sema] Visit auxiliary decls on parameters in the decl checker.

view details

Holly Borla

commit sha 369227f2524c76345077fb83fb2b74cd462bb209

[SILGen] Teach SILGen to emit property wrapper parameters.

view details

push time in 13 days

push eventhborla/swift

Holly Borla

commit sha a55fc73c372fb2560ca1f895292fc7f96e8f9c86

[Property Wrappers] Handle property wrappers on parameters in PropertyWrapperBackingPropertyInfoRequest.

view details

Holly Borla

commit sha 6fe20b51d2b7f4a3b70edee8359a41bcb40a7d3f

[ConstraintSystem] Teach the constraint system to apply property wrappers to arguments passed to a property wrapper parameters.

view details

Holly Borla

commit sha 40db82f86b3ae1c6361ca0c5d490a9ac1fe8d830

[Property Wrappers] Don't allow property wrapper attributes to have arguments when applied to parameters.

view details

Holly Borla

commit sha a1493afba6c0be10e5891a94b166c8c0689145e2

[Property Wrappers] Add a request to synthesize the local wrapped value variable for a parameter with an attached property wrapper.

view details

push time in 13 days

push eventhborla/swift

Holly Borla

commit sha 9be1edadc178dfb13cd7f8aaa0b2dcc72c96be7a

[Property Wrappers] Handle property wrappers on parameters in PropertyWrapperBackingPropertyInfoRequest.

view details

Holly Borla

commit sha 2f0a7e9ad217aa8464adf9bde9b5c70bf428cb97

[ConstraintSystem] Teach the constraint system to apply property wrappers to arguments passed to a property wrapper parameters.

view details

Holly Borla

commit sha db612cb127d350bc4f3eee08c42aae63a659749e

[Property Wrappers] Don't allow property wrapper attributes to have arguments when applied to parameters.

view details

push time in 15 days

push eventhborla/swift

Holly Borla

commit sha 87c5807053346392c37c5981aa05e7782ab285e1

[Property Wrappers] Handle property wrappers on parameters in PropertyWrapperBackingPropertyInfoRequest.

view details

Holly Borla

commit sha 75b573ceb4abbd859b78a3c68009f14f530f9dc7

[ConstraintSystem] Teach the constraint system to apply property wrappers to arguments passed to a property wrapper parameters.

view details

Holly Borla

commit sha dc1d493e2829bec0a84cb5f8c8cf2cdc765669fa

[Property Wrappers] Don't allow property wrapper attributes to have arguments when applied to parameters.

view details

push time in 15 days

pull request commentapple/swift-evolution

[Proposal] Extend Property Wrappers to Function and Closure Parameters

@benrimmington thank you for the review and suggested changes! @filip-sakel when you get a chance, would you mind incorporating the changes? I'm trying to get the implementation PR up 🙂

filip-sakel

comment created time in 15 days

Pull request review commentapple/swift-evolution

[Proposal] Extend Property Wrappers to Function and Closure Parameters

+# Extend Property Wrappers to Function and Closure Parameters++* Proposal: [SE-NNNN](NNNN-extend-property-wrappers-to-function-and-closure-parameters.md)+* Authors: [Holly Borla](https://github.com/hborla), [Filip Sakel](https://github.com/filip-sakel)+* Review Manager: TBD+* Status: **Awaiting implementation**+++## Introduction++Property Wrappers were [introduced in Swift 5.1](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md), and have since become a popular feature abstracting away common accessor patterns for properties. Currently, applying a property wrapper is solely permitted on properties inside of a type context. However, with increasing adoption demand for extending _where_ property wrappers can be applied has emerged. This proposal describes extending property wrappers to function and closure parameters.+++## Motivation++Property wrappers have undoubtably been very successful. Applying a property wrapper to a property is enabled by an incredibly lightweight and expressive syntax. Therefore, library authors can expose complex behavior through easily understandable property-wrapper types in an efficient manner. For instance, frameworks such as [SwiftUI](https://developer.apple.com/documentation/swiftui/) and [Combine](https://developer.apple.com/documentation/combine) introduce property wrappers such as [`State`](https://developer.apple.com/documentation/swiftui/state), [`Binding`](https://developer.apple.com/documentation/swiftui/binding) and [`Published`](https://developer.apple.com/documentation/combine/published) respectively to expose elaborate behavior through a succint interface, helping craft expressive yet simple APIs. However, property wrappers are only applicable to type properties, shattering the illusion that they helped realize in the first place:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {+  init(+    wrappedValue: Value,+    to range: Range<Value>+  ) { ... }+  +  var wrappedValue: Value { +    get { ... }+    set { ... }+  }+}++struct Percentage {+  @Clamped(to: 0 ... 100)+  var percent = 0+     +  mutating func increment() {+    percent += 1+    // Great!+  }++  mutating func adding(_ offset: Int) {+    percent += min(100, max(0, offset))+    //         ^~~~~~~~~~~~~~~~~~~~~~~~+    // Manual adjustment instead of using the Clamped abstraction.+  }++  mutating func adding(_ offset: Clamped<Int>) {+    //                   ^~~~~~~~~~~~~~~~~~~~+    // Unfortunately, we can't use @Clamped(to: 0 ... 100) here+    percent += offset.wrappedValue+    //               ^~~~~~~~~~~~~+    // We must access wrappedValue manually.+  }+}+```++As seen in the above example, it is quite awkward and unintuitive that property wrappers cannot be applied to function parameters. In this case, a property wrapper parameter would be useful for expressing and enforcing invariants about the `offset` argument to the `adding` method on `Percentage`. Disallowing the property wrapper attribute on the `offset` parameter causes the API author to choose between making invariant checking implementation detail, or forcing the invariant checking on every caller of the API.++This limitation in expressivity is emphasized by the fact that property wrappers were originally sought out to abstract away such patterns.  As a result, elegant APIs are undermined by this limitation. Not only is this limiting users by forcing them to carefully read documentation, which may not cover a specific use case, to make sure no invariants have been violated, but it also limits API authors in what they can create. That is, API authors can't use property-wrapper types in closure parameters nor can code be seperated into functions that accept property wrapper syntax:++```swift+extension Percentage {+  func modify(+    inSeconds seconds: Int,+    block: @escaping (Clamped<Int>) -> Void+  ) { ... }+}++let myPercentage = Percentage(percent: 50)++myPercentage+  .modify(inSeconds: 3) { percent in+    percent.wrappedValue = 100+    //    ^~~~~~~~~~~~ +    // Again, we have to +    // access count through+    // `wrappedValue`.+  }+```++In fact, establishing custom behavior on closure parameters is really powerful. For example, if such a feature were supported, it could be used in conjunction with [Function Builders](https://github.com/apple/swift-evolution/blob/master/proposals/0289-function-builders.md) to expose data managed by a 'component' type. For instance, in SwiftUI [`ForEach`](https://developer.apple.com/documentation/swiftui/foreach) could utilize this feature to expose the mutable state of its data source to its 'content' closure. Thus, instead of manually mutating the data source, as is done here:++```swift+struct MyView: View {+  // A simple Shopping Item that includes+  // a 'quantity' and a 'name' property.+  @State +  private var shoppingItems: [Item]++  var body: some View {+    ForEach(0 ..< shoppingItems.count) { index in+  +      Text(shoppingItems[index].name)+        .onTapGesture {+          // We increase the item's quantity +          // when the user taps the item. +          // Unfortunately, to mutate the item+          // we have to manually index our+          // data source.+          shoppingItems[index].quanity += 1+        }+      +    }+  }+}+```++With an appropriate initializer we would be able to simplify the above code, therefore reducing boilerplate:++```swift+struct MyView: View {+  @State +  private var shoppingItems: [Item]++  var body: some View {+    ForEach($shoppingItems) { @Binding shoppingItem in+    +      Text(shoppingItem.name)+        .onTapGesture {+          shoppingItem.quanity += 1+        }+      +    }+  }+}+```+++## Proposed solution++We propose to extend the contexts were application of property-wrapper types is allowed. Namely, application of such types will be allowed on function and closure parameters:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {+  ...+    +  var projectedValue: Self {+    self+  }+}++func increment(+  @Clamped(to: 0 ... 100) percent: Int = 100+) { ... }++myPercentage+  .modify(inSeconds: 3) { @Clamped percent in+    percent = 100 +  }+```+++## Detailed design++Property wrappers are essentially sugar wrapping a given property with compiler synthesized code. This proposal retains this principle employing the following rules for transformation.++### Property Wrappers on Function Parameters++Function parameters marked with a set of property wrapper custom attributes must conform to the following rules:++1. Each property wrapper type must have a suitable `init(wrappedValue:)` for initializing the property wrapper from an instance of its `wrappedValue` type.+2. Each `wrappedValue` getter must be `nonmutating`.+3. Default values must be expressed in terms of the innermost `wrappedValue` type.++The transformation of a property wrapper parameter will take place is as follows:++1. The external parameter name will remain unchanged.+2. The internal parameter name will be prefixed with an underscore, and the type of this parameter is the backing property wrapper type.+3. A local computed property representing  `wrappedValue` will be synthesized by the compiler and named per the original (non-prefixed) parameter name. The accessors will mirror the `wrappedValue` accessors. A setter will only be synthesized for the local property if the `wrappedValue` setter is `nonmutating`, or if the wrapper is a reference type.+4. If the property wrapper defines a `projectedValue`, a local computed property representing  `projectedValue` will be synthesized by the compiler and named per the original parameter name prefixed with a dollar sign (`$`). The same accessor rules for `wrappedValue` apply to `projectedValue`.+5. When passing an argument to a property wrapper parameter, the compiler will wrap the argument in the appropriate `init(wrappedValue:)` call.++#### Transformation Example:++```swift+@propertyWrapper+struct Percentage {

@benrimmington these are great questions. Could you please ask them on the pitch thread?

filip-sakel

comment created time in 16 days

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentapple/swift-evolution

[Proposal] Extend Property Wrappers to Function and Closure Parameters

+# Extend Property Wrappers to Function and Closure Parameters++* Proposal: [SE-NNNN](NNNN-extend-property-wrappers-to-function-and-closure-parameters.md)+* Authors: [Holly Borla](https://github.com/hborla), [Filip Sakel](https://github.com/filip-sakel)+* Review Manager: TBD+* Status: **Awaiting implementation**+++## Introduction++Property Wrappers were [introduced in Swift 5.1](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md), and have since become a popular feature abstracting away common accessor patterns for properties. Currently, applying a property wrapper is solely permitted on properties inside of a type context. However, with increasing adoption demand for extending _where_ property wrappers can be applied has emerged. This proposal aims to extend property wrappers to function and closure parameters.+++## Motivation++Property wrappers have undoubtably been very successful. Applying a property wrapper to a property is enabled by an incredibly lightweight and expressive syntax. Therefore, library authors can expose complex behavior through easily understandable property-wrapper types in an efficient manner. For instance, frameworks such as [SwiftUI](https://developer.apple.com/documentation/swiftui/) and [Combine](https://developer.apple.com/documentation/combine) introduce property wrappers such as [`State`](https://developer.apple.com/documentation/swiftui/state), [`Binding`](https://developer.apple.com/documentation/swiftui/binding) and [`Published`](https://developer.apple.com/documentation/combine/published) respectively to expose elaborate behavior through a succint interface, helping craft expressive yet simple APIs. However, property wrappers are only applicable to type properties, shattering the illusion that they helped realize in the first place:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {++  init(+    wrappedValue: Value,+    to range: Range<Value>+  ) { ... }+  +  +  var wrappedValue: Value { +    get { ... }+    set { ... }+  }+  +}+++struct Percentage {++  @Clamped(to: 0 ... 100)+  var percent = 0+     +     +  mutating func increment() {+    percent += 1+    // Great!+  }++  mutating func adding(_ offset: Int) {+    percent += min(100, max(0, offset))+    //         ^~~~~~~~~~~~~~~~~~~~~~~~+    // We are forced to manually adjust 'percent' +    // instead of utilizing the abstraction +    // property wrappers offer.+  }

The existing example is intentional. The behavior of percent += offset and percent += min(100, max(0, offset)) is different if you pass a negative offset. Although the example is contrived (and there's no real reason to adjust the value if it's above the upper bound), it's meant to remind readers of assertions or adjustments they write on parameter values that would be useful to 1) have an abstraction for, and 2) be able to communicate to callers through the API itself.

filip-sakel

comment created time in 17 days

PullRequestReviewEvent

push eventapple/swift

Holly Borla

commit sha 456a50527c5948d0acfb2a155c6be3e414a8bfd0

[Sema] Adjust mutability in buildStorageRef appropriately for accessors on local variables.

view details

Holly Borla

commit sha 0c6ef5838e171ad6a79d76e1905ce01ef3cf909d

[DeclChecker] Explicitly compute captures for local functions in the decl checker.

view details

Holly Borla

commit sha a7a47e561c8f5d16776cbe07a1d5913281300a0e

Merge pull request #34230 from hborla/build-storage-ref-lvalue [Sema] Correct lvalue computation in `buildStorageRef` for synthesizing local accessors.

view details

push time in 17 days

PR merged apple/swift

[Sema] Correct lvalue computation in `buildStorageRef` for synthesizing local accessors.

This is a follow-up to the local property wrapper implementation to address https://github.com/apple/swift/pull/34109#discussion_r496998875

The fix turned out to be pretty simple - the lvalue adjustment for the storage reference base simply needed to be moved earlier and slightly adjusted to account for cases where the base is not self.

+26 -30

1 comment

2 changed files

hborla

pr closed time in 17 days

push eventfilip-sakel/swift-evolution

Holly Borla

commit sha 26ff040cd7896fa25cbf5cfdba287c7829757947

[Property Wrapper Parameters] Update ABI/API stability sections.

view details

push time in 17 days

pull request commentapple/swift

[Sema] Correct lvalue computation in `buildStorageRef` for synthesizing local accessors.

@swift-ci please smoke test

hborla

comment created time in 17 days

PR opened apple/swift

Reviewers
[Sema] Correct lvalue computation in `buildStorageRef` for synthesizing local accessors.

This is a follow-up to the local property wrapper implementation to address https://github.com/apple/swift/pull/34109#discussion_r496998875

The fix turned out to be pretty simple - the lvalue adjustment for the storage reference base simply needed to be moved earlier and slightly adjusted to account for cases where the base is not self.

+26 -30

0 comment

2 changed files

pr created time in 17 days

create barnchhborla/swift

branch : build-storage-ref-lvalue

created branch time in 17 days

push eventhborla/swift

Antoine Cœur

commit sha 4c30f8bd6de5487603ed645cc4dd2a2983f4f0ba

appendingPathComponent(:isDirectory:) should account for isDirectory

view details

Owen Voorhees

commit sha 6b6b640e133ca547139c6586eb0dcbf7933b46ec

[Driver] Don't test for null source locations in driver diagnostics swift-driver doesn't emit these, and there's no reason to check that they're present when using the integrated driver.

view details

Xiaodi Wu

commit sha 26cda274ca78b1df246521ba1eeea33285b57d5f

[stdlib] Simplify 'BinaryFloatingPoint.init?<T: BinaryFloatingPoint>(exactly: T)'

view details

Joe Groff

commit sha 023066c1966c63ab3b7a4baee31ac24d29b7de36

SILGen: Relax assertion that incorrectly tripped on lowered opaque capture types. When lowering the SILConstantInfo for a closure implementation type with captures, we are more conservative about substituting opaque types in the capture, since the underlying types may only be available in the local context. This means the SILConstantInfo type may not in fact be exactly what you get from `SILFunction::getFunctionTypeInContext` referencing the implementation function from its originating context, since those opaque types will be substituted in the local context. Fixes SR-13480 | rdar://problem/68159831.

view details

Xiaodi Wu

commit sha 94887747a4e2746163e85438934a78a8c165fa8f

[benchmark] Add another test to floating point conversion benchmark

view details

Xiaodi Wu

commit sha 26f3c81e44d9cb53abdf51ed2f6a637bae5a3a77

[benchmark] Add another floating point conversion benchmark

view details

Xiaodi Wu

commit sha cb96bfbfdf0045383f11ed4c87e8142aafddf538

[benchmark] Tweak naming and workload for two new tests

view details

3405691582

commit sha 62a13e9ecd31da5ef335f245b66be826d6b5b4ff

[test] Erase SDKROOT since env -u is not portable. The `env -u` flag is not portable and not available on all platforms, so this unit test will fail when the feature is unavailable. Instead of trying to unset the field, just erase it instead, since trying to copy the entire invoked environment is difficult.

view details

Anthony Latsis

commit sha 103a8218380c9d72160f9ca3aa7d1e0ba4d8f1bc

Sema: Allow non-final classes to satisfy properties and subscripts with covariant Self

view details

3405691582

commit sha 42a3da29d77810fed0374ea7efe2faff02f0aef2

[test] Mark failing reflection tests XFAIL. See SR-12893. swift-reflection-dump does not properly handle offsets in ELF executable images that, when interpreted as vaddrs, belong in segments part of the image. This just empirically XFAIL's the unit tests that are crashing or failing, even though the other tests are just happening to pass anyway. There's no clear workaround; disable the expected failures for the moment.

view details

Arnold Schwaighofer

commit sha 383d47fd0061dcd01f4801eda5ba6b66148f4358

IRGen: Scalar type layouts need to profile the SIL type It might contain archetypes whose type metadata is required. rdar://68972976 SR-13555

view details

Egor Zhdan

commit sha 7ba7d9b5c1749df62cdde2d5b3184fb23d27382b

WinSDK: extract Printing submodule Currently winspool.h gets included into `WinSDK.WinSock2` via windows.h

view details

Egor Zhdan

commit sha 42dcb6948ba2332f30b833bef4913885725148ff

WinSDK: extract Multimedia submodule Some of the headers in the Multimedia subsystem were not included in any other submodule of WinSDK. This change adds them to WinSDK.

view details

Meghana Gupta

commit sha 010c1cd91f26f7f8ec1dea1a06f26cf94972debf

Convert OME into a function transform

view details

Meghana Gupta

commit sha 81a2157a7253197319bd429c4749ca5b2ca5ecd8

Handle conversion of unchecked_value_cast to non-ossa in SILCloner

view details

Meghana Gupta

commit sha 9c9a8ef2241d2be4a9d47bd2a4bbdd8b2da344b3

Allow OME to run mandatorily

view details

Mishal Shah

commit sha 40024718acf0bed26638c40abe9a61816cb2bac4

Update doc and links to support new main branch

view details

Erik Eckstein

commit sha e4e5484ab4180608efd5d0a0e25ad48e427b4d2b

LLVM-Passes: add pointer authentication to Swift's function merge pass. If during merging a function pointer is passed as a parameter to the merged function, it needs to be signed on arm64e. rdar://problem/66797689

view details

Slava Pestov

commit sha 87593fc0be4e968b2688d8f7478d7cdf85523896

ASTScope: Fold AbstractFunctionBodyScope into FunctionBodyScope

view details

Slava Pestov

commit sha 54aef7f3134383b3b203f450c95b9112d9a6830e

ASTScope: Remove isThisAnAbstractStorageDecl()

view details

push time in 18 days

create barnchhborla/swift

branch : efficient-linked-operator-solving

created branch time in 18 days

Pull request review commentapple/swift-evolution

[Proposal] Extend Property Wrappers to Function and Closure Parameters

+# Extend Property Wrappers to Function and Closure Parameters++* Proposal: [SE-NNNN](NNNN-extend-property-wrappers-to-function-and-closure-parameters.md)+* Authors: [Holly Borla](https://github.com/hborla), [Filip Sakel](https://github.com/filip-sakel)+* Review Manager: TBD+* Status: **Awaiting implementation**+++## Introduction++Property Wrappers were [introduced in Swift 5.1](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md), and have since become a popular feature abstracting away common accessor patterns for properties. Currently, applying a property wrapper is solely permitted on properties inside of a type context. However, with increasing adoption demand for extending _where_ property wrappers can be applied has emerged. This proposal aims to extend property wrappers to function and closure parameters.+++## Motivation++Property wrappers have undoubtably been very successful. Applying a property wrapper to a property is enabled by an incredibly lightweight and expressive syntax. Therefore, library authors can expose complex behavior through easily understandable property-wrapper types in an efficient manner. For instance, frameworks such as [SwiftUI](https://developer.apple.com/documentation/swiftui/) and [Combine](https://developer.apple.com/documentation/combine) introduce property wrappers such as [`State`](https://developer.apple.com/documentation/swiftui/state), [`Binding`](https://developer.apple.com/documentation/swiftui/binding) and [`Published`](https://developer.apple.com/documentation/combine/published) respectively to expose elaborate behavior through a succint interface, helping craft expressive yet simple APIs. However, property wrappers are only applicable to type properties, shattering the illusion that they helped realize in the first place:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {++  init(+    wrappedValue: Value,+    to range: Range<Value>+  ) { ... }+  +  +  var wrappedValue: Value { +    get { ... }+    set { ... }+  }+  +}+++struct Percentage {++  @Clamped(to: 0 ... 100)+  var percent = 0+     +     +  mutating func increment() {+    percent += 1+    // Great!+  }++  mutating func adding(_ offset: Int) {+    percent += min(100, max(0, offset))+    //         ^~~~~~~~~~~~~~~~~~~~~~~~+    // We are forced to manually adjust 'percent' +    // instead of utilizing the abstraction +    // property wrappers offer.+  }++  mutating func adding(_ offset: Clamped<Int>) {+    //                   ^~~~~~~~~~~~~~~~~~~~+    // Unfortunately, we can't use +    // '@Clamped(to: 0 ... 100)' here.+    +    percent += offset.wrappedValue+    //               ^~~~~~~~~~~~~+    // We must access 'wrappedValue' manually.+  }+  +}+```++As seen in the above example, it is quite awkward and unintuitive that property wrappers cannot be applied to function parameters. In this case, a property wrapper parameter would be useful for expressing and enforcing invariants about the `offset` argument to the `adding` method on `Percentage`. Inability to allow the property wrapper attribute on the `offset` parameter causes the API author to choose between making invariant checking an implementation detail, or forcing the invariant checking on every caller of the API.++This limitation in expressivity is emphasized by the fact that property wrappers were originally sought out to abstract away such patterns.  As a result, elegant APIs are undermined by this limitation. Not only is this limiting users by forcing them to carefully read documentation, which may not cover a specific use case, to make sure no invariants have been violated, but it also limits API authors in what they can create. That is, API authors can't use property-wrapper types in closure parameters nor can code be seperated into functions that accept property wrapper syntax:++```swift+extension Percentage {++  func modify(+    inSeconds seconds: Int,+    block: @escaping (inout Clamped<Int>) -> Void+  ) { ... }+  +}+++let myPercentage = Percentage(percent: 50)++myPercentage+  .modify(inSeconds: 3) { percent in+    percent.wrappedValue = 100+    //    ^~~~~~~~~~~~ +    // Again, we have to access+    // count through 'wrappedValue'.+  }+```++In fact, establishing custom behavior on closure parameters is really powerful. For example, if such a feature were supported, it could be used in conjunction with [Function Builders](https://github.com/apple/swift-evolution/blob/master/proposals/0289-function-builders.md) to expose data managed by a 'component' type. For instance, in SwiftUI [`ForEach`](https://developer.apple.com/documentation/swiftui/foreach) could leverage this feature to expose the mutable state of its data source to its 'content' closure. This would enable users to more easily work with the data source itself inside the closure instead of accessing the original property, which is particularly painful when working with collections, as shown in this example:++```swift+struct MyView: View {++  // A simple Shopping Item that includes+  // a 'quantity' and a 'name' property.+  @State +  private var shoppingItems: [Item]+++  var body: some View {+    ForEach(0 ..< shoppingItems.count) { index in+  +      TextField("Enter the item's name...", $shoppingItems[index].name)+      +    }+  }+  +}+```++we would – with an appropriate initializer – be able to simplify the above code, reducing boilerplate as a result:++```swift+struct MyView: View {++  @State +  private var shoppingItems: [Item]+++  var body: some View {+    ForEach($shoppingItems) { @Binding shoppingItem in+    +      TextField("Enter the item's name...", $shoppingItem.name)+      +    }+  }+  +}+```+++## Proposed solution++We propose to extend the contexts were application of property-wrapper types is permitted. Namely, application of such types will be allowed on function and closure parameters:+++## Detailed design++Property wrappers are essentially sugar wrapping a given property with compiler synthesized code. This proposal retains this principle employing the following rules for transformation.++### Property Wrappers on Function Parameters++Function parameters marked with a set of compatible property-wrapper custom attributes must conform to the following rules:++1. Property wrapper function parameters must support initialization through their `wrappedValue` type. Therefore, all property-wrapper types must provide a suitable `init(wrappedValue:)`.+2. Each `wrappedValue` getter shall be `nonmutating`.+3. Default values for such parameters must be expressed in terms of the innermost `wrappedValue` type.++Transformation of property-wrapper parameters will be performed as such:++1. The external parameter name will remain unchanged.+2. The internal parameter name will be prefixed with an underscore.+3. The parameter will be bound to the backing property wrapper type.+4. A local computed property representing  `wrappedValue` will be synthesized by the compiler and named per the original (non-prefixed) parameter name. The accessors will mirror the `wrappedValue` accessors. A setter will only be synthesized for the local property if the `wrappedValue` setter is `nonmutating`, or if the wrapper is a reference type.+5. If the property wrapper defines a `projectedValue`, a local computed property representing  `projectedValue` will be synthesized by the compiler and named per the original parameter name prefixed with a dollar sign (`$`). The same accessor rules for `wrappedValue` apply to `projectedValue`.+6. When passing an argument to a property wrapper parameter, the compiler will wrap the argument in the appropriate `init(wrappedValue:)` call.++#### Transformation Example:++```swift+@propertyWrapper+struct Percentage {++  init(wrappedValue: Int) { ... }+    +    +  var wrappedValue: Int {+    get { ... }+    set { ... }+  }+  +}++func reportProgress(+  @Percentage of progress: Int+) { ... }+++reportProgress(of: 50)+```++In the above code, the `reportProgress(of:)` function and its caller are equivalent to:++```swift+func reportProgress(of _progress: Percentage) {++  var progress: Int {+    get { _progress.wrappedValue }+    // The setter accessor is not synthesized+    // because the setter of Percentage's  +    // 'wrappedValue' is mutating.+  }+++  ...+  +}+++reportProgress(of: Percentage(wrappedValue: 50))+```++#### Restrictions on Property Wrapper Function Parameters++##### `@autoclosure`++Function parameters with a property wrapper custom attribute cannot have an `@autoclosure` type. `@autoclosure` is unnecessary for the wrapped value itself because the wrapped value argument at the call-site will always be wrapped in a call to `init(wrappedValue:)`, which already can support `@autoclosure` arguments. Using `@autoclosure` for the backing wrapper type would be misleading, because the type spelled out for the parameter would not be the true autoclosure type. Consider the `reportProgress` example from above with an `@autoclosure` parameter:++```swift+func reportProgress(+  @Percentage progress: @autoclosure () -> Int+) { ... }+++reportProgress(of: 50)+```+The above code would be transformed to:+```swift+func reportProgress(+  progress _progress: @autoclosure () -> Percentage<Int>+) { ... }+++reportProgress(of: Percentage(wrappedValue: 50))+```+The changing type of the `@autoclosure` is incredibly misleading, as it's not obvious that `@autoclosure` applies to the backing wrapper rather than the wrapped value. Therefore, using `@autoclosure` for a property wrapper function parameter will be a compiler error.+++### Property Wrappers on Closure Parameters++Since a property wrapper custom attribute is applied directly to the declaration that will be wrapped, application of a property wrapper type is only available within a closure expression. That is, the signature of a function that contains a closure cannot include the property wrapper attibute. Instead the application of the attrbute will be up to the caller of the function, which supplies the closure argument.++Closure parameters marked with a set of property wrapper custom attributes must conform to the following rules:++1. Each wrapper attribute must not specify any arguments.+2. Each `wrappedValue` getter shall be `nonmutating`.+3. Any contextual type for the parameter must match the outermost backing wrapper type.++The transformation of a property wrapper closure parameter will take place as follows:++1. The parameter name will be prefixed with an underscore.+2. The parameter will be bound to the backing property wrapper type.+3. A local computed property representing  `wrappedValue` will be synthesized by the compiler and named per the original (non-prefixed) parameter name. The accessors will mirror the `wrappedValue` accessors. A setter will only be synthesized for the local property if the `wrappedValue` setter is `nonmutating`, or if the wrapper is a reference type.+4. If the property wrapper defines a `projectedValue`, a local computed property representing  `projectedValue` will be synthesized by the compiler and named per the original parameter name prefixed with a dollar sign (`$`). The same accessor rules for `wrappedValue` apply to `projectedValue`.++#### Transformation Example:++```swift+@propertyWrapper+struct Reference<Value> {++  init(+    getter: @escaping () -> Value,+    setter: @escaping (Value) -> Void+  ) { ... }+    +    +  var wrappedValue: Value {+    get +    nonmutating set+  }+    +  var projectedValue: Self {+    self+  }+  +}++typealias A = (Reference<Int>) -> Void++let a: A = { @Reference reference in+  ...+}+```++In the above example, the closure `a` is equivalent to:++```swift+let a: A = { (_reference: Reference<Int>) in++  var reference: Int {+    get { +      _reference.wrappedValue+    }+    set { +      _reference.wrappedValue = newValue+    }+  }++  var $reference: Int {+    get { +      _reference.projectedValue+    }+  }+    +    +  ...+  +}+```++## Source compatibility++This is an additive change with _no_ impact on **source compatibility**.+++## Effect on ABI stability++This is an additive change with _no_ impact on **ABI stability**.+++## Effect on API resilience++This is an additive change with _no_ impact on **API resilience**.+++## Alternatives Considered++### Allow Property Wrapper Attributes as Type Attributes++One approach for marking closure parameters as property wrappers is to allow property wrapper custom attributes to be applied to types, such as:++```swift+func useReference(+  _ closure: (@Reference reference: Int) -> Void+) { ... }+++useReference { reference in+  ...+}+```++This approach enables inference of the wrapper attribute on the closure parameter from context. However, this breaks the property wrapper declaration model, and it would force callers into the property wrapper syntax. This approach also raises questions about anonymous closure parameters that have an inferred property wrapper custom attribute. If an anonymous closure parameter `$0` has the `wrappedValue` type, accessing the backing wrapper and projected value would naturally use `_$0` and `$$0`, which are far from readable. If `$0` has the backing wrapper type, this would mean that naming the parameter would cause the value to change types, which is very unexpected for the user. Finally, the property wrapper syntax is purely implementation detail for the closure body, which does not belong in the API signature.+++## Future Directions++### Support Property Wrapper Initialization from a Projected Value++Today, a property wrapper can be initialized from an instance of its `wrappedValue` type if the wrapper provides a suitable `init(wrappedValue:)`. The same initialization strategy is used in this proposal for property wrapper parameters to allow users to pass a wrapped value as a property wrapper argument. We could extend this model to support initializing a property wrapper from an instance of its `projectedValue` type by allowing property wrappers to define an `init(projectedValue:)` that follows the same rules as `init(wrappedValue:)`. This could allow users to additionally pass a projected value as a property wrapper argument, like so:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {++  ...+  ++  init(projectedValue: Self) { ... }+  +}++func distanceFromUpperBound(+  @Clamped clamped: Int+) { ... }+++distanceFromUpperBound(+  $clamped: Clamped(to: 0 ... 100, wrappedValue: 30)+) // returns: 70+```+++### Add Support for `inout` Wrapped Parameters is Functions++This proposal doesn't currently support marking function parameters to which wrapper types have been applied `inout`. We deemed that this functionality would be better tackled by another proposal due to its implementation complexity. However, such a feature would be really useful for wrapper types with value semantics and it would simplify the mental model. Furthermore, it could alleviate some confusion for users that don't understand the difference between a setter with value semantics and one with reference semantics.+++### Accessing Enclosing Self from Wrapper Types++There's currently no public feature that allows a wrapper to access its enclosing `Self` type:++```swift+@propertyWrapper+struct Mirror<EnclosingSelf, Value, Path>+  where Path : KeyPath<EnclosingSelf, Value> { +  +  let keyPath: Path +++  init(of keyPath: Path) { ... }+  +}+++struct Point {++  private var _vector: SIMD2<Double>+  +  +  init(x: Double, y: Double) {+    self._vector = SIMD2(x: x, y: y)+  }+  +  +  @Mirror(of: \._vector.x)+  var x+  +  @Mirror(of: \._vector.y)+  var y+  +} ❌+// In the above use, we'd access the enclosing+// type's '_vector' property through the provided+// keyPath. However, today that's invalid.+```++Furthermore, extending this feature's availability to function and closure parameters be really powerful:++```swift+func valueAndIdPair<Value>(+  @Mirror of property: Value+) -> (value: Value, id: Int) {+  (value: property, id: $property.keyPath.hashValue)+}+```++It's important to note that allowing use of such a feature in function parameters would entail some limitations. For example, a parameter marked with a wrapper type referencing enclosing `self` would be an error for a non-instance method, as the accessors for the `wrappedValue` and `projectedValue` need an enclosing `self` instance.++### Add Wrapper Types in the Standard Library++Adding wrapper types to the Standard Library has been discussed for types [such as `@Atomic`] and [`@Weak`](https://forums.swift.org/t/should-weak-be-a-type/34032), which would facilitate certain APIs. Another interesting Standard Library wrapper type could be `@UnsafePointer`, which would be quite useful, as access of the `pointee` property is quite common:++```swift+let myPointer: UnsafePointer<UInt8> = ...++myPointer.pointee +//        ^~~~~~~ +// This is the accessor pattern property +// wrappers were devised to tackle.+```++Instead of writing the above, in the future one might be able to write this:++```swift+let myInt = 0++withUnsafePointer(to: ...) { @UnsafePointer value in++  print(value) // 0+  +  $value.withMemoryRebound(to: UInt64.self {+    ... +  }+  +}+```++As a result, unsafe code is not dominated by visually displeasing accesses to `pointee` members; rather, more natural and clear code is enabled. ++What's more, a `@Lazy` type could be added so as to alleviate the need for custom behavior built into the compiler. Instead, `@Lazy` would act as more comprehensible, easy to maintain type, that would also allow for a more streamlined way of resetting its storage:

I think if we are going to include this, we should use an example that uses @Lazy on a parameter. Otherwise, it seems strange that this is included in the "Property Wrapper Parameters" proposal

filip-sakel

comment created time in 19 days

PullRequestReviewEvent

push eventfilip-sakel/swift-evolution

Holly Borla

commit sha 3bf938774002ce8ef6220db57f5d874f1e56fd45

[Property Wrapper Parameters] Make the text clear that property wrapper parameters must support init(wrappedValue:) initialization.

view details

push time in 19 days

push eventfilip-sakel/swift-evolution

Holly Borla

commit sha 45d40b7715a593b51546a2d23f655bdcc2a40213

[Property Wrapper Parameters] Slight modifications to the description of limitations on enclosing self property wrapper parameters.

view details

push time in 19 days

Pull request review commentapple/swift-evolution

[Proposal] Extend Property Wrappers to Function and Closure Parameters

+# Extend Property Wrappers to Function and Closure Parameters++* Proposal: [SE-NNNN](NNNN-extend-property-wrappers-to-function-and-closure-parameters.md)+* Authors: [Holly Borla](https://github.com/hborla), [Filip Sakel](https://github.com/filip-sakel)+* Review Manager: TBD+* Status: **Awaiting implementation**+++## Introduction++Property Wrappers were [introduced in Swift 5.1](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md), and have since become a popular feature abstracting away common accessor patterns for properties. Currently, applying a property wrapper is solely permitted on properties inside of a type context. However, with increasing adoption demand for extending _where_ property wrappers can be applied has emerged. This proposal aims to extend property wrappers to function and closure parameters.+++## Motivation++Property wrappers have undoubtably been very successful. Applying a property wrapper to a property is enabled by an incredibly lightweight and expressive syntax. Therefore, library authors can expose complex behavior through easily understandable property-wrapper types in an efficient manner. For instance, frameworks such as [SwiftUI](https://developer.apple.com/documentation/swiftui/) and [Combine](https://developer.apple.com/documentation/combine) introduce property wrappers such as [`State`](https://developer.apple.com/documentation/swiftui/state), [`Binding`](https://developer.apple.com/documentation/swiftui/binding) and [`Published`](https://developer.apple.com/documentation/combine/published) respectively to expose elaborate behavior through a succint interface, helping craft expressive yet simple APIs. However, property wrappers are only applicable to type properties, shattering the illusion that they helped realize in the first place:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {++  init(+    wrappedValue: Value,+    to range: Range<Value>+  ) { ... }+  +  +  var wrappedValue: Value { +    get { ... }+    set { ... }+  }+  +}+++struct Percentage {++  @Clamped(to: 0 ... 100)+  var percent = 0+     +     +  mutating func increment() {+    percent += 1+    // Great!+  }++  mutating func adding(_ offset: Int) {+    percent += min(100, max(0, offset))+    //         ^~~~~~~~~~~~~~~~~~~~~~~~+    // We are forced to manually adjust 'percent' +    // instead of utilizing the abstraction +    // property wrappers offer.+  }++  mutating func adding(_ offset: Clamped<Int>) {+    //                   ^~~~~~~~~~~~~~~~~~~~+    // Unfortunately, we can't use +    // '@Clamped(to: 0 ... 100)' here.+    +    percent += offset.wrappedValue+    //               ^~~~~~~~~~~~~+    // We must access 'wrappedValue' manually.+  }+  +}+```++As seen in the above example, it is quite awkward and unintuitive that property wrappers cannot be applied to function parameters. In this case, a property wrapper parameter would be useful for expressing and enforcing invariants about the `offset` argument to the `adding` method on `Percentage`. Inability to allow the property wrapper attribute on the `offset` parameter causes the API author to choose between making invariant checking an implementation detail, or forcing the invariant checking on every caller of the API.++This limitation in expressivity is emphasized by the fact that property wrappers were originally sought out to abstract away such patterns.  As a result, elegant APIs are undermined by this limitation. Not only is this limiting users by forcing them to carefully read documentation, which may not cover a specific use case, to make sure no invariants have been violated, but it also limits API authors in what they can create. That is, API authors can't use property-wrapper types in closure parameters nor can code be seperated into functions that accept property wrapper syntax:++```swift+extension Percentage {++  func modify(+    inSeconds seconds: Int,+    block: @escaping (inout Clamped<Int>) -> Void+  ) { ... }+  +}+++let myPercentage = Percentage(percent: 50)++myPercentage+  .modify(inSeconds: 3) { percent in+    percent.wrappedValue = 100+    //    ^~~~~~~~~~~~ +    // Again, we have to access+    // count through 'wrappedValue'.+  }+```++In fact, establishing custom behavior on closure parameters is really powerful. For example, if such a feature were supported, it could be used in conjunction with [Function Builders](https://github.com/apple/swift-evolution/blob/master/proposals/0289-function-builders.md) to expose data managed by a 'component' type. For instance, in SwiftUI [`ForEach`](https://developer.apple.com/documentation/swiftui/foreach) could leverage this feature to expose the mutable state of its data source to its 'content' closure. This would enable users to more easily work with the data source itself inside the closure instead of accessing the original property, which is particularly painful when working with collections, as shown in this example:++```swift+struct MyView: View {++  // A simple Shopping Item that includes+  // a 'quantity' and a 'name' property.+  @State +  private var shoppingItems: [Item]+++  var body: some View {+    ForEach(0 ..< shoppingItems.count) { index in+  +      TextField("Enter the item's name...", $shoppingItems[index].name)+      +    }+  }+  +}+```++we would – with an appropriate initializer – be able to simplify the above code, reducing boilerplate as a result:++```swift+struct MyView: View {++  @State +  private var shoppingItems: [Item]+++  var body: some View {+    ForEach($shoppingItems) { @Binding shoppingItem in+    +      TextField("Enter the item's name...", $shoppingItem.name)+      +    }+  }+  +}+```+++## Proposed solution++We propose to extend the contexts were application of property-wrapper types is permitted. Namely, application of such types will be allowed on function and closure parameters:+++## Detailed design++Property wrappers are essentially sugar wrapping a given property with compiler synthesized code. This proposal retains this principle employing the following rules for transformation.++### Property Wrappers on Function Parameters++Function parameters marked with compatible property-wrapper custom attributes must conform to the following rules:

Yes, thank you!

filip-sakel

comment created time in 19 days

PullRequestReviewEvent

delete branch hborla/swift

delete branch : local-property-wrappers

delete time in 23 days

push eventapple/swift

Holly Borla

commit sha 3a47087cc197aab8970a55ee265d395bc4f6f002

[Parser] Don't resolve decl references in the parser if the declaration has a custom attribute.

view details

Holly Borla

commit sha 9b2cd5e3ffa09063a8b64250cd0c62850a41fd26

[NameLookup] Teach unqualified lookup to resolve backing property wrapper and projected value references

view details

Holly Borla

commit sha b33dbedd9b8d3dc2e6ee28373c69a24764249745

[SILGen] Teach SIlGen to emit local property wrappers

view details

Holly Borla

commit sha 0842b4212773b36778d773331155df6be20d2c21

[SILGen] Only use assign_by_wrapper for wrapped instance properties inside an initializer, and for wrapped local variables.

view details

Holly Borla

commit sha 9bd3d0b67fc9599c693735d98c6ff98defccc8e5

[Property Wrappers] Make sure captures are computed for synthesized property wrapper accessors.

view details

Holly Borla

commit sha d8df6217d32cf7ec970d67bc66ff966df0c1a671

[Property Wrappers] Allow property wrappers on local variables.

view details

Holly Borla

commit sha 21cbdfa337dfa41e108573d5d99c6259bee671c9

[Property Wrappers] Add a VarDecl helper method for visiting synthesized property wrapper vars.

view details

Holly Borla

commit sha 2a67c651eecb6ccd6384a90961cfee46338c954e

[Property Wrappers] Generalize a few property wrapper decl context checks to check for type context instead of local context. This generalization will help us implement property wrappers on global variables, which should use the same approach of not adding synthesized accessors to the AST and instead lazily visit them in SILGen.

view details

Holly Borla

commit sha 9e373a240540f4bf90ed26981a9e29958445d3c6

[Name Lookup] Remove property wrapper name lookup flags and generalize unqualified lookup of auxiliary decl names.

view details

Holly Borla

commit sha 4bb98baf1364ce63e410c381aed7f9690dc5119f

[SILGen] Add a new CaptureEmission kind specifically for emitting captured local variables for the assign_by_wrapper setter. Since assign_by_wrapper will always be re-written to initialization if the captured local variable is uninitialized, it's unnecessary to mark the capture as an escape. This lets us support out-of-line initialization for local property wrappers.

view details

Holly Borla

commit sha 176391f18208898f24b5a24c5423b48d4c097ace

[Test] Start to add SILGen tests for local property wrappers.

view details

Holly Borla

commit sha af71c5dfbdfe16ec694aabf72f83f16bc68b935b

[Property Wrappers] Ban non-member property wrappers with observers, just like we do for regular non-member properties.

view details

Holly Borla

commit sha 763bcf900529152ac35f566cb5e887a4c867d9f7

[SILGen] Don't use assign_by_wrapper for local property wrappers if there is an initial wrapped value.

view details

Holly Borla

commit sha 355fbb3a8b9719b59a776b0f16bdf444bfc4a6be

Merge pull request #34109 from hborla/local-property-wrappers [Property Wrappers] Support local property wrappers

view details

push time in 23 days

PR merged apple/swift

[Property Wrappers] Support local property wrappers

Support property wrappers on local variables, e.g.

@propertyWrapper
struct Wrapper<T> {
  var wrappedValue: T
}

func test() {
  @Wrapper var value = 10
}
+346 -54

7 comments

19 changed files

hborla

pr closed time in 23 days

pull request commentapple/swift

[Property Wrappers] Support local property wrappers

@swift-ci please smoke test

hborla

comment created time in 23 days

CommitCommentEvent

push eventhborla/swift

Holly Borla

commit sha 763bcf900529152ac35f566cb5e887a4c867d9f7

[SILGen] Don't use assign_by_wrapper for local property wrappers if there is an initial wrapped value.

view details

push time in 23 days

PullRequestReviewEvent

push eventhborla/swift

Holly Borla

commit sha af71c5dfbdfe16ec694aabf72f83f16bc68b935b

[Property Wrappers] Ban non-member property wrappers with observers, just like we do for regular non-member properties.

view details

push time in 23 days

Pull request review commentapple/swift-evolution

[Proposal] Extend Property Wrappers to Function and Closure Parameters

+# Extend Property Wrappers to Function and Closure Parameters++* Proposal: [SE-NNNN](NNNN-extend-property-wrappers-to-function-and-closure-parameters.md)+* Authors: [Holly Borla](https://github.com/hborla), [Filip Sakel](https://github.com/filip-sakel)+* Review Manager: TBD+* Status: **Awaiting implementation**+++## Introduction++Property Wrappers were [introduced in Swift 5.1](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md), and have since become a popular feature abstracting away common accessor patterns for properties. Currently, applying a property wrapper is solely permitted on properties inside of a type context. However, with increasing adoption demand for extending _where_ property wrappers can be applied has emerged. This proposal aims to extend property wrappers to function and closure parameters.+++## Motivation++Property wrappers have undoubtably been very successful. Applying a property wrapper to a property is enabled by an incredibly lightweight and expressive syntax. Therefore, library authors can expose complex behavior through easily understandable property-wrapper types in an efficient manner. For instance, frameworks such as [SwiftUI](https://developer.apple.com/documentation/swiftui/) and [Combine](https://developer.apple.com/documentation/combine) introduce property wrappers such as [`State`](https://developer.apple.com/documentation/swiftui/state), [`Binding`](https://developer.apple.com/documentation/swiftui/binding) and [`Published`](https://developer.apple.com/documentation/combine/published) respectively to expose elaborate behavior through a succint interface, helping craft expressive yet simple APIs. However, property wrappers are only applicable to type properties, shattering the illusion that they helped realize in the first place:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {++  init(+    wrappedValue: Value,+    to range: Range<Value>+  ) { ... }+  +  +  var wrappedValue: Value { +    get { ... }+    set { ... }+  }+  +}+++struct Percentage {++  @Clamped(to: 0 ... 100)+  var percent = 0+     +     +  mutating func increment() {+    percent += 1+    // Great!+  }++  mutating func adding(_ offset: Int) {+    percent += min(100, max(0, offset))+    //         ^~~~~~~~~~~~~~~~~~~~~~~~+    // We are forced to manually adjust 'percent' +    // instead of utilizing the abstraction +    // property wrappers offer.+  }++  mutating func adding(_ offset: Clamped<Int>) {+    //                   ^~~~~~~~~~~~~~~~~~~~+    // Unfortunately, we can't use +    // '@Clamped(to: 0 ... 100)' here.+    +    percent += offset.wrappedValue+    //               ^~~~~~~~~~~~~+    // We must access 'wrappedValue' manually.+  }+  +}+```++As seen in the above example, it is quite awkward and unintuitive that property wrappers cannot be applied to function parameters. In this case, a property wrapper parameter would be useful for expressing and enforcing invariants about the `offset` argument to the `adding` method on `Percentage`. Inability to allow the property wrapper attribute on the `offset` parameter causes the API author to choose between making invariant checking an implementation detail, or forcing the invariant checking on every caller of the API.++This limitation in expressivity is emphasized by the fact that property wrappers were originally sought out to abstract away such patterns.  As a result, elegant APIs are undermined by this limitation. Not only is this limiting users by forcing them to carefully read documentation, which may not cover a specific use case, to make sure no invariants have been violated, but it also limits API authors in what they can create. That is, API authors can't use property-wrapper types in closure parameters nor can code be seperated into functions that accept property wrapper syntax:++```swift+extension Percentage {++  func modify(+    inSeconds seconds: Int,+    block: @escaping (inout Clamped<Int>) -> Void+  ) { ... }+  +}+++let myPercentage = Percentage(percent: 50)++myPercentage+  .modify(inSeconds: 3) { percent in+    percent.wrappedValue = 100+    //    ^~~~~~~~~~~~ +    // Again, we have to access+    // count through 'wrappedValue'.+  }+```++In fact, establishing custom behavior on closure parameters is really powerful. For example, if such a feature were supported, it could be used in conjunction with [Function Builders](https://github.com/apple/swift-evolution/blob/master/proposals/0289-function-builders.md) to expose data managed by a 'component' type. For instance, in SwiftUI [`ForEach`](https://developer.apple.com/documentation/swiftui/foreach) could leverage this feature to expose the mutable state of its data source to its 'content' closure. This would enable users to more easily work with the data source itself inside the closure instead of accessing the original property, which is particularly painful when working with collections, as shown in this example:++```swift+struct MyView: View {++  // A simple Shopping Item that includes+  // a 'quantity' and a 'name' property.+  @State +  private var shoppingItems: [Item]+++  var body: some View {+    ForEach(0 ..< shoppingItems.count) { index in+  +      TextField("Enter the item's name...", $shoppingItems[index].name)+      +    }+  }+  +}+```++we would – with an appropriate initializer – be able to simplify the above code, reducing boilerplate as a result:++```swift+struct MyView: View {++  @State +  private var shoppingItems: [Item]+++  var body: some View {+    ForEach($shoppingItems) { @Binding shoppingItem in+    +      TextField("Enter the item's name...", $shoppingItem.name)+      +    }+  }+  +}+```+++## Proposed solution++We propose to extend the contexts were application of property-wrapper types is permitted. Namely, application of such types will be allowed on function and closure parameters:+++## Detailed design++Property wrappers are essentially sugar wrapping a given property with compiler synthesized code. This proposal retains this principle employing the following rules for transformation.++### Property Wrappers on Function Parameters++Function parameters marked with compatible property-wrapper custom attributes must conform to the following rules:

@filip-sakel I noticed that you changed some of the language in these rules to be more consistent (thank you!), but I think some details got lost along the way. I wrote "a set of property wrapper custom attributes" to make it clear that these rules are generalized for property wrapper composition, e.g.

func test(@Wrapper @Wrapper @Wrapper param: Int) { ... }

Similarly, in the first rule below, it's important to say that each property wrapper type must provide a suitable init(wrappedValue:).

filip-sakel

comment created time in 23 days

PullRequestReviewEvent

push eventfilip-sakel/swift-evolution

Holly Borla

commit sha bea2401c41024b0d53b2f765d3aac9a7a5cce8a1

[Property Wrapper Parameters] Remove example from the Proposed Solution section.

view details

push time in 23 days

push eventfilip-sakel/swift-evolution

Holly Borla

commit sha 3102380fb274dc620e64091d9e3c5b10a0e69bfe

[Property Wrapper Parameters] Add an explanation for disallowing @autoclosure

view details

push time in 23 days

CommitCommentEvent

delete branch hborla/swift

delete branch : type-checker-doc

delete time in 23 days

push eventapple/swift

Holly Borla

commit sha 6173d7ec04eaa76fa4c3ef8f1193ce8fdeec7c28

[Docs] Convert TypeChecker.rst to Markdown

view details

Holly Borla

commit sha 91fd19d6db8f7b80ea0d562bd20436119021e117

[Docs] Correct a few code blocks in TypeChecker.md

view details

Holly Borla

commit sha 62a6a460594fb078897c7aba2a3b5ba6e9ec8138

Merge pull request #34150 from hborla/type-checker-doc [Docs] Convert TypeChecker.rst to Markdown

view details

push time in 23 days

PR merged apple/swift

[Docs] Convert TypeChecker.rst to Markdown

This PR is only to convert the formatting. Very minor content changes were made (like removing the paragraph about how diagnostics are terrible!)

+106 -124

1 comment

1 changed file

hborla

pr closed time in 23 days

PullRequestReviewEvent

pull request commentapple/swift

[Docs] Convert TypeChecker.rst to Markdown

@swift-ci please smoke test

hborla

comment created time in 23 days

PR opened apple/swift

Reviewers
[Docs] Convert TypeChecker.rst to Markdown

This PR is only to convert the formatting. Very minor content changes were made (like removing the paragraph about how diagnostics are terrible!)

+106 -124

0 comment

1 changed file

pr created time in 23 days

push eventhborla/swift

Holly Borla

commit sha 91fd19d6db8f7b80ea0d562bd20436119021e117

[Docs] Correct a few code blocks in TypeChecker.md

view details

push time in 23 days

create barnchhborla/swift

branch : type-checker-doc

created branch time in 23 days

PullRequestReviewEvent

pull request commentapple/swift

[Property Wrappers] Support local property wrappers

Doesn't look like there were actually any failures in the source compat suite

hborla

comment created time in 24 days

Pull request review commentapple/swift-evolution

[Proposal] Extend Property Wrappers to Function and Closure Parameters

+# Extend Property Wrappers to Function and Closure Parameters++* Proposal: [SE-NNNN](NNNN-extend-property-wrappers-to-function-and-closure-parameters.md)+* Authors: [Holly Borla](https://github.com/hborla), [Filip Sakel](https://github.com/filip-sakel)+* Review Manager: TBD+* Status: **Awaiting implementation**+++## Introduction++Property Wrappers were [introduced in Swift 5.1](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md), and have since become a popular feature abstracting away common accessor patterns for properties. Currently, applying a property wrapper is solely permitted on properties inside of a type context. However, with increasing adoption demand for extending _where_ property wrappers can be applied has emerged. This proposal aims to extend property wrappers to function and closure parameters.+++## Motivation++Property wrappers have undoubtably been very successful. Applying a property wrapper to a property is enabled by an incredibly lightweight and expressive syntax. Therefore, library authors can expose complex behavior through easily understandable property-wrapper types in an efficient manner. For instance, frameworks such as [SwiftUI](https://developer.apple.com/documentation/swiftui/) and [Combine](https://developer.apple.com/documentation/combine) introduce property wrappers such as [`State`](https://developer.apple.com/documentation/swiftui/state), [`Binding`](https://developer.apple.com/documentation/swiftui/binding) and [`Published`](https://developer.apple.com/documentation/combine/published) respectively to expose elaborate behavior through a succint interface, helping craft expressive yet simple APIs. However, property wrappers are only applicable to type properties, shattering the illusion that they helped realize in the first place:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {++  init(+    wrappedValue: Value,+    to range: Range<Value>+  ) { ... }+  +  +  var wrappedValue: Value { +    get { ... }+    set { ... }+  }+  +}+++struct Percentage {++  @Clamped(to: 0 ... 100)+  var percent = 0+     +     +  mutating func increment() {+    percent += 1+    // Great!+  }++  mutating func adding(_ offset: Int) {+    percent += min(100, max(0, offset))+    //         ^~~~~~~~~~~~~~~~~~~~~~~~+    // We are forced to manually adjust 'percent' +    // instead of utilizing the abstraction +    // property wrappers offer.+  }++  mutating func adding(_ offset: Clamped<Int>) {+    //                   ^~~~~~~~~~~~~~~~~~~~+    // Unfortunately, we can't use +    // '@Clamped(to: 0 ... 100)' here.+    +    percent += offset.wrappedValue+    //               ^~~~~~~~~~~~~+    // We must access 'wrappedValue' manually.+  }+  +}+```++As seen in the above example, it is quite awkward and unintuitive that property wrappers cannot be applied to function parameters. In this case, a property wrapper parameter would be useful for expressing and enforcing invariants about the `offset` argument to the `adding` method on `Percentage`. Inability to allow the property wrapper attribute on the `offset` parameter causes the API author to choose between making invariant checking an implementation detail, or forcing the invariant checking on every caller of the API.++This limitation in expressivity is emphasized by the fact that property wrappers were originally sought out to abstract away such patterns.  As a result, elegant APIs are undermined by this limitation. Not only is this limiting users by forcing them to carefully read documentation, which may not cover a specific use case, to make sure no invariants have been violated, but it also limits API authors in what they can create. That is, API authors can't use property-wrapper types in closure parameters nor can code be seperated into functions that accept property wrapper syntax:++```swift+extension Percentage {++  func modify(+    inSeconds seconds: Int,+    block: @escaping (Clamped<Int>) -> Void+  ) { ... }+  +}+++let myPercentage = Percentage(percent: 50)++myPercentage+  .modify(inSeconds: 3) { percent in+    percent.wrappedValue = 100+    //    ^~~~~~~~~~~~ +    // Again, we have to access+    // count through 'wrappedValue'.+  }+```++In fact, establishing custom behavior on closure parameters is really powerful. For example, if such a feature were supported, it could be used in conjunction with [Function Builders](https://github.com/apple/swift-evolution/blob/master/proposals/0289-function-builders.md) to expose data managed by a 'component' type. For instance, in SwiftUI [`ForEach`](https://developer.apple.com/documentation/swiftui/foreach) could leverage this feature to expose the mutable state of its data source to its 'content' closure. Thus, instead of manually mutating the data source, as is done here:++```swift+struct MyView: View {++  // A simple Shopping Item that includes+  // a 'quantity' and a 'name' property.+  @State +  private var shoppingItems: [Item]+++  var body: some View {+    ForEach(0 ..< shoppingItems.count) { index in+  +      Text(shoppingItems[index].name)+        .onTapGesture {+          // We increase the item's quantity +          // when the user taps the item. +          // Unfortunately, to mutate the item+          // we have to manually index our+          // data source.+          shoppingItems[index].quanity += 1+        }+      +    }+  }+  +}+```++we would – with an appropriate initializer – be able to simplify the above code, reducing boilerplate as a result:++```swift+struct MyView: View {++  @State +  private var shoppingItems: [Item]+++  var body: some View {+    ForEach($shoppingItems) { @Binding shoppingItem in+    +      Text(shoppingItem.name)+        .onTapGesture {+          shoppingItem.quanity += 1+        }+      +    }+  }+  +}+```+++## Proposed solution++We propose to extend the contexts were application of property-wrapper types is permitted. Namely, application of such types will be allowed on function and closure parameters:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {++  ...+    +    +  var projectedValue: Self {+    self+  }+  +}++func increment(+  @Clamped(to: 0 ... 100) percent: Int = 100+) { ... }++myPercentage+  .modify(inSeconds: 3) { @Clamped percent in+    percent = 100 +  }+```+++## Detailed design++Property wrappers are essentially sugar wrapping a given property with compiler synthesized code. This proposal retains this principle employing the following rules for transformation.++### Property Wrappers on Function Parameters++Function parameters marked with compatible property-wrapper custom attributes must conform to the following rules:++1. For initalization through `wrappedValue` type, the property wrapper type must provide a suitable `init(wrappedValue:)`.+2. Each `wrappedValue` getter shall be `nonmutating`.+3. Default values for such parameters must be expressed in terms of the innermost `wrappedValue` type.++Transformation of property-wrapper parameters will be performed as such:++1. The external parameter name will remain unchanged.+2. The internal parameter name will be prefixed with an underscore.+3. The parameter will be bound to the backing property wrapper type.+4. A local computed property representing  `wrappedValue` will be synthesized by the compiler and named per the original (non-prefixed) parameter name. The accessors will mirror the `wrappedValue` accessors. A setter will only be synthesized for the local property if the `wrappedValue` setter is `nonmutating`, or if the wrapper is a reference type.+5. If the property wrapper defines a `projectedValue`, a local computed property representing  `projectedValue` will be synthesized by the compiler and named per the original parameter name prefixed with a dollar sign (`$`). The same accessor rules for `wrappedValue` apply to `projectedValue`.+6. When passing an argument to a property wrapper parameter, the compiler will wrap the argument in the appropriate `init(wrappedValue:)` call – should one be provided.++#### Transformation Example:++```swift+@propertyWrapper+struct Percentage {++  init(wrappedValue: Int) { ... }+    +    +  var wrappedValue: Int {+    get { ... }+    set { ... }+  }+  +}++func reportProgress(+  @Percentage of progress: Int+) { ... }+++reportProgress(of: 50)+```++In the above code, the `reportProgress(of:)` function and its caller are equivalent to:++```swift+func reportProgress(of _progress: Percentage) {++  var progress: Int {+    get { _progress.wrappedValue }+    // The setter accessor is not synthesized+    // because the setter of Percentage's  +    // 'wrappedValue' is mutating.+  }+++  ...+  +}+++reportProgress(of: Percentage(wrappedValue: 50))+```++### Property Wrappers on Closure Parameters++Since a property wrapper custom attribute is applied directly to the declaration that will be wrapped, application of a property wrapper type is only available within a closure expression. That is, the signature of a function that contains a closure cannot include the property wrapper attibute. Instead the application of the attrbute will be up to the caller of the function, which supplies the closure argument.++Closure parameters marked with a set of property wrapper custom attributes must conform to the following rules:++1. Each wrapper attribute must not specify any arguments.+2. Each `wrappedValue` getter shall be `nonmutating`.+3. Any contextual type for the parameter must match the outermost backing wrapper type.++The transformation of a property wrapper closure parameter will take place as follows:++1. The parameter name will be prefixed with an underscore.+2. The parameter will be bound to the backing property wrapper type.+3. A local computed property representing  `wrappedValue` will be synthesized by the compiler and named per the original (non-prefixed) parameter name. The accessors will mirror the `wrappedValue` accessors. A setter will only be synthesized for the local property if the `wrappedValue` setter is `nonmutating`, or if the wrapper is a reference type.+4. If the property wrapper defines a `projectedValue`, a local computed property representing  `projectedValue` will be synthesized by the compiler and named per the original parameter name prefixed with a dollar sign (`$`). The same accessor rules for `wrappedValue` apply to `projectedValue`.++#### Transformation Example:++```swift+@propertyWrapper+struct Reference<Value> {++  init(+    getter: @escaping () -> Value,+    setter: @escaping (Value) -> Void+  ) { ... }+    +    +  var wrappedValue: Value {+    get +    nonmutating set+  }+    +  var projectedValue: Self {+    self+  }+  +}++typealias A = (Reference<Int>) -> Void++let a: A = { @Reference reference in+  ...+}+```++In the above example, the closure `a` is equivalent to:++```swift+let a: A = { (_reference: Reference<Int>) in++  var reference: Int {+    get { +      _reference.wrappedValue+    }+    set { +      _reference.wrappedValue = newValue+    }+  }++  var $reference: Int {+    get { +      _reference.projectedValue+    }+  }+    +    +  ...+  +}+```++## Source compatibility++This is an additive change with _no_ impact on **source compatibility**.+++## Effect on ABI stability++This is an additive change with _no_ impact on **ABI stability**.+++## Effect on API resilience++This is an additive change with _no_ impact on **API resilience**.+++## Alternatives Considered++### Allow Property Wrapper Attributes as Type Attributes++One approach for marking closure parameters as property wrappers is to allow property wrapper custom attributes to be applied to types, such as:++```swift+func useReference(+  _ closure: (@Reference reference: Int) -> Void+) { ... }+++useReference { reference in+  ...+}+```++This approach enables inference of the wrapper attribute on the closure parameter from context. However, this breaks the property wrapper declaration model, and it would force callers into the property wrapper syntax. This approach also raises questions about anonymous closure parameters that have an inferred property wrapper custom attribute. If an anonymous closure parameter `$0` has the `wrappedValue` type, accessing the backing wrapper and projected value would naturally use `_$0` and `$$0`, which are far from readable. If `$0` has the backing wrapper type, this would mean that naming the parameter would cause the value to change types, which is very unexpected for the user. Finally, the property wrapper syntax is purely implementation detail for the closure body, which does not belong in the API signature.+++### Support `@autoclosure` and `@escaping` in Function Parameters++TBD+++## Future Directions++### Allow Arguments in Parameter Wrapper Attributes using Shared Wrapper Context++TODO (Holly)++### Support Property Wrapper Initialization from a Projected Value++Today, a property wrapper can be initialized from an instance of its `wrappedValue` type if the wrapper provides a suitable `init(wrappedValue:)`. The same initialization strategy is used in this proposal for property wrapper parameters to allow users to pass a wrapped value as a property wrapper argument. We could extend this model to support initializing a property wrapper from an instance of its `projectedValue` type by allowing property wrappers to define an `init(projectedValue:)` that follows the same rules as `init(wrappedValue:)`. This could allow users to additionally pass a projected value as a property wrapper argument, like so:++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {++  ...+  ++  init(projectedValue: Self) { ... }+  +}++func distanceFromUpperBound(+  @Clamped clamped: Int+) { ... }+++distanceFromUpperBound(+  $clamped: Clamped(to: 0 ... 100, wrappedValue: 30)+) // returns: 70+```+++### Add Support for `inout` Wrapped Parameters is Functions++This proposal doesn't currently support marking function parameters to which wrapper types have been applied `inout`. We deemed that this functionality would be better tackled by another proposal due to its implementation complexity. However, such a feature would be really useful for wrapper types with value semantics and it would simplify the mental model. Furthermore, it could alleviate some confusion for users that don't understand the difference between a setter with value semantics and one with reference semantics.+++### Accessing Enclosing Self from Wrapper Types++There's currently no public feature that allows a wrapper to access its enclosing `Self` type:++```swift+@propertyWrapper+struct Mirror<EnclosingSelf, Value, Path>+  where Path : KeyPath<EnclosingSelf, Value> { +  +  let keyPath: Path +++  init(of keyPath: Path) { ... }+  +}+++struct Point {++  private var _vector: SIMD2<Double>+  +  +  init(x: Double, y: Double) {+    self._vector = SIMD2(x: x, y: y)+  }+  +  +  @Mirror(of: \._vector.x)+  var x+  +  @Mirror(of: \._vector.y)+  var y+  +} ❌+// In the above use, we'd access the enclosing+// type's '_vector' property through the provided+// keyPath. However, today that's invalid.+```++Furthermore, extending this feature's availability to function and closure parameters be really powerful:++```swift+func valueAndIdPair<Value>(+  @Mirror of property: Value+) -> (value: Value, id: Int) {+  (value: property, id: $property.keyPath.hashValue)+}+```++It's important to note that allowing use of such a feature in function parameters would entail some limitations. For example, a parameter makred with a wrapper type referencing enclosing `Self` would not be initializable with the sugared function call that utilizes `init(wrappedValue: ...)`. That's because it would require access to the enclosing `Self`; however, in the case of calling a function this would be undefined.+++### Add Wrapper Types in the Standard Library++The has been some discussion of adding wrapper types to the Standard Library, such as an `@Atomic` wrapper, so as to facilitate certain APIs. For example, `@UnsafePointer` could be a very useful one, due to the way one accesses the `pointee` property of an `UnsafePointer` type:

Hmm, not off the top of my head but I'll keep thinking about it

filip-sakel

comment created time in 24 days

PullRequestReviewEvent

push eventfilip-sakel/swift-evolution

Holly Borla

commit sha b9b72072d221f4992e1c17b2e08ec7750b3dc33d

[Property Wrapper Parameters] Minor tweaks to Motivation section

view details

push time in 24 days

Pull request review commentapple/swift

[Property Wrappers] Support local property wrappers

 VarDecl *VarDecl::getPropertyWrapperProjectionVar() const {   return getPropertyWrapperBackingPropertyInfo().projectionVar; } +void VarDecl::visitAuxiliaryDecls(llvm::function_ref<void(VarDecl *)> visit) const {+  if (getDeclContext()->isTypeContext())+    return;++  if (auto *backingVar = getPropertyWrapperBackingProperty())+    visit(backingVar);++  if (auto *projectionVar = getPropertyWrapperProjectionVar())+    visit(projectionVar);+}

Yes, that's right - with this approach, I've added calls to visitAuxiliaryDecls in name lookup, the decl checker, and SILGen, so the synthesized VarDecls don't need to be added to the BraceStmt, but they're still visited in the appropriate places.

hborla

comment created time in 24 days

PullRequestReviewEvent

pull request commentapple/swift

[Property Wrappers] Support local property wrappers

@swift-ci please test source compatibility

hborla

comment created time in 24 days

pull request commentapple/swift

[Property Wrappers] Support local property wrappers

@swift-ci please smoke test

hborla

comment created time in 24 days

push eventhborla/swift

Holly Borla

commit sha 176391f18208898f24b5a24c5423b48d4c097ace

[Test] Start to add SILGen tests for local property wrappers.

view details

push time in 24 days

pull request commentapple/swift

[Property Wrappers] Support local property wrappers

@slavapestov could you also take a look at https://github.com/apple/swift/pull/34109/commits/4bb98baf1364ce63e410c381aed7f9690dc5119f ? I want to make sure it's not a terrible idea

hborla

comment created time in 24 days

Pull request review commentapple/swift

[Property Wrappers] Support local property wrappers

 VarDecl *VarDecl::getPropertyWrapperProjectionVar() const {   return getPropertyWrapperBackingPropertyInfo().projectionVar; } +void VarDecl::visitAuxiliaryDecls(llvm::function_ref<void(VarDecl *)> visit) const {+  if (getDeclContext()->isTypeContext())+    return;++  if (auto *backingVar = getPropertyWrapperBackingProperty())+    visit(backingVar);++  if (auto *projectionVar = getPropertyWrapperProjectionVar())+    visit(projectionVar);+}

(unless somebody else gets to it first 🙂 )

hborla

comment created time in 24 days

more