Skip to content

Commit eab5d98

Browse files
bors[bot]Veykril
andauthored
Merge #9512
9512: Record coercion adjustments r=Veykril a=Veykril cc #9475 Co-authored-by: Lukas Wirth <[email protected]>
2 parents 80f193e + 9272942 commit eab5d98

File tree

9 files changed

+479
-169
lines changed

9 files changed

+479
-169
lines changed

crates/hir_ty/src/diagnostics/match_check.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl<'a> PatCtxt<'a> {
109109
self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold(
110110
unadjusted_pat,
111111
|subpattern, ref_ty| Pat {
112-
ty: ref_ty.clone(),
112+
ty: ref_ty.target.clone(),
113113
kind: Box::new(PatKind::Deref { subpattern }),
114114
},
115115
)

crates/hir_ty/src/infer.rs

Lines changed: 123 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
use std::ops::Index;
1717
use std::sync::Arc;
1818

19-
use chalk_ir::{cast::Cast, DebruijnIndex, Mutability};
19+
use chalk_ir::{cast::Cast, DebruijnIndex, Mutability, Safety};
2020
use hir_def::{
2121
body::Body,
2222
data::{ConstData, FunctionData, StaticData},
@@ -34,10 +34,10 @@ use rustc_hash::FxHashMap;
3434
use stdx::impl_from;
3535
use syntax::SmolStr;
3636

37-
use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty};
3837
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,
4141
};
4242

4343
// This lint has a false positive here. See the link below for details.
@@ -103,12 +103,20 @@ impl Default for BindingMode {
103103
}
104104

105105
#[derive(Debug)]
106-
pub(crate) struct InferOk {
106+
pub(crate) struct InferOk<T> {
107+
value: T,
107108
goals: Vec<InEnvironment<Goal>>,
108109
}
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+
109117
#[derive(Debug)]
110118
pub(crate) struct TypeError;
111-
pub(crate) type InferResult = Result<InferOk, TypeError>;
119+
pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
112120

113121
#[derive(Debug, PartialEq, Eq, Clone)]
114122
pub enum InferenceDiagnostic {
@@ -133,6 +141,108 @@ impl Default for InternedStandardTypes {
133141
InternedStandardTypes { unknown: TyKind::Error.intern(&Interner) }
134142
}
135143
}
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+
}
136246

137247
/// The result of type inference: A mapping from expressions and patterns to types.
138248
#[derive(Clone, PartialEq, Eq, Debug, Default)]
@@ -156,7 +266,8 @@ pub struct InferenceResult {
156266
/// Interned Unknown to return references to.
157267
standard_types: InternedStandardTypes,
158268
/// 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>>,
160271
}
161272

162273
impl InferenceResult {
@@ -238,7 +349,7 @@ struct InferenceContext<'a> {
238349
#[derive(Clone, Debug)]
239350
struct BreakableContext {
240351
may_break: bool,
241-
break_ty: Ty,
352+
coerce: CoerceMany,
242353
label: Option<name::Name>,
243354
}
244355

@@ -303,6 +414,10 @@ impl<'a> InferenceContext<'a> {
303414
self.result.type_of_expr.insert(expr, ty);
304415
}
305416

417+
fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec<Adjustment>) {
418+
self.result.expr_adjustments.insert(expr, adjustments);
419+
}
420+
306421
fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
307422
self.result.method_resolutions.insert(expr, (func, subst));
308423
}

crates/hir_ty/src/infer/closure.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Inference of closure parameter types based on the closure's expected type.
22
33
use chalk_ir::{cast::Cast, AliasTy, FnSubst, WhereClause};
4-
use hir_def::HasModule;
4+
use hir_def::{expr::ExprId, HasModule};
55
use smallvec::SmallVec;
66

77
use crate::{
@@ -14,6 +14,7 @@ use super::{Expectation, InferenceContext};
1414
impl InferenceContext<'_> {
1515
pub(super) fn deduce_closure_type_from_expectations(
1616
&mut self,
17+
closure_expr: ExprId,
1718
closure_ty: &Ty,
1819
sig_ty: &Ty,
1920
expectation: &Expectation,
@@ -24,7 +25,7 @@ impl InferenceContext<'_> {
2425
};
2526

2627
// Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here.
27-
self.coerce(closure_ty, &expected_ty);
28+
let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty);
2829

2930
// Deduction based on the expected `dyn Fn` is done separately.
3031
if let TyKind::Dyn(dyn_ty) = expected_ty.kind(&Interner) {

0 commit comments

Comments
 (0)