Introduce TypeInformationCtxt to abstract over LateCtxt/FnCtxt
This commit is contained in:
parent
72eccf2c6e
commit
e4209f19fd
2 changed files with 160 additions and 134 deletions
|
@ -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"));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue