@@ -51,34 +51,60 @@ An example implementation:
51
51
52
52
```
53
53
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
54
+ impl<T: ?Sized+CoerceUnsized<U>, U: ?Sized> NonZero<U> for NonZero<T> {}
54
55
55
- // For reference, the definition of Rc:
56
+ // For reference, the definitions of Rc and NonZero :
56
57
pub struct Rc<T: ?Sized> {
57
58
_ptr: NonZero<*mut RcBox<T>>,
58
59
}
60
+ pub struct NonZero<T: Zeroable+?Sized>(T);
59
61
```
60
62
61
63
Implementing ` CoerceUnsized ` indicates that the self type should be able to be
62
64
coerced to the ` Target ` type. E.g., the above implementation means that
63
- ` Rc<[i32; 42]> ` can be coerced to ` Rc<[i32]> ` .
65
+ ` Rc<[i32; 42]> ` can be coerced to ` Rc<[i32]> ` . There will be ` CoerceUnsized ` impls
66
+ for the various pointer kinds available in Rust and which allow coercions, therefore
67
+ ` CoerceUnsized ` when used as a bound indicates coercible types. E.g.,
64
68
69
+ ```
70
+ fn foo<T: CoerceUnsized<U>, U>(x: T) -> U {
71
+ x
72
+ }
73
+ ```
74
+
75
+ Built-in pointer impls:
65
76
66
- ## Newtype coercions
77
+ ```
78
+ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
79
+ impl<T: ?Sized+Unsize<U>, U: ?Sized, 'a> CoerceUnsized<&'a U> for Box<T> {}
80
+ impl<T: ?Sized+Unsize<U>, U: ?Sized, 'a> CoerceUnsized<&mut 'a U> for Box<T> {}
81
+ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for Box<T> {}
82
+ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for Box<T> {}
83
+
84
+ impl<T: ?Sized+Unsize<U>, U: ?Sized, 'a, 'b: 'a> CoerceUnsized<&'a U> for &mut 'b U {}
85
+ impl<T: ?Sized+Unsize<U>, U: ?Sized, 'a> CoerceUnsized<&mut 'a U> for &mut 'a U {}
86
+ impl<T: ?Sized+Unsize<U>, U: ?Sized, 'a> CoerceUnsized<*const U> for &mut 'a U {}
87
+ impl<T: ?Sized+Unsize<U>, U: ?Sized, 'a> CoerceUnsized<*mut U> for &mut 'a U {}
67
88
68
- We also add a new built-in coercion for 'newtype's. If ` Foo<T> ` is a tuple
69
- struct with a single field with type ` T ` , then coerce_inner(` Foo<T> ` ) = ` Foo<U> `
70
- holds for any ` T ` and ` U ` where ` T ` coerces to ` U ` .
89
+ impl<T: ?Sized+Unsize<U>, U: ?Sized, 'a, 'b> CoerceUnsized<&'a U> for &'b U {}
90
+ impl<T: ?Sized+Unsize<U>, U: ?Sized, 'b> CoerceUnsized<*const U> for &'b U {}
71
91
72
- This coercion is not opt-in. It is best thought of as an extension to the
73
- coercion rule for structs with an unsized field, the extension is that here the
74
- field conversion is a proper coercion, not an application of ` coerce_inner ` .
75
- Note that this coercion can be recursively applied.
92
+ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut U {}
93
+ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut U {}
94
+
95
+ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const U {}
96
+ ```
97
+
98
+ Note that there are some coercions which are not given by ` CoerceUnsized ` , e.g.,
99
+ from safe to unsafe function pointers, so it really is a ` CoerceUnsized ` trait,
100
+ not a general ` Coerce ` trait.
76
101
77
102
78
103
## Compiler checking
79
104
80
105
### On encountering an implementation of ` CoerceUnsized ` (type collection phase)
81
106
107
+ * If the impl is for a built-in pointer type, we check nothing, otherwise...
82
108
* The compiler checks that the ` Self ` type is a struct or tuple struct and that
83
109
the ` Target ` type is a simple substitution of type parameters from the ` Self `
84
110
type (one day, with HKT, this could be a regular part of type checking, for now
@@ -87,63 +113,46 @@ form `X/Y` where `X` and `Y` are both formal type parameters of the
87
113
implementation (I don't think this is necessary, but it makes checking coercions
88
114
easier and is satisfied for all smart pointers).
89
115
* The compiler checks each field in the ` Self ` type against the corresponding field
90
- in the ` Target ` type. Either the field types must be subtypes or be coercible from the
91
- ` Self ` field to the ` Target ` field (this is checked taking into account any
92
- ` Unsize ` bounds in the environment which indicate that some coercion can take
93
- place). Note that this per-field check uses only the built-in coercion
94
- mechanics. It does not take into account ` CoerceUnsized ` impls (although we
95
- might allow this in the future).
116
+ in the ` Target ` type. Assuming ` Fs ` is the type of a field in ` Self ` and ` Ft ` is
117
+ the type of the corresponding field in ` Target ` , then either ` Ft <: Fs ` or
118
+ ` Fs: CoerceUnsized<Ft> ` (note that this includes built-in coercions).
96
119
* There must be only one field that is coerced.
97
- * We record in a side table a mapping from the impl to an adjustment. The
98
- adjustment will contain the field which is coerced and a nested adjustment
99
- representing that coercion. The nested adjustment will have a placeholder for
100
- any use of the ` Unsize ` bound (we should require that there is exactly one such use).
120
+ * We record for each impl, the index of the field in the ` Self ` type which is
121
+ coerced.
101
122
102
- ### On encountering a potential coercion
123
+ ### On encountering a potential coercion (type checking phase)
103
124
104
125
* If we have an expression with type ` E ` where the type ` F ` is required during
105
126
type checking and ` E ` is not a subtype of ` F ` , nor is it coercible using the
106
- built-in coercions, then we search for an implementation of ` CoerceUnsized<F> `
107
- for ` E ` . A match will give us a substitution of the formal type parameters of
108
- the impl by some actual types.
109
- * We look up the impl in the side table described above. The substitution is used
110
- with the placeholder in the recorded adjustment to create a new coercion which
111
- will map one field of the struct being coerced. That coercion should always be
112
- valid (if it is not, there is a compiler bug).
113
- * We create a new adjustment for the coerced expression. This will include the
114
- index of the field which is deeply coerced and the adjustment for the coercion
115
- described in the previous step.
116
- * In trans, the adjustment is used to codegen a coercion by moving the coerced
117
- value and changing the indicated field to a new type according to the nested
118
- adjustment.
127
+ built-in coercions, then we search for a bound of ` E: CoerceUnsized<F> ` . Note
128
+ that we may not at this stage find the actual impl, but finding the bound is
129
+ good enough for type checking.
119
130
120
- ### Adjustment types
131
+ * If we require a coercion in the receiver of a method call or field lookup, we
132
+ perform the same search that we currently do, except that where we currently
133
+ check for coercions, we check for built-in coercions and then for ` CoerceUnsized `
134
+ bounds. We must also check for ` Unsize ` bounds for the case where the receiver
135
+ is auto-deref'ed, but not autoref'ed.
121
136
122
- We add ` AdjustCustom(usize, Box<AutoAdjustment>) ` and
123
- ` AdjustNewtype(Box<AutoDerefRef>) ` to the ` AutoAdjustment ` enum. These
124
- represent the new custom and newtype coercions, respectively. We add
125
- ` UnsizePlaceHolder(Ty, Ty) ` to the ` UnsizeKind ` enum to represent a placeholder
126
- adjustment due to an ` Unsize ` bound.
127
137
128
- ### Example
138
+ ### On encountering an adjustment (translation phase)
129
139
130
- For the above ` Rc ` impl, we record the following adjustment (with some trivial
131
- bits and pieces elided):
140
+ * In trans (which is post-monomorphisation) we should always be able to find an
141
+ impl for any ` CoerceUnsized ` bound.
142
+ * If the impl is for a built-in pointer type, then we use the current coercion
143
+ code for the various pointer kinds (` Box<T> ` has different behaviour than ` & ` and
144
+ ` * ` pointers).
145
+ * Otherwise, we lookup which field is coerced due to the opt-in coercion, move
146
+ the object being coerced and coerce the field in question by recursing (the
147
+ built-in pointers are the base cases).
132
148
133
- ```
134
- AdjustCustom(0, AdjustNewType(
135
- AutoDerefRef {
136
- autoderefs: 1,
137
- autoref: AutoUnsafe(mut, AutoUnsize(
138
- UnsizeStruct(UnsizePlaceholder(T, U))))
139
- }))
140
- ```
141
149
142
- When we need to coerce ` Rc<[i32; 42]> ` to ` Rc<[i32]> ` , we look up the impl and
143
- find ` T = [i32; 42] ` and ` U = [i32] ` (note that we automatically require that
144
- ` Unsize ` is satisfied when looking up the impl). We can therefore replace the
145
- placeholder in the above adjustment with ` UnsizeLength(42) ` . That gives us the
146
- real adjustment to store for trans.
150
+ ### Adjustment types
151
+
152
+ We add ` AdjustCustom ` to the ` AutoAdjustment ` enum as a placeholder for coercions
153
+ due to a ` CoerceUnsized ` bound. I don't think we need the ` UnsizeKind ` enum at
154
+ all now, since all checking is postponed until trans or relies on traits and impls.
155
+
147
156
148
157
# Drawbacks
149
158
@@ -164,8 +173,7 @@ intrinsics. Although more flexible, this allows for implcicit excecution of
164
173
arbitrary code. If we need the increased flexibility, I believe we can add a
165
174
manual option to the ` CoerceUnsized ` trait backwards compatibly.
166
175
167
- The proposed design could be tweaked: we could make newtype coercions opt-in
168
- (this would complicate other parts of the proposal though). We could change the
176
+ The proposed design could be tweaked: for example, we could change the
169
177
` CoerceUnsized ` trait in many ways (we experimented with an associated type to
170
178
indicate the field type which is coerced, for example).
171
179
0 commit comments