1
Fork 0

Introduce TypeInformationCtxt to abstract over LateCtxt/FnCtxt

This commit is contained in:
Michael Goulet 2024-05-08 13:40:50 -04:00
parent 72eccf2c6e
commit e4209f19fd
2 changed files with 160 additions and 134 deletions

View file

@ -2,7 +2,8 @@
//! normal visitor, which just walks the entire body in one shot, the //! normal visitor, which just walks the entire body in one shot, the
//! `ExprUseVisitor` determines how expressions are being used. //! `ExprUseVisitor` determines how expressions are being used.
use std::cell::RefCell; use std::cell::{Ref, RefCell};
use std::ops::Deref;
use std::slice::from_ref; use std::slice::from_ref;
use hir::def::DefKind; use hir::def::DefKind;
@ -16,7 +17,6 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, Res}; use rustc_hir::def::{CtorOf, Res};
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_hir::{HirId, PatKind}; use rustc_hir::{HirId, PatKind};
use rustc_infer::infer::InferCtxt;
use rustc_middle::hir::place::ProjectionKind; use rustc_middle::hir::place::ProjectionKind;
use rustc_middle::mir::FakeReadCause; use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::{ use rustc_middle::ty::{
@ -24,9 +24,11 @@ use rustc_middle::ty::{
}; };
use rustc_span::{ErrorGuaranteed, Span}; use rustc_span::{ErrorGuaranteed, Span};
use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::infer::InferCtxtExt;
use ty::BorrowKind::ImmBorrow; use ty::BorrowKind::ImmBorrow;
use crate::fn_ctxt::FnCtxt;
type McResult<T> = Result<T, ErrorGuaranteed>; type McResult<T> = Result<T, ErrorGuaranteed>;
/// This trait defines the callbacks you can expect to receive when /// This trait defines the callbacks you can expect to receive when
@ -122,16 +124,61 @@ impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D {
} }
} }
pub trait TypeInformationCtxt<'tcx> {
type TypeckResults<'a>: Deref<Target = ty::TypeckResults<'tcx>>
where
Self: 'a;
fn typeck_results(&self) -> Self::TypeckResults<'_>;
fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T;
fn tainted_by_errors(&self) -> Option<ErrorGuaranteed>;
fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
fn body_owner_def_id(&self) -> LocalDefId;
fn tcx(&self) -> TyCtxt<'tcx>;
}
impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
type TypeckResults<'a> = Ref<'a, ty::TypeckResults<'tcx>>
where
Self: 'a;
fn typeck_results(&self) -> Self::TypeckResults<'_> {
self.typeck_results.borrow()
}
fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
self.infcx.resolve_vars_if_possible(t)
}
fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
if let Some(guar) = self.infcx.tainted_by_errors() { Err(guar) } else { Ok(()) }
}
fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
}
fn body_owner_def_id(&self) -> LocalDefId {
self.body_id
}
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
}
/// The ExprUseVisitor type /// The ExprUseVisitor type
/// ///
/// This is the code that actually walks the tree. /// This is the code that actually walks the tree.
pub struct ExprUseVisitor<'a, 'tcx, D: Delegate<'tcx>> { pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> {
typeck_results: &'a ty::TypeckResults<'tcx>, cx: Cx,
infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
upvars: Option<&'tcx FxIndexMap<HirId, hir::Upvar>>,
body_owner: LocalDefId,
delegate: RefCell<D>, delegate: RefCell<D>,
upvars: Option<&'tcx FxIndexMap<HirId, hir::Upvar>>,
} }
/// If the MC results in an error, it's because the type check /// If the MC results in an error, it's because the type check
@ -153,30 +200,20 @@ macro_rules! return_if_err {
}; };
} }
impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> { impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> {
/// Creates the ExprUseVisitor, configuring it with the various options provided: /// Creates the ExprUseVisitor, configuring it with the various options provided:
/// ///
/// - `delegate` -- who receives the callbacks /// - `delegate` -- who receives the callbacks
/// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`) /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`)
/// - `typeck_results` --- typeck results for the code being analyzed /// - `typeck_results` --- typeck results for the code being analyzed
pub fn new( pub fn new(cx: Cx, delegate: D) -> Self {
delegate: D,
infcx: &'a InferCtxt<'tcx>,
body_owner: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
) -> Self {
ExprUseVisitor { ExprUseVisitor {
infcx,
param_env,
typeck_results,
body_owner,
delegate: RefCell::new(delegate), delegate: RefCell::new(delegate),
upvars: infcx.tcx.upvars_mentioned(body_owner), upvars: cx.tcx().upvars_mentioned(cx.body_owner_def_id()),
cx,
} }
} }
#[instrument(skip(self), level = "debug")]
pub fn consume_body(&self, body: &hir::Body<'_>) { pub fn consume_body(&self, body: &hir::Body<'_>) {
for param in body.params { for param in body.params {
let param_ty = return_if_err!(self.pat_ty_adjusted(param.pat)); let param_ty = return_if_err!(self.pat_ty_adjusted(param.pat));
@ -190,14 +227,10 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
self.consume_expr(body.value); self.consume_expr(body.value);
} }
fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn consume_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { fn consume_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
debug!("delegate_consume(place_with_id={:?})", place_with_id); debug!("delegate_consume(place_with_id={:?})", place_with_id);
if self.type_is_copy_modulo_regions(place_with_id.place.ty()) { if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) {
self.delegate.borrow_mut().copy(place_with_id, diag_expr_id) self.delegate.borrow_mut().copy(place_with_id, diag_expr_id)
} else { } else {
self.delegate.borrow_mut().consume(place_with_id, diag_expr_id) self.delegate.borrow_mut().consume(place_with_id, diag_expr_id)
@ -390,7 +423,7 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
} }
hir::ExprKind::AssignOp(_, lhs, rhs) => { hir::ExprKind::AssignOp(_, lhs, rhs) => {
if self.typeck_results.is_method_call(expr) { if self.cx.typeck_results().is_method_call(expr) {
self.consume_expr(lhs); self.consume_expr(lhs);
} else { } else {
self.mutate_expr(lhs); self.mutate_expr(lhs);
@ -461,7 +494,7 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
// A `Path` pattern is just a name like `Foo`. This is either a // A `Path` pattern is just a name like `Foo`. This is either a
// named constant or else it refers to an ADT variant // named constant or else it refers to an ADT variant
let res = self.typeck_results.qpath_res(qpath, pat.hir_id); let res = self.cx.typeck_results().qpath_res(qpath, pat.hir_id);
match res { match res {
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => { Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
// Named constants have to be equated with the value // Named constants have to be equated with the value
@ -587,8 +620,11 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
self.consume_expr(field.expr); self.consume_expr(field.expr);
// The struct path probably didn't resolve // The struct path probably didn't resolve
if self.typeck_results.opt_field_index(field.hir_id).is_none() { if self.cx.typeck_results().opt_field_index(field.hir_id).is_none() {
self.tcx().dcx().span_delayed_bug(field.span, "couldn't resolve index for field"); self.cx
.tcx()
.dcx()
.span_delayed_bug(field.span, "couldn't resolve index for field");
} }
} }
@ -607,14 +643,14 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
ty::Adt(adt, args) if adt.is_struct() => { ty::Adt(adt, args) if adt.is_struct() => {
// Consume those fields of the with expression that are needed. // Consume those fields of the with expression that are needed.
for (f_index, with_field) in adt.non_enum_variant().fields.iter_enumerated() { for (f_index, with_field) in adt.non_enum_variant().fields.iter_enumerated() {
let is_mentioned = fields let is_mentioned = fields.iter().any(|f| {
.iter() self.cx.typeck_results().opt_field_index(f.hir_id) == Some(f_index)
.any(|f| self.typeck_results.opt_field_index(f.hir_id) == Some(f_index)); });
if !is_mentioned { if !is_mentioned {
let field_place = self.cat_projection( let field_place = self.cat_projection(
with_expr.hir_id, with_expr.hir_id,
with_place.clone(), with_place.clone(),
with_field.ty(self.tcx(), args), with_field.ty(self.cx.tcx(), args),
ProjectionKind::Field(f_index, FIRST_VARIANT), ProjectionKind::Field(f_index, FIRST_VARIANT),
); );
self.consume_or_copy(&field_place, field_place.hir_id); self.consume_or_copy(&field_place, field_place.hir_id);
@ -626,7 +662,7 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
// struct; however, when EUV is run during typeck, it // struct; however, when EUV is run during typeck, it
// may not. This will generate an error earlier in typeck, // may not. This will generate an error earlier in typeck,
// so we can just ignore it. // so we can just ignore it.
if self.tcx().dcx().has_errors().is_none() { if self.cx.tcx().dcx().has_errors().is_none() {
span_bug!(with_expr.span, "with expression doesn't evaluate to a struct"); span_bug!(with_expr.span, "with expression doesn't evaluate to a struct");
} }
} }
@ -641,7 +677,8 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
/// consumed or borrowed as part of the automatic adjustment /// consumed or borrowed as part of the automatic adjustment
/// process. /// process.
fn walk_adjustment(&self, expr: &hir::Expr<'_>) { fn walk_adjustment(&self, expr: &hir::Expr<'_>) {
let adjustments = self.typeck_results.expr_adjustments(expr); let typeck_results = self.cx.typeck_results();
let adjustments = typeck_results.expr_adjustments(expr);
let mut place_with_id = return_if_err!(self.cat_expr_unadjusted(expr)); let mut place_with_id = return_if_err!(self.cat_expr_unadjusted(expr));
for adjustment in adjustments { for adjustment in adjustments {
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
@ -749,12 +786,12 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
fn walk_pat(&self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>, has_guard: bool) { fn walk_pat(&self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>, has_guard: bool) {
debug!("walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})", discr_place, pat, has_guard); debug!("walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})", discr_place, pat, has_guard);
let tcx = self.tcx(); let tcx = self.cx.tcx();
return_if_err!(self.cat_pattern(discr_place.clone(), pat, |place, pat| { return_if_err!(self.cat_pattern(discr_place.clone(), pat, |place, pat| {
if let PatKind::Binding(_, canonical_id, ..) = pat.kind { if let PatKind::Binding(_, canonical_id, ..) = pat.kind {
debug!("walk_pat: binding place={:?} pat={:?}", place, pat); debug!("walk_pat: binding place={:?} pat={:?}", place, pat);
if let Some(bm) = if let Some(bm) =
self.typeck_results.extract_binding_mode(tcx.sess, pat.hir_id, pat.span) self.cx.typeck_results().extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
{ {
debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
@ -794,7 +831,7 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
// determines whether to borrow *at the level of the deref pattern* rather than // determines whether to borrow *at the level of the deref pattern* rather than
// borrowing the bound place (since that inner place is inside the temporary that // borrowing the bound place (since that inner place is inside the temporary that
// stores the result of calling `deref()`/`deref_mut()` so can't be captured). // stores the result of calling `deref()`/`deref_mut()` so can't be captured).
let mutable = self.typeck_results.pat_has_ref_mut_binding(subpattern); let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpattern);
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
let bk = ty::BorrowKind::from_mutbl(mutability); let bk = ty::BorrowKind::from_mutbl(mutability);
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk); self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
@ -832,21 +869,21 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
debug!("walk_captures({:?})", closure_expr); debug!("walk_captures({:?})", closure_expr);
let tcx = self.tcx(); let tcx = self.cx.tcx();
let closure_def_id = closure_expr.def_id; let closure_def_id = closure_expr.def_id;
let upvars = tcx.upvars_mentioned(self.body_owner);
// For purposes of this function, coroutine and closures are equivalent. // For purposes of this function, coroutine and closures are equivalent.
let body_owner_is_closure = let body_owner_is_closure = matches!(
matches!(tcx.hir().body_owner_kind(self.body_owner), hir::BodyOwnerKind::Closure,); tcx.hir().body_owner_kind(self.cx.body_owner_def_id()),
hir::BodyOwnerKind::Closure
);
// If we have a nested closure, we want to include the fake reads present in the nested closure. // If we have a nested closure, we want to include the fake reads present in the nested closure.
if let Some(fake_reads) = self.typeck_results.closure_fake_reads.get(&closure_def_id) { if let Some(fake_reads) = self.cx.typeck_results().closure_fake_reads.get(&closure_def_id) {
for (fake_read, cause, hir_id) in fake_reads.iter() { for (fake_read, cause, hir_id) in fake_reads.iter() {
match fake_read.base { match fake_read.base {
PlaceBase::Upvar(upvar_id) => { PlaceBase::Upvar(upvar_id) => {
if upvar_is_local_variable( if upvar_is_local_variable(
upvars, self.upvars,
upvar_id.var_path.hir_id, upvar_id.var_path.hir_id,
body_owner_is_closure, body_owner_is_closure,
) { ) {
@ -884,9 +921,14 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
} }
} }
if let Some(min_captures) = self.typeck_results.closure_min_captures.get(&closure_def_id) { if let Some(min_captures) =
self.cx.typeck_results().closure_min_captures.get(&closure_def_id)
{
for (var_hir_id, min_list) in min_captures.iter() { for (var_hir_id, min_list) in min_captures.iter() {
if upvars.map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id)) { if self
.upvars
.map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id))
{
// The nested closure might be capturing the current (enclosing) closure's local variables. // The nested closure might be capturing the current (enclosing) closure's local variables.
// We check if the root variable is ever mentioned within the enclosing closure, if not // We check if the root variable is ever mentioned within the enclosing closure, if not
// then for the current body (if it's a closure) these aren't captures, we will ignore them. // then for the current body (if it's a closure) these aren't captures, we will ignore them.
@ -898,7 +940,7 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
let place_base = if body_owner_is_closure { let place_base = if body_owner_is_closure {
// Mark the place to be captured by the enclosing closure // Mark the place to be captured by the enclosing closure
PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.body_owner)) PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.cx.body_owner_def_id()))
} else { } else {
// If the body owner isn't a closure then the variable must // If the body owner isn't a closure then the variable must
// be a local variable // be a local variable
@ -931,46 +973,29 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
} }
} }
fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
}
fn resolve_vars_if_possible<T>(&self, value: T) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
self.infcx.resolve_vars_if_possible(value)
}
fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
self.infcx.tainted_by_errors()
}
fn resolve_type_vars_or_error(&self, id: HirId, ty: Option<Ty<'tcx>>) -> McResult<Ty<'tcx>> { fn resolve_type_vars_or_error(&self, id: HirId, ty: Option<Ty<'tcx>>) -> McResult<Ty<'tcx>> {
match ty { match ty {
Some(ty) => { Some(ty) => {
let ty = self.resolve_vars_if_possible(ty); let ty = self.cx.resolve_vars_if_possible(ty);
if let Err(guar) = ty.error_reported() { self.cx.error_reported_in_ty(ty)?;
debug!("resolve_type_vars_or_error: error from {:?}", ty); if ty.is_ty_var() {
Err(guar)
} else if ty.is_ty_var() {
debug!("resolve_type_vars_or_error: infer var from {:?}", ty); debug!("resolve_type_vars_or_error: infer var from {:?}", ty);
Err(self Err(self.cx.tcx().dcx().span_delayed_bug(
.tcx() self.cx.tcx().hir().span(id),
.dcx() "encountered type variable",
.span_delayed_bug(self.tcx().hir().span(id), "encountered type variable")) ))
} else { } else {
Ok(ty) Ok(ty)
} }
} }
None => { None => {
// FIXME // FIXME
if let Some(guar) = self.tainted_by_errors() { if let Some(guar) = self.cx.tainted_by_errors() {
Err(guar) Err(guar)
} else { } else {
bug!( bug!(
"no type for node {} in mem_categorization", "no type for node {} in mem_categorization",
self.tcx().hir().node_to_string(id) self.cx.tcx().hir().node_to_string(id)
); );
} }
} }
@ -978,15 +1003,18 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
} }
fn node_ty(&self, hir_id: HirId) -> McResult<Ty<'tcx>> { fn node_ty(&self, hir_id: HirId) -> McResult<Ty<'tcx>> {
self.resolve_type_vars_or_error(hir_id, self.typeck_results.node_type_opt(hir_id)) self.resolve_type_vars_or_error(hir_id, self.cx.typeck_results().node_type_opt(hir_id))
} }
fn expr_ty(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> { fn expr_ty(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> {
self.resolve_type_vars_or_error(expr.hir_id, self.typeck_results.expr_ty_opt(expr)) self.resolve_type_vars_or_error(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr))
} }
fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> { fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> {
self.resolve_type_vars_or_error(expr.hir_id, self.typeck_results.expr_ty_adjusted_opt(expr)) self.resolve_type_vars_or_error(
expr.hir_id,
self.cx.typeck_results().expr_ty_adjusted_opt(expr),
)
} }
/// Returns the type of value that this pattern matches against. /// Returns the type of value that this pattern matches against.
@ -1004,7 +1032,7 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
// that these are never attached to binding patterns, so // that these are never attached to binding patterns, so
// actually this is somewhat "disjoint" from the code below // actually this is somewhat "disjoint" from the code below
// that aims to account for `ref x`. // that aims to account for `ref x`.
if let Some(vec) = self.typeck_results.pat_adjustments().get(pat.hir_id) { if let Some(vec) = self.cx.typeck_results().pat_adjustments().get(pat.hir_id) {
if let Some(first_ty) = vec.first() { if let Some(first_ty) = vec.first() {
debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty); debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
return Ok(*first_ty); return Ok(*first_ty);
@ -1015,7 +1043,6 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
} }
/// Like `pat_ty`, but ignores implicit `&` patterns. /// Like `pat_ty`, but ignores implicit `&` patterns.
#[instrument(level = "debug", skip(self), ret)]
fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> { fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
let base_ty = self.node_ty(pat.hir_id)?; let base_ty = self.node_ty(pat.hir_id)?;
trace!(?base_ty); trace!(?base_ty);
@ -1025,7 +1052,8 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
match pat.kind { match pat.kind {
PatKind::Binding(..) => { PatKind::Binding(..) => {
let bm = *self let bm = *self
.typeck_results .cx
.typeck_results()
.pat_binding_modes() .pat_binding_modes()
.get(pat.hir_id) .get(pat.hir_id)
.expect("missing binding mode"); .expect("missing binding mode");
@ -1039,6 +1067,7 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
None => { None => {
debug!("By-ref binding of non-derefable type"); debug!("By-ref binding of non-derefable type");
Err(self Err(self
.cx
.tcx() .tcx()
.dcx() .dcx()
.span_delayed_bug(pat.span, "by-ref binding of non-derefable type")) .span_delayed_bug(pat.span, "by-ref binding of non-derefable type"))
@ -1053,22 +1082,22 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
} }
fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> { fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
// This recursion helper avoids going through *too many* self.cat_expr_(expr, self.cx.typeck_results().expr_adjustments(expr))
// adjustments, since *only* non-overloaded deref recurses. }
fn helper<'a, 'tcx, D: Delegate<'tcx>>(
this: &ExprUseVisitor<'a, 'tcx, D>, /// This recursion helper avoids going through *too many*
expr: &hir::Expr<'_>, /// adjustments, since *only* non-overloaded deref recurses.
adjustments: &[adjustment::Adjustment<'tcx>], fn cat_expr_(
) -> McResult<PlaceWithHirId<'tcx>> { &self,
match adjustments.split_last() { expr: &hir::Expr<'_>,
None => this.cat_expr_unadjusted(expr), adjustments: &[adjustment::Adjustment<'tcx>],
Some((adjustment, previous)) => { ) -> McResult<PlaceWithHirId<'tcx>> {
this.cat_expr_adjusted_with(expr, || helper(this, expr, previous), adjustment) match adjustments.split_last() {
} None => self.cat_expr_unadjusted(expr),
Some((adjustment, previous)) => {
self.cat_expr_adjusted_with(expr, || self.cat_expr_(expr, previous), adjustment)
} }
} }
helper(self, expr, self.typeck_results.expr_adjustments(expr))
} }
fn cat_expr_adjusted( fn cat_expr_adjusted(
@ -1080,7 +1109,6 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment) self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
} }
#[instrument(level = "debug", skip(self, previous))]
fn cat_expr_adjusted_with<F>( fn cat_expr_adjusted_with<F>(
&self, &self,
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
@ -1090,12 +1118,12 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
where where
F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>, F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>,
{ {
let target = self.resolve_vars_if_possible(adjustment.target); let target = self.cx.resolve_vars_if_possible(adjustment.target);
match adjustment.kind { match adjustment.kind {
adjustment::Adjust::Deref(overloaded) => { adjustment::Adjust::Deref(overloaded) => {
// Equivalent to *expr or something similar. // Equivalent to *expr or something similar.
let base = if let Some(deref) = overloaded { let base = if let Some(deref) = overloaded {
let ref_ty = Ty::new_ref(self.tcx(), deref.region, target, deref.mutbl); let ref_ty = Ty::new_ref(self.cx.tcx(), deref.region, target, deref.mutbl);
self.cat_rvalue(expr.hir_id, ref_ty) self.cat_rvalue(expr.hir_id, ref_ty)
} else { } else {
previous()? previous()?
@ -1113,12 +1141,11 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
} }
} }
#[instrument(level = "debug", skip(self), ret)]
fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> { fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
let expr_ty = self.expr_ty(expr)?; let expr_ty = self.expr_ty(expr)?;
match expr.kind { match expr.kind {
hir::ExprKind::Unary(hir::UnOp::Deref, e_base) => { hir::ExprKind::Unary(hir::UnOp::Deref, e_base) => {
if self.typeck_results.is_method_call(expr) { if self.cx.typeck_results().is_method_call(expr) {
self.cat_overloaded_place(expr, e_base) self.cat_overloaded_place(expr, e_base)
} else { } else {
let base = self.cat_expr(e_base)?; let base = self.cat_expr(e_base)?;
@ -1131,7 +1158,8 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
debug!(?base); debug!(?base);
let field_idx = self let field_idx = self
.typeck_results .cx
.typeck_results()
.field_indices() .field_indices()
.get(expr.hir_id) .get(expr.hir_id)
.cloned() .cloned()
@ -1146,7 +1174,7 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
} }
hir::ExprKind::Index(base, _, _) => { hir::ExprKind::Index(base, _, _) => {
if self.typeck_results.is_method_call(expr) { if self.cx.typeck_results().is_method_call(expr) {
// If this is an index implemented by a method call, then it // If this is an index implemented by a method call, then it
// will include an implicit deref of the result. // will include an implicit deref of the result.
// The call to index() returns a `&T` value, which // The call to index() returns a `&T` value, which
@ -1160,7 +1188,7 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
} }
hir::ExprKind::Path(ref qpath) => { hir::ExprKind::Path(ref qpath) => {
let res = self.typeck_results.qpath_res(qpath, expr.hir_id); let res = self.cx.typeck_results().qpath_res(qpath, expr.hir_id);
self.cat_res(expr.hir_id, expr.span, expr_ty, res) self.cat_res(expr.hir_id, expr.span, expr_ty, res)
} }
@ -1198,7 +1226,6 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
} }
} }
#[instrument(level = "debug", skip(self, span), ret)]
fn cat_res( fn cat_res(
&self, &self,
hir_id: HirId, hir_id: HirId,
@ -1239,9 +1266,8 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
/// Note: the actual upvar access contains invisible derefs of closure /// Note: the actual upvar access contains invisible derefs of closure
/// environment and upvar reference as appropriate. Only regionck cares /// environment and upvar reference as appropriate. Only regionck cares
/// about these dereferences, so we let it compute them as needed. /// about these dereferences, so we let it compute them as needed.
#[instrument(level = "debug", skip(self), ret)]
fn cat_upvar(&self, hir_id: HirId, var_id: HirId) -> McResult<PlaceWithHirId<'tcx>> { fn cat_upvar(&self, hir_id: HirId, var_id: HirId) -> McResult<PlaceWithHirId<'tcx>> {
let closure_expr_def_id = self.body_owner; let closure_expr_def_id = self.cx.body_owner_def_id();
let upvar_id = ty::UpvarId { let upvar_id = ty::UpvarId {
var_path: ty::UpvarPath { hir_id: var_id }, var_path: ty::UpvarPath { hir_id: var_id },
@ -1252,12 +1278,10 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new())) Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()))
} }
#[instrument(level = "debug", skip(self), ret)]
fn cat_rvalue(&self, hir_id: HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx> { fn cat_rvalue(&self, hir_id: HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx> {
PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new()) PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new())
} }
#[instrument(level = "debug", skip(self, node), ret)]
fn cat_projection( fn cat_projection(
&self, &self,
node: HirId, node: HirId,
@ -1268,7 +1292,7 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
let place_ty = base_place.place.ty(); let place_ty = base_place.place.ty();
let mut projections = base_place.place.projections; let mut projections = base_place.place.projections;
let node_ty = self.typeck_results.node_type(node); let node_ty = self.cx.typeck_results().node_type(node);
// Opaque types can't have field projections, but we can instead convert // Opaque types can't have field projections, but we can instead convert
// the current place in-place (heh) to the hidden type, and then apply all // the current place in-place (heh) to the hidden type, and then apply all
// follow up projections on that. // follow up projections on that.
@ -1279,7 +1303,6 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections) PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections)
} }
#[instrument(level = "debug", skip(self))]
fn cat_overloaded_place( fn cat_overloaded_place(
&self, &self,
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
@ -1294,13 +1317,12 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
let ty::Ref(region, _, mutbl) = *base_ty.kind() else { let ty::Ref(region, _, mutbl) = *base_ty.kind() else {
span_bug!(expr.span, "cat_overloaded_place: base is not a reference"); span_bug!(expr.span, "cat_overloaded_place: base is not a reference");
}; };
let ref_ty = Ty::new_ref(self.tcx(), region, place_ty, mutbl); let ref_ty = Ty::new_ref(self.cx.tcx(), region, place_ty, mutbl);
let base = self.cat_rvalue(expr.hir_id, ref_ty); let base = self.cat_rvalue(expr.hir_id, ref_ty);
self.cat_deref(expr.hir_id, base) self.cat_deref(expr.hir_id, base)
} }
#[instrument(level = "debug", skip(self, node), ret)]
fn cat_deref( fn cat_deref(
&self, &self,
node: HirId, node: HirId,
@ -1311,8 +1333,8 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
Some(mt) => mt.ty, Some(mt) => mt.ty,
None => { None => {
debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
return Err(self.tcx().dcx().span_delayed_bug( return Err(self.cx.tcx().dcx().span_delayed_bug(
self.tcx().hir().span(node), self.cx.tcx().hir().span(node),
"explicit deref of non-derefable type", "explicit deref of non-derefable type",
)); ));
} }
@ -1343,10 +1365,11 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
pat_hir_id: HirId, pat_hir_id: HirId,
span: Span, span: Span,
) -> McResult<VariantIdx> { ) -> McResult<VariantIdx> {
let res = self.typeck_results.qpath_res(qpath, pat_hir_id); let res = self.cx.typeck_results().qpath_res(qpath, pat_hir_id);
let ty = self.typeck_results.node_type(pat_hir_id); let ty = self.cx.typeck_results().node_type(pat_hir_id);
let ty::Adt(adt_def, _) = ty.kind() else { let ty::Adt(adt_def, _) = ty.kind() else {
return Err(self return Err(self
.cx
.tcx() .tcx()
.dcx() .dcx()
.span_delayed_bug(span, "struct or tuple struct pattern not applied to an ADT")); .span_delayed_bug(span, "struct or tuple struct pattern not applied to an ADT"));
@ -1377,11 +1400,12 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
variant_index: VariantIdx, variant_index: VariantIdx,
span: Span, span: Span,
) -> McResult<usize> { ) -> McResult<usize> {
let ty = self.typeck_results.node_type(pat_hir_id); let ty = self.cx.typeck_results().node_type(pat_hir_id);
match ty.kind() { match ty.kind() {
ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()), ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()),
_ => { _ => {
self.tcx() self.cx
.tcx()
.dcx() .dcx()
.span_bug(span, "struct or tuple struct pattern not applied to an ADT"); .span_bug(span, "struct or tuple struct pattern not applied to an ADT");
} }
@ -1391,12 +1415,14 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
/// Returns the total number of fields in a tuple used within a Tuple pattern. /// Returns the total number of fields in a tuple used within a Tuple pattern.
/// Here `pat_hir_id` is the HirId of the pattern itself. /// Here `pat_hir_id` is the HirId of the pattern itself.
fn total_fields_in_tuple(&self, pat_hir_id: HirId, span: Span) -> McResult<usize> { fn total_fields_in_tuple(&self, pat_hir_id: HirId, span: Span) -> McResult<usize> {
let ty = self.typeck_results.node_type(pat_hir_id); let ty = self.cx.typeck_results().node_type(pat_hir_id);
match ty.kind() { match ty.kind() {
ty::Tuple(args) => Ok(args.len()), ty::Tuple(args) => Ok(args.len()),
_ => { _ => Err(self
Err(self.tcx().dcx().span_delayed_bug(span, "tuple pattern not applied to a tuple")) .cx
} .tcx()
.dcx()
.span_delayed_bug(span, "tuple pattern not applied to a tuple")),
} }
} }
@ -1406,7 +1432,6 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
/// In general, the way that this works is that we walk down the pattern, /// In general, the way that this works is that we walk down the pattern,
/// constructing a `PlaceWithHirId` that represents the path that will be taken /// constructing a `PlaceWithHirId` that represents the path that will be taken
/// to reach the value being matched. /// to reach the value being matched.
#[instrument(skip(self, op), ret, level = "debug")]
fn cat_pattern_<F>( fn cat_pattern_<F>(
&self, &self,
mut place_with_id: PlaceWithHirId<'tcx>, mut place_with_id: PlaceWithHirId<'tcx>,
@ -1448,7 +1473,9 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
// Then we see that to get the same result, we must start with // Then we see that to get the same result, we must start with
// `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)` // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
// and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`. // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) { for _ in
0..self.cx.typeck_results().pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len())
{
debug!("applying adjustment to place_with_id={:?}", place_with_id); debug!("applying adjustment to place_with_id={:?}", place_with_id);
place_with_id = self.cat_deref(pat.hir_id, place_with_id)?; place_with_id = self.cat_deref(pat.hir_id, place_with_id)?;
} }
@ -1513,7 +1540,8 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
for fp in field_pats { for fp in field_pats {
let field_ty = self.pat_ty_adjusted(fp.pat)?; let field_ty = self.pat_ty_adjusted(fp.pat)?;
let field_index = self let field_index = self
.typeck_results .cx
.typeck_results()
.field_indices() .field_indices()
.get(fp.hir_id) .get(fp.hir_id)
.cloned() .cloned()
@ -1547,11 +1575,11 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
self.cat_pattern_(subplace, subpat, op)?; self.cat_pattern_(subplace, subpat, op)?;
} }
PatKind::Deref(subpat) => { PatKind::Deref(subpat) => {
let mutable = self.typeck_results.pat_has_ref_mut_binding(subpat); let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpat);
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
let re_erased = self.tcx().lifetimes.re_erased; let re_erased = self.cx.tcx().lifetimes.re_erased;
let ty = self.pat_ty_adjusted(subpat)?; let ty = self.pat_ty_adjusted(subpat)?;
let ty = Ty::new_ref(self.tcx(), re_erased, ty, mutability); let ty = Ty::new_ref(self.cx.tcx(), re_erased, ty, mutability);
// A deref pattern generates a temporary. // A deref pattern generates a temporary.
let place = self.cat_rvalue(pat.hir_id, ty); let place = self.cat_rvalue(pat.hir_id, ty);
self.cat_pattern_(place, subpat, op)?; self.cat_pattern_(place, subpat, op)?;
@ -1561,6 +1589,7 @@ impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'a, 'tcx, D> {
let Some(element_ty) = place_with_id.place.ty().builtin_index() else { let Some(element_ty) = place_with_id.place.ty().builtin_index() else {
debug!("explicit index of non-indexable type {:?}", place_with_id); debug!("explicit index of non-indexable type {:?}", place_with_id);
return Err(self return Err(self
.cx
.tcx() .tcx()
.dcx() .dcx()
.span_delayed_bug(pat.span, "explicit index of non-indexable type")); .span_delayed_bug(pat.span, "explicit index of non-indexable type"));

View file

@ -253,11 +253,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
euv::ExprUseVisitor::new( euv::ExprUseVisitor::new(
&FnCtxt::new(self, self.tcx.param_env(closure_def_id), closure_def_id),
&mut delegate, &mut delegate,
&self.infcx,
closure_def_id,
self.param_env,
&self.typeck_results.borrow(),
) )
.consume_body(body); .consume_body(body);