2014-11-25 21:17:11 -05:00
|
|
|
//! # Categorization
|
|
|
|
//!
|
|
|
|
//! The job of the categorization module 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;
|
2019-02-08 14:53:55 +01:00
|
|
|
//! whether the memory is mutable, etc.).
|
2014-11-25 21:17:11 -05:00
|
|
|
//!
|
|
|
|
//! 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):
|
2022-04-15 15:04:34 -07:00
|
|
|
//! ```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
|
|
|
|
//! ```
|
2014-11-25 21:17:11 -05:00
|
|
|
//! Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
|
2019-02-08 14:53:55 +01:00
|
|
|
//! 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
|
2014-11-25 21:17:11 -05:00
|
|
|
//! some temporary spot in memory where the result is stored.
|
|
|
|
//!
|
2019-02-08 14:53:55 +01:00
|
|
|
//! Now, `cat_expr()` classifies the expression `Expr` and the address `A = ToAddr(Expr)`
|
2014-11-25 21:17:11 -05:00
|
|
|
//! as follows:
|
|
|
|
//!
|
2019-02-08 14:53:55 +01:00
|
|
|
//! - `cat`: what kind of expression was this? This is a subset of the
|
2014-11-25 21:17:11 -05:00
|
|
|
//! full expression forms which only includes those that we care about
|
|
|
|
//! for the purpose of the analysis.
|
2019-02-08 14:53:55 +01:00
|
|
|
//! - `mutbl`: mutability of the address `A`.
|
|
|
|
//! - `ty`: the type of data found at the address `A`.
|
2014-11-25 21:17:11 -05:00
|
|
|
//!
|
|
|
|
//! The resulting categorization tree differs somewhat from the expressions
|
2020-05-01 22:28:15 +02:00
|
|
|
//! themselves. For example, auto-derefs are explicit. Also, an index `a[b]` is
|
2014-11-25 21:17:11 -05:00
|
|
|
//! 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
|
|
|
|
//!
|
2018-05-08 16:10:16 +03:00
|
|
|
//! One part of the codegen which may be non-obvious is that we translate
|
2014-11-25 21:17:11 -05:00
|
|
|
//! closure upvars into the dereference of a borrowed pointer; this more closely
|
2018-05-08 16:10:16 +03:00
|
|
|
//! resembles the runtime codegen. So, for example, if we had:
|
2014-11-25 21:17:11 -05:00
|
|
|
//!
|
|
|
|
//! let mut x = 3;
|
|
|
|
//! let y = 5;
|
|
|
|
//! let inc = || x += y;
|
|
|
|
//!
|
|
|
|
//! Then when we categorize `x` (*within* the closure) we would yield a
|
2015-10-03 21:36:16 +02:00
|
|
|
//! result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference
|
2014-11-25 21:17:11 -05:00
|
|
|
//! tied to `x`. The type of `x'` will be a borrowed pointer.
|
2012-06-01 10:46:17 -07:00
|
|
|
|
2020-07-05 22:06:37 -04:00
|
|
|
use rustc_middle::hir::place::*;
|
2020-03-29 16:41:09 +02:00
|
|
|
use rustc_middle::ty::adjustment;
|
|
|
|
use rustc_middle::ty::fold::TypeFoldable;
|
2022-06-17 13:15:00 +01:00
|
|
|
use rustc_middle::ty::visit::TypeVisitable;
|
2020-03-29 16:41:09 +02:00
|
|
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
2020-01-06 23:12:31 +01:00
|
|
|
|
2019-05-20 21:51:55 +03:00
|
|
|
use rustc_data_structures::fx::FxIndexMap;
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_hir as hir;
|
2020-07-01 23:48:48 -04:00
|
|
|
use rustc_hir::def::{CtorOf, DefKind, Res};
|
2020-04-18 16:06:06 +01:00
|
|
|
use rustc_hir::def_id::LocalDefId;
|
2020-07-01 23:48:48 -04:00
|
|
|
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_hir::PatKind;
|
2020-07-01 23:48:48 -04:00
|
|
|
use rustc_index::vec::Idx;
|
2020-01-06 23:12:31 +01:00
|
|
|
use rustc_infer::infer::InferCtxt;
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_span::Span;
|
2020-07-01 23:48:48 -04:00
|
|
|
use rustc_target::abi::VariantIdx;
|
2020-02-11 21:19:40 +01:00
|
|
|
use rustc_trait_selection::infer::InferCtxtExt;
|
2014-04-10 16:26:26 +03:00
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) trait HirNode {
|
2018-06-02 18:50:40 -07:00
|
|
|
fn hir_id(&self) -> hir::HirId;
|
2013-08-31 18:13:04 +02:00
|
|
|
fn span(&self) -> Span;
|
2012-08-08 08:15:32 -07:00
|
|
|
}
|
|
|
|
|
2019-11-30 15:08:22 +01:00
|
|
|
impl HirNode for hir::Expr<'_> {
|
2018-06-02 18:50:40 -07:00
|
|
|
fn hir_id(&self) -> hir::HirId {
|
|
|
|
self.hir_id
|
|
|
|
}
|
2013-08-31 18:13:04 +02:00
|
|
|
fn span(&self) -> Span {
|
|
|
|
self.span
|
|
|
|
}
|
2012-08-08 08:15:32 -07:00
|
|
|
}
|
|
|
|
|
2019-11-30 15:08:22 +01:00
|
|
|
impl HirNode for hir::Pat<'_> {
|
2018-06-02 18:50:40 -07:00
|
|
|
fn hir_id(&self) -> hir::HirId {
|
|
|
|
self.hir_id
|
|
|
|
}
|
2013-08-31 18:13:04 +02:00
|
|
|
fn span(&self) -> Span {
|
|
|
|
self.span
|
|
|
|
}
|
2012-08-08 08:15:32 -07:00
|
|
|
}
|
|
|
|
|
2017-04-10 00:00:08 -07:00
|
|
|
#[derive(Clone)]
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) struct MemCategorizationContext<'a, 'tcx> {
|
|
|
|
pub(crate) typeck_results: &'a ty::TypeckResults<'tcx>,
|
2022-09-09 13:01:06 -05:00
|
|
|
infcx: &'a InferCtxt<'tcx>,
|
2019-11-08 22:11:03 +00:00
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2020-04-18 16:06:06 +01:00
|
|
|
body_owner: LocalDefId,
|
2019-11-08 22:11:03 +00:00
|
|
|
upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
|
2015-03-30 09:38:44 -04:00
|
|
|
}
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 17:01:33 -08:00
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) type McResult<T> = Result<T, ()>;
|
2015-01-02 03:51:49 -05:00
|
|
|
|
2019-06-14 00:48:52 +03:00
|
|
|
impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
2019-11-08 22:11:03 +00:00
|
|
|
/// Creates a `MemCategorizationContext`.
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn new(
|
2022-09-09 13:01:06 -05:00
|
|
|
infcx: &'a InferCtxt<'tcx>,
|
2019-03-26 00:13:09 +01:00
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2020-04-18 16:06:06 +01:00
|
|
|
body_owner: LocalDefId,
|
2020-07-17 08:47:04 +00:00
|
|
|
typeck_results: &'a ty::TypeckResults<'tcx>,
|
2019-06-14 00:48:52 +03:00
|
|
|
) -> MemCategorizationContext<'a, 'tcx> {
|
2017-09-11 13:09:14 -04:00
|
|
|
MemCategorizationContext {
|
2020-07-17 08:47:04 +00:00
|
|
|
typeck_results,
|
2019-11-08 22:11:03 +00:00
|
|
|
infcx,
|
2019-03-26 00:13:09 +01:00
|
|
|
param_env,
|
2019-11-08 22:11:03 +00:00
|
|
|
body_owner,
|
2020-05-23 19:29:49 -04:00
|
|
|
upvars: infcx.tcx.upvars_mentioned(body_owner),
|
2017-09-11 13:09:14 -04:00
|
|
|
}
|
2017-06-08 23:57:16 +03:00
|
|
|
}
|
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn tcx(&self) -> TyCtxt<'tcx> {
|
2019-11-08 22:11:03 +00:00
|
|
|
self.infcx.tcx
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
2019-11-08 22:11:03 +00:00
|
|
|
self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span)
|
2014-02-07 14:41:58 -05:00
|
|
|
}
|
|
|
|
|
2020-10-24 02:21:18 +02:00
|
|
|
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
2017-06-08 23:57:01 +03:00
|
|
|
where
|
|
|
|
T: TypeFoldable<'tcx>,
|
|
|
|
{
|
2019-11-08 22:11:03 +00:00
|
|
|
self.infcx.resolve_vars_if_possible(value)
|
2017-06-08 23:57:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn is_tainted_by_errors(&self) -> bool {
|
2019-11-08 22:11:03 +00:00
|
|
|
self.infcx.is_tainted_by_errors()
|
2017-06-08 23:57:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_type_vars_or_error(
|
|
|
|
&self,
|
2017-08-07 14:43:43 +02:00
|
|
|
id: hir::HirId,
|
2017-06-08 23:57:01 +03:00
|
|
|
ty: Option<Ty<'tcx>>,
|
|
|
|
) -> McResult<Ty<'tcx>> {
|
|
|
|
match ty {
|
|
|
|
Some(ty) => {
|
2020-10-24 02:21:18 +02:00
|
|
|
let ty = self.resolve_vars_if_possible(ty);
|
2017-06-08 23:57:01 +03:00
|
|
|
if ty.references_error() || ty.is_ty_var() {
|
|
|
|
debug!("resolve_type_vars_or_error: error from {:?}", ty);
|
|
|
|
Err(())
|
|
|
|
} else {
|
|
|
|
Ok(ty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// FIXME
|
|
|
|
None if self.is_tainted_by_errors() => Err(()),
|
|
|
|
None => {
|
|
|
|
bug!(
|
|
|
|
"no type for node {}: {} in mem_categorization",
|
2019-11-08 22:11:03 +00:00
|
|
|
id,
|
|
|
|
self.tcx().hir().node_to_string(id)
|
|
|
|
);
|
2015-07-17 08:21:11 -04:00
|
|
|
}
|
|
|
|
}
|
2013-05-03 12:11:15 -04:00
|
|
|
}
|
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn node_ty(&self, hir_id: hir::HirId) -> McResult<Ty<'tcx>> {
|
2020-07-17 08:47:04 +00:00
|
|
|
self.resolve_type_vars_or_error(hir_id, self.typeck_results.node_type_opt(hir_id))
|
2017-06-08 23:57:01 +03:00
|
|
|
}
|
|
|
|
|
2019-11-30 15:08:22 +01:00
|
|
|
fn expr_ty(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> {
|
2020-07-17 08:47:04 +00:00
|
|
|
self.resolve_type_vars_or_error(expr.hir_id, self.typeck_results.expr_ty_opt(expr))
|
2013-05-03 12:11:15 -04:00
|
|
|
}
|
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> {
|
2020-07-17 08:47:04 +00:00
|
|
|
self.resolve_type_vars_or_error(expr.hir_id, self.typeck_results.expr_ty_adjusted_opt(expr))
|
2014-02-07 14:41:58 -05:00
|
|
|
}
|
|
|
|
|
2018-04-05 17:16:07 -04:00
|
|
|
/// Returns the type of value that this pattern matches against.
|
|
|
|
/// Some non-obvious cases:
|
|
|
|
///
|
|
|
|
/// - a `ref x` binding matches against a value of type `T` and gives
|
|
|
|
/// `x` the type `&T`; we return `T`.
|
|
|
|
/// - a pattern with implicit derefs (thanks to default binding
|
|
|
|
/// modes #42640) may look like `Some(x)` but in fact have
|
|
|
|
/// implicit deref patterns attached (e.g., it is really
|
|
|
|
/// `&Some(x)`). In that case, we return the "outermost" type
|
2022-10-09 16:15:23 +02:00
|
|
|
/// (e.g., `&Option<T>`).
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
|
2018-04-05 17:16:07 -04:00
|
|
|
// Check for implicit `&` types wrapping the pattern; note
|
|
|
|
// that these are never attached to binding patterns, so
|
|
|
|
// actually this is somewhat "disjoint" from the code below
|
|
|
|
// that aims to account for `ref x`.
|
2020-07-17 08:47:04 +00:00
|
|
|
if let Some(vec) = self.typeck_results.pat_adjustments().get(pat.hir_id) {
|
2018-04-05 17:16:07 -04:00
|
|
|
if let Some(first_ty) = vec.first() {
|
|
|
|
debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
|
Overhaul `TyS` and `Ty`.
Specifically, change `Ty` from this:
```
pub type Ty<'tcx> = &'tcx TyS<'tcx>;
```
to this
```
pub struct Ty<'tcx>(Interned<'tcx, TyS<'tcx>>);
```
There are two benefits to this.
- It's now a first class type, so we can define methods on it. This
means we can move a lot of methods away from `TyS`, leaving `TyS` as a
barely-used type, which is appropriate given that it's not meant to
be used directly.
- The uniqueness requirement is now explicit, via the `Interned` type.
E.g. the pointer-based `Eq` and `Hash` comes from `Interned`, rather
than via `TyS`, which wasn't obvious at all.
Much of this commit is boring churn. The interesting changes are in
these files:
- compiler/rustc_middle/src/arena.rs
- compiler/rustc_middle/src/mir/visit.rs
- compiler/rustc_middle/src/ty/context.rs
- compiler/rustc_middle/src/ty/mod.rs
Specifically:
- Most mentions of `TyS` are removed. It's very much a dumb struct now;
`Ty` has all the smarts.
- `TyS` now has `crate` visibility instead of `pub`.
- `TyS::make_for_test` is removed in favour of the static `BOOL_TY`,
which just works better with the new structure.
- The `Eq`/`Ord`/`Hash` impls are removed from `TyS`. `Interned`s impls
of `Eq`/`Hash` now suffice. `Ord` is now partly on `Interned`
(pointer-based, for the `Equal` case) and partly on `TyS`
(contents-based, for the other cases).
- There are many tedious sigil adjustments, i.e. adding or removing `*`
or `&`. They seem to be unavoidable.
2022-01-25 14:13:38 +11:00
|
|
|
return Ok(*first_ty);
|
2018-04-05 17:16:07 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.pat_ty_unadjusted(pat)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Like `pat_ty`, but ignores implicit `&` patterns.
|
2019-11-30 15:08:22 +01:00
|
|
|
fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
|
2017-08-07 14:43:43 +02:00
|
|
|
let base_ty = self.node_ty(pat.hir_id)?;
|
2018-04-05 17:16:07 -04:00
|
|
|
debug!("pat_ty(pat={:?}) base_ty={:?}", pat, base_ty);
|
|
|
|
|
2017-10-07 13:19:34 +03:00
|
|
|
// This code detects whether we are looking at a `ref x`,
|
|
|
|
// and if so, figures out what the type *being borrowed* is.
|
2019-09-26 16:18:31 +01:00
|
|
|
let ret_ty = match pat.kind {
|
2017-07-21 19:29:43 -04:00
|
|
|
PatKind::Binding(..) => {
|
2020-07-17 08:47:04 +00:00
|
|
|
let bm = *self
|
|
|
|
.typeck_results
|
|
|
|
.pat_binding_modes()
|
|
|
|
.get(pat.hir_id)
|
|
|
|
.expect("missing binding mode");
|
2017-08-07 15:06:10 +02:00
|
|
|
|
2017-07-21 19:29:43 -04:00
|
|
|
if let ty::BindByReference(_) = bm {
|
|
|
|
// a bind-by-ref means that the base_ty will be the type of the ident itself,
|
|
|
|
// but what we want here is the type of the underlying value being borrowed.
|
|
|
|
// So peel off one-level, turning the &T into T.
|
2018-01-28 23:29:40 +02:00
|
|
|
match base_ty.builtin_deref(false) {
|
2017-07-21 19:29:43 -04:00
|
|
|
Some(t) => t.ty,
|
|
|
|
None => {
|
|
|
|
debug!("By-ref binding of non-derefable type {:?}", base_ty);
|
|
|
|
return Err(());
|
|
|
|
}
|
2017-04-27 16:40:49 +03:00
|
|
|
}
|
2017-07-21 19:29:43 -04:00
|
|
|
} else {
|
|
|
|
base_ty
|
2015-01-02 03:54:45 -05:00
|
|
|
}
|
2014-10-14 03:21:54 +02:00
|
|
|
}
|
|
|
|
_ => base_ty,
|
|
|
|
};
|
2018-04-05 17:16:07 -04:00
|
|
|
debug!("pat_ty(pat={:?}) ret_ty={:?}", pat, ret_ty);
|
|
|
|
|
2015-01-02 03:54:45 -05:00
|
|
|
Ok(ret_ty)
|
2014-02-07 14:41:58 -05:00
|
|
|
}
|
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
|
2017-05-27 10:29:24 +03:00
|
|
|
// This recursion helper avoids going through *too many*
|
|
|
|
// adjustments, since *only* non-overloaded deref recurses.
|
2019-06-14 01:32:15 +03:00
|
|
|
fn helper<'a, 'tcx>(
|
|
|
|
mc: &MemCategorizationContext<'a, 'tcx>,
|
2019-11-30 15:08:22 +01:00
|
|
|
expr: &hir::Expr<'_>,
|
2019-06-14 01:32:15 +03:00
|
|
|
adjustments: &[adjustment::Adjustment<'tcx>],
|
2020-06-17 18:13:05 -04:00
|
|
|
) -> McResult<PlaceWithHirId<'tcx>> {
|
2017-05-27 10:29:24 +03:00
|
|
|
match adjustments.split_last() {
|
|
|
|
None => mc.cat_expr_unadjusted(expr),
|
|
|
|
Some((adjustment, previous)) => {
|
|
|
|
mc.cat_expr_adjusted_with(expr, || helper(mc, expr, previous), adjustment)
|
|
|
|
}
|
2012-09-11 21:25:01 -07:00
|
|
|
}
|
2017-05-27 10:29:24 +03:00
|
|
|
}
|
2012-09-11 21:25:01 -07:00
|
|
|
|
2020-07-17 08:47:04 +00:00
|
|
|
helper(self, expr, self.typeck_results.expr_adjustments(expr))
|
2017-05-27 10:29:24 +03:00
|
|
|
}
|
2015-03-16 18:45:01 +02:00
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn cat_expr_adjusted(
|
2019-11-09 10:38:06 +00:00
|
|
|
&self,
|
2019-11-30 15:08:22 +01:00
|
|
|
expr: &hir::Expr<'_>,
|
2020-06-17 18:13:05 -04:00
|
|
|
previous: PlaceWithHirId<'tcx>,
|
2017-05-27 10:29:24 +03:00
|
|
|
adjustment: &adjustment::Adjustment<'tcx>,
|
2020-06-17 18:13:05 -04:00
|
|
|
) -> McResult<PlaceWithHirId<'tcx>> {
|
2017-05-27 10:29:24 +03:00
|
|
|
self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
|
|
|
|
}
|
|
|
|
|
2022-05-18 16:01:10 +00:00
|
|
|
#[instrument(level = "debug", skip(self, previous))]
|
2017-05-27 10:29:24 +03:00
|
|
|
fn cat_expr_adjusted_with<F>(
|
|
|
|
&self,
|
2019-11-30 15:08:22 +01:00
|
|
|
expr: &hir::Expr<'_>,
|
2017-05-27 10:29:24 +03:00
|
|
|
previous: F,
|
|
|
|
adjustment: &adjustment::Adjustment<'tcx>,
|
2020-06-17 18:13:05 -04:00
|
|
|
) -> McResult<PlaceWithHirId<'tcx>>
|
2019-11-08 21:53:36 +00:00
|
|
|
where
|
2020-06-17 18:13:05 -04:00
|
|
|
F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>,
|
2017-05-27 10:29:24 +03:00
|
|
|
{
|
2020-10-24 02:21:18 +02:00
|
|
|
let target = self.resolve_vars_if_possible(adjustment.target);
|
2017-05-27 10:29:24 +03:00
|
|
|
match adjustment.kind {
|
|
|
|
adjustment::Adjust::Deref(overloaded) => {
|
|
|
|
// Equivalent to *expr or something similar.
|
2019-11-08 22:54:00 +00:00
|
|
|
let base = if let Some(deref) = overloaded {
|
2019-11-08 22:11:03 +00:00
|
|
|
let ref_ty = self
|
|
|
|
.tcx()
|
|
|
|
.mk_ref(deref.region, ty::TypeAndMut { ty: target, mutbl: deref.mutbl });
|
2019-11-08 22:54:00 +00:00
|
|
|
self.cat_rvalue(expr.hir_id, expr.span, ref_ty)
|
2017-05-27 10:29:24 +03:00
|
|
|
} else {
|
|
|
|
previous()?
|
2019-11-08 22:54:00 +00:00
|
|
|
};
|
|
|
|
self.cat_deref(expr, base)
|
2017-05-27 10:29:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
adjustment::Adjust::NeverToAny
|
2019-04-16 13:40:04 +05:30
|
|
|
| adjustment::Adjust::Pointer(_)
|
|
|
|
| adjustment::Adjust::Borrow(_) => {
|
2017-05-27 10:29:24 +03:00
|
|
|
// Result is an rvalue.
|
2019-11-08 22:54:00 +00:00
|
|
|
Ok(self.cat_rvalue(expr.hir_id, expr.span, target))
|
2012-09-11 21:25:01 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-07-20 16:37:45 -07:00
|
|
|
|
2022-05-18 16:01:10 +00:00
|
|
|
#[instrument(level = "debug", skip(self))]
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn cat_expr_unadjusted(
|
|
|
|
&self,
|
|
|
|
expr: &hir::Expr<'_>,
|
|
|
|
) -> McResult<PlaceWithHirId<'tcx>> {
|
2019-02-24 09:33:17 +01:00
|
|
|
debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr);
|
2012-06-01 10:46:17 -07:00
|
|
|
|
2016-03-22 22:01:37 -05:00
|
|
|
let expr_ty = self.expr_ty(expr)?;
|
2019-09-26 14:39:48 +01:00
|
|
|
match expr.kind {
|
2021-02-09 11:15:53 +03:00
|
|
|
hir::ExprKind::Unary(hir::UnOp::Deref, ref e_base) => {
|
2020-07-17 08:47:04 +00:00
|
|
|
if self.typeck_results.is_method_call(expr) {
|
2019-11-08 22:54:00 +00:00
|
|
|
self.cat_overloaded_place(expr, e_base)
|
2018-10-02 18:29:48 +02:00
|
|
|
} else {
|
2021-09-30 19:38:50 +02:00
|
|
|
let base = self.cat_expr(e_base)?;
|
2019-11-08 22:54:00 +00:00
|
|
|
self.cat_deref(expr, base)
|
2018-10-02 18:29:48 +02:00
|
|
|
}
|
2017-05-19 12:46:34 +03:00
|
|
|
}
|
2018-10-02 18:29:48 +02:00
|
|
|
|
2019-11-08 22:54:00 +00:00
|
|
|
hir::ExprKind::Field(ref base, _) => {
|
2021-09-30 19:38:50 +02:00
|
|
|
let base = self.cat_expr(base)?;
|
2018-10-02 18:29:48 +02:00
|
|
|
debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base);
|
2020-07-01 23:48:48 -04:00
|
|
|
|
|
|
|
let field_idx = self
|
2020-07-17 08:47:04 +00:00
|
|
|
.typeck_results
|
2020-07-01 23:48:48 -04:00
|
|
|
.field_indices()
|
|
|
|
.get(expr.hir_id)
|
|
|
|
.cloned()
|
|
|
|
.expect("Field index not found");
|
|
|
|
|
|
|
|
Ok(self.cat_projection(
|
|
|
|
expr,
|
|
|
|
base,
|
|
|
|
expr_ty,
|
|
|
|
ProjectionKind::Field(field_idx as u32, VariantIdx::new(0)),
|
|
|
|
))
|
2018-10-02 18:29:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
hir::ExprKind::Index(ref base, _) => {
|
2020-07-17 08:47:04 +00:00
|
|
|
if self.typeck_results.is_method_call(expr) {
|
2018-10-02 18:29:48 +02:00
|
|
|
// If this is an index implemented by a method call, then it
|
|
|
|
// will include an implicit deref of the result.
|
|
|
|
// The call to index() returns a `&T` value, which
|
|
|
|
// is an rvalue. That is what we will be
|
|
|
|
// dereferencing.
|
2019-11-08 22:54:00 +00:00
|
|
|
self.cat_overloaded_place(expr, base)
|
2018-10-02 18:29:48 +02:00
|
|
|
} else {
|
2021-09-30 19:38:50 +02:00
|
|
|
let base = self.cat_expr(base)?;
|
2020-07-01 23:48:48 -04:00
|
|
|
Ok(self.cat_projection(expr, base, expr_ty, ProjectionKind::Index))
|
2018-10-02 18:29:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hir::ExprKind::Path(ref qpath) => {
|
2020-07-17 08:47:04 +00:00
|
|
|
let res = self.typeck_results.qpath_res(qpath, expr.hir_id);
|
2019-04-20 19:36:05 +03:00
|
|
|
self.cat_res(expr.hir_id, expr.span, expr_ty, res)
|
2018-10-02 18:29:48 +02:00
|
|
|
}
|
|
|
|
|
2021-09-30 19:38:50 +02:00
|
|
|
hir::ExprKind::Type(ref e, _) => self.cat_expr(e),
|
2019-12-22 17:42:04 -05:00
|
|
|
|
2018-10-02 18:29:48 +02:00
|
|
|
hir::ExprKind::AddrOf(..)
|
|
|
|
| hir::ExprKind::Call(..)
|
|
|
|
| hir::ExprKind::Assign(..)
|
|
|
|
| hir::ExprKind::AssignOp(..)
|
2022-06-11 21:25:25 +02:00
|
|
|
| hir::ExprKind::Closure { .. }
|
2018-10-02 18:29:48 +02:00
|
|
|
| hir::ExprKind::Ret(..)
|
|
|
|
| hir::ExprKind::Unary(..)
|
|
|
|
| hir::ExprKind::Yield(..)
|
2019-04-30 17:46:59 +02:00
|
|
|
| hir::ExprKind::MethodCall(..)
|
|
|
|
| hir::ExprKind::Cast(..)
|
|
|
|
| hir::ExprKind::DropTemps(..)
|
2019-03-11 16:43:27 +01:00
|
|
|
| hir::ExprKind::Array(..)
|
2021-01-01 15:38:11 -03:00
|
|
|
| hir::ExprKind::If(..)
|
2019-03-11 16:43:27 +01:00
|
|
|
| hir::ExprKind::Tup(..)
|
2019-06-19 17:21:28 +02:00
|
|
|
| hir::ExprKind::Binary(..)
|
2018-10-02 18:29:48 +02:00
|
|
|
| hir::ExprKind::Block(..)
|
2021-08-08 11:49:13 -03:00
|
|
|
| hir::ExprKind::Let(..)
|
2018-10-02 18:29:48 +02:00
|
|
|
| hir::ExprKind::Loop(..)
|
|
|
|
| hir::ExprKind::Match(..)
|
|
|
|
| hir::ExprKind::Lit(..)
|
2020-10-06 17:52:32 -03:00
|
|
|
| hir::ExprKind::ConstBlock(..)
|
2018-10-02 18:29:48 +02:00
|
|
|
| hir::ExprKind::Break(..)
|
|
|
|
| hir::ExprKind::Continue(..)
|
|
|
|
| hir::ExprKind::Struct(..)
|
|
|
|
| hir::ExprKind::Repeat(..)
|
2020-02-13 11:00:55 +00:00
|
|
|
| hir::ExprKind::InlineAsm(..)
|
2018-12-17 04:57:32 +03:00
|
|
|
| hir::ExprKind::Box(..)
|
2019-11-08 22:54:00 +00:00
|
|
|
| hir::ExprKind::Err => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
|
2012-06-01 10:46:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-18 16:01:10 +00:00
|
|
|
#[instrument(level = "debug", skip(self, span))]
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn cat_res(
|
2019-11-08 22:54:00 +00:00
|
|
|
&self,
|
2018-06-02 18:50:40 -07:00
|
|
|
hir_id: hir::HirId,
|
2013-08-31 18:13:04 +02:00
|
|
|
span: Span,
|
2014-09-29 22:11:30 +03:00
|
|
|
expr_ty: Ty<'tcx>,
|
2019-04-20 19:36:05 +03:00
|
|
|
res: Res,
|
2020-06-17 18:13:05 -04:00
|
|
|
) -> McResult<PlaceWithHirId<'tcx>> {
|
2019-04-20 19:36:05 +03:00
|
|
|
match res {
|
2020-04-16 17:38:52 -07:00
|
|
|
Res::Def(
|
|
|
|
DefKind::Ctor(..)
|
|
|
|
| DefKind::Const
|
|
|
|
| DefKind::ConstParam
|
|
|
|
| DefKind::AssocConst
|
|
|
|
| DefKind::Fn
|
|
|
|
| DefKind::AssocFn,
|
|
|
|
_,
|
|
|
|
)
|
2019-11-08 22:54:00 +00:00
|
|
|
| Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, span, expr_ty)),
|
2016-01-17 22:57:54 +03:00
|
|
|
|
2022-03-29 17:11:12 +02:00
|
|
|
Res::Def(DefKind::Static(_), _) => {
|
2020-06-17 18:13:05 -04:00
|
|
|
Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new()))
|
|
|
|
}
|
2018-10-02 18:29:48 +02:00
|
|
|
|
2019-05-20 21:51:55 +03:00
|
|
|
Res::Local(var_id) => {
|
2019-05-28 18:06:01 +03:00
|
|
|
if self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id)) {
|
2020-06-17 18:13:05 -04:00
|
|
|
self.cat_upvar(hir_id, var_id)
|
2019-05-28 18:06:01 +03:00
|
|
|
} else {
|
2020-06-17 18:13:05 -04:00
|
|
|
Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Local(var_id), Vec::new()))
|
2019-05-28 18:06:01 +03:00
|
|
|
}
|
2017-08-08 18:22:51 +03:00
|
|
|
}
|
2015-12-11 20:59:11 +13:00
|
|
|
|
2018-10-02 18:29:48 +02:00
|
|
|
def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def),
|
2012-06-01 10:46:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-08 22:54:00 +00:00
|
|
|
/// Categorize an upvar.
|
|
|
|
///
|
|
|
|
/// Note: the actual upvar access contains invisible derefs of closure
|
|
|
|
/// environment and upvar reference as appropriate. Only regionck cares
|
|
|
|
/// about these dereferences, so we let it compute them as needed.
|
2020-06-17 18:13:05 -04:00
|
|
|
fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult<PlaceWithHirId<'tcx>> {
|
2019-05-22 17:02:40 +03:00
|
|
|
let closure_expr_def_id = self.body_owner;
|
2017-06-08 23:57:01 +03:00
|
|
|
|
2017-08-08 14:34:37 +02:00
|
|
|
let upvar_id = ty::UpvarId {
|
2019-06-14 12:28:47 +02:00
|
|
|
var_path: ty::UpvarPath { hir_id: var_id },
|
2020-04-18 16:06:06 +01:00
|
|
|
closure_expr_id: closure_expr_def_id,
|
2017-08-08 14:34:37 +02:00
|
|
|
};
|
2019-06-14 12:28:47 +02:00
|
|
|
let var_ty = self.node_ty(var_id)?;
|
2014-02-07 14:41:58 -05:00
|
|
|
|
2020-06-17 18:13:05 -04:00
|
|
|
let ret = PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new());
|
2015-01-24 15:54:52 -05:00
|
|
|
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("cat_upvar ret={:?}", ret);
|
2015-03-28 09:52:47 +01:00
|
|
|
Ok(ret)
|
2015-01-24 15:54:52 -05:00
|
|
|
}
|
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn cat_rvalue(
|
2020-06-17 18:13:05 -04:00
|
|
|
&self,
|
|
|
|
hir_id: hir::HirId,
|
|
|
|
span: Span,
|
|
|
|
expr_ty: Ty<'tcx>,
|
|
|
|
) -> PlaceWithHirId<'tcx> {
|
2019-11-08 22:54:00 +00:00
|
|
|
debug!("cat_rvalue hir_id={:?}, expr_ty={:?}, span={:?}", hir_id, expr_ty, span);
|
2020-06-17 18:13:05 -04:00
|
|
|
let ret = PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new());
|
2019-11-08 22:54:00 +00:00
|
|
|
debug!("cat_rvalue ret={:?}", ret);
|
2015-03-28 09:52:47 +01:00
|
|
|
ret
|
2012-06-01 10:46:17 -07:00
|
|
|
}
|
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn cat_projection<N: HirNode>(
|
2019-11-08 22:54:00 +00:00
|
|
|
&self,
|
|
|
|
node: &N,
|
2020-06-17 18:13:05 -04:00
|
|
|
base_place: PlaceWithHirId<'tcx>,
|
2019-11-08 22:54:00 +00:00
|
|
|
ty: Ty<'tcx>,
|
2020-07-01 23:48:48 -04:00
|
|
|
kind: ProjectionKind,
|
2020-06-17 18:13:05 -04:00
|
|
|
) -> PlaceWithHirId<'tcx> {
|
|
|
|
let mut projections = base_place.place.projections;
|
2020-12-29 22:02:47 +01:00
|
|
|
projections.push(Projection { kind, ty });
|
2020-06-24 16:33:31 -04:00
|
|
|
let ret = PlaceWithHirId::new(
|
|
|
|
node.hir_id(),
|
|
|
|
base_place.place.base_ty,
|
|
|
|
base_place.place.base,
|
|
|
|
projections,
|
|
|
|
);
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("cat_field ret {:?}", ret);
|
2015-03-28 09:52:47 +01:00
|
|
|
ret
|
2012-06-01 10:46:17 -07:00
|
|
|
}
|
|
|
|
|
2022-05-18 16:01:10 +00:00
|
|
|
#[instrument(level = "debug", skip(self))]
|
2019-11-30 15:08:22 +01:00
|
|
|
fn cat_overloaded_place(
|
|
|
|
&self,
|
|
|
|
expr: &hir::Expr<'_>,
|
|
|
|
base: &hir::Expr<'_>,
|
2020-06-17 18:13:05 -04:00
|
|
|
) -> McResult<PlaceWithHirId<'tcx>> {
|
2017-05-19 12:46:34 +03:00
|
|
|
// Reconstruct the output assuming it's a reference with the
|
|
|
|
// same region and mutability as the receiver. This holds for
|
|
|
|
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
|
2018-01-29 01:49:29 +02:00
|
|
|
let place_ty = self.expr_ty(expr)?;
|
2017-05-19 12:46:34 +03:00
|
|
|
let base_ty = self.expr_ty_adjusted(base)?;
|
|
|
|
|
2022-02-19 00:44:45 +01:00
|
|
|
let ty::Ref(region, _, mutbl) = *base_ty.kind() else {
|
|
|
|
span_bug!(expr.span, "cat_overloaded_place: base is not a reference");
|
2017-05-19 12:46:34 +03:00
|
|
|
};
|
2019-11-08 22:11:03 +00:00
|
|
|
let ref_ty = self.tcx().mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
|
2017-05-19 12:46:34 +03:00
|
|
|
|
2019-11-09 10:21:33 +00:00
|
|
|
let base = self.cat_rvalue(expr.hir_id, expr.span, ref_ty);
|
|
|
|
self.cat_deref(expr, base)
|
2017-05-19 12:46:34 +03:00
|
|
|
}
|
|
|
|
|
2022-05-18 16:01:10 +00:00
|
|
|
#[instrument(level = "debug", skip(self, node))]
|
2020-06-17 18:13:05 -04:00
|
|
|
fn cat_deref(
|
|
|
|
&self,
|
|
|
|
node: &impl HirNode,
|
|
|
|
base_place: PlaceWithHirId<'tcx>,
|
|
|
|
) -> McResult<PlaceWithHirId<'tcx>> {
|
2020-06-24 16:33:31 -04:00
|
|
|
let base_curr_ty = base_place.place.ty();
|
|
|
|
let deref_ty = match base_curr_ty.builtin_deref(true) {
|
2017-05-19 12:46:34 +03:00
|
|
|
Some(mt) => mt.ty,
|
2012-09-11 21:25:01 -07:00
|
|
|
None => {
|
2020-06-24 16:33:31 -04:00
|
|
|
debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
|
2015-01-02 03:54:45 -05:00
|
|
|
return Err(());
|
2012-09-11 21:25:01 -07:00
|
|
|
}
|
2017-05-19 12:46:34 +03:00
|
|
|
};
|
2020-06-17 18:13:05 -04:00
|
|
|
let mut projections = base_place.place.projections;
|
2020-06-24 16:33:31 -04:00
|
|
|
projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty });
|
|
|
|
|
|
|
|
let ret = PlaceWithHirId::new(
|
|
|
|
node.hir_id(),
|
|
|
|
base_place.place.base_ty,
|
|
|
|
base_place.place.base,
|
|
|
|
projections,
|
|
|
|
);
|
2017-05-19 12:46:34 +03:00
|
|
|
debug!("cat_deref ret {:?}", ret);
|
|
|
|
Ok(ret)
|
2012-06-01 10:46:17 -07:00
|
|
|
}
|
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn cat_pattern<F>(
|
2019-11-30 15:08:22 +01:00
|
|
|
&self,
|
2020-06-17 18:13:05 -04:00
|
|
|
place: PlaceWithHirId<'tcx>,
|
2019-11-30 15:08:22 +01:00
|
|
|
pat: &hir::Pat<'_>,
|
|
|
|
mut op: F,
|
|
|
|
) -> McResult<()>
|
2019-11-08 22:54:00 +00:00
|
|
|
where
|
2020-06-17 18:13:05 -04:00
|
|
|
F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
|
2014-12-30 19:59:09 -05:00
|
|
|
{
|
2019-11-08 22:54:00 +00:00
|
|
|
self.cat_pattern_(place, pat, &mut op)
|
2014-12-30 19:59:09 -05:00
|
|
|
}
|
|
|
|
|
2020-07-01 23:48:48 -04:00
|
|
|
/// 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.
|
|
|
|
fn variant_index_for_adt(
|
|
|
|
&self,
|
|
|
|
qpath: &hir::QPath<'_>,
|
|
|
|
pat_hir_id: hir::HirId,
|
|
|
|
span: Span,
|
|
|
|
) -> McResult<VariantIdx> {
|
2020-07-17 08:47:04 +00:00
|
|
|
let res = self.typeck_results.qpath_res(qpath, pat_hir_id);
|
|
|
|
let ty = self.typeck_results.node_type(pat_hir_id);
|
2022-02-19 00:44:45 +01:00
|
|
|
let ty::Adt(adt_def, _) = ty.kind() else {
|
|
|
|
self.tcx()
|
|
|
|
.sess
|
|
|
|
.delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT");
|
|
|
|
return Err(());
|
2020-07-01 23:48:48 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
match res {
|
|
|
|
Res::Def(DefKind::Variant, variant_id) => Ok(adt_def.variant_index_with_id(variant_id)),
|
|
|
|
Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
|
|
|
|
Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id))
|
|
|
|
}
|
|
|
|
Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
|
|
|
|
| Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
|
|
|
|
| Res::SelfCtor(..)
|
2022-09-16 11:45:33 +10:00
|
|
|
| Res::SelfTyParam { .. }
|
|
|
|
| Res::SelfTyAlias { .. } => {
|
2020-07-01 23:48:48 -04:00
|
|
|
// Structs and Unions have only have one variant.
|
|
|
|
Ok(VariantIdx::new(0))
|
|
|
|
}
|
|
|
|
_ => bug!("expected ADT path, found={:?}", res),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the total number of fields in an ADT variant used within a pattern.
|
|
|
|
/// Here `pat_hir_id` is the HirId of the pattern itself.
|
|
|
|
fn total_fields_in_adt_variant(
|
|
|
|
&self,
|
|
|
|
pat_hir_id: hir::HirId,
|
|
|
|
variant_index: VariantIdx,
|
|
|
|
span: Span,
|
|
|
|
) -> McResult<usize> {
|
2020-07-17 08:47:04 +00:00
|
|
|
let ty = self.typeck_results.node_type(pat_hir_id);
|
2020-08-03 00:49:11 +02:00
|
|
|
match ty.kind() {
|
2022-03-05 07:28:41 +11:00
|
|
|
ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()),
|
2020-07-01 23:48:48 -04:00
|
|
|
_ => {
|
|
|
|
self.tcx()
|
|
|
|
.sess
|
|
|
|
.delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT");
|
2020-08-08 00:39:38 +02:00
|
|
|
Err(())
|
2020-07-01 23:48:48 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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.
|
|
|
|
fn total_fields_in_tuple(&self, pat_hir_id: hir::HirId, span: Span) -> McResult<usize> {
|
2020-07-17 08:47:04 +00:00
|
|
|
let ty = self.typeck_results.node_type(pat_hir_id);
|
2020-08-03 00:49:11 +02:00
|
|
|
match ty.kind() {
|
2020-07-01 23:48:48 -04:00
|
|
|
ty::Tuple(substs) => Ok(substs.len()),
|
|
|
|
_ => {
|
|
|
|
self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple");
|
2020-08-08 00:39:38 +02:00
|
|
|
Err(())
|
2020-07-01 23:48:48 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-30 19:59:09 -05:00
|
|
|
// FIXME(#19596) This is a workaround, but there should be a better way to do this
|
2019-11-30 15:08:22 +01:00
|
|
|
fn cat_pattern_<F>(
|
|
|
|
&self,
|
2020-06-17 18:13:05 -04:00
|
|
|
mut place_with_id: PlaceWithHirId<'tcx>,
|
2019-11-30 15:08:22 +01:00
|
|
|
pat: &hir::Pat<'_>,
|
|
|
|
op: &mut F,
|
|
|
|
) -> McResult<()>
|
2019-11-08 22:54:00 +00:00
|
|
|
where
|
2020-06-17 18:13:05 -04:00
|
|
|
F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
|
2014-12-03 13:30:02 -05:00
|
|
|
{
|
2020-06-17 18:13:05 -04:00
|
|
|
// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
|
2019-11-08 22:54:00 +00:00
|
|
|
// is being matched against.
|
2012-08-08 08:15:32 -07:00
|
|
|
//
|
2019-11-08 22:54:00 +00:00
|
|
|
// In general, the way that this works is that we walk down the pattern,
|
2020-06-17 18:13:05 -04:00
|
|
|
// constructing a `PlaceWithHirId` that represents the path that will be taken
|
2019-11-08 22:54:00 +00:00
|
|
|
// to reach the value being matched.
|
2012-07-18 16:18:02 -07:00
|
|
|
|
2020-06-17 18:13:05 -04:00
|
|
|
debug!("cat_pattern(pat={:?}, place_with_id={:?})", pat, place_with_id);
|
2013-01-24 19:33:48 -08:00
|
|
|
|
2020-06-17 18:13:05 -04:00
|
|
|
// If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly.
|
|
|
|
// `PlaceWithHirId`s are constructed differently from patterns. For example, in
|
2017-10-06 16:30:23 -04:00
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// match foo {
|
|
|
|
// &&Some(x, ) => { ... },
|
|
|
|
// _ => { ... },
|
|
|
|
// }
|
|
|
|
// ```
|
|
|
|
//
|
|
|
|
// the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the
|
2020-06-17 18:13:05 -04:00
|
|
|
// corresponding `PlaceWithHirId` we start with the `PlaceWithHirId` for `foo`, and then, by traversing the
|
2017-10-06 16:30:23 -04:00
|
|
|
// pattern, try to answer the question: given the address of `foo`, how is `x` reached?
|
|
|
|
//
|
2019-11-08 22:54:00 +00:00
|
|
|
// `&&Some(x,)` `place_foo`
|
|
|
|
// `&Some(x,)` `deref { place_foo}`
|
|
|
|
// `Some(x,)` `deref { deref { place_foo }}`
|
2019-11-09 10:21:33 +00:00
|
|
|
// (x,)` `field0 { deref { deref { place_foo }}}` <- resulting place
|
2017-10-06 16:30:23 -04:00
|
|
|
//
|
|
|
|
// The above example has no adjustments. If the code were instead the (after adjustments,
|
|
|
|
// equivalent) version
|
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// match foo {
|
|
|
|
// Some(x, ) => { ... },
|
|
|
|
// _ => { ... },
|
|
|
|
// }
|
|
|
|
// ```
|
|
|
|
//
|
2019-11-08 22:54:00 +00:00
|
|
|
// 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,)`
|
|
|
|
// and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
|
2021-01-11 20:45:33 +01:00
|
|
|
for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) {
|
2020-06-17 18:13:05 -04:00
|
|
|
debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id);
|
|
|
|
place_with_id = self.cat_deref(pat, place_with_id)?;
|
2017-10-06 16:30:23 -04:00
|
|
|
}
|
2020-06-17 18:13:05 -04:00
|
|
|
let place_with_id = place_with_id; // lose mutability
|
|
|
|
debug!("cat_pattern: applied adjustment derefs to get place_with_id={:?}", place_with_id);
|
2017-10-06 16:30:23 -04:00
|
|
|
|
2020-06-17 18:13:05 -04:00
|
|
|
// Invoke the callback, but only now, after the `place_with_id` has adjusted.
|
2017-10-06 16:30:23 -04:00
|
|
|
//
|
|
|
|
// To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that
|
2020-06-17 18:13:05 -04:00
|
|
|
// case, the initial `place_with_id` will be that for `&Some(3)` and the pattern is `Some(x)`. We
|
2017-10-06 16:30:23 -04:00
|
|
|
// don't want to call `op` with these incompatible values. As written, what happens instead
|
2019-11-09 10:21:33 +00:00
|
|
|
// is that `op` is called with the adjusted place (that for `*&Some(3)`) and the pattern
|
2017-10-06 16:30:23 -04:00
|
|
|
// `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)`
|
2019-11-09 10:21:33 +00:00
|
|
|
// result in the place `Downcast<Some>(*&Some(3)).0` associated to `x` and invoke `op` with
|
2017-10-06 16:30:23 -04:00
|
|
|
// that (where the `ref` on `x` is implied).
|
2020-06-17 18:13:05 -04:00
|
|
|
op(&place_with_id, pat);
|
2014-09-16 14:14:59 +02:00
|
|
|
|
2019-09-26 16:18:31 +01:00
|
|
|
match pat.kind {
|
2021-09-30 19:38:50 +02:00
|
|
|
PatKind::Tuple(subpats, dots_pos) => {
|
2020-07-01 23:48:48 -04:00
|
|
|
// (p1, ..., pN)
|
|
|
|
let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?;
|
|
|
|
|
|
|
|
for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
|
2021-09-30 19:38:50 +02:00
|
|
|
let subpat_ty = self.pat_ty_adjusted(subpat)?;
|
2020-07-01 23:48:48 -04:00
|
|
|
let projection_kind = ProjectionKind::Field(i as u32, VariantIdx::new(0));
|
|
|
|
let sub_place =
|
|
|
|
self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind);
|
2021-09-30 19:38:50 +02:00
|
|
|
self.cat_pattern_(sub_place, subpat, op)?;
|
2012-11-02 09:56:09 -07:00
|
|
|
}
|
2018-10-02 18:29:48 +02:00
|
|
|
}
|
|
|
|
|
2021-09-30 19:38:50 +02:00
|
|
|
PatKind::TupleStruct(ref qpath, subpats, dots_pos) => {
|
2020-07-01 23:48:48 -04:00
|
|
|
// S(p1, ..., pN)
|
|
|
|
let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
|
|
|
|
let total_fields =
|
|
|
|
self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?;
|
|
|
|
|
|
|
|
for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
|
2021-09-30 19:38:50 +02:00
|
|
|
let subpat_ty = self.pat_ty_adjusted(subpat)?;
|
2020-07-01 23:48:48 -04:00
|
|
|
let projection_kind = ProjectionKind::Field(i as u32, variant_index);
|
|
|
|
let sub_place =
|
|
|
|
self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind);
|
2021-09-30 19:38:50 +02:00
|
|
|
self.cat_pattern_(sub_place, subpat, op)?;
|
2020-07-01 23:48:48 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PatKind::Struct(ref qpath, field_pats, _) => {
|
2019-11-08 22:54:00 +00:00
|
|
|
// S { f1: p1, ..., fN: pN }
|
2020-07-01 23:48:48 -04:00
|
|
|
|
|
|
|
let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
|
|
|
|
|
2018-10-02 18:29:48 +02:00
|
|
|
for fp in field_pats {
|
2021-09-30 19:38:50 +02:00
|
|
|
let field_ty = self.pat_ty_adjusted(fp.pat)?;
|
2020-07-01 23:48:48 -04:00
|
|
|
let field_index = self
|
2020-07-17 08:47:04 +00:00
|
|
|
.typeck_results
|
2020-07-01 23:48:48 -04:00
|
|
|
.field_indices()
|
|
|
|
.get(fp.hir_id)
|
|
|
|
.cloned()
|
|
|
|
.expect("no index for a field");
|
|
|
|
|
|
|
|
let field_place = self.cat_projection(
|
|
|
|
pat,
|
|
|
|
place_with_id.clone(),
|
|
|
|
field_ty,
|
|
|
|
ProjectionKind::Field(field_index as u32, variant_index),
|
|
|
|
);
|
2021-09-30 19:38:50 +02:00
|
|
|
self.cat_pattern_(field_place, fp.pat, op)?;
|
2012-11-02 09:56:09 -07:00
|
|
|
}
|
2018-10-02 18:29:48 +02:00
|
|
|
}
|
2015-03-25 10:53:28 -06:00
|
|
|
|
2019-11-30 15:08:22 +01:00
|
|
|
PatKind::Or(pats) => {
|
2018-10-19 15:40:07 +01:00
|
|
|
for pat in pats {
|
2021-09-30 19:38:50 +02:00
|
|
|
self.cat_pattern_(place_with_id.clone(), pat, op)?;
|
2018-10-19 15:40:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-02 18:29:48 +02:00
|
|
|
PatKind::Binding(.., Some(ref subpat)) => {
|
2021-09-30 19:38:50 +02:00
|
|
|
self.cat_pattern_(place_with_id, subpat, op)?;
|
2012-08-08 08:15:32 -07:00
|
|
|
}
|
2018-10-02 18:29:48 +02:00
|
|
|
|
2019-02-18 18:34:42 +00:00
|
|
|
PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) => {
|
2018-10-02 18:29:48 +02:00
|
|
|
// box p1, &p1, &mut p1. we can ignore the mutability of
|
|
|
|
// PatKind::Ref since that information is already contained
|
|
|
|
// in the type.
|
2020-06-17 18:13:05 -04:00
|
|
|
let subplace = self.cat_deref(pat, place_with_id)?;
|
2021-09-30 19:38:50 +02:00
|
|
|
self.cat_pattern_(subplace, subpat, op)?;
|
2012-08-08 08:15:32 -07:00
|
|
|
}
|
2018-10-02 18:29:48 +02:00
|
|
|
|
2019-11-30 15:08:22 +01:00
|
|
|
PatKind::Slice(before, ref slice, after) => {
|
2022-02-19 00:44:45 +01:00
|
|
|
let Some(element_ty) = place_with_id.place.ty().builtin_index() else {
|
|
|
|
debug!("explicit index of non-indexable type {:?}", place_with_id);
|
|
|
|
return Err(());
|
2018-10-02 18:29:48 +02:00
|
|
|
};
|
2020-07-01 23:48:48 -04:00
|
|
|
let elt_place = self.cat_projection(
|
|
|
|
pat,
|
|
|
|
place_with_id.clone(),
|
|
|
|
element_ty,
|
|
|
|
ProjectionKind::Index,
|
|
|
|
);
|
2018-10-02 18:29:48 +02:00
|
|
|
for before_pat in before {
|
2021-09-30 19:38:50 +02:00
|
|
|
self.cat_pattern_(elt_place.clone(), before_pat, op)?;
|
2018-10-02 18:29:48 +02:00
|
|
|
}
|
|
|
|
if let Some(ref slice_pat) = *slice {
|
2021-09-30 19:38:50 +02:00
|
|
|
let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?;
|
2020-07-01 23:48:48 -04:00
|
|
|
let slice_place = self.cat_projection(
|
|
|
|
pat,
|
|
|
|
place_with_id,
|
|
|
|
slice_pat_ty,
|
|
|
|
ProjectionKind::Subslice,
|
|
|
|
);
|
2021-09-30 19:38:50 +02:00
|
|
|
self.cat_pattern_(slice_place, slice_pat, op)?;
|
2018-10-02 18:29:48 +02:00
|
|
|
}
|
|
|
|
for after_pat in after {
|
2021-09-30 19:38:50 +02:00
|
|
|
self.cat_pattern_(elt_place.clone(), after_pat, op)?;
|
2017-05-19 12:46:34 +03:00
|
|
|
}
|
2016-06-11 18:47:47 +03:00
|
|
|
}
|
2013-01-24 19:33:48 -08:00
|
|
|
|
2018-10-02 18:29:48 +02:00
|
|
|
PatKind::Path(_)
|
|
|
|
| PatKind::Binding(.., None)
|
|
|
|
| PatKind::Lit(..)
|
|
|
|
| PatKind::Range(..)
|
|
|
|
| PatKind::Wild => {
|
|
|
|
// always ok
|
|
|
|
}
|
2012-08-08 08:15:32 -07:00
|
|
|
}
|
2014-10-07 20:04:45 -07:00
|
|
|
|
2015-01-02 04:09:35 -05:00
|
|
|
Ok(())
|
2012-08-08 08:15:32 -07:00
|
|
|
}
|
2012-06-01 10:46:17 -07:00
|
|
|
}
|