16
16
use std:: ops:: Index ;
17
17
use std:: sync:: Arc ;
18
18
19
- use chalk_ir:: { cast:: Cast , DebruijnIndex , Mutability } ;
19
+ use chalk_ir:: { cast:: Cast , DebruijnIndex , Mutability , Safety } ;
20
20
use hir_def:: {
21
21
body:: Body ,
22
22
data:: { ConstData , FunctionData , StaticData } ,
@@ -34,10 +34,10 @@ use rustc_hash::FxHashMap;
34
34
use stdx:: impl_from;
35
35
use syntax:: SmolStr ;
36
36
37
- use super :: { DomainGoal , InEnvironment , ProjectionTy , TraitEnvironment , TraitRef , Ty } ;
38
37
use crate :: {
39
- db:: HirDatabase , fold_tys, lower:: ImplTraitLoweringMode , to_assoc_type_id, AliasEq , AliasTy ,
40
- Goal , Interner , Substitution , TyBuilder , TyExt , TyKind ,
38
+ db:: HirDatabase , fold_tys, infer:: coerce:: CoerceMany , lower:: ImplTraitLoweringMode ,
39
+ to_assoc_type_id, AliasEq , AliasTy , DomainGoal , Goal , InEnvironment , Interner , ProjectionTy ,
40
+ Substitution , TraitEnvironment , TraitRef , Ty , TyBuilder , TyExt , TyKind ,
41
41
} ;
42
42
43
43
// This lint has a false positive here. See the link below for details.
@@ -103,12 +103,20 @@ impl Default for BindingMode {
103
103
}
104
104
105
105
#[ derive( Debug ) ]
106
- pub ( crate ) struct InferOk {
106
+ pub ( crate ) struct InferOk < T > {
107
+ value : T ,
107
108
goals : Vec < InEnvironment < Goal > > ,
108
109
}
110
+
111
+ impl < T > InferOk < T > {
112
+ fn map < U > ( self , f : impl FnOnce ( T ) -> U ) -> InferOk < U > {
113
+ InferOk { value : f ( self . value ) , goals : self . goals }
114
+ }
115
+ }
116
+
109
117
#[ derive( Debug ) ]
110
118
pub ( crate ) struct TypeError ;
111
- pub ( crate ) type InferResult = Result < InferOk , TypeError > ;
119
+ pub ( crate ) type InferResult < T > = Result < InferOk < T > , TypeError > ;
112
120
113
121
#[ derive( Debug , PartialEq , Eq , Clone ) ]
114
122
pub enum InferenceDiagnostic {
@@ -133,6 +141,108 @@ impl Default for InternedStandardTypes {
133
141
InternedStandardTypes { unknown : TyKind :: Error . intern ( & Interner ) }
134
142
}
135
143
}
144
+ /// Represents coercing a value to a different type of value.
145
+ ///
146
+ /// We transform values by following a number of `Adjust` steps in order.
147
+ /// See the documentation on variants of `Adjust` for more details.
148
+ ///
149
+ /// Here are some common scenarios:
150
+ ///
151
+ /// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
152
+ /// Here the pointer will be dereferenced N times (where a dereference can
153
+ /// happen to raw or borrowed pointers or any smart pointer which implements
154
+ /// Deref, including Box<_>). The types of dereferences is given by
155
+ /// `autoderefs`. It can then be auto-referenced zero or one times, indicated
156
+ /// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
157
+ /// `false`.
158
+ ///
159
+ /// 2. A thin-to-fat coercion involves unsizing the underlying data. We start
160
+ /// with a thin pointer, deref a number of times, unsize the underlying data,
161
+ /// then autoref. The 'unsize' phase may change a fixed length array to a
162
+ /// dynamically sized one, a concrete object to a trait object, or statically
163
+ /// sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is
164
+ /// represented by:
165
+ ///
166
+ /// ```
167
+ /// Deref(None) -> [i32; 4],
168
+ /// Borrow(AutoBorrow::Ref) -> &[i32; 4],
169
+ /// Unsize -> &[i32],
170
+ /// ```
171
+ ///
172
+ /// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
173
+ /// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
174
+ /// The autoderef and -ref are the same as in the above example, but the type
175
+ /// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
176
+ /// the underlying conversions from `[i32; 4]` to `[i32]`.
177
+ ///
178
+ /// 3. Coercing a `Box<T>` to `Box<dyn Trait>` is an interesting special case. In
179
+ /// that case, we have the pointer we need coming in, so there are no
180
+ /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
181
+ /// At some point, of course, `Box` should move out of the compiler, in which
182
+ /// case this is analogous to transforming a struct. E.g., Box<[i32; 4]> ->
183
+ /// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
184
+ #[ derive( Clone , Debug , PartialEq , Eq , Hash ) ]
185
+ pub struct Adjustment {
186
+ pub kind : Adjust ,
187
+ pub target : Ty ,
188
+ }
189
+
190
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
191
+ pub enum Adjust {
192
+ /// Go from ! to any type.
193
+ NeverToAny ,
194
+ /// Dereference once, producing a place.
195
+ Deref ( Option < OverloadedDeref > ) ,
196
+ /// Take the address and produce either a `&` or `*` pointer.
197
+ Borrow ( AutoBorrow ) ,
198
+ Pointer ( PointerCast ) ,
199
+ }
200
+
201
+ /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
202
+ /// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
203
+ /// The target type is `U` in both cases, with the region and mutability
204
+ /// being those shared by both the receiver and the returned reference.
205
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
206
+ pub struct OverloadedDeref ( Mutability ) ;
207
+
208
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
209
+ pub enum AutoBorrow {
210
+ /// Converts from T to &T.
211
+ Ref ( Mutability ) ,
212
+ /// Converts from T to *T.
213
+ RawPtr ( Mutability ) ,
214
+ }
215
+
216
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
217
+ pub enum PointerCast {
218
+ /// Go from a fn-item type to a fn-pointer type.
219
+ ReifyFnPointer ,
220
+
221
+ /// Go from a safe fn pointer to an unsafe fn pointer.
222
+ UnsafeFnPointer ,
223
+
224
+ /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
225
+ /// It cannot convert a closure that requires unsafe.
226
+ ClosureFnPointer ( Safety ) ,
227
+
228
+ /// Go from a mut raw pointer to a const raw pointer.
229
+ MutToConstPointer ,
230
+
231
+ /// Go from `*const [T; N]` to `*const T`
232
+ ArrayToPointer ,
233
+
234
+ /// Unsize a pointer/reference value, e.g., `&[T; n]` to
235
+ /// `&[T]`. Note that the source could be a thin or fat pointer.
236
+ /// This will do things like convert thin pointers to fat
237
+ /// pointers, or convert structs containing thin pointers to
238
+ /// structs containing fat pointers, or convert between fat
239
+ /// pointers. We don't store the details of how the transform is
240
+ /// done (in fact, we don't know that, because it might depend on
241
+ /// the precise type parameters). We just store the target
242
+ /// type. Codegen backends and miri figure out what has to be done
243
+ /// based on the precise source/target type at hand.
244
+ Unsize ,
245
+ }
136
246
137
247
/// The result of type inference: A mapping from expressions and patterns to types.
138
248
#[ derive( Clone , PartialEq , Eq , Debug , Default ) ]
@@ -156,7 +266,8 @@ pub struct InferenceResult {
156
266
/// Interned Unknown to return references to.
157
267
standard_types : InternedStandardTypes ,
158
268
/// Stores the types which were implicitly dereferenced in pattern binding modes.
159
- pub pat_adjustments : FxHashMap < PatId , Vec < Ty > > ,
269
+ pub pat_adjustments : FxHashMap < PatId , Vec < Adjustment > > ,
270
+ pub expr_adjustments : FxHashMap < ExprId , Vec < Adjustment > > ,
160
271
}
161
272
162
273
impl InferenceResult {
@@ -238,7 +349,7 @@ struct InferenceContext<'a> {
238
349
#[ derive( Clone , Debug ) ]
239
350
struct BreakableContext {
240
351
may_break : bool ,
241
- break_ty : Ty ,
352
+ coerce : CoerceMany ,
242
353
label : Option < name:: Name > ,
243
354
}
244
355
@@ -303,6 +414,10 @@ impl<'a> InferenceContext<'a> {
303
414
self . result . type_of_expr . insert ( expr, ty) ;
304
415
}
305
416
417
+ fn write_expr_adj ( & mut self , expr : ExprId , adjustments : Vec < Adjustment > ) {
418
+ self . result . expr_adjustments . insert ( expr, adjustments) ;
419
+ }
420
+
306
421
fn write_method_resolution ( & mut self , expr : ExprId , func : FunctionId , subst : Substitution ) {
307
422
self . result . method_resolutions . insert ( expr, ( func, subst) ) ;
308
423
}
0 commit comments