1 //! This module contains the functionality to convert from the wacky tcx data
2 //! structures into the THIR. The `builder` is generally ignorant of the tcx,
3 //! etc., and instead goes through the `Cx` for most of its work.
5 use crate::thir
::pattern
::pat_from_hir
;
6 use crate::thir
::util
::UserAnnotatedTyHelpers
;
8 use rustc_data_structures
::steal
::Steal
;
9 use rustc_errors
::ErrorGuaranteed
;
11 use rustc_hir
::def
::DefKind
;
12 use rustc_hir
::def_id
::{DefId, LocalDefId}
;
13 use rustc_hir
::lang_items
::LangItem
;
16 use rustc_middle
::middle
::region
;
17 use rustc_middle
::thir
::*;
18 use rustc_middle
::ty
::{self, RvalueScopes, Ty, TyCtxt}
;
20 pub(crate) fn thir_body(
22 owner_def
: LocalDefId
,
23 ) -> Result
<(&Steal
<Thir
<'_
>>, ExprId
), ErrorGuaranteed
> {
25 let body
= hir
.body(hir
.body_owned_by(owner_def
));
26 let mut cx
= Cx
::new(tcx
, owner_def
);
27 if let Some(reported
) = cx
.typeck_results
.tainted_by_errors
{
30 let expr
= cx
.mirror_expr(&body
.value
);
32 let owner_id
= hir
.local_def_id_to_hir_id(owner_def
);
33 if let Some(ref fn_decl
) = hir
.fn_decl_by_hir_id(owner_id
) {
34 let closure_env_param
= cx
.closure_env_param(owner_def
, owner_id
);
35 let explicit_params
= cx
.explicit_params(owner_id
, fn_decl
, body
);
36 cx
.thir
.params
= closure_env_param
.into_iter().chain(explicit_params
).collect();
38 // The resume argument may be missing, in that case we need to provide it here.
39 // It will always be `()` in this case.
40 if tcx
.def_kind(owner_def
) == DefKind
::Coroutine
&& body
.params
.is_empty() {
41 cx
.thir
.params
.push(Param
{
42 ty
: Ty
::new_unit(tcx
),
51 Ok((tcx
.alloc_steal_thir(cx
.thir
), expr
))
58 param_env
: ty
::ParamEnv
<'tcx
>,
60 region_scope_tree
: &'tcx region
::ScopeTree
,
61 typeck_results
: &'tcx ty
::TypeckResults
<'tcx
>,
62 rvalue_scopes
: &'tcx RvalueScopes
,
64 /// False to indicate that adjustments should not be applied. Only used for `custom_mir`
65 apply_adjustments
: bool
,
67 /// The `DefId` of the owner of this body.
72 fn new(tcx
: TyCtxt
<'tcx
>, def
: LocalDefId
) -> Cx
<'tcx
> {
73 let typeck_results
= tcx
.typeck(def
);
75 let hir_id
= hir
.local_def_id_to_hir_id(def
);
77 let body_type
= if hir
.body_owner_kind(def
).is_fn_or_closure() {
78 // fetch the fully liberated fn signature (that is, all bound
79 // types/lifetimes replaced)
80 BodyTy
::Fn(typeck_results
.liberated_fn_sigs()[hir_id
])
82 // Get the revealed type of this const. This is *not* the adjusted
83 // type of its body, which may be a subtype of this type. For
87 // static X: fn(&'static ()) = foo;
89 // The adjusted type of the body of X is `for<'a> fn(&'a ())` which
90 // is not the same as the type of X. We need the type of the return
91 // place to be the type of the constant because NLL typeck will
93 BodyTy
::Const(typeck_results
.node_type(hir_id
))
98 thir
: Thir
::new(body_type
),
99 param_env
: tcx
.param_env(def
),
100 region_scope_tree
: tcx
.region_scope_tree(def
),
102 rvalue_scopes
: &typeck_results
.rvalue_scopes
,
103 body_owner
: def
.to_def_id(),
104 apply_adjustments
: hir
107 .all(|attr
| attr
.name_or_empty() != rustc_span
::sym
::custom_mir
),
111 #[instrument(level = "debug", skip(self))]
112 fn pattern_from_hir(&mut self, p
: &hir
::Pat
<'_
>) -> Box
<Pat
<'tcx
>> {
113 let p
= match self.tcx
.hir().get(p
.hir_id
) {
115 node
=> bug
!("pattern became {:?}", node
),
117 pat_from_hir(self.tcx
, self.param_env
, self.typeck_results(), p
)
120 fn closure_env_param(&self, owner_def
: LocalDefId
, owner_id
: HirId
) -> Option
<Param
<'tcx
>> {
121 match self.tcx
.def_kind(owner_def
) {
122 DefKind
::Closure
=> {
123 let closure_ty
= self.typeck_results
.node_type(owner_id
);
125 let ty
::Closure(closure_def_id
, closure_args
) = *closure_ty
.kind() else {
126 bug
!("closure expr does not have closure type: {:?}", closure_ty
);
130 self.tcx
.mk_bound_variable_kinds(&[ty
::BoundVariableKind
::Region(ty
::BrEnv
)]);
131 let br
= ty
::BoundRegion
{
132 var
: ty
::BoundVar
::from_usize(bound_vars
.len() - 1),
135 let env_region
= ty
::Region
::new_late_bound(self.tcx
, ty
::INNERMOST
, br
);
137 self.tcx
.closure_env_ty(closure_def_id
, closure_args
, env_region
).unwrap();
138 let liberated_closure_env_ty
= self.tcx
.erase_late_bound_regions(
139 ty
::Binder
::bind_with_vars(closure_env_ty
, bound_vars
),
141 let env_param
= Param
{
142 ty
: liberated_closure_env_ty
,
151 DefKind
::Coroutine
=> {
152 let coroutine_ty
= self.typeck_results
.node_type(owner_id
);
153 let coroutine_param
= Param
{
160 Some(coroutine_param
)
166 fn explicit_params
<'a
>(
169 fn_decl
: &'tcx hir
::FnDecl
<'tcx
>,
170 body
: &'tcx hir
::Body
<'tcx
>,
171 ) -> impl Iterator
<Item
= Param
<'tcx
>> + 'a
{
172 let fn_sig
= self.typeck_results
.liberated_fn_sigs()[owner_id
];
174 body
.params
.iter().enumerate().map(move |(index
, param
)| {
175 let ty_span
= fn_decl
178 // Make sure that inferred closure args have no type span
179 .and_then(|ty
| if param
.pat
.span
!= ty
.span { Some(ty.span) }
else { None }
);
181 let self_kind
= if index
== 0 && fn_decl
.implicit_self
.has_implicit_self() {
182 Some(fn_decl
.implicit_self
)
187 // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
188 // (as it's created inside the body itself, not passed in from outside).
189 let ty
= if fn_decl
.c_variadic
&& index
== fn_decl
.inputs
.len() {
190 let va_list_did
= self.tcx
.require_lang_item(LangItem
::VaList
, Some(param
.span
));
193 .type_of(va_list_did
)
194 .instantiate(self.tcx
, &[self.tcx
.lifetimes
.re_erased
.into()])
196 fn_sig
.inputs()[index
]
199 let pat
= self.pattern_from_hir(param
.pat
);
200 Param { pat: Some(pat), ty, ty_span, self_kind, hir_id: Some(param.hir_id) }
205 impl<'tcx
> UserAnnotatedTyHelpers
<'tcx
> for Cx
<'tcx
> {
206 fn tcx(&self) -> TyCtxt
<'tcx
> {
210 fn typeck_results(&self) -> &ty
::TypeckResults
<'tcx
> {