Skip to content

Commit 67abf72

Browse files
Modifying resolve for property access part
1 parent 316fa61 commit 67abf72

File tree

1 file changed

+76
-11
lines changed

1 file changed

+76
-11
lines changed

docs/src/md/kotlin.core/overload-resolution.md

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -621,12 +621,22 @@ TODO(Explain why anonymous function declarations DO NOT have a defined type w.r.
621621
> }
622622
> ```
623623
624-
### Resolving properties
624+
### Resolving property access
625625
626626
As [properties][Property declaration] in Kotlin can have custom [getters and setters], be [extension][Extension property declaration], [delegated][Delegated property declaration] or [contextual][Contextual property declaration], they are also subject to overload resolution.
627-
Overload resolution for properties works similarly to how it works for [callables][Callables and `invoke` convention], i.e., it consists of two steps: [building the overload candidate set] of [applicable][Determining function applicability for a specific call] candidates, and then [choosing the most specific candidate from the overload candidate set].
627+
Overload resolution for property access works similarly to how it works for [callables][Callables and `invoke` convention], i.e., it consists of two steps: [building the overload candidate set] of [applicable][Determining function applicability for a specific call] candidates, and then [choosing the most specific candidate from the overload candidate set].
628628
629-
Informally, access to a property is resolved as if it is a callable invocation corresponding to its getter or setter, and the overload resolution is performed on this invocation.
629+
> *Important*: this section concerns *only* properties accessed using property access syntax `a.x` or just `x` *without call suffix*.
630+
> If a property is accessed with a call suffix, it is treated as any other callable and is required to have a suitable `invoke` overload available, see the rest of this part for details
631+
632+
There are two variants of property access syntax: readonly property access and property assignment.
633+
634+
> Note: there is also [safe navigation syntax][Navigation operators] for both assignment and readonly access, but that is expanded to non-safe navigation syntax covered by this section.
635+
> Please refer to corresponding sections for details.
636+
637+
Readonly property access `a.x` is resolved the same way as if the property access in question was a special function call `a.x$get()` and each property `val/var x: T` was replaced with corresponding function `fun x$get(): T` having all the same extension receivers, context receivers, type parameters and scope as the original property and providing direct access to the property getter.
638+
For different flavors of property declarations and getters, refer to [corresponding section][Property declaration].
639+
Please note that this excludes any possibility to employ `invoke`-convention as these ephemeral functions cannot be properties themselves.
630640
631641
> Example: one may consider property access in class `A` to be resolved as if it has been transformed to class `AA`.
632642
>
@@ -652,19 +662,75 @@ Informally, access to a property is resolved as if it is a callable invocation c
652662
>
653663
> ```kotlin
654664
> class AA {
655-
> fun a(): Int = 5 // (1)
665+
> fun a$get(): Int = 5 // (1)
656666
>
657-
> fun Double.a(): Boolean // (2)
667+
> fun Double.a$get(): Boolean // (2)
658668
> = this != 42.0
659669
>
660670
> fun test() {
661671
>
662-
> println(a()) // Resolves to (1)
672+
> println(a$get()) // Resolves to (1)
673+
>
674+
> with(42.0) {
675+
> println(this@AA.a$get()) // Resolves to (1)
676+
> println(this.a$get()) // Resolves to (2)
677+
> println(a$get()) // Resolves to (2)
678+
> }
679+
> }
680+
> }
681+
> ```
682+
683+
Property assignment `a.x = y` is resolved the same way as if it was replaced with a special function call `a.x$set(y)` and each property `var/val x: T` was replaced with a corresponding function `fun x$set(value: T)` having all the same extension receiver parameters, context receiver parameters, type parameters and scope as the original property and providing direct access to the property setter.
684+
For different flavors of property declarations and setters, refer to [corresponding section][Property declaration].
685+
Please note that, although a readonly property declaration (using the keyword `val`) does not allow for assignment or having a setter, it still takes part in overload resolution for property assignment and may still be picked up as a candidate.
686+
Such a candidate (in case it is selected as the final candidate) will result in compiler error at later stages of compilation.
687+
688+
> Note: informally, one may look at property assignment resolution as a sub-kind of readonly property resolution described above, first resolving the property as if it was accessed in a readonly fashion, and then using the setter.
689+
> Readonly property access and property assignment syntax used in the same position **never** resolve to different property candidates
690+
691+
> Example: one may consider property access in class `B` to be resolved as if it has been transformed to class `BB`.
692+
> Declaration bodies for ephemeral functions are ommited to avoid confusion
693+
>
694+
> ```kotlin
695+
> class B {
696+
> var b: Int = 5 // (1)
697+
>
698+
> val Double.b: Int // (2)
699+
> get() = this.toInt()
700+
>
701+
> fun test() {
702+
> b = 5 // Resolves to (1)
703+
>
704+
> with(42.0) {
705+
> // Resolves to (1)
706+
> this@B.b = 5
707+
> // Resolves to (2) and compiler error: cannot assign readonly property
708+
> this.b = 5
709+
> // Resolves to (2) and compiler error: cannot assign readonly property
710+
> b = 5
711+
> }
712+
> }
713+
> }
714+
> ```
715+
>
716+
> ```kotlin
717+
> class BB {
718+
> fun b$get(): Int // (1, getter)
719+
> fun b$set(value: Int) // (1, setter)
720+
>
721+
> fun Double.b$get(): Int // (2, getter)
722+
> fun Double.b$set(value: Int) // (2, setter)
723+
>
724+
> fun test() {
725+
> b$set(5) // Resolves to (1)
663726
>
664727
> with(42.0) {
665-
> println(this@AA.a()) // Resolves to (1)
666-
> println(this.a()) // Resolves to (2)
667-
> println(a()) // Resolves to (2)
728+
> // Resolves to (1)
729+
> this@B.b$set(5)
730+
> // Resolves to (2)
731+
> this.b$set(5)
732+
> // Resolves to (2)
733+
> this.b$set(5)
668734
> }
669735
> }
670736
> }
@@ -674,8 +740,7 @@ The overload resolution for properties has the following features distinct from
674740
675741
* Properties without getter or setter are assumed to have default implementations for accessors (ones which get or set its [backing field][Getters and setters]);
676742
* The overload resolution takes into account the kind of property, meaning an extension read-only property is considered to have an extension getter, a contextual mutable property is considered to have a contextual getter and setter, etc.;
677-
* When building the overload candidate set, only candidates which are property getters and setters are considered;
678-
> Note: this means `invoke` operator convention cannot take part in _property_ overload resolution.
743+
* [Object declarations][object declaration] and [enumeration entries][Enum class declaration] may be accessed using the property access syntax given that they may be resolved in the current scope.
679744
680745
TODO(Anything else?)
681746

0 commit comments

Comments
 (0)