Don't concatenate binders across types

This commit is contained in:
Jack Huey 2021-04-05 00:10:09 -04:00
parent 4fdac23f31
commit 1a14315975
4 changed files with 215 additions and 86 deletions

View file

@ -1802,29 +1802,94 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
define_scoped_cx!(self);
let mut region_index = self.region_index;
let new_value = self.tcx.replace_late_bound_regions(value.clone(), |br| {
let _ = start_or_continue(&mut self, "for<", ", ");
let kind = match br.kind {
ty::BrNamed(_, name) => {
let _ = write!(self, "{}", name);
br.kind
// If we want to print verbosly, then print *all* binders, even if they
// aren't named. Eventually, we might just want this as the default, but
// this is not *quite* right and changes the ordering of some output
// anyways.
let new_value = if self.tcx().sess.verbose() {
// anon index + 1 (BrEnv takes 0) -> name
let mut region_map: BTreeMap<u32, Symbol> = BTreeMap::default();
let bound_vars = value.bound_vars();
for var in bound_vars {
match var {
ty::BoundVariableKind::Region(ty::BrNamed(_, name)) => {
let _ = start_or_continue(&mut self, "for<", ", ");
let _ = write!(self, "{}", name);
}
ty::BoundVariableKind::Region(ty::BrAnon(i)) => {
let _ = start_or_continue(&mut self, "for<", ", ");
let name = loop {
let name = name_by_region_index(region_index);
region_index += 1;
if !self.used_region_names.contains(&name) {
break name;
}
};
let _ = write!(self, "{}", name);
region_map.insert(i + 1, name);
}
ty::BoundVariableKind::Region(ty::BrEnv) => {
let _ = start_or_continue(&mut self, "for<", ", ");
let name = loop {
let name = name_by_region_index(region_index);
region_index += 1;
if !self.used_region_names.contains(&name) {
break name;
}
};
let _ = write!(self, "{}", name);
region_map.insert(0, name);
}
_ => continue,
}
ty::BrAnon(_) | ty::BrEnv => {
let name = loop {
let name = name_by_region_index(region_index);
region_index += 1;
if !self.used_region_names.contains(&name) {
break name;
}
};
let _ = write!(self, "{}", name);
ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
}
};
self.tcx
.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
});
start_or_continue(&mut self, "", "> ")?;
}
start_or_continue(&mut self, "", "> ")?;
self.tcx.replace_late_bound_regions(value.clone(), |br| {
let kind = match br.kind {
ty::BrNamed(_, _) => br.kind,
ty::BrAnon(i) => {
let name = region_map[&(i + 1)];
ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
}
ty::BrEnv => {
let name = region_map[&0];
ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
}
};
self.tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
ty::BoundRegion { var: br.var, kind },
))
})
} else {
let new_value = self.tcx.replace_late_bound_regions(value.clone(), |br| {
let _ = start_or_continue(&mut self, "for<", ", ");
let kind = match br.kind {
ty::BrNamed(_, name) => {
let _ = write!(self, "{}", name);
br.kind
}
ty::BrAnon(_) | ty::BrEnv => {
let name = loop {
let name = name_by_region_index(region_index);
region_index += 1;
if !self.used_region_names.contains(&name) {
break name;
}
};
let _ = write!(self, "{}", name);
ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
}
};
self.tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
ty::BoundRegion { var: br.var, kind },
))
});
start_or_continue(&mut self, "", "> ")?;
new_value
};
self.binder_depth += 1;
self.region_index = region_index;

View file

@ -751,9 +751,10 @@ fn sanitize_witness<'tcx>(
span_bug!(
body.span,
"Broken MIR: generator contains type {} in MIR, \
but typeck only knows about {}",
decl.ty,
witness,
but typeck only knows about {} and {:?}",
decl_ty,
allowed,
allowed_upvars
);
}
}

View file

@ -72,8 +72,8 @@ impl RegionExt for Region {
let def_id = hir_map.local_def_id(param.hir_id);
let origin = LifetimeDefOrigin::from_param(param);
debug!(
"Region::late: param={:?} depth={:?} def_id={:?} origin={:?}",
param, depth, def_id, origin,
"Region::late: idx={:?}, param={:?} depth={:?} def_id={:?} origin={:?}",
idx, param, depth, def_id, origin,
);
(
param.name.normalize_to_macros_2_0(),
@ -326,6 +326,10 @@ enum Scope<'a> {
s: ScopeRef<'a>,
},
TraitRefBoundary {
s: ScopeRef<'a>,
},
Root,
}
@ -374,6 +378,7 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
.field("lifetimes", lifetimes)
.field("s", &"..")
.finish(),
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
Scope::Root => f.debug_struct("Root").finish(),
}
}
@ -877,9 +882,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
debug!(?bounds, ?lifetime, "TraitObject");
for bound in bounds {
self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
}
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |_, this| {
for bound in bounds {
this.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
}
});
match lifetime.name {
LifetimeName::Implicit => {
// For types like `dyn Foo`, we should
@ -1058,9 +1066,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
};
this.with(scope, |_old_scope, this| {
this.visit_generics(generics);
for bound in bounds {
this.visit_param_bound(bound);
}
let scope = Scope::TraitRefBoundary { s: this.scope };
this.with(scope, |_, this| {
for bound in bounds {
this.visit_param_bound(bound);
}
})
});
});
} else {
@ -1074,10 +1085,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
from_poly_trait_ref: false,
};
self.with(scope, |_old_scope, this| {
this.visit_generics(generics);
for bound in bounds {
this.visit_param_bound(bound);
}
let scope = Scope::TraitRefBoundary { s: this.scope };
this.with(scope, |_, this| {
this.visit_generics(generics);
for bound in bounds {
this.visit_param_bound(bound);
}
})
});
}
}
@ -1131,13 +1145,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
};
self.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &generics.params);
this.visit_generics(generics);
for bound in bounds {
this.visit_param_bound(bound);
}
if let Some(ty) = ty {
this.visit_ty(ty);
}
let scope = Scope::TraitRefBoundary { s: this.scope };
this.with(scope, |_, this| {
this.visit_generics(generics);
for bound in bounds {
this.visit_param_bound(bound);
}
if let Some(ty) = ty {
this.visit_ty(ty);
}
})
});
self.missing_named_lifetime_spots.pop();
}
@ -1197,8 +1214,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
};
self.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &generics.params);
this.visit_generics(generics);
this.visit_ty(ty);
let scope = Scope::TraitRefBoundary { s: this.scope };
this.with(scope, |_, this| {
this.visit_generics(generics);
this.visit_ty(ty);
})
});
self.missing_named_lifetime_spots.pop();
}
@ -1292,29 +1312,31 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
})
.unzip();
self.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone());
if !lifetimes.is_empty() {
let next_early_index = self.next_early_index();
let scope = Scope::Binder {
hir_id: bounded_ty.hir_id,
lifetimes,
s: self.scope,
next_early_index,
track_lifetime_uses: true,
opaque_type_parent: false,
from_poly_trait_ref: true,
};
let result = self.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &bound_generic_params);
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |_, this| {
if !lifetimes.is_empty() {
let next_early_index = this.next_early_index();
let scope = Scope::Binder {
hir_id: bounded_ty.hir_id,
lifetimes,
s: this.scope,
next_early_index,
track_lifetime_uses: true,
opaque_type_parent: false,
from_poly_trait_ref: true,
};
this.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &bound_generic_params);
this.visit_ty(&bounded_ty);
this.trait_ref_hack = Some(bounded_ty.hir_id);
walk_list!(this, visit_param_bound, bounds);
this.trait_ref_hack = None;
})
} else {
this.visit_ty(&bounded_ty);
this.trait_ref_hack = Some(bounded_ty.hir_id);
walk_list!(this, visit_param_bound, bounds);
this.trait_ref_hack = None;
});
result
} else {
self.visit_ty(&bounded_ty);
walk_list!(self, visit_param_bound, bounds);
}
}
})
}
&hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
ref lifetime,
@ -1438,6 +1460,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
scope = s;
}
Scope::TraitRefBoundary { .. } => {
// We should only see super trait lifetimes if there is a `Binder` above
assert!(supertrait_lifetimes.is_empty());
break vec![];
}
Scope::Binder { hir_id, from_poly_trait_ref, .. } => {
if !from_poly_trait_ref {
// We should only see super trait lifetimes if there is a `Binder` above
@ -1653,7 +1681,8 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) {
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::TraitRefHackInner { s, .. }
| Scope::Supertrait { s, .. } => {
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
scope = s;
}
@ -2261,7 +2290,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::TraitRefHackInner { s, .. }
| Scope::Supertrait { s, .. } => scope = s,
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => scope = s,
}
}
}
@ -2311,6 +2341,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
break None;
}
Scope::TraitRefBoundary { s, .. } => {
// We've exited nested poly trait refs; mark that we are no longer in nested trait refs.
// We don't increase the late depth because this isn't a `Binder` scope
in_poly_trait_ref = false;
scope = s;
}
Scope::Binder { ref lifetimes, from_poly_trait_ref, s, .. } => {
match lifetime_ref.name {
LifetimeName::Param(param_name) => {
@ -2504,7 +2541,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::TraitRefHackInner { s, .. }
| Scope::Supertrait { s, .. } => {
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
scope = s;
}
}
@ -2700,7 +2738,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
Scope::Body { id, .. } => break id.hir_id,
Scope::ObjectLifetimeDefault { ref s, .. }
| Scope::Elision { ref s, .. }
| Scope::Supertrait { ref s, .. } => {
| Scope::Supertrait { ref s, .. }
| Scope::TraitRefBoundary { ref s, .. } => {
scope = *s;
}
Scope::Root => bug!("In fn_like_elision without appropriate scope above"),
@ -2982,6 +3021,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
self.have_bound_regions = true;
}
_ => {
// FIXME(jackh726): nested trait refs?
self.lifetimes.insert(lifetime.shifted_out_to_binder(self.outer_index));
}
}
@ -3047,6 +3087,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
Scope::Root => break None,
Scope::TraitRefBoundary { s, .. } => {
// We've exited nested poly trait refs; mark that we are no longer in nested trait refs.
// We don't increase the late depth because this isn't a `Binder` scope
in_poly_trait_ref = false;
scope = s;
}
Scope::Binder { s, ref lifetimes, from_poly_trait_ref, .. } => {
// collect named lifetimes for suggestions
for name in lifetimes.keys() {
@ -3100,7 +3147,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
scope = s;
}
Scope::ObjectLifetimeDefault { ref s, .. }
| Scope::Elision { ref s, .. } => {
| Scope::Elision { ref s, .. }
| Scope::TraitRefBoundary { ref s, .. } => {
scope = s;
}
_ => break,
@ -3228,6 +3276,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut scope = self.scope;
let lifetime = loop {
match *scope {
Scope::TraitRefBoundary { s, .. } => {
// We've exited nested poly trait refs; mark that we are no longer in nested trait refs.
// We don't increase the late depth because this isn't a `Binder` scope
in_poly_trait_ref = false;
scope = s;
}
Scope::Binder { s, from_poly_trait_ref, .. } => {
match (from_poly_trait_ref, in_poly_trait_ref) {
(true, false) => {
@ -3380,7 +3435,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::TraitRefHackInner { s, .. }
| Scope::Supertrait { s, .. } => {
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
old_scope = s;
}
@ -3438,7 +3494,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
Scope::ObjectLifetimeDefault { s, .. }
| Scope::TraitRefHackInner { s, .. }
| Scope::Supertrait { s, .. } => scope = s,
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => scope = s,
}
}
}
@ -3492,13 +3549,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// "Constrained" basically means that it appears in any type but
/// not amongst the inputs to a projection. In other words, `<&'a
/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
#[tracing::instrument(level = "debug", skip(map))]
fn insert_late_bound_lifetimes(
map: &mut NamedRegionMap,
decl: &hir::FnDecl<'_>,
generics: &hir::Generics<'_>,
) {
debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics);
let mut constrained_by_input = ConstrainedCollector::default();
for arg_ty in decl.inputs {
constrained_by_input.visit_ty(arg_ty);
@ -3507,7 +3563,7 @@ fn insert_late_bound_lifetimes(
let mut appears_in_output = AllCollector::default();
intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output);
debug!("insert_late_bound_lifetimes: constrained_by_input={:?}", constrained_by_input.regions);
debug!(?constrained_by_input.regions);
// Walk the lifetimes that appear in where clauses.
//
@ -3527,10 +3583,7 @@ fn insert_late_bound_lifetimes(
}
}
debug!(
"insert_late_bound_lifetimes: appears_in_where_clause={:?}",
appears_in_where_clause.regions
);
debug!(?appears_in_where_clause.regions);
// Late bound regions are those that:
// - appear in the inputs
@ -3557,11 +3610,7 @@ fn insert_late_bound_lifetimes(
continue;
}
debug!(
"insert_late_bound_lifetimes: lifetime {:?} with id {:?} is late-bound",
param.name.ident(),
param.hir_id
);
debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id);
let inserted = map.late_bound.insert(param.hir_id);
assert!(inserted, "visited lifetime {:?} twice", param.hir_id);

View file

@ -0,0 +1,14 @@
// build-pass
// compile-flags: --edition 2018
// compile-flags: --crate-type rlib
use std::future::Future;
async fn handle<F>(slf: &F)
where
F: Fn(&()) -> Box<dyn Future<Output = ()> + Unpin>,
{
(slf)(&()).await;
}
fn main() {}