Apply nits

This commit is contained in:
Michael Goulet 2024-05-09 11:32:05 -04:00
parent 5ab6dca6d3
commit fb298e80c3
2 changed files with 105 additions and 49 deletions

View File

@ -30,8 +30,6 @@
use crate::fn_ctxt::FnCtxt; use crate::fn_ctxt::FnCtxt;
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
/// employing the ExprUseVisitor. /// employing the ExprUseVisitor.
pub trait Delegate<'tcx> { pub trait Delegate<'tcx> {
@ -219,6 +217,8 @@ fn tcx(&self) -> TyCtxt<'tcx> {
/// This is the code that actually walks the tree. /// This is the code that actually walks the tree.
pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> { pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> {
cx: Cx, cx: Cx,
/// We use a `RefCell` here so that delegates can mutate themselves, but we can
/// still have calls to our own helper functions.
delegate: RefCell<D>, delegate: RefCell<D>,
upvars: Option<&'tcx FxIndexMap<HirId, hir::Upvar>>, upvars: Option<&'tcx FxIndexMap<HirId, hir::Upvar>>,
} }
@ -517,14 +517,14 @@ fn maybe_read_scrutinee<'t>(
discr: &Expr<'_>, discr: &Expr<'_>,
discr_place: PlaceWithHirId<'tcx>, discr_place: PlaceWithHirId<'tcx>,
pats: impl Iterator<Item = &'t hir::Pat<'t>>, pats: impl Iterator<Item = &'t hir::Pat<'t>>,
) -> McResult<()> { ) -> Result<(), ErrorGuaranteed> {
// Matching should not always be considered a use of the place, hence // Matching should not always be considered a use of the place, hence
// discr does not necessarily need to be borrowed. // discr does not necessarily need to be borrowed.
// We only want to borrow discr if the pattern contain something other // We only want to borrow discr if the pattern contain something other
// than wildcards. // than wildcards.
let mut needs_to_be_read = false; let mut needs_to_be_read = false;
for pat in pats { for pat in pats {
self.cat_pattern(discr_place.clone(), pat, |place, pat| { self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
match &pat.kind { match &pat.kind {
PatKind::Binding(.., opt_sub_pat) => { PatKind::Binding(.., opt_sub_pat) => {
// If the opt_sub_pat is None, then the binding does not count as // If the opt_sub_pat is None, then the binding does not count as
@ -836,7 +836,7 @@ fn walk_pat(&self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>, has_g
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.cx.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, &mut |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) =
@ -1021,8 +1021,61 @@ fn upvar_is_local_variable(
} }
} }
} }
}
fn resolve_type_vars_or_error(&self, id: HirId, ty: Option<Ty<'tcx>>) -> McResult<Ty<'tcx>> { /// The job of the categorization methods is to analyze an expression to
/// determine what kind of memory is used in evaluating it (for example,
/// where dereferences occur and what kind of pointer is dereferenced;
/// whether the memory is mutable, etc.).
///
/// Categorization effectively transforms all of our expressions into
/// expressions of the following forms (the actual enum has many more
/// possibilities, naturally, but they are all variants of these base
/// forms):
/// ```ignore (not-rust)
/// E = rvalue // some computed rvalue
/// | x // address of a local variable or argument
/// | *E // deref of a ptr
/// | E.comp // access to an interior component
/// ```
/// Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
/// address where the result is to be found. If Expr is a place, then this
/// is the address of the place. If `Expr` is an rvalue, this is the address of
/// some temporary spot in memory where the result is stored.
///
/// Now, `cat_expr()` classifies the expression `Expr` and the address `A = ToAddr(Expr)`
/// as follows:
///
/// - `cat`: what kind of expression was this? This is a subset of the
/// full expression forms which only includes those that we care about
/// for the purpose of the analysis.
/// - `mutbl`: mutability of the address `A`.
/// - `ty`: the type of data found at the address `A`.
///
/// The resulting categorization tree differs somewhat from the expressions
/// themselves. For example, auto-derefs are explicit. Also, an index `a[b]` is
/// decomposed into two operations: a dereference to reach the array data and
/// then an index to jump forward to the relevant item.
///
/// ## By-reference upvars
///
/// One part of the codegen which may be non-obvious is that we translate
/// closure upvars into the dereference of a borrowed pointer; this more closely
/// resembles the runtime codegen. So, for example, if we had:
///
/// let mut x = 3;
/// let y = 5;
/// let inc = || x += y;
///
/// Then when we categorize `x` (*within* the closure) we would yield a
/// result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference
/// tied to `x`. The type of `x'` will be a borrowed pointer.
impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> {
fn resolve_type_vars_or_error(
&self,
id: HirId,
ty: Option<Ty<'tcx>>,
) -> Result<Ty<'tcx>, ErrorGuaranteed> {
match ty { match ty {
Some(ty) => { Some(ty) => {
let ty = self.cx.resolve_vars_if_possible(ty); let ty = self.cx.resolve_vars_if_possible(ty);
@ -1051,15 +1104,15 @@ fn resolve_type_vars_or_error(&self, id: HirId, ty: Option<Ty<'tcx>>) -> McResul
} }
} }
fn node_ty(&self, hir_id: HirId) -> McResult<Ty<'tcx>> { fn node_ty(&self, hir_id: HirId) -> Result<Ty<'tcx>, ErrorGuaranteed> {
self.resolve_type_vars_or_error(hir_id, self.cx.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<'_>) -> Result<Ty<'tcx>, ErrorGuaranteed> {
self.resolve_type_vars_or_error(expr.hir_id, self.cx.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<'_>) -> Result<Ty<'tcx>, ErrorGuaranteed> {
self.resolve_type_vars_or_error( self.resolve_type_vars_or_error(
expr.hir_id, expr.hir_id,
self.cx.typeck_results().expr_ty_adjusted_opt(expr), self.cx.typeck_results().expr_ty_adjusted_opt(expr),
@ -1076,7 +1129,7 @@ fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> {
/// implicit deref patterns attached (e.g., it is really /// implicit deref patterns attached (e.g., it is really
/// `&Some(x)`). In that case, we return the "outermost" type /// `&Some(x)`). In that case, we return the "outermost" type
/// (e.g., `&Option<T>`). /// (e.g., `&Option<T>`).
fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> { fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> Result<Ty<'tcx>, ErrorGuaranteed> {
// Check for implicit `&` types wrapping the pattern; note // Check for implicit `&` types wrapping the pattern; note
// 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
@ -1091,8 +1144,8 @@ fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
self.pat_ty_unadjusted(pat) self.pat_ty_unadjusted(pat)
} }
/// Like `pat_ty`, but ignores implicit `&` patterns. /// Like `TypeckResults::pat_ty`, but ignores implicit `&` patterns.
fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> { fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> Result<Ty<'tcx>, ErrorGuaranteed> {
let base_ty = self.node_ty(pat.hir_id)?; let base_ty = self.node_ty(pat.hir_id)?;
trace!(?base_ty); trace!(?base_ty);
@ -1134,7 +1187,7 @@ fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
} }
} }
fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> { fn cat_expr(&self, expr: &hir::Expr<'_>) -> Result<PlaceWithHirId<'tcx>, ErrorGuaranteed> {
self.cat_expr_(expr, self.cx.typeck_results().expr_adjustments(expr)) self.cat_expr_(expr, self.cx.typeck_results().expr_adjustments(expr))
} }
@ -1144,7 +1197,7 @@ fn cat_expr_(
&self, &self,
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
adjustments: &[adjustment::Adjustment<'tcx>], adjustments: &[adjustment::Adjustment<'tcx>],
) -> McResult<PlaceWithHirId<'tcx>> { ) -> Result<PlaceWithHirId<'tcx>, ErrorGuaranteed> {
match adjustments.split_last() { match adjustments.split_last() {
None => self.cat_expr_unadjusted(expr), None => self.cat_expr_unadjusted(expr),
Some((adjustment, previous)) => { Some((adjustment, previous)) => {
@ -1158,7 +1211,7 @@ fn cat_expr_adjusted(
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
previous: PlaceWithHirId<'tcx>, previous: PlaceWithHirId<'tcx>,
adjustment: &adjustment::Adjustment<'tcx>, adjustment: &adjustment::Adjustment<'tcx>,
) -> McResult<PlaceWithHirId<'tcx>> { ) -> Result<PlaceWithHirId<'tcx>, ErrorGuaranteed> {
self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment) self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
} }
@ -1167,9 +1220,9 @@ fn cat_expr_adjusted_with<F>(
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
previous: F, previous: F,
adjustment: &adjustment::Adjustment<'tcx>, adjustment: &adjustment::Adjustment<'tcx>,
) -> McResult<PlaceWithHirId<'tcx>> ) -> Result<PlaceWithHirId<'tcx>, ErrorGuaranteed>
where where
F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>, F: FnOnce() -> Result<PlaceWithHirId<'tcx>, ErrorGuaranteed>,
{ {
let target = self.cx.resolve_vars_if_possible(adjustment.target); let target = self.cx.resolve_vars_if_possible(adjustment.target);
match adjustment.kind { match adjustment.kind {
@ -1194,7 +1247,10 @@ fn cat_expr_adjusted_with<F>(
} }
} }
fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> { fn cat_expr_unadjusted(
&self,
expr: &hir::Expr<'_>,
) -> Result<PlaceWithHirId<'tcx>, ErrorGuaranteed> {
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) => {
@ -1285,7 +1341,7 @@ fn cat_res(
span: Span, span: Span,
expr_ty: Ty<'tcx>, expr_ty: Ty<'tcx>,
res: Res, res: Res,
) -> McResult<PlaceWithHirId<'tcx>> { ) -> Result<PlaceWithHirId<'tcx>, ErrorGuaranteed> {
match res { match res {
Res::Def( Res::Def(
DefKind::Ctor(..) DefKind::Ctor(..)
@ -1319,7 +1375,11 @@ fn cat_res(
/// 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.
fn cat_upvar(&self, hir_id: HirId, var_id: HirId) -> McResult<PlaceWithHirId<'tcx>> { fn cat_upvar(
&self,
hir_id: HirId,
var_id: HirId,
) -> Result<PlaceWithHirId<'tcx>, ErrorGuaranteed> {
let closure_expr_def_id = self.cx.body_owner_def_id(); let closure_expr_def_id = self.cx.body_owner_def_id();
let upvar_id = ty::UpvarId { let upvar_id = ty::UpvarId {
@ -1368,7 +1428,7 @@ fn cat_overloaded_place(
&self, &self,
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
base: &hir::Expr<'_>, base: &hir::Expr<'_>,
) -> McResult<PlaceWithHirId<'tcx>> { ) -> Result<PlaceWithHirId<'tcx>, ErrorGuaranteed> {
// Reconstruct the output assuming it's a reference with the // Reconstruct the output assuming it's a reference with the
// same region and mutability as the receiver. This holds for // same region and mutability as the receiver. This holds for
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
@ -1390,7 +1450,7 @@ fn cat_deref(
&self, &self,
node: HirId, node: HirId,
base_place: PlaceWithHirId<'tcx>, base_place: PlaceWithHirId<'tcx>,
) -> McResult<PlaceWithHirId<'tcx>> { ) -> Result<PlaceWithHirId<'tcx>, ErrorGuaranteed> {
let base_curr_ty = base_place.place.ty(); let base_curr_ty = base_place.place.ty();
let deref_ty = match self let deref_ty = match self
.cx .cx
@ -1415,18 +1475,6 @@ fn cat_deref(
Ok(PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections)) Ok(PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections))
} }
fn cat_pattern<F>(
&self,
place: PlaceWithHirId<'tcx>,
pat: &hir::Pat<'_>,
mut op: F,
) -> McResult<()>
where
F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
{
self.cat_pattern_(place, pat, &mut op)
}
/// Returns the variant index for an ADT used within a Struct or TupleStruct pattern /// Returns the variant index for an ADT used within a Struct or TupleStruct pattern
/// Here `pat_hir_id` is the HirId of the pattern itself. /// Here `pat_hir_id` is the HirId of the pattern itself.
fn variant_index_for_adt( fn variant_index_for_adt(
@ -1434,7 +1482,7 @@ fn variant_index_for_adt(
qpath: &hir::QPath<'_>, qpath: &hir::QPath<'_>,
pat_hir_id: HirId, pat_hir_id: HirId,
span: Span, span: Span,
) -> McResult<VariantIdx> { ) -> Result<VariantIdx, ErrorGuaranteed> {
let res = self.cx.typeck_results().qpath_res(qpath, pat_hir_id); let res = self.cx.typeck_results().qpath_res(qpath, pat_hir_id);
let ty = self.cx.typeck_results().node_type(pat_hir_id); let ty = self.cx.typeck_results().node_type(pat_hir_id);
let ty::Adt(adt_def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() else { let ty::Adt(adt_def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() else {
@ -1469,7 +1517,7 @@ fn total_fields_in_adt_variant(
pat_hir_id: HirId, pat_hir_id: HirId,
variant_index: VariantIdx, variant_index: VariantIdx,
span: Span, span: Span,
) -> McResult<usize> { ) -> Result<usize, ErrorGuaranteed> {
let ty = self.cx.typeck_results().node_type(pat_hir_id); let ty = self.cx.typeck_results().node_type(pat_hir_id);
match self.cx.try_structurally_resolve_type(span, ty).kind() { match self.cx.try_structurally_resolve_type(span, 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()),
@ -1484,7 +1532,11 @@ fn total_fields_in_adt_variant(
/// 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,
) -> Result<usize, ErrorGuaranteed> {
let ty = self.cx.typeck_results().node_type(pat_hir_id); let ty = self.cx.typeck_results().node_type(pat_hir_id);
match self.cx.try_structurally_resolve_type(span, ty).kind() { match self.cx.try_structurally_resolve_type(span, ty).kind() {
ty::Tuple(args) => Ok(args.len()), ty::Tuple(args) => Ok(args.len()),
@ -1502,12 +1554,12 @@ fn total_fields_in_tuple(&self, pat_hir_id: HirId, span: Span) -> McResult<usize
/// 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.
fn cat_pattern_<F>( fn cat_pattern<F>(
&self, &self,
mut place_with_id: PlaceWithHirId<'tcx>, mut place_with_id: PlaceWithHirId<'tcx>,
pat: &hir::Pat<'_>, pat: &hir::Pat<'_>,
op: &mut F, op: &mut F,
) -> McResult<()> ) -> Result<(), ErrorGuaranteed>
where where
F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>), F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
{ {
@ -1578,7 +1630,7 @@ fn cat_pattern_<F>(
subpat_ty, subpat_ty,
projection_kind, projection_kind,
); );
self.cat_pattern_(sub_place, subpat, op)?; self.cat_pattern(sub_place, subpat, op)?;
} }
} }
@ -1598,7 +1650,7 @@ fn cat_pattern_<F>(
subpat_ty, subpat_ty,
projection_kind, projection_kind,
); );
self.cat_pattern_(sub_place, subpat, op)?; self.cat_pattern(sub_place, subpat, op)?;
} }
} }
@ -1623,18 +1675,18 @@ fn cat_pattern_<F>(
field_ty, field_ty,
ProjectionKind::Field(field_index, variant_index), ProjectionKind::Field(field_index, variant_index),
); );
self.cat_pattern_(field_place, fp.pat, op)?; self.cat_pattern(field_place, fp.pat, op)?;
} }
} }
PatKind::Or(pats) => { PatKind::Or(pats) => {
for pat in pats { for pat in pats {
self.cat_pattern_(place_with_id.clone(), pat, op)?; self.cat_pattern(place_with_id.clone(), pat, op)?;
} }
} }
PatKind::Binding(.., Some(subpat)) => { PatKind::Binding(.., Some(subpat)) => {
self.cat_pattern_(place_with_id, subpat, op)?; self.cat_pattern(place_with_id, subpat, op)?;
} }
PatKind::Box(subpat) | PatKind::Ref(subpat, _) => { PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
@ -1642,7 +1694,7 @@ fn cat_pattern_<F>(
// PatKind::Ref since that information is already contained // PatKind::Ref since that information is already contained
// in the type. // in the type.
let subplace = self.cat_deref(pat.hir_id, place_with_id)?; let subplace = self.cat_deref(pat.hir_id, place_with_id)?;
self.cat_pattern_(subplace, subpat, op)?; self.cat_pattern(subplace, subpat, op)?;
} }
PatKind::Deref(subpat) => { PatKind::Deref(subpat) => {
let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpat); let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpat);
@ -1652,7 +1704,7 @@ fn cat_pattern_<F>(
let ty = Ty::new_ref(self.cx.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)?;
} }
PatKind::Slice(before, ref slice, after) => { PatKind::Slice(before, ref slice, after) => {
@ -1671,7 +1723,7 @@ fn cat_pattern_<F>(
ProjectionKind::Index, ProjectionKind::Index,
); );
for before_pat in before { for before_pat in before {
self.cat_pattern_(elt_place.clone(), before_pat, op)?; self.cat_pattern(elt_place.clone(), before_pat, op)?;
} }
if let Some(slice_pat) = *slice { if let Some(slice_pat) = *slice {
let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?; let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?;
@ -1681,10 +1733,10 @@ fn cat_pattern_<F>(
slice_pat_ty, slice_pat_ty,
ProjectionKind::Subslice, ProjectionKind::Subslice,
); );
self.cat_pattern_(slice_place, slice_pat, op)?; self.cat_pattern(slice_place, slice_pat, op)?;
} }
for after_pat in after { for after_pat in after {
self.cat_pattern_(elt_place.clone(), after_pat, op)?; self.cat_pattern(elt_place.clone(), after_pat, op)?;
} }
} }

View File

@ -1,6 +1,10 @@
//@ compile-flags: -Znext-solver //@ compile-flags: -Znext-solver
//@ check-pass //@ check-pass
// Fixes a regression in icu_provider_adaptors where we weren't normalizing the
// return type of a function type before performing a `Ty::builtin_deref` call,
// leading to an ICE.
struct Struct { struct Struct {
field: i32, field: i32,
} }