summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck/src/generator_interior
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_typeck/src/generator_interior')
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs63
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs129
3 files changed, 136 insertions, 60 deletions
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index 122ad7009..fd8ea1ad7 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
@@ -9,9 +9,10 @@ use hir::{
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_index::vec::IndexVec;
+use rustc_infer::infer::InferCtxt;
use rustc_middle::{
hir::map::Map,
- ty::{TyCtxt, TypeckResults},
+ ty::{ParamEnv, TyCtxt, TypeVisitable, TypeckResults},
};
use std::mem::swap;
@@ -21,20 +22,29 @@ use std::mem::swap;
/// The resulting structure still needs to be iterated to a fixed point, which
/// can be done with propagate_to_fixpoint in cfg_propagate.
pub(super) fn build_control_flow_graph<'tcx>(
- hir: Map<'tcx>,
- tcx: TyCtxt<'tcx>,
+ infcx: &InferCtxt<'tcx>,
typeck_results: &TypeckResults<'tcx>,
+ param_env: ParamEnv<'tcx>,
consumed_borrowed_places: ConsumedAndBorrowedPlaces,
body: &'tcx Body<'tcx>,
num_exprs: usize,
) -> (DropRangesBuilder, FxHashSet<HirId>) {
- let mut drop_range_visitor =
- DropRangeVisitor::new(hir, tcx, typeck_results, consumed_borrowed_places, num_exprs);
+ let mut drop_range_visitor = DropRangeVisitor::new(
+ infcx,
+ typeck_results,
+ param_env,
+ consumed_borrowed_places,
+ num_exprs,
+ );
intravisit::walk_body(&mut drop_range_visitor, body);
drop_range_visitor.drop_ranges.process_deferred_edges();
- if let Some(filename) = &tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg {
- super::cfg_visualize::write_graph_to_file(&drop_range_visitor.drop_ranges, filename, tcx);
+ if let Some(filename) = &infcx.tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg {
+ super::cfg_visualize::write_graph_to_file(
+ &drop_range_visitor.drop_ranges,
+ filename,
+ infcx.tcx,
+ );
}
(drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries)
@@ -82,40 +92,44 @@ pub(super) fn build_control_flow_graph<'tcx>(
/// ```
struct DropRangeVisitor<'a, 'tcx> {
- hir: Map<'tcx>,
+ typeck_results: &'a TypeckResults<'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
places: ConsumedAndBorrowedPlaces,
drop_ranges: DropRangesBuilder,
expr_index: PostOrderId,
- tcx: TyCtxt<'tcx>,
- typeck_results: &'a TypeckResults<'tcx>,
label_stack: Vec<(Option<rustc_ast::Label>, PostOrderId)>,
}
impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
fn new(
- hir: Map<'tcx>,
- tcx: TyCtxt<'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
typeck_results: &'a TypeckResults<'tcx>,
+ param_env: ParamEnv<'tcx>,
places: ConsumedAndBorrowedPlaces,
num_exprs: usize,
) -> Self {
debug!("consumed_places: {:?}", places.consumed);
let drop_ranges = DropRangesBuilder::new(
places.consumed.iter().flat_map(|(_, places)| places.iter().cloned()),
- hir,
+ infcx.tcx.hir(),
num_exprs,
);
Self {
- hir,
+ infcx,
+ typeck_results,
+ param_env,
places,
drop_ranges,
expr_index: PostOrderId::from_u32(0),
- typeck_results,
- tcx,
label_stack: vec![],
}
}
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.infcx.tcx
+ }
+
fn record_drop(&mut self, value: TrackedValue) {
if self.places.borrowed.contains(&value) {
debug!("not marking {:?} as dropped because it is borrowed at some point", value);
@@ -137,7 +151,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
.map_or(vec![], |places| places.iter().cloned().collect());
for place in places {
trace!(?place, "consuming place");
- for_each_consumable(self.hir, place, |value| self.record_drop(value));
+ for_each_consumable(self.tcx().hir(), place, |value| self.record_drop(value));
}
}
@@ -214,10 +228,15 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
/// return.
fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
let ty = self.typeck_results.expr_ty(expr);
- let ty = self.tcx.erase_regions(ty);
- let m = self.tcx.parent_module(expr.hir_id).to_def_id();
- let param_env = self.tcx.param_env(m.expect_local());
- if self.tcx.is_ty_uninhabited_from(m, ty, param_env) {
+ let ty = self.infcx.resolve_vars_if_possible(ty);
+ if ty.has_non_region_infer() {
+ self.tcx()
+ .sess
+ .delay_span_bug(expr.span, format!("could not resolve infer vars in `{ty}`"));
+ }
+ let ty = self.tcx().erase_regions(ty);
+ let m = self.tcx().parent_module(expr.hir_id).to_def_id();
+ if !ty.is_inhabited_from(self.tcx(), m, self.param_env) {
// This function will not return. We model this fact as an infinite loop.
self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
}
@@ -238,7 +257,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
destination: hir::Destination,
) -> Result<HirId, LoopIdError> {
destination.target_id.map(|target| {
- let node = self.hir.get(target);
+ let node = self.tcx().hir().get(target);
match node {
hir::Node::Expr(_) => target,
hir::Node::Block(b) => find_last_block_expression(b),
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
index 4f3bdfbe7..2abcadcc9 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
@@ -43,9 +43,9 @@ pub fn compute_drop_ranges<'a, 'tcx>(
let typeck_results = &fcx.typeck_results.borrow();
let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
let (mut drop_ranges, borrowed_temporaries) = build_control_flow_graph(
- fcx.tcx.hir(),
- fcx.tcx,
+ &fcx,
typeck_results,
+ fcx.param_env,
consumed_borrowed_places,
body,
num_exprs,
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index b7dd599cd..3b1518ff7 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -13,10 +13,13 @@ use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
+use rustc_infer::infer::RegionVariableOrigin;
use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
-use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::fold::FnMutDelegate;
+use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitable};
use rustc_span::symbol::sym;
use rustc_span::Span;
+use smallvec::{smallvec, SmallVec};
mod drop_ranges;
@@ -95,8 +98,8 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
expr, scope, ty, self.expr_count, yield_data.span
);
- if let Some((unresolved_type, unresolved_type_span)) =
- self.fcx.unresolved_type_vars(&ty)
+ if let Some((unresolved_term, unresolved_type_span)) =
+ self.fcx.first_unresolved_const_or_ty_var(&ty)
{
// If unresolved type isn't a ty_var then unresolved_type_span is None
let span = self
@@ -105,21 +108,22 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
// If we encounter an int/float variable, then inference fallback didn't
// finish due to some other error. Don't emit spurious additional errors.
- if let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) =
- unresolved_type.kind()
+ if let Some(unresolved_ty) = unresolved_term.ty()
+ && let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) = unresolved_ty.kind()
{
self.fcx
.tcx
.sess
- .delay_span_bug(span, &format!("Encountered var {:?}", unresolved_type));
+ .delay_span_bug(span, &format!("Encountered var {:?}", unresolved_term));
} else {
let note = format!(
"the type is part of the {} because of this {}",
- self.kind, yield_data.source
+ self.kind.descr(),
+ yield_data.source
);
self.fcx
- .need_type_info_err_in_generator(self.kind, span, unresolved_type)
+ .need_type_info_err_in_generator(self.kind, span, unresolved_term)
.span_note(yield_data.span, &*note)
.emit();
}
@@ -159,7 +163,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
expr.map(|e| e.span)
);
if let Some((unresolved_type, unresolved_type_span)) =
- self.fcx.unresolved_type_vars(&ty)
+ self.fcx.first_unresolved_const_or_ty_var(&ty)
{
debug!(
"remained unresolved_type = {:?}, unresolved_type_span: {:?}",
@@ -211,31 +215,57 @@ pub fn resolve_interior<'a, 'tcx>(
debug!("types in generator {:?}, span = {:?}", types, body.value.span);
- let mut counter = 0;
+ // We want to deduplicate if the lifetimes are the same modulo some non-informative counter.
+ // So, we need to actually do two passes: first by type to anonymize (preserving information
+ // required for diagnostics), then a second pass over all captured types to reassign disjoint
+ // region indices.
let mut captured_tys = FxHashSet::default();
let type_causes: Vec<_> = types
.into_iter()
.filter_map(|mut cause| {
- // Erase regions and canonicalize late-bound regions to deduplicate as many types as we
- // can.
- let ty = fcx.normalize_associated_types_in(cause.span, cause.ty);
- let erased = fcx.tcx.erase_regions(ty);
- if captured_tys.insert(erased) {
- // Replace all regions inside the generator interior with late bound regions.
- // Note that each region slot in the types gets a new fresh late bound region,
- // which means that none of the regions inside relate to any other, even if
- // typeck had previously found constraints that would cause them to be related.
- let folded = fcx.tcx.fold_regions(erased, |_, current_depth| {
- let br = ty::BoundRegion {
- var: ty::BoundVar::from_u32(counter),
- kind: ty::BrAnon(counter),
- };
- let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
- counter += 1;
- r
- });
-
- cause.ty = folded;
+ // Replace all regions inside the generator interior with late bound regions.
+ // Note that each region slot in the types gets a new fresh late bound region,
+ // which means that none of the regions inside relate to any other, even if
+ // typeck had previously found constraints that would cause them to be related.
+
+ let mut counter = 0;
+ let mut mk_bound_region = |span| {
+ let kind = ty::BrAnon(counter, span);
+ let var = ty::BoundVar::from_u32(counter);
+ counter += 1;
+ ty::BoundRegion { var, kind }
+ };
+ let ty = fcx.normalize(cause.span, cause.ty);
+ let ty = fcx.tcx.fold_regions(ty, |region, current_depth| {
+ let br = match region.kind() {
+ ty::ReVar(vid) => {
+ let origin = fcx.region_var_origin(vid);
+ match origin {
+ RegionVariableOrigin::EarlyBoundRegion(span, _) => {
+ mk_bound_region(Some(span))
+ }
+ _ => mk_bound_region(None),
+ }
+ }
+ // FIXME: these should use `BrNamed`
+ ty::ReEarlyBound(region) => {
+ mk_bound_region(Some(fcx.tcx.def_span(region.def_id)))
+ }
+ ty::ReLateBound(_, ty::BoundRegion { kind, .. })
+ | ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind {
+ ty::BoundRegionKind::BrAnon(_, span) => mk_bound_region(span),
+ ty::BoundRegionKind::BrNamed(def_id, _) => {
+ mk_bound_region(Some(fcx.tcx.def_span(def_id)))
+ }
+ ty::BoundRegionKind::BrEnv => mk_bound_region(None),
+ },
+ _ => mk_bound_region(None),
+ };
+ let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
+ r
+ });
+ if captured_tys.insert(ty) {
+ cause.ty = ty;
Some(cause)
} else {
None
@@ -243,11 +273,38 @@ pub fn resolve_interior<'a, 'tcx>(
})
.collect();
+ let mut bound_vars: SmallVec<[BoundVariableKind; 4]> = smallvec![];
+ let mut counter = 0;
+ // Optimization: If there is only one captured type, then we don't actually
+ // need to fold and reindex (since the first type doesn't change).
+ let type_causes = if captured_tys.len() > 0 {
+ // Optimization: Use `replace_escaping_bound_vars_uncached` instead of
+ // `fold_regions`, since we only have late bound regions, and it skips
+ // types without bound regions.
+ fcx.tcx.replace_escaping_bound_vars_uncached(
+ type_causes,
+ FnMutDelegate {
+ regions: &mut |br| {
+ let kind = match br.kind {
+ ty::BrAnon(_, span) => ty::BrAnon(counter, span),
+ _ => br.kind,
+ };
+ let var = ty::BoundVar::from_usize(bound_vars.len());
+ bound_vars.push(ty::BoundVariableKind::Region(kind));
+ counter += 1;
+ fcx.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var, kind }))
+ },
+ types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"),
+ consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"),
+ },
+ )
+ } else {
+ type_causes
+ };
+
// Extract type components to build the witness type.
let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty));
- let bound_vars = fcx.tcx.mk_bound_variable_kinds(
- (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
- );
+ let bound_vars = fcx.tcx.mk_bound_variable_kinds(bound_vars.iter());
let witness =
fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
@@ -486,10 +543,10 @@ fn check_must_not_suspend_ty<'tcx>(
data: SuspendCheckData<'_, 'tcx>,
) -> bool {
if ty.is_unit()
- // FIXME: should this check `is_ty_uninhabited_from`. This query is not available in this stage
+ // FIXME: should this check `Ty::is_inhabited_from`. This query is not available in this stage
// of typeck (before ReVar and RePlaceholder are removed), but may remove noise, like in
// `must_use`
- // || fcx.tcx.is_ty_uninhabited_from(fcx.tcx.parent_module(hir_id).to_def_id(), ty, fcx.param_env)
+ // || !ty.is_inhabited_from(fcx.tcx, fcx.tcx.parent_module(hir_id).to_def_id(), fcx.param_env)
{
return false;
}
@@ -510,7 +567,7 @@ fn check_must_not_suspend_ty<'tcx>(
let mut has_emitted = false;
for &(predicate, _) in fcx.tcx.explicit_item_bounds(def) {
// We only look at the `DefId`, so it is safe to skip the binder here.
- if let ty::PredicateKind::Trait(ref poly_trait_predicate) =
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) =
predicate.kind().skip_binder()
{
let def_id = poly_trait_predicate.trait_ref.def_id;