1
Fork 0

Revert "Rollup merge of #98582 - oli-obk:unconstrained_opaque_type, r=estebank"

This reverts commit 6f8fb911ad, reversing
changes made to 7210e46dc6.
This commit is contained in:
Oli Scherer 2022-07-20 07:55:58 +00:00
parent 03d488b48a
commit 4a742a691e
47 changed files with 205 additions and 396 deletions

View file

@ -7,7 +7,6 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::hir::place::Projection as HirProjection;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
use rustc_middle::middle::region;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::AssertKind::BoundsCheck;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
@ -72,7 +71,7 @@ pub(crate) enum PlaceBase {
/// 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> {
pub(crate) struct PlaceBuilder<'tcx> {
base: PlaceBase,
projection: Vec<PlaceElem<'tcx>>,
}
@ -105,8 +104,6 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
variant = Some(*idx);
continue;
}
// These do not affect anything, they just make sure we know the right type.
ProjectionElem::OpaqueCast(_) => continue,
ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {
@ -204,10 +201,10 @@ fn find_capture_matching_projections<'a, 'tcx>(
/// `PlaceBuilder` now starts from `PlaceBase::Local`.
///
/// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found.
#[instrument(level = "trace", skip(cx))]
fn to_upvars_resolved_place_builder<'tcx>(
fn to_upvars_resolved_place_builder<'a, 'tcx>(
from_builder: PlaceBuilder<'tcx>,
cx: &Builder<'_, 'tcx>,
tcx: TyCtxt<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
match from_builder.base {
PlaceBase::Local(_) => Ok(from_builder),
@ -222,13 +219,13 @@ fn to_upvars_resolved_place_builder<'tcx>(
let Some((capture_index, capture)) =
find_capture_matching_projections(
cx.typeck_results,
typeck_results,
var_hir_id,
closure_def_id,
&from_builder.projection,
) else {
let closure_span = cx.tcx.def_span(closure_def_id);
if !enable_precise_capture(cx.tcx, closure_span) {
let closure_span = tcx.def_span(closure_def_id);
if !enable_precise_capture(tcx, closure_span) {
bug!(
"No associated capture found for {:?}[{:#?}] even though \
capture_disjoint_fields isn't enabled",
@ -245,8 +242,8 @@ fn to_upvars_resolved_place_builder<'tcx>(
};
// We won't be building MIR if the closure wasn't local
let closure_hir_id = cx.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
let closure_ty = cx.typeck_results.node_type(closure_hir_id);
let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
let closure_ty = typeck_results.node_type(closure_hir_id);
let substs = match closure_ty.kind() {
ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
@ -273,14 +270,12 @@ fn to_upvars_resolved_place_builder<'tcx>(
// We used some of the projections to build the capture itself,
// now we apply the remaining to the upvar resolved place.
trace!(?capture.place, ?from_builder.projection);
let remaining_projections = strip_prefix(
capture.place.base_ty,
from_builder.projection,
&capture.place.projections,
);
upvar_resolved_place_builder.projection.extend(remaining_projections);
trace!(?upvar_resolved_place_builder);
Ok(upvar_resolved_place_builder)
}
@ -299,21 +294,16 @@ fn strip_prefix<'tcx>(
prefix_projections: &[HirProjection<'tcx>],
) -> impl Iterator<Item = PlaceElem<'tcx>> {
let mut iter = projections.into_iter();
let mut next = || match iter.next()? {
// Filter out opaque casts, they are unnecessary in the prefix.
ProjectionElem::OpaqueCast(..) => iter.next(),
other => Some(other),
};
for projection in prefix_projections {
match projection.kind {
HirProjectionKind::Deref => {
assert!(matches!(next(), Some(ProjectionElem::Deref)));
assert!(matches!(iter.next(), Some(ProjectionElem::Deref)));
}
HirProjectionKind::Field(..) => {
if base_ty.is_enum() {
assert!(matches!(next(), Some(ProjectionElem::Downcast(..))));
assert!(matches!(iter.next(), Some(ProjectionElem::Downcast(..))));
}
assert!(matches!(next(), Some(ProjectionElem::Field(..))));
assert!(matches!(iter.next(), Some(ProjectionElem::Field(..))));
}
HirProjectionKind::Index | HirProjectionKind::Subslice => {
bug!("unexpected projection kind: {:?}", projection);
@ -325,32 +315,24 @@ fn strip_prefix<'tcx>(
}
impl<'tcx> PlaceBuilder<'tcx> {
pub(crate) fn into_place(self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> {
pub(crate) fn into_place<'a>(
self,
tcx: TyCtxt<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
) -> Place<'tcx> {
if let PlaceBase::Local(local) = self.base {
let mut projections = vec![];
let mut ty = PlaceTy::from_ty(cx.local_decls[local].ty);
for projection in self.projection {
// Only preserve those opaque casts that actually go from an opaque type
// to another type.
if let ProjectionElem::OpaqueCast(t) = projection {
if let ty::Opaque(..) = ty.ty.kind() {
if t != ty.ty {
projections.push(ProjectionElem::OpaqueCast(t));
}
}
} else {
projections.push(projection);
}
ty = ty.projection_ty(cx.tcx, projection);
}
Place { local, projection: cx.tcx.intern_place_elems(&projections) }
Place { local, projection: tcx.intern_place_elems(&self.projection) }
} else {
self.expect_upvars_resolved(cx).into_place(cx)
self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
}
}
fn expect_upvars_resolved(self, cx: &Builder<'_, 'tcx>) -> PlaceBuilder<'tcx> {
to_upvars_resolved_place_builder(self, cx).unwrap()
fn expect_upvars_resolved<'a>(
self,
tcx: TyCtxt<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
) -> PlaceBuilder<'tcx> {
to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap()
}
/// Attempts to resolve the `PlaceBuilder`.
@ -364,11 +346,12 @@ impl<'tcx> PlaceBuilder<'tcx> {
/// not captured. This can happen because the final mir that will be
/// generated doesn't require a read for this place. Failures will only
/// happen inside closures.
pub(crate) fn try_upvars_resolved(
pub(crate) fn try_upvars_resolved<'a>(
self,
cx: &Builder<'_, 'tcx>,
tcx: TyCtxt<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
to_upvars_resolved_place_builder(self, cx)
to_upvars_resolved_place_builder(self, tcx, typeck_results)
}
pub(crate) fn base(&self) -> PlaceBase {
@ -428,7 +411,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr: &Expr<'tcx>,
) -> BlockAnd<Place<'tcx>> {
let place_builder = unpack!(block = self.as_place_builder(block, expr));
block.and(place_builder.into_place(self))
block.and(place_builder.into_place(self.tcx, self.typeck_results))
}
/// This is used when constructing a compound `Place`, so that we can avoid creating
@ -452,7 +435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr: &Expr<'tcx>,
) -> BlockAnd<Place<'tcx>> {
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
block.and(place_builder.into_place(self))
block.and(place_builder.into_place(self.tcx, self.typeck_results))
}
/// This is used when constructing a compound `Place`, so that we can avoid creating
@ -547,7 +530,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
inferred_ty: expr.ty,
});
let place = place_builder.clone().into_place(this);
let place = place_builder.clone().into_place(this.tcx, this.typeck_results);
this.cfg.push(
block,
Statement {
@ -699,7 +682,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if is_outermost_index {
self.read_fake_borrows(block, fake_borrow_temps, source_info)
} else {
base_place = base_place.expect_upvars_resolved(self);
base_place = base_place.expect_upvars_resolved(self.tcx, self.typeck_results);
self.add_fake_borrows_of_base(
&base_place,
block,
@ -727,7 +710,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let lt = self.temp(bool_ty, expr_span);
// len = len(slice)
self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.into_place(self)));
self.cfg.push_assign(
block,
source_info,
len,
Rvalue::Len(slice.into_place(self.tcx, self.typeck_results)),
);
// lt = idx < len
self.cfg.push_assign(
block,
@ -807,7 +795,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
ProjectionElem::Field(..)
| ProjectionElem::Downcast(..)
| ProjectionElem::OpaqueCast(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => (),
}

View file

@ -321,8 +321,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let place_builder =
unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
if let Ok(place_builder_resolved) = place_builder.try_upvars_resolved(this) {
let mir_place = place_builder_resolved.into_place(this);
if let Ok(place_builder_resolved) =
place_builder.try_upvars_resolved(this.tcx, this.typeck_results)
{
let mir_place =
place_builder_resolved.into_place(this.tcx, this.typeck_results);
this.cfg.push_fake_read(
block,
this.source_info(this.tcx.hir().span(*hir_id)),
@ -613,7 +616,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// by the parent itself. The mutability of the current capture
// is same as that of the capture in the parent closure.
PlaceBase::Upvar { .. } => {
let enclosing_upvars_resolved = arg_place_builder.clone().into_place(this);
let enclosing_upvars_resolved =
arg_place_builder.clone().into_place(this.tcx, this.typeck_results);
match enclosing_upvars_resolved.as_ref() {
PlaceRef {
@ -650,7 +654,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
};
let arg_place = arg_place_builder.into_place(this);
let arg_place = arg_place_builder.into_place(this.tcx, this.typeck_results);
this.cfg.push_assign(
block,

View file

@ -23,7 +23,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability))
}
#[instrument(skip(self), level = "debug")]
fn as_temp_inner(
&mut self,
mut block: BasicBlock,
@ -31,6 +30,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr: &Expr<'tcx>,
mutability: Mutability,
) -> BlockAnd<Local> {
debug!(
"as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
block, temp_lifetime, expr, mutability
);
let this = self;
let expr_span = expr.span;

View file

@ -15,13 +15,14 @@ use std::iter;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, storing the result into `destination`, which
/// is assumed to be uninitialized.
#[instrument(level = "debug", skip(self))]
pub(crate) fn expr_into_dest(
&mut self,
destination: Place<'tcx>,
mut block: BasicBlock,
expr: &Expr<'tcx>,
) -> BlockAnd<()> {
debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
// since we frequently have to reference `self` from within a
// closure, where `self` would be shadowed, it's easier to
// just use the name `this` uniformly
@ -365,7 +366,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
None => {
let place_builder = place_builder.clone();
this.consume_by_copy_or_move(
place_builder.field(n, *ty).into_place(this),
place_builder
.field(n, *ty)
.into_place(this.tcx, this.typeck_results),
)
}
})

View file

@ -220,8 +220,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let cause_matched_place = FakeReadCause::ForMatchedPlace(None);
let source_info = self.source_info(scrutinee_span);
if let Ok(scrutinee_builder) = scrutinee_place_builder.clone().try_upvars_resolved(self) {
let scrutinee_place = scrutinee_builder.into_place(self);
if let Ok(scrutinee_builder) =
scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results)
{
let scrutinee_place = scrutinee_builder.into_place(self.tcx, self.typeck_results);
self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
}
@ -346,10 +348,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// ```
let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
let scrutinee_place: Place<'tcx>;
if let Ok(scrutinee_builder) =
scrutinee_place_builder.clone().try_upvars_resolved(this)
if let Ok(scrutinee_builder) = scrutinee_place_builder
.clone()
.try_upvars_resolved(this.tcx, this.typeck_results)
{
scrutinee_place = scrutinee_builder.into_place(this);
scrutinee_place =
scrutinee_builder.into_place(this.tcx, this.typeck_results);
opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
}
let scope = this.declare_bindings(
@ -598,6 +602,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
while let Some(next) = {
for binding in &candidate_ref.bindings {
let local = self.var_local_id(binding.var_id, OutsideGuard);
let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
)))) = self.local_decls[local].local_info else {
bug!("Let binding to non-user variable.")
};
// `try_upvars_resolved` may fail if it is unable to resolve the given
// `PlaceBuilder` inside a closure. In this case, we don't want to include
// a scrutinee place. `scrutinee_place_builder` will fail for destructured
@ -612,15 +622,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// let (v1, v2) = foo;
// };
// ```
if let Ok(match_pair_resolved) = initializer.clone().try_upvars_resolved(self) {
let place = match_pair_resolved.into_place(self);
let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
)))) = self.local_decls[local].local_info else {
bug!("Let binding to non-user variable.")
};
if let Ok(match_pair_resolved) =
initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results)
{
let place = match_pair_resolved.into_place(self.tcx, self.typeck_results);
*match_place = Some(place);
}
}
@ -649,7 +654,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// scope for the bindings in these patterns, if such a scope had to be
/// created. NOTE: Declaring the bindings should always be done in their
/// drop scope.
#[instrument(skip(self), level = "debug")]
pub(crate) fn declare_bindings(
&mut self,
mut visibility_scope: Option<SourceScope>,
@ -658,6 +662,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
has_guard: ArmHasGuard,
opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
) -> Option<SourceScope> {
debug!("declare_bindings: pattern={:?}", pattern);
self.visit_primary_bindings(
&pattern,
UserTypeProjections::none(),
@ -867,7 +872,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
Candidate {
span: pattern.span,
has_guard,
match_pairs: smallvec![MatchPair::new(place, pattern)],
match_pairs: smallvec![MatchPair { place, pattern }],
bindings: Vec::new(),
ascriptions: Vec::new(),
subcandidates: Vec::new(),
@ -1043,7 +1048,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// if `x.0` matches `false` (for the third arm). In the (impossible at
/// runtime) case when `x.0` is now `true`, we branch to
/// `otherwise_block`.
#[instrument(skip(self, fake_borrows), level = "debug")]
fn match_candidates<'pat>(
&mut self,
span: Span,
@ -1053,6 +1057,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidates: &mut [&mut Candidate<'pat, 'tcx>],
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) {
debug!(
"matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})",
span, candidates, start_block, otherwise_block,
);
// Start by simplifying candidates. Once this process is complete, all
// the match pairs which remain require some form of test, whether it
// be a switch or pattern comparison.
@ -1371,10 +1380,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
)
}
#[instrument(
skip(self, otherwise, or_span, place, fake_borrows, candidate, pats),
level = "debug"
)]
fn test_or_pattern<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
@ -1384,7 +1389,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place: PlaceBuilder<'tcx>,
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) {
debug!("candidate={:#?}\npats={:#?}", candidate, pats);
debug!("test_or_pattern:\ncandidate={:#?}\npats={:#?}", candidate, pats);
let mut or_candidates: Vec<_> = pats
.iter()
.map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard))
@ -1600,9 +1605,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Insert a Shallow borrow of any places that is switched on.
if let Some(fb) = fake_borrows && let Ok(match_place_resolved) =
match_place.clone().try_upvars_resolved(self)
match_place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
{
let resolved_place = match_place_resolved.into_place(self);
let resolved_place = match_place_resolved.into_place(self.tcx, self.typeck_results);
fb.insert(resolved_place);
}
@ -1629,14 +1634,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidates = rest;
}
// at least the first candidate ought to be tested
assert!(
total_candidate_count > candidates.len(),
"{}, {:#?}",
total_candidate_count,
candidates
);
debug!("tested_candidates: {}", total_candidate_count - candidates.len());
debug!("untested_candidates: {}", candidates.len());
assert!(total_candidate_count > candidates.len());
debug!("test_candidates: tested_candidates: {}", total_candidate_count - candidates.len());
debug!("test_candidates: untested_candidates: {}", candidates.len());
// HACK(matthewjasper) This is a closure so that we can let the test
// create its blocks before the rest of the match. This currently
@ -1794,8 +1794,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None;
let expr_place: Place<'tcx>;
if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self) {
expr_place = expr_builder.into_place(self);
if let Ok(expr_builder) =
expr_place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
{
expr_place = expr_builder.into_place(self.tcx, self.typeck_results);
opt_expr_place = Some((Some(&expr_place), expr_span));
}
let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
@ -2193,7 +2195,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// first local is a binding for occurrences of `var` in the guard, which
/// will have type `&T`. The second local is a binding for occurrences of
/// `var` in the arm body, which will have type `T`.
#[instrument(skip(self), level = "debug")]
fn declare_binding(
&mut self,
source_info: SourceInfo,
@ -2208,12 +2209,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
pat_span: Span,
) {
debug!(
"declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
visibility_scope={:?}, source_info={:?})",
var_id, name, mode, var_ty, visibility_scope, source_info
);
let tcx = self.tcx;
let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
let binding_mode = match mode {
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability),
BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability),
};
debug!("declare_binding: user_ty={:?}", user_ty);
let local = LocalDecl::<'tcx> {
mutability,
ty: var_ty,
@ -2263,7 +2271,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} else {
LocalsForNode::One(for_arm_body)
};
debug!(?locals);
debug!("declare_binding: vars={:?}", locals);
self.var_indices.insert(var_id, locals);
}

View file

@ -37,13 +37,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
///
/// only generates a single switch. If this happens this method returns
/// `true`.
#[instrument(skip(self, candidate), level = "debug")]
pub(super) fn simplify_candidate<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
) -> bool {
// repeatedly simplify match pairs until fixed point is reached
debug!("{:#?}", candidate);
debug!(?candidate, "simplify_candidate");
// existing_bindings and new_bindings exists to keep the semantics in order.
// Reversing the binding order for bindings after `@` changes the binding order in places
@ -156,10 +155,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ascription: thir::Ascription { ref annotation, variance },
} => {
// Apply the type ascription to the value at `match_pair.place`, which is the
if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
if let Ok(place_resolved) =
match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
{
candidate.ascriptions.push(Ascription {
annotation: annotation.clone(),
source: place_resolved.into_place(self),
source: place_resolved.into_place(self.tcx, self.typeck_results),
variance,
});
}
@ -183,10 +184,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ref subpattern,
is_primary: _,
} => {
if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
if let Ok(place_resolved) =
match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
{
candidate.bindings.push(Binding {
span: match_pair.pattern.span,
source: place_resolved.into_place(self),
source: place_resolved.into_place(self.tcx, self.typeck_results),
var_id: var,
binding_mode: mode,
});

View file

@ -144,7 +144,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
#[instrument(skip(self, make_target_blocks, place_builder), level = "debug")]
pub(super) fn perform_test(
&mut self,
match_start_span: Span,
@ -154,9 +153,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
test: &Test<'tcx>,
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
) {
let place = place_builder.into_place(self);
let place_ty = place.ty(&self.local_decls, self.tcx);
debug!(?place, ?place_ty,);
let place: Place<'tcx>;
if let Ok(test_place_builder) =
place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
{
place = test_place_builder.into_place(self.tcx, self.typeck_results);
} else {
return;
}
debug!(
"perform_test({:?}, {:?}: {:?}, {:?})",
block,
place,
place.ty(&self.local_decls, self.tcx),
test
);
let source_info = self.source_info(test.span);
match test.kind {
@ -724,7 +735,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
// we want to create a set of derived match-patterns like
// `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)`
let elem =
ProjectionElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index);
let downcast_place = match_pair.place.project(elem); // `(x as Variant)`
let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
// e.g., `(x as Variant).0`
let place = downcast_place.clone().field(subpattern.field, subpattern.pattern.ty);

View file

@ -31,15 +31,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
suffix: &'pat [Pat<'tcx>],
) {
let tcx = self.tcx;
let (min_length, exact_size) =
if let Ok(place_resolved) = place.clone().try_upvars_resolved(self) {
match place_resolved.into_place(self).ty(&self.local_decls, tcx).ty.kind() {
ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
}
} else {
((prefix.len() + suffix.len()).try_into().unwrap(), false)
};
let (min_length, exact_size) = if let Ok(place_resolved) =
place.clone().try_upvars_resolved(tcx, self.typeck_results)
{
match place_resolved
.into_place(tcx, self.typeck_results)
.ty(&self.local_decls, tcx)
.ty
.kind()
{
ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
}
} else {
((prefix.len() + suffix.len()).try_into().unwrap(), false)
};
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
let elem =
@ -94,14 +100,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
pub(in crate::build) fn new(
pub(crate) fn new(
place: PlaceBuilder<'tcx>,
pattern: &'pat Pat<'tcx>,
) -> MatchPair<'pat, 'tcx> {
// Force the place type to the pattern's type.
// FIXME(oli-obk): only do this when we don't already know the place type.
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
let place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
MatchPair { place, pattern }
}
}

View file

@ -553,7 +553,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Convenience wrapper that pushes a scope and then executes `f`
/// to build its contents, popping the scope afterwards.
#[instrument(skip(self, f), level = "debug")]
pub(crate) fn in_scope<F, R>(
&mut self,
region_scope: (region::Scope, SourceInfo),
@ -563,6 +562,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
where
F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
{
debug!("in_scope(region_scope={:?})", region_scope);
let source_scope = self.source_scope;
let tcx = self.tcx;
if let LintLevel::Explicit(current_hir_id) = lint_level {
@ -589,7 +589,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let rv = unpack!(block = f(self));
unpack!(block = self.pop_scope(region_scope, block));
self.source_scope = source_scope;
debug!(?block);
debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block);
block.and(rv)
}

View file

@ -48,8 +48,6 @@ impl<'tcx> Cx<'tcx> {
_ => None,
};
trace!(?expr.ty);
// Now apply adjustments, if any.
for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
trace!(?expr, ?adjustment);
@ -58,8 +56,6 @@ impl<'tcx> Cx<'tcx> {
self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span));
}
trace!(?expr.ty, "after adjustments");
// Next, wrap this up in the expr's scope.
expr = Expr {
temp_lifetime,

View file

@ -1202,32 +1202,35 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
/// Creates a new list of wildcard fields for a given constructor. The result must have a
/// length of `constructor.arity()`.
#[instrument(level = "trace")]
pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
pub(super) fn wildcards(
cx: &MatchCheckCtxt<'p, 'tcx>,
ty: Ty<'tcx>,
constructor: &Constructor<'tcx>,
) -> Self {
let ret = match constructor {
Single | Variant(_) => match pcx.ty.kind() {
ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()),
ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)),
Single | Variant(_) => match ty.kind() {
ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter()),
ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)),
ty::Adt(adt, substs) => {
if adt.is_box() {
// The only legal patterns of type `Box` (outside `std`) are `_` and box
// patterns. If we're here we can assume this is a box pattern.
Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0)))
Fields::wildcards_from_tys(cx, once(substs.type_at(0)))
} else {
let variant = &adt.variant(constructor.variant_index_for_adt(*adt));
let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant)
let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant)
.map(|(_, ty)| ty);
Fields::wildcards_from_tys(pcx.cx, tys)
Fields::wildcards_from_tys(cx, tys)
}
}
_ => bug!("Unexpected type for `Single` constructor: {:?}", pcx),
_ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
},
Slice(slice) => match *pcx.ty.kind() {
Slice(slice) => match *ty.kind() {
ty::Slice(ty) | ty::Array(ty, _) => {
let arity = slice.arity();
Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty))
Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty))
}
_ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
_ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
},
Str(..)
| FloatRange(..)
@ -1240,7 +1243,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
bug!("called `Fields::wildcards` on an `Or` ctor")
}
};
debug!(?ret);
debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
ret
}
@ -1283,7 +1286,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
/// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
/// `Some(_)`.
pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
let fields = Fields::wildcards(pcx, &ctor);
let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP)
}
@ -1550,13 +1553,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
/// `other_ctor` can be different from `self.ctor`, but must be covered by it.
pub(super) fn specialize<'a>(
&'a self,
pcx: PatCtxt<'_, 'p, 'tcx>,
cx: &MatchCheckCtxt<'p, 'tcx>,
other_ctor: &Constructor<'tcx>,
) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> {
match (&self.ctor, other_ctor) {
(Wildcard, _) => {
// We return a wildcard for each field of `other_ctor`.
Fields::wildcards(pcx, other_ctor).iter_patterns().collect()
Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect()
}
(Slice(self_slice), Slice(other_slice))
if self_slice.arity() != other_slice.arity() =>
@ -1575,7 +1578,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
let prefix = &self.fields.fields[..prefix];
let suffix = &self.fields.fields[self_slice.arity() - suffix..];
let wildcard: &_ =
pcx.cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
let extra_wildcards = other_slice.arity() - self_slice.arity();
let extra_wildcards = (0..extra_wildcards).map(|_| wildcard);
prefix.iter().chain(extra_wildcards).chain(suffix).collect()

View file

@ -196,7 +196,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
}
#[instrument(skip(self), level = "debug")]
fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
let mut ty = self.typeck_results.node_type(pat.hir_id);

View file

@ -411,12 +411,12 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
/// This is roughly the inverse of `Constructor::apply`.
fn pop_head_constructor(
&self,
pcx: PatCtxt<'_, 'p, 'tcx>,
cx: &MatchCheckCtxt<'p, 'tcx>,
ctor: &Constructor<'tcx>,
) -> PatStack<'p, 'tcx> {
// We pop the head pattern and push the new fields extracted from the arguments of
// `self.head()`.
let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor);
let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor);
new_fields.extend_from_slice(&self.pats[1..]);
PatStack::from_vec(new_fields)
}
@ -475,7 +475,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
let mut matrix = Matrix::empty();
for row in &self.patterns {
if ctor.is_covered_by(pcx, row.head().ctor()) {
let new_row = row.pop_head_constructor(pcx, ctor);
let new_row = row.pop_head_constructor(pcx.cx, ctor);
matrix.push(new_row);
}
}
@ -786,7 +786,7 @@ fn is_useful<'p, 'tcx>(
is_under_guard: bool,
is_top_level: bool,
) -> Usefulness<'p, 'tcx> {
debug!(?matrix, ?v);
debug!("matrix,v={:?}{:?}", matrix, v);
let Matrix { patterns: rows, .. } = matrix;
// The base case. We are pattern-matching on () and the return value is
@ -806,6 +806,11 @@ fn is_useful<'p, 'tcx>(
debug_assert!(rows.iter().all(|r| r.len() == v.len()));
let ty = v.head().ty();
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
// If the first pattern is an or-pattern, expand it.
let mut ret = Usefulness::new_not_useful(witness_preference);
if v.head().is_or_pat() {
@ -827,19 +832,6 @@ fn is_useful<'p, 'tcx>(
}
}
} else {
let mut ty = v.head().ty();
// Opaque types can't get destructured/split, but the patterns can
// actually hint at hidden types, so we use the patterns' types instead.
if let ty::Opaque(..) = v.head().ty().kind() {
if let Some(row) = rows.first() {
ty = row.head().ty();
}
}
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
let v_ctor = v.head().ctor();
debug!(?v_ctor);
if let Constructor::IntRange(ctor_range) = &v_ctor {
@ -861,7 +853,7 @@ fn is_useful<'p, 'tcx>(
debug!("specialize({:?})", ctor);
// We cache the result of `Fields::wildcards` because it is used a lot.
let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
let v = v.pop_head_constructor(pcx, &ctor);
let v = v.pop_head_constructor(cx, &ctor);
let usefulness = ensure_sufficient_stack(|| {
is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false)
});