get field ty during projecting
This commit is contained in:
parent
fd6fed3027
commit
4040734e44
52
Cargo.lock
52
Cargo.lock
@ -285,7 +285,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cargo"
|
||||
version = "0.67.0"
|
||||
version = "0.68.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"atty",
|
||||
@ -307,6 +307,7 @@ dependencies = [
|
||||
"glob",
|
||||
"hex 0.4.2",
|
||||
"home",
|
||||
"http-auth",
|
||||
"humantime 2.0.1",
|
||||
"ignore",
|
||||
"im-rc",
|
||||
@ -349,11 +350,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cargo-credential"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
|
||||
[[package]]
|
||||
name = "cargo-credential-1password"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"cargo-credential",
|
||||
"serde",
|
||||
@ -362,7 +363,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cargo-credential-macos-keychain"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"cargo-credential",
|
||||
"security-framework",
|
||||
@ -370,7 +371,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cargo-credential-wincred"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"cargo-credential",
|
||||
"winapi",
|
||||
@ -424,7 +425,6 @@ dependencies = [
|
||||
"glob",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"remove_dir_all",
|
||||
"serde_json",
|
||||
"snapbox",
|
||||
"tar",
|
||||
@ -436,7 +436,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cargo-util"
|
||||
version = "0.2.2"
|
||||
version = "0.2.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"core-foundation",
|
||||
@ -446,7 +446,7 @@ dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
"log",
|
||||
"miow",
|
||||
"miow 0.5.0",
|
||||
"same-file",
|
||||
"shell-escape",
|
||||
"tempfile",
|
||||
@ -808,7 +808,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"libc",
|
||||
"miow",
|
||||
"miow 0.3.7",
|
||||
"miropt-test-tools",
|
||||
"regex",
|
||||
"rustfix",
|
||||
@ -833,7 +833,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"miow",
|
||||
"miow 0.3.7",
|
||||
"regex",
|
||||
"rustfix",
|
||||
"serde",
|
||||
@ -846,9 +846,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "concolor"
|
||||
version = "0.0.8"
|
||||
version = "0.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "015267563b1df20adccdd00cb05257b1dfbea70a04928e9cf88ffb850c1a40af"
|
||||
checksum = "b90f9dcd9490a97db91a85ccd79e38a87e14323f0bb824659ee3274e9143ba37"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
@ -857,9 +857,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "concolor-query"
|
||||
version = "0.0.5"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6417fe6fc03a8b533fd2177742eeb39a90c7233eedec7bac96d4d6b69a09449"
|
||||
checksum = "82a90734b3d5dcf656e7624cca6bce9c3a90ee11f900e80141a7427ccfb3d317"
|
||||
|
||||
[[package]]
|
||||
name = "content_inspector"
|
||||
@ -909,7 +909,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crates-io"
|
||||
version = "0.34.0"
|
||||
version = "0.35.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"curl",
|
||||
@ -1698,6 +1698,15 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-auth"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0b40b39d66c28829a0cf4d09f7e139ff8201f7500a5083732848ed3b4b4d850"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "1.3.0"
|
||||
@ -2300,6 +2309,15 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miri"
|
||||
version = "0.1.0"
|
||||
@ -4693,9 +4711,9 @@ checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e"
|
||||
|
||||
[[package]]
|
||||
name = "snapbox"
|
||||
version = "0.3.3"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d199ccf8f606592df2d145db26f2aa45344e23c64b074cc5a4047f1d99b0f7"
|
||||
checksum = "827c00e91b15e2674d8a5270bae91f898693cbf9561cbb58d8eaa31974597293"
|
||||
dependencies = [
|
||||
"concolor",
|
||||
"content_inspector",
|
||||
|
@ -21,21 +21,28 @@
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::iter;
|
||||
|
||||
/// The "outermost" place that holds this value.
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub(crate) enum PlaceBase {
|
||||
/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
|
||||
/// place by pushing more and more projections onto the end, and then convert the final set into a
|
||||
/// place using the `into_place` method.
|
||||
///
|
||||
/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
|
||||
/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(in crate::build) enum PlaceBuilder<'tcx> {
|
||||
/// Denotes the start of a `Place`.
|
||||
Local(Local),
|
||||
///
|
||||
/// We use `PlaceElem` since this has all `Field` types available.
|
||||
Local(Local, Vec<PlaceElem<'tcx>>),
|
||||
|
||||
/// When building place for an expression within a closure, the place might start off a
|
||||
/// captured path. When `capture_disjoint_fields` is enabled, we might not know the capture
|
||||
/// index (within the desugared closure) of the captured path until most of the projections
|
||||
/// are applied. We use `PlaceBase::Upvar` to keep track of the root variable off of which the
|
||||
/// are applied. We use `PlaceBuilder::Upvar` to keep track of the root variable off of which the
|
||||
/// captured path starts, the closure the capture belongs to and the trait the closure
|
||||
/// implements.
|
||||
///
|
||||
/// Once we have figured out the capture index, we can convert the place builder to start from
|
||||
/// `PlaceBase::Local`.
|
||||
/// Once we have figured out the capture index, we can convert the place builder to
|
||||
/// `PlaceBuilder::Local`.
|
||||
///
|
||||
/// Consider the following example
|
||||
/// ```rust
|
||||
@ -56,24 +63,16 @@ pub(crate) enum PlaceBase {
|
||||
///
|
||||
/// When `capture_disjoint_fields` is enabled, `t.0.0.0` is captured and we won't be able to
|
||||
/// figure out that it is captured until all the `Field` projections are applied.
|
||||
Upvar {
|
||||
/// HirId of the upvar
|
||||
var_hir_id: LocalVarId,
|
||||
/// DefId of the closure
|
||||
closure_def_id: LocalDefId,
|
||||
},
|
||||
///
|
||||
/// Note: in contrast to `PlaceBuilder::Local` we have not yet determined all `Field` types
|
||||
/// and will only do so once converting to `PlaceBuilder::Local`.
|
||||
UpVar(UpVar, Vec<PlaceElem<'tcx>>),
|
||||
}
|
||||
|
||||
/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
|
||||
/// place by pushing more and more projections onto the end, and then convert the final set into a
|
||||
/// place using the `to_place` method.
|
||||
///
|
||||
/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
|
||||
/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(in crate::build) struct PlaceBuilder<'tcx> {
|
||||
base: PlaceBase,
|
||||
projection: Vec<PlaceElem<'tcx>>,
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub(crate) struct UpVar {
|
||||
var_hir_id: LocalVarId,
|
||||
closure_def_id: LocalDefId,
|
||||
}
|
||||
|
||||
/// Given a list of MIR projections, convert them to list of HIR ProjectionKind.
|
||||
@ -175,7 +174,7 @@ fn to_upvars_resolved_place_builder<'tcx>(
|
||||
cx: &Builder<'_, 'tcx>,
|
||||
var_hir_id: LocalVarId,
|
||||
closure_def_id: LocalDefId,
|
||||
projection: &[PlaceElem<'tcx>],
|
||||
projection: &[UpvarProjectionElem<'tcx>],
|
||||
) -> Option<PlaceBuilder<'tcx>> {
|
||||
let Some((capture_index, capture)) =
|
||||
find_capture_matching_projections(
|
||||
@ -197,23 +196,31 @@ fn to_upvars_resolved_place_builder<'tcx>(
|
||||
var_hir_id, projection,
|
||||
);
|
||||
}
|
||||
|
||||
return None;
|
||||
};
|
||||
|
||||
// Access the capture by accessing the field within the Closure struct.
|
||||
let capture_info = &cx.upvars[capture_index];
|
||||
|
||||
let mut upvar_resolved_place_builder = PlaceBuilder::from(capture_info.use_place);
|
||||
let Place { local: upvar_resolved_local, projection: local_projection } =
|
||||
capture_info.use_place;
|
||||
|
||||
// We used some of the projections to build the capture itself,
|
||||
// now we apply the remaining to the upvar resolved place.
|
||||
trace!(?capture.captured_place, ?projection);
|
||||
let remaining_projections = strip_prefix(
|
||||
let upvar_projection = strip_prefix(
|
||||
capture.captured_place.place.base_ty,
|
||||
projection,
|
||||
&capture.captured_place.place.projections,
|
||||
)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let upvar_resolved_place_builder = PlaceBuilder::construct_local_place_builder(
|
||||
cx,
|
||||
upvar_resolved_local,
|
||||
local_projection.to_vec(),
|
||||
upvar_projection,
|
||||
);
|
||||
upvar_resolved_place_builder.projection.extend(remaining_projections);
|
||||
|
||||
Some(upvar_resolved_place_builder)
|
||||
}
|
||||
@ -235,6 +242,8 @@ fn strip_prefix<'a, 'tcx>(
|
||||
// Filter out opaque casts, they are unnecessary in the prefix.
|
||||
.filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..)));
|
||||
for projection in prefix_projections {
|
||||
debug!(?projection, ?projection.ty);
|
||||
|
||||
match projection.kind {
|
||||
HirProjectionKind::Deref => {
|
||||
assert_matches!(iter.next(), Some(ProjectionElem::Deref));
|
||||
@ -249,6 +258,7 @@ fn strip_prefix<'a, 'tcx>(
|
||||
bug!("unexpected projection kind: {:?}", projection);
|
||||
}
|
||||
}
|
||||
|
||||
base_ty = projection.ty;
|
||||
}
|
||||
iter
|
||||
@ -263,9 +273,9 @@ pub(in crate::build) fn to_place(&self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> {
|
||||
pub(in crate::build) fn try_to_place(&self, cx: &Builder<'_, 'tcx>) -> Option<Place<'tcx>> {
|
||||
let resolved = self.resolve_upvar(cx);
|
||||
let builder = resolved.as_ref().unwrap_or(self);
|
||||
let PlaceBase::Local(local) = builder.base else { return None };
|
||||
let projection = cx.tcx.intern_place_elems(&builder.projection);
|
||||
Some(Place { local, projection })
|
||||
let PlaceBuilder::Local(local, projection) = builder else { return None };
|
||||
let projection = cx.tcx.intern_place_elems(&projection);
|
||||
Some(Place { local: *local, projection })
|
||||
}
|
||||
|
||||
/// Attempts to resolve the `PlaceBuilder`.
|
||||
@ -282,22 +292,39 @@ pub(in crate::build) fn resolve_upvar(
|
||||
&self,
|
||||
cx: &Builder<'_, 'tcx>,
|
||||
) -> Option<PlaceBuilder<'tcx>> {
|
||||
let PlaceBase::Upvar { var_hir_id, closure_def_id } = self.base else {
|
||||
let PlaceBuilder::Upvar( Upvar {var_hir_id, closure_def_id }, projection) = self else {
|
||||
return None;
|
||||
};
|
||||
to_upvars_resolved_place_builder(cx, var_hir_id, closure_def_id, &self.projection)
|
||||
|
||||
to_upvars_resolved_place_builder(cx, var_hir_id, closure_def_id, &projection)
|
||||
}
|
||||
|
||||
pub(crate) fn base(&self) -> PlaceBase {
|
||||
self.base
|
||||
pub(crate) fn get_local_projection(&self) -> &[PlaceElem<'tcx>] {
|
||||
match self {
|
||||
Self::Local(_, projection) => projection,
|
||||
Self::UpVar(..) => {
|
||||
bug!("get_local_projection_mut can only be called on PlaceBuilder::Local")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn projection(&self) -> &[PlaceElem<'tcx>] {
|
||||
&self.projection
|
||||
}
|
||||
#[instrument(skip(cx), level = "debug")]
|
||||
pub(crate) fn field(
|
||||
self,
|
||||
cx: &Builder<'_, 'tcx>,
|
||||
f: Field,
|
||||
default_field_ty: Ty<'tcx>,
|
||||
) -> Self {
|
||||
let field_ty = match self {
|
||||
PlaceBuilder::Local(..) => {
|
||||
let base_place = self.clone();
|
||||
PlaceBuilder::try_compute_field_ty(cx, f, base_place)
|
||||
.unwrap_or_else(|| default_field_ty)
|
||||
}
|
||||
PlaceBuilder::UpVar(..) => default_field_ty,
|
||||
};
|
||||
|
||||
pub(crate) fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
|
||||
self.project(PlaceElem::Field(f, ty))
|
||||
self.project(ProjectionElem::Field(f, field_ty))
|
||||
}
|
||||
|
||||
pub(crate) fn deref(self) -> Self {
|
||||
@ -312,16 +339,34 @@ fn index(self, index: Local) -> Self {
|
||||
self.project(PlaceElem::Index(index))
|
||||
}
|
||||
|
||||
pub(crate) fn project(mut self, elem: PlaceElem<'tcx>) -> Self {
|
||||
self.projection.push(elem);
|
||||
self
|
||||
#[instrument(level = "debug")]
|
||||
pub(crate) fn project(self, elem: PlaceElem<'tcx>) -> Self {
|
||||
let result = match self {
|
||||
PlaceBuilder::Local(local, mut proj) => {
|
||||
proj.push(elem);
|
||||
PlaceBuilder::Local(local, proj)
|
||||
}
|
||||
PlaceBuilder::UpVar(upvar, mut proj) => {
|
||||
proj.push(elem);
|
||||
PlaceBuilder::UpVar(upvar, proj)
|
||||
}
|
||||
};
|
||||
|
||||
debug!(?result);
|
||||
result
|
||||
}
|
||||
|
||||
/// Same as `.clone().project(..)` but more efficient
|
||||
pub(crate) fn clone_project(&self, elem: PlaceElem<'tcx>) -> Self {
|
||||
Self {
|
||||
base: self.base,
|
||||
projection: Vec::from_iter(self.projection.iter().copied().chain([elem])),
|
||||
match self {
|
||||
PlaceBuilder::Local(local, proj) => PlaceBuilder::Local(
|
||||
*local,
|
||||
Vec::from_iter(proj.iter().copied().chain([elem.into()])),
|
||||
),
|
||||
PlaceBuilder::Upvar(upvar, proj) => PlaceBuilder::UpVar(
|
||||
upvar,
|
||||
Vec::from_iter(proj.iter().copied().chain([elem.into()])),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -332,59 +377,96 @@ pub(crate) fn clone_project(&self, elem: PlaceElem<'tcx>) -> Self {
|
||||
///
|
||||
/// Fallible as the root of this place may be an upvar for
|
||||
/// which no base type can be determined.
|
||||
pub fn try_compute_ty<D>(
|
||||
&self,
|
||||
local_decls: &D,
|
||||
#[instrument(skip(cx), level = "debug")]
|
||||
fn try_compute_field_ty(
|
||||
cx: &Builder<'_, 'tcx>,
|
||||
) -> Option<PlaceTy<'tcx>>
|
||||
where
|
||||
D: HasLocalDecls<'tcx>,
|
||||
{
|
||||
match self.base {
|
||||
PlaceBase::Local(_) => Some(self.clone().into_place(cx).ty(local_decls, cx.tcx)),
|
||||
PlaceBase::Upvar { .. } => {
|
||||
match to_upvars_resolved_place_builder(self.clone(), cx) {
|
||||
Ok(resolved_place_builder) => {
|
||||
// `base` is guaranteed to be `PlaceBase::Local` now, so recursive call is ok
|
||||
resolved_place_builder.try_compute_ty(local_decls, cx)
|
||||
}
|
||||
Err(place_builder) => {
|
||||
match &place_builder.projection[..] {
|
||||
&[ProjectionElem::OpaqueCast(base_ty), ref projections @ ..] => {
|
||||
let place_ty = projections
|
||||
.iter()
|
||||
.fold(PlaceTy::from_ty(base_ty), |place_ty, &elem| {
|
||||
place_ty.projection_ty(cx.tcx, elem)
|
||||
});
|
||||
field: Field,
|
||||
base_place: PlaceBuilder<'tcx>,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
let field_idx = field.as_usize();
|
||||
let PlaceTy { ty, variant_index } = base_place.to_place(cx).ty(&cx.local_decls, cx.tcx);
|
||||
let base_ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
|
||||
debug!(?base_ty);
|
||||
|
||||
debug!(?place_ty);
|
||||
let field_ty = match base_ty.kind() {
|
||||
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
|
||||
let variant_idx = variant_index.unwrap();
|
||||
adt_def.variant(variant_idx).fields[field_idx].ty(cx.tcx, substs)
|
||||
}
|
||||
ty::Adt(adt_def, substs) => adt_def
|
||||
.all_fields()
|
||||
.nth(field_idx)
|
||||
.unwrap_or_else(|| {
|
||||
bug!("expected to take field idx {:?} of fields of {:?}", field_idx, adt_def)
|
||||
})
|
||||
.ty(cx.tcx, substs),
|
||||
ty::Tuple(elems) => elems.iter().nth(field_idx).unwrap_or_else(|| {
|
||||
bug!("expected to take field idx {:?} of {:?}", field_idx, elems)
|
||||
}),
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(place_ty)
|
||||
}
|
||||
_ => None, // would need a base `Ty` for these
|
||||
}
|
||||
}
|
||||
Some(cx.tcx.normalize_erasing_regions(cx.param_env, field_ty))
|
||||
}
|
||||
|
||||
/// Creates a `PlaceBuilder::Local` from a `PlaceBuilder::UpVar` whose upvars
|
||||
/// are resolved. This function takes two kinds of projections: `local_projection`
|
||||
/// contains the projections of the captured upvar and `upvar_projection` the
|
||||
/// projections that are applied to the captured upvar. The main purpose of this
|
||||
/// function is to figure out the `Ty`s of the field projections in `upvar_projection`.
|
||||
#[instrument(skip(cx, local))]
|
||||
fn construct_local_place_builder(
|
||||
cx: &Builder<'_, 'tcx>,
|
||||
local: Local,
|
||||
mut local_projection: Vec<PlaceElem<'tcx>>,
|
||||
upvar_projection: Vec<PlaceElem<'tcx>>,
|
||||
) -> Self {
|
||||
// We iterate through `upvar_projection` and whenever we find a `ProjectionElem::Field` we use
|
||||
// the ancestor projections, i.e. those projection elements that come before the field projection,
|
||||
// to get the `Ty` for the field.
|
||||
|
||||
for proj in upvar_projection.iter() {
|
||||
debug!("proj: {:?}, local_projection: {:?}", proj, local_projection);
|
||||
match *proj {
|
||||
ProjectionElem::Field(field, default_field_ty) => {
|
||||
let ancestor_proj = local_projection.to_vec();
|
||||
let base_place = PlaceBuilder::Local(local, ancestor_proj);
|
||||
let field_ty = PlaceBuilder::try_compute_field_ty(cx, field, base_place)
|
||||
.unwrap_or_else(|| default_field_ty);
|
||||
debug!(?field_ty);
|
||||
|
||||
local_projection.push(ProjectionElem::Field(field, field_ty));
|
||||
debug!(?local_projection);
|
||||
}
|
||||
ProjectionElem::Deref => local_projection.push(ProjectionElem::Deref),
|
||||
ProjectionElem::Index(idx) => local_projection.push(ProjectionElem::Index(idx)),
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end } => local_projection
|
||||
.push(ProjectionElem::ConstantIndex { offset, min_length, from_end }),
|
||||
ProjectionElem::Subslice { from, to, from_end } => {
|
||||
local_projection.push(ProjectionElem::Subslice { from, to, from_end })
|
||||
}
|
||||
ProjectionElem::Downcast(sym, variant_idx) => {
|
||||
local_projection.push(ProjectionElem::Downcast(sym, variant_idx))
|
||||
}
|
||||
ProjectionElem::OpaqueCast(ty) => {
|
||||
local_projection.push(ProjectionElem::OpaqueCast(ty))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlaceBuilder::Local(local, local_projection)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> From<Local> for PlaceBuilder<'tcx> {
|
||||
fn from(local: Local) -> Self {
|
||||
Self { base: PlaceBase::Local(local), projection: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> From<PlaceBase> for PlaceBuilder<'tcx> {
|
||||
fn from(base: PlaceBase) -> Self {
|
||||
Self { base, projection: Vec::new() }
|
||||
Self::Local(local, Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> From<Place<'tcx>> for PlaceBuilder<'tcx> {
|
||||
fn from(p: Place<'tcx>) -> Self {
|
||||
Self { base: PlaceBase::Local(p.local), projection: p.projection.to_vec() }
|
||||
Self::Local(p.local, p.projection.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
@ -448,6 +530,7 @@ fn as_read_only_place_builder(
|
||||
self.expr_as_place(block, expr, Mutability::Not, None)
|
||||
}
|
||||
|
||||
#[instrument(skip(self, fake_borrow_temps), level = "debug")]
|
||||
fn expr_as_place(
|
||||
&mut self,
|
||||
mut block: BasicBlock,
|
||||
@ -455,8 +538,6 @@ fn expr_as_place(
|
||||
mutability: Mutability,
|
||||
fake_borrow_temps: Option<&mut Vec<Local>>,
|
||||
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||
debug!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability);
|
||||
|
||||
let this = self;
|
||||
let expr_span = expr.span;
|
||||
let source_info = this.source_info(expr_span);
|
||||
@ -470,12 +551,13 @@ fn expr_as_place(
|
||||
let lhs = &this.thir[lhs];
|
||||
let mut place_builder =
|
||||
unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
|
||||
debug!(?place_builder);
|
||||
if let ty::Adt(adt_def, _) = lhs.ty.kind() {
|
||||
if adt_def.is_enum() {
|
||||
place_builder = place_builder.downcast(*adt_def, variant_index);
|
||||
}
|
||||
}
|
||||
block.and(place_builder.field(name, expr.ty))
|
||||
block.and(place_builder.field(this, name, expr.ty))
|
||||
}
|
||||
ExprKind::Deref { arg } => {
|
||||
let place_builder = unpack!(
|
||||
@ -617,7 +699,7 @@ fn expr_as_place(
|
||||
}
|
||||
|
||||
/// Lower a captured upvar. Note we might not know the actual capture index,
|
||||
/// so we create a place starting from `PlaceBase::Upvar`, which will be resolved
|
||||
/// so we create a place starting from `UpVar`, which will be resolved
|
||||
/// once all projections that allow us to identify a capture have been applied.
|
||||
fn lower_captured_upvar(
|
||||
&mut self,
|
||||
@ -625,7 +707,7 @@ fn lower_captured_upvar(
|
||||
closure_def_id: LocalDefId,
|
||||
var_hir_id: LocalVarId,
|
||||
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||
block.and(PlaceBuilder::from(PlaceBase::Upvar { var_hir_id, closure_def_id }))
|
||||
block.and(PlaceBuilder::UpVar(UpVar { var_hir_id, closure_def_id }, vec![]))
|
||||
}
|
||||
|
||||
/// Lower an index expression
|
||||
@ -716,8 +798,8 @@ fn add_fake_borrows_of_base(
|
||||
source_info: SourceInfo,
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
|
||||
let place_ty = base_place.ty(&self.local_decls, tcx);
|
||||
|
||||
if let ty::Slice(_) = place_ty.ty.kind() {
|
||||
// We need to create fake borrows to ensure that the bounds
|
||||
// check that we just did stays valid. Since we can't assign to
|
||||
|
@ -4,9 +4,8 @@
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_target::abi::{Abi, Primitive};
|
||||
|
||||
use crate::build::expr::as_place::PlaceBase;
|
||||
use crate::build::expr::category::{Category, RvalueFunc};
|
||||
use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
|
||||
use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary, PlaceBuilder};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::AssertKind;
|
||||
@ -651,15 +650,15 @@ fn limit_capture_mutability(
|
||||
|
||||
let arg_place_builder = unpack!(block = this.as_place_builder(block, arg));
|
||||
|
||||
let mutability = match arg_place_builder.base() {
|
||||
let mutability = match arg_place_builder {
|
||||
// We are capturing a path that starts off a local variable in the parent.
|
||||
// The mutability of the current capture is same as the mutability
|
||||
// of the local declaration in the parent.
|
||||
PlaceBase::Local(local) => this.local_decls[local].mutability,
|
||||
PlaceBuilder::Local(local, _) => this.local_decls[local].mutability,
|
||||
// Parent is a closure and we are capturing a path that is captured
|
||||
// by the parent itself. The mutability of the current capture
|
||||
// is same as that of the capture in the parent closure.
|
||||
PlaceBase::Upvar { .. } => {
|
||||
PlaceBuilder::UpVar(..) => {
|
||||
let enclosing_upvars_resolved = arg_place_builder.to_place(this);
|
||||
|
||||
match enclosing_upvars_resolved.as_ref() {
|
||||
|
@ -358,8 +358,10 @@ pub(crate) fn expr_into_dest(
|
||||
.map(|(n, ty)| match fields_map.get(&n) {
|
||||
Some(v) => v.clone(),
|
||||
None => {
|
||||
let place = place_builder.clone_project(PlaceElem::Field(n, *ty));
|
||||
this.consume_by_copy_or_move(place.to_place(this))
|
||||
let place_builder = place_builder.clone();
|
||||
this.consume_by_copy_or_move(
|
||||
place_builder.field(this, n, *ty).to_place(this),
|
||||
)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
@ -760,8 +760,7 @@ fn candidate_after_variant_switch<'pat>(
|
||||
let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)`
|
||||
let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
|
||||
// e.g., `(x as Variant).0`
|
||||
let place = downcast_place
|
||||
.clone_project(PlaceElem::Field(subpattern.field, subpattern.pattern.ty));
|
||||
let place = downcast_place.clone().field(self, subpattern.field, subpattern.pattern.ty);
|
||||
// e.g., `(x as Variant).0 @ P1`
|
||||
MatchPair::new(place, &subpattern.pattern, self)
|
||||
});
|
||||
|
@ -1,4 +1,3 @@
|
||||
use crate::build::expr::as_place::PlaceBase;
|
||||
use crate::build::expr::as_place::PlaceBuilder;
|
||||
use crate::build::matches::MatchPair;
|
||||
use crate::build::Builder;
|
||||
@ -18,70 +17,7 @@ pub(crate) fn field_match_pairs<'pat>(
|
||||
subpatterns
|
||||
.iter()
|
||||
.map(|fieldpat| {
|
||||
let place =
|
||||
place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
|
||||
MatchPair::new(place, &fieldpat.pattern, self)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub(crate) fn field_match_pairs_tuple_struct<'pat>(
|
||||
&mut self,
|
||||
place_builder: PlaceBuilder<'tcx>,
|
||||
subpatterns: &'pat [FieldPat<'tcx>],
|
||||
) -> Vec<MatchPair<'pat, 'tcx>> {
|
||||
let place_ty_and_variant_idx =
|
||||
place_builder.try_compute_ty(&self.local_decls, self).map(|place_ty| {
|
||||
(
|
||||
self.tcx.normalize_erasing_regions(self.param_env, place_ty.ty),
|
||||
place_ty.variant_index,
|
||||
)
|
||||
});
|
||||
debug!(?place_ty_and_variant_idx);
|
||||
|
||||
subpatterns
|
||||
.iter()
|
||||
.map(|fieldpat| {
|
||||
// NOTE: With type ascriptions it can happen that we get errors
|
||||
// during borrow-checking on higher-ranked types if we use the
|
||||
// ascribed type as the field type, so we try to get the actual field
|
||||
// type from the `Place`, if possible, see issue #96514
|
||||
let field_ty = if let Some((place_ty, opt_variant_idx)) = place_ty_and_variant_idx {
|
||||
let field_idx = fieldpat.field.as_usize();
|
||||
let field_ty = match place_ty.kind() {
|
||||
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
|
||||
let variant_idx = opt_variant_idx.unwrap();
|
||||
adt_def.variant(variant_idx).fields[field_idx].ty(self.tcx, substs)
|
||||
}
|
||||
ty::Adt(adt_def, substs) => adt_def
|
||||
.all_fields()
|
||||
.nth(field_idx)
|
||||
.unwrap_or_else(|| {
|
||||
bug!(
|
||||
"expected to take field idx {:?} of fields of {:?}",
|
||||
field_idx,
|
||||
adt_def
|
||||
)
|
||||
})
|
||||
.ty(self.tcx, substs),
|
||||
ty::Tuple(elems) => elems.iter().nth(field_idx).unwrap_or_else(|| {
|
||||
bug!("expected to take field idx {:?} of {:?}", field_idx, elems)
|
||||
}),
|
||||
_ => bug!(
|
||||
"no field available, place_ty: {:#?}, kind: {:?}",
|
||||
place_ty,
|
||||
place_ty.kind()
|
||||
),
|
||||
};
|
||||
|
||||
self.tcx.normalize_erasing_regions(self.param_env, field_ty)
|
||||
} else {
|
||||
fieldpat.pattern.ty
|
||||
};
|
||||
|
||||
let place = place_builder.clone().field(fieldpat.field, field_ty);
|
||||
debug!(?place, ?field_ty);
|
||||
let place = place.clone().field(self, fieldpat.field, fieldpat.pattern.ty);
|
||||
|
||||
MatchPair::new(place, &fieldpat.pattern, self)
|
||||
})
|
||||
@ -171,9 +107,10 @@ pub(in crate::build) fn new(
|
||||
|
||||
// Only add the OpaqueCast projection if the given place is an opaque type and the
|
||||
// expected type from the pattern is not.
|
||||
let may_need_cast = match place.base() {
|
||||
PlaceBase::Local(local) => {
|
||||
let ty = Place::ty_from(local, place.projection(), &cx.local_decls, cx.tcx).ty;
|
||||
let may_need_cast = match place {
|
||||
PlaceBuilder::Local(local, _) => {
|
||||
let ty =
|
||||
Place::ty_from(local, place.get_local_projection(), &cx.local_decls, cx.tcx).ty;
|
||||
ty != pattern.ty && ty.has_opaque_types()
|
||||
}
|
||||
_ => true,
|
||||
|
Loading…
Reference in New Issue
Block a user