diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md new file mode 100644 index 00000000000..d92fbfa706f --- /dev/null +++ b/text/0000-partial_types.md @@ -0,0 +1,642 @@ +- Feature Name: `partial_types` +- Start Date: 2023-04-28 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + + +# Summary +[summary]: #summary + +Partial Types proposal is a generalization on "partial borrowing"-like proposals. + +This proposal is universal flexible tool to work **safe** with partial parameters, partial arguments, partial references and partial borrowing. + +Advantages: maximum type safety, maximum type control guarantee, no ambiguities, flexibility, usability and universality. + + +# Motivation +[motivation]: #motivation + +Safe, Flexible controllable partial parameters for functions and partial consumption (including partial not borrowing) are highly needed. + +Partial Types extension gives to type-checker a **mathematical guarantee** that using _simultaneously_ partial typed variable, it multiple partial references and partial borrowing is as **safe** as using them _at a sequence_. A guarantee to borrow-checker that by & var.{x,y} or &mut var.{z,t} borrowing the whole variable and pretending to borrow just several fields is **fully safe**. + +And since it is a guarantee by **type**, not by **values**, it has _zero cost_ in binary! Any type error is a compiler error, so no errors in the runtime. + +We could apply _theoretically_ this extension to all Product Types (`PT = T1 and T2 and T3 and ...`) and it fully covers all variants of possible uses of Product Types. + +So, most promised candidates are Structs and Tuples. + +This extension is not only fully backward-compatible, but is fully forward-compatible! Forward-compatibility is an ability to use updated functions old way. + + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +For Product Types `PT = T1 and T2 and T3 and ...` (structs, tuples) we assume they are like structs with controllable field-access. + +`<%permit>` - field is accessible (always implicit), `%deny` - field is forbidden to use, `%miss` - it is uninitialized field, field is forbidden to use. + +Let we wish to have next structure: +```rust +struct SR { + val : T, + lnk : & T, // reference to val +} +``` +Now it is impossible to write immutable self-referential types. But with partial initialization it becomes easy: +```rust +let x = SR {val : 5i32 }; + // omitted field is uninitialized, it has %miss field-access + // x : SR.{val, %miss lnk} + +x.lnk let= & x.val; + // (let=) "extender", late initialized field + // x : SR; + // x : SR.%full; +``` +Easy-peasy! We create partial type and extend by late initializing fields! + +```rust +let baz = (7i16, &51i32, "some_other_string").{1, 2, %unfill}; + // or set access-filer before tuple constructor + // baz : (i16, &i32, &str).{1, 2, %miss 0}; + +let bar = (%miss 7i16, &51i32, "some_other_string"); + // or set access-filer before tuple constructor + // baz : (i16, &i32, &str).{1, 2, %miss 0}; + +bar.0 let= 68; + // (let=) "extender", late initialized field + // bar : (i16, &i32, &str); + // bar : (i16, &i32, &str).%full; +``` +Same with tuples. + +Ok, let's try a bit more impossible now - two mutual borrowings of same variable (but different fields): +```rust +struct Point { + x: f64, + y: f64, + was_x: f64, + was_y: f64, + state : f64, +} +let mut p1 = Point {x:1.0, y:2.0, was_x: 4.0, was_y: 5.0, state: 12.0}; + // p1 : Point + +let ref_p1was = &mut p1.{wax_x, was_y}; + // ".{}" is a getter several fields, similar to "." get 1 field + // pfull : &mut Point.%{was_x, was_y, %unfill} + +let ref_p1now = &mut p1.{x, y}; + // pfull : &mut Point.%{x, y, %unfill} + +let Point {%deny x, %deny y, was_x: upd_x, was_y: upd_y, %deny state} = ref_p1was; + // all %deny and %miss fields must be '_', error in other case + // similar with binding deconstruction +``` +It is simple and will be possible. + +Same easy to write functions, which consume partial parameters: +```rust +fn re_ref_t (&self : & Self.%{t, %any}) -> &f64 { + &self.t +} + +fn refmut_w (&mut self : &mut Self.%{w, %any}) -> &mut f64 { + &mut self.w +} +``` + +We could do much harder things: we wish parallel using function implementation, which update either `x` or `y` and both read `state` field. +```rust +impl { + pub fn mx_rstate(&mut self1 : &mut Self.%{x, %any}, &self2 : & Self.{state, %any}) + { /* ... */ } + + pub fn my_rstate(&mut self1 : &mut Self.%{y, %any}, &self2 : & Self.{state, %any}) + { /* ... */ } + + // Unfortunately it is a mandatory to extensive mut-borrow 'state' field! + pub fn mxystate(&mut self : &mut Self.%{x, y, state, %any}) + { + /* ... */ + self.{x, state}.mx_rstate(); + /* ... */ + self.{y, state}.my_rstate(); + /* ... */ + } +} +``` +We need for this ... several selfs! Wow! + +Anyway, it is easy, useful and universal! + + +# Reference-level explanation + +This proposal of Partial Types (A) for full control on parameters and arguments requires mixed-mutable (B) references and mixed-mutable dereference (of mixed-mutable references). + +Full implementation of mixed-mutable variables (B) is welcomed, but minimal requirement is 2-links only of partly type variables as representative one variable of mixed-mutable type. + +If mixed mutable variables (B) is hard to implement, simple Multi-Selfs (C) alternative without mixed mutable variables is possible, but it covers only part of problems. + +It is totally Ok if on "Stage 1" implements (A + C), then on "Stage 2" implements (B). + +- [Partial type access] +- [Fields names and field-access] +- [Detailed access] +- [Access-filter] +- [New Picker several fields] +- [Partially Initialized Variables] + - [miss field-access] + - [Auto converting miss by borrowing] + - [Late initialized permit field from miss field] +- [Partial Parameters] +- [Partial Arguments] +- [Partial Parameters] +- [Private fields] +- [Enum Type] + +In brief, simple rules are: +| context Partial types | desugar | +| ----------------------------|------------------------------------------| +| `let r : Type = ...` | `let r : Type.%full = ...` | +| `let r = var` | `let r = var.%max` | +| `let r = & var` | `let r = & var.%max` | +| `let r = &mut var` | `let r = &mut var.%max` | +| `return var` | `return var.%exact` | +| `return & var` | `return & var.%exact` | +| `return &mut var` | `return &mut var.%exact` | +| `self.call(&mut var)` | `self.call(&mut var.%arg)` | +| `let var = S{fld1:val1,..}` | `let var = S{%permit fld1:val1,..}.%max` | +| `let var = S{}` | `let var = S{%miss fld1,..}.%max` | + +## Partial type access + +I propose to extend type system by adding type access after type name (for Product Types), like `(i16, &i32, &str).%full`. + +If we omit to write type access, it means `.%full` access. Symbol (`%` percent) mean percent or part of the whole thing (variable in our case). + +Access has similar names and meanings as lifetimes: `.%full`(full access, soft keyword), `.%_`(don't care how partial access is, soft keyword) and any other `.%a`(some "a" access). But in most cases we use detailed access `.%{}`. + +## Fields names and field-access + +Fields names inside detailed access: +- named field-names for structs(and units) +- unnamed numbered for tuples +- `*` "all fields" quasi-field +- `..` "rest of fields" quasi-field +- `self` pseudo-field for unsupported types + +Filed-access can be in 4 values: +- `` or `%permit` - field is accessible, +- `` or %deny` - field is forbidden to use, +- `%miss` (E) - it is uninitialized field, field is forbidden to use, +- `%ignore` (F) - quasi-field access, which hides truthful field access. + +`%permit` filed-access is a default behavior: permit to read, to write, to borrow, to move. + +_A word %permit is need **for explanations only**, just use default `` access._ + +`%deny` filed-access forbids to have an access to read, to write, to borrow, to move (like outside access to private field). It is a compile error if someone try to access. + +_A word %deny is need **for explanations mostly**, just use default `` access._ It can be used explicitly in tuple initialization and binding deconstructions. + +`%unfill` is a shortcut for `%miss _`. + +`%any` is a shortcut for `%ignore _`. + +## Detailed access and mutability + +Detailed field-access has next structure: `.%{%field-access1 field-name1, %field-access2 field-name2, ..}` + +Detailed access is a set of unordered and unsorted field-names and their filed-accesses. + +First `%field-access1` field-access if it is omitted means `%permit`. First `%field-accessM` field-access for _first omitted_ filed-name means `%opposite`. + +The rest of omitted `%field-accessN` field-accesses means `%same` (same as previous `%field-accessN-1`) + +| `%field-accessN-1` | `%same` | `%opposite` | +|--------------------|-----------|-------------| +| `%permit` | `%permit` | `%deny` | +| `%deny` | `%deny` | `%permit` | +| `%miss` (E) | `%miss` | `%permit` | + +Examples: +```rust +struct Point {x: f64, y: f64, was_x: f64, was_y: f64} + +let pfull = Point {was_x: 4.0, was_y: 5.0}; + // pfull : Point.%{was_x, was_y, %miss x, y} +``` + +Type access `.%full` is a shortcut for `.%{*}`. + +It is forbidden to have `.%{%deny *}` values and `.%{%deny *}` references (but who knows, maybe they are suitable uninhabited types, phantom types or proxy types). + +## Access-filter and Mutable Filter + +Rust consumer use same names for action and for type clarifications, so we follow this style. + +Access-filter is an action, which is looks like detailed access and it is written left to variable at consuming (moving, borrowing, referencing, initializing, returning, pick fields). + +| ↓filter / →var access | `%permit` | `%deny` | `%miss` (E) | `%ignore` (D) | +|-----------------------|-----------|-----------|-------------|---------------| +| `%permit` | `%permit` | !ERROR | !ERROR | !ERROR | +| `%deny` | `%deny` | `%deny` | `%deny` | `%deny` | +| `%miss` (E) | !ERROR | !ERROR | `%miss` | !ERROR | +| `%ignore` (F) | !ERROR | !ERROR | !ERROR | `%ignore` | + +It is allowed to write explicitly specific access-filter with same rules as detailed access. + +Default filter on consumption if filter is omitted for: + - `var ~ var.%max` + - `& var ~ & var.%max` + - `&mut var ~ &mut var.%max` + +(A + D) + - `return var ~ return var.%exact` + - `return & var ~ return & var.%exact` + - `return &mut var ~ return &mut var.%exact` + + where filters are based on variable field-access: + +| ↓var access | `.%max` | `.%exact` (D) | +|--------------|-----------|---------------| +| `%permit` | `%permit` | `%permit` | +| `%deny` | `%deny` | `%deny` | +| `%miss` (E) | `%miss` | `%miss` | +| `%ignore` | `%deny` | `%ignore` | + +## New Picker several fields + +Rust has special syntax for "pick one field" (get field-access): +```rust +struct Point {x: f64, y: f64, was_x: f64, was_y: f64} + +let mut pfull = Point {was_x: 4.0, was_y: 5.0}; + +let px = pfull.x; +let rpy = & pfull.y; +let bpwasx = &mut pfull.was_x; +``` + +But it is still impossible to "pick several fields". With partial types it become possible. + +I suggest to add additional picker for variables `var.{fld1, fld2, ..}` (similar to partiality `var.%{fld1, fld2}`): +```rust +let pxy = pfull.{x, y}; +// same as +let pxy = pfull.%{x, y}; + +let rpxy = & pfull.{x,y}; +// same as +let rpxy = & pfull.%{x,y}; + +let rpwas = & pfull.{was_x, was_y}; +// same as +let rpwas = & pfull.%{was_x, was_y}; +``` + +## Partially Initialized Variables + +Partially Initialized Variable has next structure: +- for structs: `Construct{%field-access1 field-name1: value1, %field-access1 field-name2: value2, ..}.%access-filter;` +- for tuples: `(%field-access1 value1, %field-access1 value2, ..).%access-filter;` + +Access filter `%access-filter` if it is omitted means `.%max`. + +All `%field-accessN` field-access in tuples if they are omitted mean `%permit`. + +All `%field-accessN` field-accesses (for explicit filed-names in structs) if they are omitted mean `%permit`. All `%field-accessM` field-accesses for omitted filed-names in structs mean `%miss`. + +Now it is impossible to initialize outside a new struct with private fields. With partial types it is possible, but variable type access cannot be `.%full` in that case. + +Also, constructor could copy "rest of fields" not from single variable, but from several variables (if they don't overlap permitted fields) and even fill empty constructor: +```rust +struct Point {x: f64, y: f64, was_x: f64, was_y: f64} + +let pwas = Point {was_x: 4.0, was_y: 5.0}; + // pwas : Point.%{was_x, was_y} + +let pnow = Point {x: 1.0, y: 2.0}; + // pnow : Point.%{x, y} + +let pfull1 = Point {..p1, ..p2}; + // pfull1 : Point + // pfull1 : Point.%full + +let pfull2 = Point {x: 42.0, was_x: -5.0, ..p1, ..p2}; + // pfull2 : Point + // pfull2 : Point.%full +``` + +## miss field-access + +(A + E) + +Theory of types do not forbid extension of Partial Type, but internal Rust representation of variables gives significant limitations on such action. + +`%miss` field-access allows to extend Partial Type. + +`%miss` filed-access like `%deny` filed-access forbids to have an access to read, to write, to borrow, to move like access to private field. It is a compile error if someone try to access. + +`%unfill` is a shortcut for `%miss ..`. + +### Auto converting miss by borrowing + +(A + E) + +Mutable and immutable borrowing (but not moving) automatically convert `%miss` field access into `%deny` for reference. +```rust +let pfull = Point {was_x: 4.0, was_y: 5.0}; + // pfull : Point.%{was_x, was_y, %unfill} + +let ref_pful = & pfull; + // ref_pful : Point.%{was_x, was_y} +``` + +### Late initialized permit field from miss field + +(A + E) + +If field has `%miss` field-access we could change it to `%permit` together with initializing the field by `let=` operator. +```rust +struct SR { + val : T, + lnk : & T, // reference to val +} + +let x = SR {val : 5i32 }; + // x : SR.%{val, %miss lnk} + +x.lnk let= & x.val; + // (let=) "extender", late initialized field + // change from .%{%miss lnk, ..} to .%{%permit lnk, ..} + // x : SR; + // x : SR.%full; +``` + +It is an compiler error if `let=` operator tries to extend not `%miss` filed-accessed fields (`%permit` or `%deny` or `%ignore`). + +We could also extend several fields in single expression: +```rust +let pfull = Point {x : 5.0, y : 6.0, was_x : 7.0, was_y : 13.0}; + // pfull : Point + +let pxy = Point {x : 5.0, y : 6.0 }; + // pxy : Point.%{x, y} + +pxy.{was_x, was_y} let= pfull.{was_x, was_y}; + // pxy : Point; + // pxy : Point.%full; +``` + +I assumed, that `%miss` field-access could preserve at move action, but maybe it was my over-optimistic guess. + +Is is possible after creating one variable with missed field, move (partly) it into another variable, and then independently extend same field at both variables? +```rust +let p = Point{x : 1.0, y: 2.0}; +let rp = & p.{x}; + // rp : & Point.%{x} not rp : & Point.%{x, %miss y} + +rp.y let= &8.0; +// or +*rp.y let= 8.0; +// error : cannot extend denied field by let= +``` +By theory of types it is not forbidden, but in reality due Rust variable representations this "extender" rewrites `p.y`. + +That's why we need to distinguish `%deny` from `%miss`. + +## Partial Parameters + +(A + F) + +Partial Parameters has additional field-access on type - `%ignore`. + +Inside function body all `%ignore` fields of parameter hide filter-access of incoming argument into `%ignore` and they remain ignorant till return. + +No one could consume `%ignore` fields (except return-consumer) because we have no guarantee, that some field is permitted. It is a compiler error! +```rust + pub fn t_refmut(&self : &mut Self.%{t, %any}) -> &mut f64 { + &mut self.x + // ^~~~~~ + // error: 'x' is an ignored field + } +``` + +`%any` is a shortcut to `%any = %ignore ..`. + +(A + D) + +Return consumers (omitted or explicit) could consume `%ignore` field, that's why default omitted access filter for return consumers is not `%max`, but `%exact`. + +Fill the difference: +```rust + pub fn t_refmut1(&self : &mut Self.%{t, %any}) -> &mut Self.%{t} { + &mut self.%max + } + + pub fn t_refmut2(&self : &mut Self.%a@%{t, %any}) -> &mut Self.%a { + &mut self + // same as + &mut self.%exact + } +``` + +(A + C) + +Multi-Sefs of Partial types partly allows to write controllable access to parameters. Sure, new keywords: `self1`, `self2`, `self3`, `self4`. +```rust +impl { + // we could accurate write this function + pub fn mx_rstate(&mut self1 : &mut Self.%{x, %any}, & self2 : & Self.%{state, %any}) + { /* ... */ } + + // we could accurate write this function + pub fn my_rstate(&mut self1 : &mut Self.%{y, %any}, & self2 : & Self.%{state, %any}) + { /* ... */ } + + // Unfortunately it is a mandatory to extensive mut-borrow 'state' field! + pub fn mxystate(&mut self : &mut Self.%{x, y, state, %any}) + { + /* ... */ + self.{x, state}.mx_rstate(); + /* ... */ + self.{y, state}.my_rstate(); + /* ... */ + } +} +``` + +## Partial Arguments + +For function argument we add another default omitted access filter `%arg` - qualified safe filter with minimum permit-fields, but it refers not to variable access, but to parameter accesses, so we could use it in arguments consumption only! It is an compile error if `%arg` is written outside of contents! + +| param access | `.%arg` | +|---------------|-----------| +| `%permit` | `%permit` | +| `%deny` | `%deny` | +| `%ignore` (F) | `%deny` | + +Implementations always consumes `self` by `.%arg` filter! + +```rust +let mut p1 : Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; + +fn re_ref_t (& p : & Point.%{t, %any}) -> &f64 { + &p.t +} + +let reft = re_ref_t(& p1); +// same as +let reft = re_ref_t(& p1.%arg); + +let mut p2 : Point2 = Point {x:1.0, was_x:2.0}; + +fn px_store (&mut p1 : &mut Point2.%{was_x, %any}, &p2 : & Point2.%{x, %any}) { + *p1.was_x = *p2.x; +} + +px_store(&mut p2, & p2); +// same as +px_store(&mut p2.%arg, & p2.%arg); +``` +(F) + +The difference in argument use for parameters with ignored fields and without: +```rust +fn updx_with_ignore (&mut p : &mut Point.%{x, %any}, newx : f64) { + *p.x = newx; +} + +fn updx_without (&mut p : &mut Point.%{x}, newx : f64) { + *p.x = newx; +} + +updx_with_ignore(&mut p2, 6.0); // Ok +// same as +updx_with_ignore(&mut p2.%arg, 6.0); // Ok + +updx_with_ignore(&mut p2.{x,y}, 6.0); // still Ok +updx_with_ignore(&mut p2.{x,y,z}, 6.0); // still Ok +updx_with_ignore(&mut p2.%max, 6.0); // still Ok +updx_with_ignore(&mut p2.%full, 6.0); // almost Ok + + +updx_without(&mut p2, 6.0); // Ok +// same as +updx_without(&mut p2.%arg, 6.0); // Ok + +updx_without(&mut p2.{x,y}, 6.0); // error +updx_without(&mut p2.{x,y,z}, 6.0); // error +updx_without(&mut p2.%max, 6.0); // error +updx_without(&mut p2.%full, 6.0); // error +``` + +## Partial Parameters and Mixed Parameters in Traits + +Partial Parameters in Traits could have generalized type access variants: +```rust +trait Getable { + type Target; + + fn get_val<%a>(& self: & Self.%a) -> Self::Target; +} +``` + +## Private fields + +Access to private fields looks like access to partial types. Extra denying private fields led to extra compile errors, but it is secure to control type access of private fields without extra rules. + +## Enum Type + +What's about Enums? Enum is not a "Product" Type, but a "Sum" Type (`ST = T1 or T2 or T3 or ..`). + +But this proposal grant some **type** access, not a **value** access! + +So, this proposal ignore this type! But Partial Tyes could be used anyway, in a differnt contenxt. + +Emums becomes partial in patterns. + +Partial Enums could used in function pamaters and inner patterns. + +```rust +enum MyEnum { + A(u32), + B { x: u32 }, +} + +fn print_A(a: MyEnum.%{A}) { + println!("a is {}", a.0); +} + +fn print_B(b: MyEnum.%{B}) { + println!("b is {}", b.x); +} + +fn print_no_pattern(e: MyEnum) { + match e { + MyEnum::A(_) => print_A(e); // e.%{A} + MyEnum::B(..) => print_B(e); // e.%{B} + } +} +``` + + +# Drawbacks +[drawbacks]: #drawbacks + +- it is definitely not a minor change +- type system became much more complicated + + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +(A) A lot of proposals that are alternatives to Partial Product Types in a whole: + - Partial Types [#3420](https://github.com/rust-lang/rfcs/pull/3420) + - Partial borrowing [issue#1215](https://github.com/rust-lang/rfcs/issues/1215) + - View patterns [internals#16879](https://internals.rust-lang.org/t/view-types-based-on-pattern-matching/16879) + - Permissions [#3380](https://github.com/rust-lang/rfcs/pull/3380) + - Field projection [#3318](https://github.com/rust-lang/rfcs/pull/3318) + - Fields in Traits [#1546](https://github.com/rust-lang/rfcs/pull/1546) + - ImplFields [issue#3269](https://github.com/rust-lang/rfcs/issues/3269) + +(A) A lot of proposals that are alternatives to Partial Sum Types in a whole: + - Enum variant types [#2593](https://github.com/rust-lang/rfcs/pull/2593) + - Enum Variant Types [lang_t#122](https://github.com/rust-lang/lang-team/issues/122) + +(C), not (B): Instead of implementing (or before implementing) mixed mutable types, multi-selfs is quite simple alternative + +(D) if retuning-consumer is complicated in implementation or if returning exact accessed variable has insignificant importance, this part of proposal could not be implemented. But this could led to backward incompatibility if return to implementing. So in this case we must reserve possible changes to return consumer. + +(E) if implementation of operator`%%=` is almost impossible, we could get rid of `%miss` field-access and field-access filter. + +(F) if we ignore forward-compatibility and ignore of access flexibility on arguments, we could not implement `%ignore` field-access and field-access filter. + +(any.details) Alternative for another names or corrections for Partial Types. + - `%empty` or `%!` name + + +# Prior art +[prior-art]: #prior-art + +Most languages don't have such strict rules for references and links as Rust, so this feature is almost unnecessary for them. + + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +I assumed, that `%miss` field-access could preserve at move action, but maybe it was my over-optimistic guess. +Is is possible after creating one variable with missed field, move (partly) it into another variable, and then independently extend same field at both variables? + + +# Future possibilities +[future-possibilities]: #future-possibilities + +(B) mixed mutable types after (A + C) realization. + diff --git a/text/0000-partial_types2.md b/text/0000-partial_types2.md new file mode 100644 index 00000000000..3298ccb849d --- /dev/null +++ b/text/0000-partial_types2.md @@ -0,0 +1,847 @@ +- Feature Name: `partial_types` +- Start Date: 2023-04-18 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + + +# Summary +[summary]: #summary + +Partial types proposal is a generalization on "partial borrowing"-like proposals (more correct name is "partial not borrowing" or "qualified borrowing" since Rust allows partial borrowing already). + +This proposal is a universal road-map "how to do partial not consumption (including partial not borrowing) right", and not under the hood of the Rust compiler. + +Advantages: maximum type safety, maximum type control guarantee, no ambiguities, flexibility, usability and universality. + + +# Motivation +[motivation]: #motivation + +Safe, Flexible controllable partial parameters for functions and partial not consumption (including partial not borrowing) are highly needed and this feature unlock huge amount of possibilities. + +But partial parameters are forbidden now, as qualified consumption: partial not borrowing, partial not referencing, partial not moving and partial initializing. + +Partial Types extension gives to type-checker a **mathematical guarantee** that using simultaneously partial typed variable, it multiple references and borrowing is as **safe** as using them at a sequence. + +And since it is guarantee by **type**, not by **values**, it has _zero cost_ in binary. + +Any type error is a compiler error, so no errors in runtime. + +We could apply _theoretically_ this extension to all Product Types (`PT = T1 and T2 and T3 and ...`). + +So, most promised candidates are Structs and Tuples. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +Let we have a structure: +```rust +struct Point { + x: f64, + y: f64, + was_x: f64, + was_y: f64 +} +let mut pfull = Point {x: 1.0, y: 2.0, was_x: 4.0, was_y: 5.0}; +``` + +If we need to write a function, which use partial parameters: +```rust +// partial parameters +type PointJustX = %{Self::x, %any} Point; +type PointJustWasX = %{Self::was_x, %any} Point; + +fn x_restore(&mut p1 : &mut PointJustWasX, & p2 : & PointJustX) { + *p1.x = *p2.was_x; +} +``` +Which mean that `p1` parameters could use variables with any partial type of `Point`, which has permit access to field `was_x` and we don't care of rest fields. And `p2` parameters could use variables with any partial type of `Point`, which has permit access to field `x` and we don't care of rest fields. + +If we try to use same variable simultaneously for that, we must insert arguments partially - we cut type by `%min` access-filter: +```rust +x_restore(&mut %min pfull, & %min pfull); +``` +If we wish to write same function via implementation, we need several selves! +```rust +impl Point { + pub fn x_restore(&mut self1 : &mut %{Self::saved_x, %any} Self, &self2 : & %{Self::x, %any} Self) { + *self1.x = *self2.saved_x; + } +``` +Why it is useful? If we need several functions which read common field, but mutually write different fields we could use them together! +```rust +pub fn mf1_rfc(&mut self1 : &mut %{Self::fld1, %any} Self, &self2 : & %{Self::common, %any} Self) +{ /* ... */ } + +pub fn mf2_rfc(&mut self1 : &mut %{Self::fld2, %any} Self, &self2 : & %{Self::common, %any} Self) +{ /* ... */ } +``` + +And Partial Types have more. They are not limited to parameters/arguments only. + +```rust +let ref_was = & %{Self::was_x, Self::was_y, %cut} pfull; + +let brwd_now = &mut %{Self::x, Self::y, %cut} pfull; + +let refref_was = & ref_was; +``` +So we have a read-only reference to "was"-fields and mutable "now"-fields. + +It is easy, useful and universal! + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + + - [Partial types by type access] + - [Detailed access] + - [Detailed Struct Type] + - [Detailed Primitive Types] + - [Detailed Tuples] + - [Detailed Arrays] + - [Detailed Enum Type] + - [Partial parameters] + - [Partial parameter styles] + - [Partial parameters on implementations] + - [Several selfs] + - [Partial parameters via Access variants] + - [Partial parameter errors] + - [Partial not consumption] + - [Max access filter] + - [Min access filter] + - [Partially Initialized Variables] + - [Private fields] + + +## Partial types by type access + +```rust +struct PointXY { + x: f64, + y: f64, +} +// case (A1) +let mut foo : mut PointXY = PointXY {x:11.0, y:2.0}; +``` + +I propose to extend type system by adding type access to sub-type. So, our variable will have next type: + +```rust +// case (A2) +// FROM case (A1) +// foo : mut PointXY; +// foo : mut %a PointXY; +// foo : mut %full PointXY; +``` + +Lifetime variants are `'static` (for static lifetime), `'_`(don't care lifetime) and any other `'b`(some "b" lifetime). + +By the same analogy, access has similar names and meanings: `%full`(full access, soft keyword), `%_`(don't care how partial access is, soft keyword), `%empty` or `%!` (no access, soft keyword) and any other `%a`(some "a" access). + +If we omit to write type access, it means `%full` access. + +Symbol `%` percent mean percent or part of the whole thing (variable in our case). + +_Note: It is highly recommended to deprecate operator `%` as a remainder function (it is still no ambiguities to write "`\s+%\s+`"), and replace it with another operator (for example: `%mod` / `%rem` / `mod` / `rem`) to not to be confused by type access. But it is not a mandatory._ + +## Detailed access + +Unfortunately, having variants of type access is not enough to write **safe** implementations or other non-abstract function declarations. + +We need to have more specific access by detailed access. + +### Detailed Struct Type +Let's try simple uninhabited type + +We need for this some new quasi-fields and some field access (which should be soft keywords). +```rust +struct Point { + x: f64, + y: f64, + z: f64, + t: f64, + w: f64, +} + +// case (C1) +let &mut p1 : &mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; + // + // p1 : &mut Point; + // p1 : &mut %full Point; + // p1 : &mut %{Self::*} Point; + // p1 : &mut %{Self::x, Self::y, Self::z, Self::t, Self::w} Point; + // p1 : &mut %{Self::{x, y, z, w}} Point; +``` + +Where : + - `Self` is an "link" to variable type itself + - `::*` is an "every field" quasi-field + - `::{, , }` is an field-set quasi-field + +```rust +// case (B1) +struct Nothing {} + +let mut bar : mut Nothing = Nothing {}; + // + // bar : Nothing + // bar : %full Nothing; + // bar : %{Self::*} Nothing; + // bar : %{Self::self} Nothing; + // bar : %{%permit Self::self} Nothing; +``` +Where : + - `::self` a single quasi-field for uninhabited structs + +It is a compile error if we try to %deny a ::self field! + +We assume, that each field could be in one of two specific field-access - `%permit` and `%deny`. + +_We also must reserve as a keyword a `%miss` field-access for future ReExtendeded Partial Types, which allows to create **safe** self-referential types._ + +`%permit` is default field-access (if we omit to write specific field-access) and it means we have an access to this field and could use it as we wish. But if we try to access to `%deny` field it cause a compiler error. + +```rust +// case (C2) +// FROM case (C1) +let &mut p1 : &mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; + // + // p1 : &mut %{%permit Self::*} Point; + // p1 : &mut %{%permit Self::*, %deny Self::_}; + // p1 : &mut %{%permit Self::{x, y, z, w}} Point; +``` + +Where : + - `%permit` access + - `%deny` access + - `::_` is a "rest of fields" quasi-field + +As we see, + - `%empty : %{%deny Self::*}` or `%empty : %{}` access + - `%full : %{%permit Self::*}` or `%full : %{Self::*}` access + +### Detailed Tuples + +For Tuples we assume that **every** variable is a `struct`-like objects (even if it is not) and has unnamed numbered fields. + +```rust +// case (C4) +let bar = (0i16, &5i32, "some_string"); + // + // bar : (i16, &i32, &str); + // bar : %full (i16, &i32, &str); + // bar : %{Self::*} (i16, &i32, &str); + // bar : %{%permit Self::{0,1,2}} (i16, &i32, &str); +``` + +### Detailed Arrays + +For Arrays we wish to assume that **every** variable is a `tuple`-like objects (even if it is not) and has unnamed numbered fields. + +Unfortunately, Arrays are a bit magical, so it is _unclear_ if we could represent it access like a tuple access. + +### Detailed Enum Type + +What's about Enums? Enum is not a "Product" Type, but a "Sum" Type (`ST = T1 or T2 or T3 or ..`). + +But this proposal grant some **type** access, not a **value** access! + +So, all possible constructors are permitted! + +## Partial parameters + +We add enough access, and could write partial parameters for function declarations: +```rust +// case (D1) +fn re_ref_t (& p : & %{Self::t, %ignore Self::_} Point) -> &f64 { + &p.t +} + +// case (D2) +fn refmut_w (&mut p : &mut %{Self::w, %any} Point) -> &mut f64 { + &mut p.w +} +``` + +Where : + - `%ignore` is a "don't care which exactly" quasi filed-access (`%_` is a whole type access and it is unclear if we could use it in both contents) + +But `%ignore Self::_` quasi-filed-access of quasi-field looks annoying, so we simplify a bit adding `%any : %ignore Self::_`. + +Since using `%ignore` filed in the function body is **unsafe by type** (we have no guarantee, that some field is permitted), trying to use ignoring field is a compile error. + +Now type access guarantee to compiler, that only some fields has an access inside function, but not the rest of them. +So, no extra lock on `self` is needed, only for `%permit` fields. + +### Partial parameter styles + +We could write partial parameters using different styles. + +Default one: + +```rust +// case (D3) +// FROM case (D1) +fn re_ref_t (& p : & %{Self::t, %any} Point) -> &f64 { + &p.t +} + +// case (D5) +struct PointExtra { + x: f64, + y: f64, + saved_x: f64, + saved_y: f64, +} + +fn x_store(&mut p1 : &mut %{Self::saved_x, %any} PointExtra, & p2 : & %{Self::x, %any} PointExtra) { + *p1.saved_x = *p2.x; +} + +fn x_restore(&mut p1 : &mut %{Self::x, %any} PointExtra, & p2 : & %{Self::saved_x, %any} PointExtra) { + *p1.x = *p2.saved_x; +} +``` + +or use `where` clauses if access is extra verbose: +```rust +// case (D6) +// FROM case (D5) + +fn x_store(&mut p1 : &mut %permit_sv_x PointExtra, & p2 : & %permit_x PointExtra) + where %permit_sv_x : %{Self::saved_x, %any}, + %permit_x : %{Self::x, %any} +{ + *p1.saved_x = *p2.x; +} + +fn x_restore(&mut p1 : &mut %permit_x PointExtra, & p2 : & %permit_sv_x PointExtra) + where %permit_sv_x : %{Self::saved_x, %any}, + %permit_x : %{Self::x, %any} +{ + *p1.x = *p2.saved_x; +} +``` + +or add `type` synonym +```rust +// case (D7) +// FROM case (D5) + +type PointSaveX = %{Self::saved_x, %any} PointExtra; +type PointX = %{Self::x, %any} PointExtra; + + +fn x_store(&mut p1 : &mut PointSaveX, & p2 : & PointX) { + *p1.saved_x = *p2.x; +} + +fn x_restore(&mut p1 : &mut PointX, & p2 : & PointSaveX) { + *p1.x = *p2.saved_x; +} +``` + +### Partial parameters on implementations + +Writing Implementation parameters is mostly the same, but we use Self type as "outer Self" type: +```rust +// case (D8) +impl Point { + pub fn x_refmut(&mut self : &mut %{Self::x, %any} Self) -> &mut f64 { + &mut self.x + } + + pub fn y_refmut(&mut self : &mut %{Self::y, %any} Self) -> &mut f64 { + &mut self.y + } +} +``` + +We could also use multiple sub-parameters of same parameter +```rust +// case (D9) + pub fn xy_swich(&mut self : &mut %{Self::{x, y}, %any} Self) { + let tmp = *self.x; + *self.x = *self.y; + *self.y = tmp; + } +``` + +## Several selfs + +If we want to include `x_store` and `x_restore` from case (D5) for implementation we find something weird: we need **several** selfs! + +Sure, they must be a keywords. It could be either `self1, self2, ..` or `self-1, self-2, ..` or `self#1, self#2` or `self_ref, self_refmut` or any other. + +```rust +// case (E1) +trait St { + + fn x_store<%a, %b>(&mut self1: &mut %a Self, &self2: & %b Self); + + fn x_restore<%a, %b>(&mut self1: &mut %a Self, &self2: & %b Self); +} + +// case (E2) + pub fn x_store(&mut self1 : &mut %{Self::x, %any} Self, &self2 : & %{Self::saved_x, %any} Self) + { + *self1.saved_x = *self2.x + } + + pub fn x_restore(&mut self1 : &mut %{Self::saved_x, %any} Self, &self2 : & %{Self::x, %any} Self) { + *self1.x = *self2.saved_x; + } +``` + +Sure, if we use several `self`s, their permit fileds access cannot overlap! + +```rust +// case (E3) + pub fn x2_store(&mut self1 : &mut %{Self::x, %any} Self, &self2 : & %{Self::x, %any} Self) { + // ^~~~~~ ^~~~~ + // error: cannot overlap permit-field 'Self::x' on self1 and self2 + *self1.x = *self2.x; + } +``` + +### Partial parameters via Access variants + +We could write Traits with **safe** abstract functions (with no body), which consumes partial access type having only variants of type access. +```rust +// case (B1) +pub trait Upd { + type UpdType; + + fn summarize<%a>(&self: & %a Self) -> String; + + fn update_value<%a>(&mut self : &mut %a Self, newvalue: UpdType); + + fn update_sametype<%a, %b>(&mut self : &mut %a Self, &another: & %b Self); +} +``` + +### Partial parameter errors + +Now compiler can catch "out of scope parameter" errors +```rust +// case (D10) + pub fn xt_refmut(&self : &mut %{Self::xt, %any} Self) -> &mut f64 { + // ^~~~~~ + // error: no field 'Self::xt' on type `Self` + &mut self.xt + } +``` + +Since using `%ignore` filed is **unsafe by type** (we have no guarantee, that some field is permitted), trying to use ignoring field is a compile error: +```rust +// case (D11) + pub fn t_refmut(&self : &mut %{Self::t, %any} Self) -> &mut f64 { + &mut self.x + // ^~~~~~ + // error: cannot find value 'Self::x' in this scope + } +``` + +Compile could catch more dead code warnings +```rust +// case (D12) + pub fn x_refmut(&self : &mut %{Self::x, Self::y, %any} Self) -> &mut f64 { + // ^~~~~~ + // warning: '#[warn(dead_code)]' field is never read: `Self::y` + &mut self.x + } +``` + +Fortunately, these additions is enough to write **any safe** function declarations. + + +## Partial not consumption + +We wrote function declaration. Could we already partially not consume variables in arguments? + +Fortunately, we could qualified consume implicit `self` arguments. + +Unfortunately, implicit `self` argument is the only qualified consumed argument. + +Exists 5 "pseudo-function" consumption for variables in expressions: + - `&mut` - (mutable-)borrowing consumption + - `&` - referential (immutable borrowing) consumption + - `<_nothing>` - move consumption + - `` initialized consumption + - `.` access to the filed + +Partial access to the field is already granted (exept arrays). + +Rust consumer use same names for action and for type clarifications, so we follow this style. + +We need to add access filter to them, omiting it mean `%max` filter. Since it is not possibe to consume more than `%max`, it has no sence to use `%full` instead! + +`%full` means consumer consume all fields, `%max` consume all permited fields. + +```rust +struct A { f1: String, f2: String, f3: String } +let mut x: A; + +// case (F1) +let a: &mut String = &mut x.f1; // x.f1 borrowed mutably +let b: &String = &x.f2; // x.f2 borrowed immutably +let c: &String = &x.f2; +// error:Can borrow again +let d: String = x.f3; // Move out of x.f3 + +// case (F2) +// FROM case (F1) +let a: &mut String = &mut %full x.f1; +let b: &String = & %full x.f2; +let d: String = %full x.f3; +``` + +Trying to consume `%deny` field is a compile error! The consumer DO NOT consume `%deny` EVER. + +Resulted field access is the following: + +| ↓filter / →access | `%permit` | `%deny` | +|-------------------|-----------|-----------| +| `%permit` | `%permit` | !ERROR | +| `%deny` | `%deny` | `%deny` | + + +```rust +struct S5 { f1: String, f2: String, f3: String, f4: String, f5: String } +let mut x: S5; + +// case (F3) +let ref1: &mut String = &mut x.f1; +// +let ref_x23 = & %{Self::f2, Self::f3, %deny Self::_} x; + // + // ref_x23 : & %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; + // +let move_x45 = %{Self::{f4, f5}, %cut} x; + // + // move_x45 : %{%permit Self::{f4, f5}, %deny Self::{f1, f2, f3}} S5; +``` + +But `%deny Self::_` quasi-filed-access of quasi-field looks annoying, so we simplify a bit adding `%cut : %deny Self::_`. + +### Max access filter + +What to do if we wish to create a reference to `ref_x23`. Do we need to write explicitly an access or exists implicit way? + +No, we could use `%max`(or `%id`) - qualified safe filter with maximum permit-fields, but technically is an `id` filter to variable access: + +| var access | `%max` | +|--------------|-----------| +| `%permit` | `%permit` | +| `%deny` | `%deny` | + +Having this we could write next implicitly +```rust +// FROM case (F1) + // ref_x23: & %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; + +// case (F4) +let refref_x23 = & ref_x23; +// it mean '& %max ref_x23', not '& %full ref_x23' +// + // refref_x23: && %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; +``` + +### Min access filter + +For function argument we add another filter `%min` - qualified safe filter with minimum permit-fields, but it refers not to variable access, but to parameter access, so we could use it in arguments consumption only! It is an compile error if `%min` is written outside of contents! + +| param access | `%min` | +|---------------|-----------| +| `%permit` | `%permit` | +| `%deny` | `%deny` | +| `%ignore` | `%deny` | + +Implementations always consumes `self` by `%min` filter! + +```rust +// FROM case (D3) +fn re_ref_t (& p : & %{Self::t, %any} Point) -> &f64 { + &p.t +} +let mut p1 : mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; + +// case (F5) +let reft = re_ref_t(& %min p1); + + +// case (F6) + fn update_sametype<%a, %b>(&mut self : &mut %a Self, & another: & %b Self); +// +p1.update_sametype(& %min p2); + + +// case (F7) + fn update_another<%a, %b>(& self : & %a Self, & mut another: & %b Self); +p3.update_sametype(&mut %min p2); +``` + + +### Partially Initialized Variables + +We must have an ability to create partially initialized variables. So we need to add a filter-access to a constructor. +Default access-fiter to constructor is `%full`, not `%max`. + +```rust +struct Point { + x: f64, + y: f64, + z: f64, + t: f64, + w: f64, +} + +// case (G1) +let p1_full = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; + // + // p1_full : Point; + // p1_full : %full Point; + +// case (G2) +let p_x = %{Self::x, %cut} Point {x:1.0}; + // + // p_x : %{%permit Self::x, %deny Self::_} Point; + // + +let p_yz = %{Self::{y,z}, %cut} Point {y:1.0, z: 2.0}; + // + // p_yz : %{%permit Self::{y,z}, %deny Self::_} Point; + // +``` + +Also it would be nice if constructor allows several filler variables (which do not overlap permit-fields) +```rust +// case (G3) +let p_xyz = %max Point {..p_x, ..p_yz}; + // + // p_xyz : %{%permit Self::{x,y,z}, %deny Self::{t,w}}; + +// case (G4) +let p2_full = Point {t:1.0, w:2.0, ..p_xyz}; + // + // p2_full : Point; + // p2_fill : %full Point; +``` + +A bit unclear how to fill unused fields, so we write unused values to a fill the type for tuple constructor + +```rust +// case (G5) +let t4_02 = %{Self::{0,2}, %cut} ("str", 1i32, &0u16, 0.0f32); + // + // t4_02 : %{%permit Self::{0,2}, %deny Self::{1,3}} (&str, i32, &u16, f32); +``` + +access filter could help to deconstruct types for matching: + +```rust +// case (G6) +let opt_t4_1 = Some ( %{Self::1, %cut} ("str", 1i32, &0u16, 0.0f32)); + // + // opt_t4_1 : Option<%{%permit Self::{1}, %deny Self::{1,3}} (&str, i32, &u16, f32)>; + // + let Some (%max (_, ref y, _, _)) = opt_t4_1; + // ^~~~~~~~~~^~~^~~~ if we writee variables here, it cause an error +``` + +If we try to write not "`_`" on deny accessed fields, but a variable - it is a compile error. + +## Private fields + +And finally, what to do with private fields? + +If variable has private fields, it has always at access `%hidden Self::private` quasi-field. +```rust +mod hp { + pub struct HiddenPoint { + pub x: f64, + pub y: f64, + z: f64, + t: f64, + w: f64, + } +} + +use hp::HiddenPoint; + +// case (H1) +let p1 : HiddenPoint; + // p1 : %full HiddenPoint; + // p1 : %{%permit Self::*} HiddenPoint; +``` + +# Drawbacks +[drawbacks]: #drawbacks + +- it is definitely not a minor change +- type system became much more complicated + + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +(A) A lot of proposals that are alternatives to Partial Types in a whole: + - Partial borrowing [issue#1215](https://github.com/rust-lang/rfcs/issues/1215) + - View patterns [internals#16879](https://internals.rust-lang.org/t/view-types-based-on-pattern-matching/16879) + - Permissions [#3380](https://github.com/rust-lang/rfcs/pull/3380) + - Field projection [#3318](https://github.com/rust-lang/rfcs/pull/3318) + - Fields in Traits [#1546](https://github.com/rust-lang/rfcs/pull/1546) + - ImplFields [issue#3269](https://github.com/rust-lang/rfcs/issues/3269) + +(B) Alternative for another names or corrections for Partial Types. + - `%empty` or `%!` name + - `self1, self2, ..` or `self-1, self-2, ..` or `self#1, self#2`. Or add only 2 specific selfs: `self_ref, self_refmut` + + +# Prior art +[prior-art]: #prior-art + +Most languages don't have such strict rules for references and links as Rust, so this feature is almost unnecessary for them. + + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +None known. + +# Future possibilities +[future-possibilities]: #future-possibilities + +## ReExtendeded Partial Types + +We could add additional ReExtendeded Partial Types for **safe** Self-Referential Types. + +Theory of types do not forbid extension of Partial Type, but internal Rust representation of variables gives significant limitations on such action. + +It is need the `%miss`(aka `%deny` but extendible) field access to initialized constructor consumption only. And additional "extender" `%%=`. + +Partly self-referential types example: +```rust +struct SR { + val : T, + lnk : & T, // reference to Self::val +} + +// case (FP1) +let x = %{%miss Self::lnk, %permit Self::_} SR {val : 5i32 }; + // + // x : %{%miss Self::lnk, %permit Self::val} SR + // +x.lnk %%= & x.val; + // + // x : SR; + // x : %full SR; +``` +And even AlmostFully self-referential types: +And another shortcut `%unfill : %miss Self::_` + +```rust +struct FSR { + val : T, + lnk : & %{%deny Self::lnk, %permit Self::val} FSR, + // reference to almost self! +} + +// case (FP2) +let x = %{Self::val, %unfill} FSR {val : 5i32 }; + // + // x : %{%miss Self::lnk, %permit Self::val} FSR; + // +x.lnk %%= & %max x; + // + // x : FSR; + // x : %full FSR; +``` + +First difficulty - `%max` is no longer `id`, `%max(on %miss) ~ %deny`. Both `filter-%permit on %miss` and `filter-%ignore on %miss` must cause a compiler error for 3 main consumers. + +Second and most difficult, that `return` consumption (yes, 6th type of consumers) from function could preserve `%miss`, so also we need filter `%max_miss`, where `%max_miss(on %miss) ~ %miss`! + +```rust +// case (FP3) +// FROM case (FP2) +fn create_var()-> %{%miss Self::lnk, %permit Self::_} FSR { + let x = %{Self::val, %unfill} FSR {val : 5i32 }; + // + // x : %{%miss Self::lnk, %permit Self::val} FSR + // + %max_miss return x; + // filter access before 'return' to not to confused with `move` consumer! +} + +let y = create_var(); +y.lnk %%= & %max y; + // + // y : FSR; + // y : %full FSR; +``` + +```rust +struct Point { + x: f64, + y: f64, + z: f64, + t: f64, + w: f64, +} + +let p1 : Point = Point {x:1.0, y:2.0, w:5.0}; + // p1 : %{x,y,w, %miss {z,t}} Point + // p1 : %{%permit {x,y,w}} Point + // p1 : %{%permit {x,y,w}, %miss {z,t}} Point +let ref_x = & p.x; + // ref_x : f64 +let ref_p1xy = & p.{x,y}; + // ref_p1xy : & %{x,y} Point +let ref_p1x = & p.{x}; + // ref_p1xy : & %{x} Point +let refref_p1x = & ref_p1xy.{x,y}; + // refref_p1x : && %{x,y} Point + +p1.t %%= 7.0; + // p1 : %{x,y,t,w, %miss z} Point +p1.z %%= 7.0; + // p1 : Point + // p1 : %full Point + +let p2 : Point = Point {z:1.0, t:2.0, w:5.0}; + // p1 : %{z,t,w, %miss {x,y}} Point + +p2.{x,y} %%= *ref_p1xy; + // p1 : Point + // p1 : %full Point +``` + + +```rust +struct SRT { + val: T, + lnk: & T, +} + +let srt : STR = STR { val: 5_i32}; + // srt : %{%permit val, %miss lnk} STR + +srt.lnk %%= & srt.val; + // srt : STR + // srt : %full STR + + +struct FSR { + val : T, + lnk : & %{%deny lnk} FSR, + // reference to almost self! +} + +// case (FP2) +let x = FSR {val : 5i32}; + +x.lnk %%= & x; + +``` +