Cleanup some remains of hr_lifetime_in_assoc_type compatibility lint

This commit is contained in:
Vadim Petrochenkov 2017-07-29 17:19:57 +03:00
parent ad36f8feba
commit 80cf3f99f4
17 changed files with 113 additions and 278 deletions

View File

@ -368,7 +368,6 @@ for ty::RegionParameterDef {
name, name,
def_id, def_id,
index, index,
issue_32330: _,
pure_wrt_drop pure_wrt_drop
} = *self; } = *self;

View File

@ -66,8 +66,7 @@ use hir::map as hir_map;
use hir::def_id::DefId; use hir::def_id::DefId;
use middle::region; use middle::region;
use traits::{ObligationCause, ObligationCauseCode}; use traits::{ObligationCause, ObligationCauseCode};
use ty::{self, TyCtxt, TypeFoldable}; use ty::{self, Region, TyCtxt, TypeFoldable};
use ty::{Region, Issue32330};
use ty::error::TypeError; use ty::error::TypeError;
use syntax::ast::DUMMY_NODE_ID; use syntax::ast::DUMMY_NODE_ID;
use syntax_pos::{Pos, Span}; use syntax_pos::{Pos, Span};
@ -713,35 +712,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.tcx.note_and_explain_type_err(diag, terr, span); self.tcx.note_and_explain_type_err(diag, terr, span);
} }
pub fn note_issue_32330(&self,
diag: &mut DiagnosticBuilder<'tcx>,
terr: &TypeError<'tcx>)
{
debug!("note_issue_32330: terr={:?}", terr);
match *terr {
TypeError::RegionsInsufficientlyPolymorphic(_, _, Some(box Issue32330 {
fn_def_id, region_name
})) |
TypeError::RegionsOverlyPolymorphic(_, _, Some(box Issue32330 {
fn_def_id, region_name
})) => {
diag.note(
&format!("lifetime parameter `{0}` declared on fn `{1}` \
appears only in the return type, \
but here is required to be higher-ranked, \
which means that `{0}` must appear in both \
argument and return types",
region_name,
self.tcx.item_path_str(fn_def_id)));
diag.note(
&format!("this error is the result of a recent bug fix; \
for more information, see issue #33685 \
<https://github.com/rust-lang/rust/issues/33685>"));
}
_ => {}
}
}
pub fn report_and_explain_type_error(&self, pub fn report_and_explain_type_error(&self,
trace: TypeTrace<'tcx>, trace: TypeTrace<'tcx>,
terr: &TypeError<'tcx>) terr: &TypeError<'tcx>)
@ -761,7 +731,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
} }
}; };
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr); self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr);
self.note_issue_32330(&mut diag, terr);
diag diag
} }
@ -934,7 +903,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
format!(" for lifetime parameter {}in trait containing associated type `{}`", format!(" for lifetime parameter {}in trait containing associated type `{}`",
br_string(br), type_name) br_string(br), type_name)
} }
infer::EarlyBoundRegion(_, name, _) => { infer::EarlyBoundRegion(_, name) => {
format!(" for lifetime parameter `{}`", format!(" for lifetime parameter `{}`",
name) name)
} }

View File

@ -13,9 +13,7 @@
use super::{CombinedSnapshot, use super::{CombinedSnapshot,
InferCtxt, InferCtxt,
LateBoundRegion,
HigherRankedType, HigherRankedType,
RegionVariableOrigin,
SubregionOrigin, SubregionOrigin,
SkolemizationMap}; SkolemizationMap};
use super::combine::CombineFields; use super::combine::CombineFields;
@ -29,15 +27,6 @@ use util::nodemap::{FxHashMap, FxHashSet};
pub struct HrMatchResult<U> { pub struct HrMatchResult<U> {
pub value: U, pub value: U,
/// Normally, when we do a higher-ranked match operation, we
/// expect all higher-ranked regions to be constrained as part of
/// the match operation. However, in the transition period for
/// #32330, it can happen that we sometimes have unconstrained
/// regions that get instantiated with fresh variables. In that
/// case, we collect the set of unconstrained bound regions here
/// and replace them with fresh variables.
pub unconstrained_regions: Vec<ty::BoundRegion>,
} }
impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
@ -108,7 +97,6 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
/// that do not appear in `T`. If that happens, those regions are /// that do not appear in `T`. If that happens, those regions are
/// unconstrained, and this routine replaces them with `'static`. /// unconstrained, and this routine replaces them with `'static`.
pub fn higher_ranked_match<T, U>(&mut self, pub fn higher_ranked_match<T, U>(&mut self,
span: Span,
a_pair: &Binder<(T, U)>, a_pair: &Binder<(T, U)>,
b_match: &T, b_match: &T,
a_is_expected: bool) a_is_expected: bool)
@ -158,28 +146,16 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
// be any region from the sets above, except for other members of // be any region from the sets above, except for other members of
// `skol_map`. There should always be a representative if things // `skol_map`. There should always be a representative if things
// are properly well-formed. // are properly well-formed.
let mut unconstrained_regions = vec![];
let skol_representatives: FxHashMap<_, _> = let skol_representatives: FxHashMap<_, _> =
skol_resolution_map skol_resolution_map
.iter() .iter()
.map(|(&skol, &(br, ref regions))| { .map(|(&skol, &(_, ref regions))| {
let representative = let representative =
regions.iter() regions.iter()
.filter(|&&r| !skol_resolution_map.contains_key(r)) .filter(|&&r| !skol_resolution_map.contains_key(r))
.cloned() .cloned()
.next() .next()
.unwrap_or_else(|| { // [1] .expect("no representative region");
unconstrained_regions.push(br);
self.infcx.next_region_var(
LateBoundRegion(span, br, HigherRankedType))
});
// [1] There should always be a representative,
// unless the higher-ranked region did not appear
// in the values being matched. We should reject
// as ill-formed cases that can lead to this, but
// right now we sometimes issue warnings (see
// #32330).
(skol, representative) (skol, representative)
}) })
@ -216,10 +192,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
// We are now done with these skolemized variables. // We are now done with these skolemized variables.
self.infcx.pop_skolemized(skol_map, snapshot); self.infcx.pop_skolemized(skol_map, snapshot);
Ok(HrMatchResult { Ok(HrMatchResult { value: a_value })
value: a_value,
unconstrained_regions,
})
}); });
} }
@ -657,28 +630,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
skol_br, skol_br,
tainted_region); tainted_region);
let issue_32330 = if let &ty::ReVar(vid) = tainted_region { return Err(if overly_polymorphic {
match self.region_vars.var_origin(vid) {
RegionVariableOrigin::EarlyBoundRegion(_, _, issue_32330) => {
issue_32330.map(Box::new)
}
_ => None
}
} else {
None
};
if overly_polymorphic {
debug!("Overly polymorphic!"); debug!("Overly polymorphic!");
return Err(TypeError::RegionsOverlyPolymorphic(skol_br, TypeError::RegionsOverlyPolymorphic(skol_br, tainted_region)
tainted_region,
issue_32330));
} else { } else {
debug!("Not as polymorphic!"); debug!("Not as polymorphic!");
return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br, TypeError::RegionsInsufficientlyPolymorphic(skol_br, tainted_region)
tainted_region, })
issue_32330));
}
} }
} }

View File

@ -299,7 +299,7 @@ pub enum RegionVariableOrigin {
Coercion(Span), Coercion(Span),
// Region variables created as the values for early-bound regions // Region variables created as the values for early-bound regions
EarlyBoundRegion(Span, ast::Name, Option<ty::Issue32330>), EarlyBoundRegion(Span, ast::Name),
// Region variables created for bound regions // Region variables created for bound regions
// in a function or method that is called // in a function or method that is called
@ -989,7 +989,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
span: Span, span: Span,
def: &ty::RegionParameterDef) def: &ty::RegionParameterDef)
-> ty::Region<'tcx> { -> ty::Region<'tcx> {
self.next_region_var(EarlyBoundRegion(span, def.name, def.issue_32330)) self.next_region_var(EarlyBoundRegion(span, def.name))
} }
/// Create a type inference variable for the given /// Create a type inference variable for the given
@ -1278,14 +1278,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-> InferResult<'tcx, HrMatchResult<Ty<'tcx>>> -> InferResult<'tcx, HrMatchResult<Ty<'tcx>>>
{ {
let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref(self.tcx), p.ty)); let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref(self.tcx), p.ty));
let span = cause.span;
let trace = TypeTrace { let trace = TypeTrace {
cause, cause,
values: TraitRefs(ExpectedFound::new(true, match_pair.skip_binder().0, match_b)) values: TraitRefs(ExpectedFound::new(true, match_pair.skip_binder().0, match_b))
}; };
let mut combine = self.combine_fields(trace, param_env); let mut combine = self.combine_fields(trace, param_env);
let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?; let result = combine.higher_ranked_match(&match_pair, &match_b, true)?;
Ok(InferOk { value: result, obligations: combine.obligations }) Ok(InferOk { value: result, obligations: combine.obligations })
} }

View File

@ -153,10 +153,6 @@ pub struct NamedRegionMap {
// (b) it DOES appear in the arguments. // (b) it DOES appear in the arguments.
pub late_bound: NodeSet, pub late_bound: NodeSet,
// Contains the node-ids for lifetimes that were (incorrectly) categorized
// as late-bound, until #32330 was fixed.
pub issue_32330: NodeMap<ty::Issue32330>,
// For each type and trait definition, maps type parameters // For each type and trait definition, maps type parameters
// to the trait object lifetime defaults computed from them. // to the trait object lifetime defaults computed from them.
pub object_lifetime_defaults: NodeMap<Vec<ObjectLifetimeDefault>>, pub object_lifetime_defaults: NodeMap<Vec<ObjectLifetimeDefault>>,
@ -261,7 +257,6 @@ pub fn krate(sess: &Session,
let mut map = NamedRegionMap { let mut map = NamedRegionMap {
defs: NodeMap(), defs: NodeMap(),
late_bound: NodeSet(), late_bound: NodeSet(),
issue_32330: NodeMap(),
object_lifetime_defaults: compute_object_lifetime_defaults(sess, hir_map), object_lifetime_defaults: compute_object_lifetime_defaults(sess, hir_map),
}; };
sess.track_errors(|| { sess.track_errors(|| {
@ -303,7 +298,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) { fn visit_item(&mut self, item: &'tcx hir::Item) {
match item.node { match item.node {
hir::ItemFn(ref decl, _, _, _, ref generics, _) => { hir::ItemFn(ref decl, _, _, _, ref generics, _) => {
self.visit_early_late(item.id, None, decl, generics, |this| { self.visit_early_late(None, decl, generics, |this| {
intravisit::walk_item(this, item); intravisit::walk_item(this, item);
}); });
} }
@ -355,7 +350,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
match item.node { match item.node {
hir::ForeignItemFn(ref decl, _, ref generics) => { hir::ForeignItemFn(ref decl, _, ref generics) => {
self.visit_early_late(item.id, None, decl, generics, |this| { self.visit_early_late(None, decl, generics, |this| {
intravisit::walk_foreign_item(this, item); intravisit::walk_foreign_item(this, item);
}) })
} }
@ -406,7 +401,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
if let hir::TraitItemKind::Method(ref sig, _) = trait_item.node { if let hir::TraitItemKind::Method(ref sig, _) = trait_item.node {
self.visit_early_late( self.visit_early_late(
trait_item.id,
Some(self.hir_map.get_parent(trait_item.id)), Some(self.hir_map.get_parent(trait_item.id)),
&sig.decl, &sig.generics, &sig.decl, &sig.generics,
|this| intravisit::walk_trait_item(this, trait_item)) |this| intravisit::walk_trait_item(this, trait_item))
@ -418,7 +412,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
self.visit_early_late( self.visit_early_late(
impl_item.id,
Some(self.hir_map.get_parent(impl_item.id)), Some(self.hir_map.get_parent(impl_item.id)),
&sig.decl, &sig.generics, &sig.decl, &sig.generics,
|this| intravisit::walk_impl_item(this, impl_item)) |this| intravisit::walk_impl_item(this, impl_item))
@ -811,18 +804,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// bound lifetimes are resolved by name and associated with a binder id (`binder_id`), so the /// bound lifetimes are resolved by name and associated with a binder id (`binder_id`), so the
/// ordering is not important there. /// ordering is not important there.
fn visit_early_late<F>(&mut self, fn visit_early_late<F>(&mut self,
fn_id: ast::NodeId,
parent_id: Option<ast::NodeId>, parent_id: Option<ast::NodeId>,
decl: &'tcx hir::FnDecl, decl: &'tcx hir::FnDecl,
generics: &'tcx hir::Generics, generics: &'tcx hir::Generics,
walk: F) where walk: F) where
F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
{ {
let fn_def_id = self.hir_map.local_def_id(fn_id); insert_late_bound_lifetimes(self.map, decl, generics);
insert_late_bound_lifetimes(self.map,
fn_def_id,
decl,
generics);
// Find the start of nested early scopes, e.g. in methods. // Find the start of nested early scopes, e.g. in methods.
let mut index = 0; let mut index = 0;
@ -1549,7 +1537,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// not amongst the inputs to a projection. In other words, `<&'a /// not amongst the inputs to a projection. In other words, `<&'a
/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
fn_def_id: DefId,
decl: &hir::FnDecl, decl: &hir::FnDecl,
generics: &hir::Generics) { generics: &hir::Generics) {
debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics); debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics);
@ -1607,22 +1594,9 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
// any `impl Trait` in the return type? early-bound. // any `impl Trait` in the return type? early-bound.
if appears_in_output.impl_trait { continue; } if appears_in_output.impl_trait { continue; }
// does not appear in the inputs, but appears in the return // does not appear in the inputs, but appears in the return type? early-bound.
// type? eventually this will be early-bound, but for now we if !constrained_by_input.regions.contains(&name) &&
// just mark it so we can issue warnings. appears_in_output.regions.contains(&name) {
let constrained_by_input = constrained_by_input.regions.contains(&name);
let appears_in_output = appears_in_output.regions.contains(&name);
if !constrained_by_input && appears_in_output {
debug!("inserting issue_32330 entry for {:?}, {:?} on {:?}",
lifetime.lifetime.id,
name,
fn_def_id);
map.issue_32330.insert(
lifetime.lifetime.id,
ty::Issue32330 {
fn_def_id,
region_name: name,
});
continue; continue;
} }

View File

@ -479,9 +479,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty); let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty);
match project_type(selcx, &obligation) { match project_type(selcx, &obligation) {
Ok(ProjectedTy::Progress(Progress { ty: projected_ty, Ok(ProjectedTy::Progress(Progress { ty: projected_ty, mut obligations })) => {
mut obligations,
cacheable })) => {
// if projection succeeded, then what we get out of this // if projection succeeded, then what we get out of this
// is also non-normalized (consider: it was derived from // is also non-normalized (consider: it was derived from
// an impl, where-clause etc) and hence we must // an impl, where-clause etc) and hence we must
@ -490,12 +488,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
debug!("opt_normalize_projection_type: \ debug!("opt_normalize_projection_type: \
projected_ty={:?} \ projected_ty={:?} \
depth={} \ depth={} \
obligations={:?} \ obligations={:?}",
cacheable={:?}",
projected_ty, projected_ty,
depth, depth,
obligations, obligations);
cacheable);
let result = if projected_ty.has_projection_types() { let result = if projected_ty.has_projection_types() {
let mut normalizer = AssociatedTypeNormalizer::new(selcx, let mut normalizer = AssociatedTypeNormalizer::new(selcx,
@ -520,8 +516,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
obligations, obligations,
} }
}; };
infcx.projection_cache.borrow_mut() infcx.projection_cache.borrow_mut().complete(projection_ty, &result);
.complete(projection_ty, &result, cacheable);
Some(result) Some(result)
} }
Ok(ProjectedTy::NoProgress(projected_ty)) => { Ok(ProjectedTy::NoProgress(projected_ty)) => {
@ -532,8 +527,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
value: projected_ty, value: projected_ty,
obligations: vec![] obligations: vec![]
}; };
infcx.projection_cache.borrow_mut() infcx.projection_cache.borrow_mut().complete(projection_ty, &result);
.complete(projection_ty, &result, true);
Some(result) Some(result)
} }
Err(ProjectionTyError::TooManyCandidates) => { Err(ProjectionTyError::TooManyCandidates) => {
@ -606,7 +600,6 @@ enum ProjectedTy<'tcx> {
struct Progress<'tcx> { struct Progress<'tcx> {
ty: Ty<'tcx>, ty: Ty<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>, obligations: Vec<PredicateObligation<'tcx>>,
cacheable: bool,
} }
impl<'tcx> Progress<'tcx> { impl<'tcx> Progress<'tcx> {
@ -614,7 +607,6 @@ impl<'tcx> Progress<'tcx> {
Progress { Progress {
ty: tcx.types.err, ty: tcx.types.err,
obligations: vec![], obligations: vec![],
cacheable: true
} }
} }
@ -1228,7 +1220,6 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
Progress { Progress {
ty: ty_match.value, ty: ty_match.value,
obligations, obligations,
cacheable: ty_match.unconstrained_regions.is_empty(),
} }
} }
Err(e) => { Err(e) => {
@ -1272,7 +1263,6 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
Progress { Progress {
ty: ty.subst(tcx, substs), ty: ty.subst(tcx, substs),
obligations: nested, obligations: nested,
cacheable: true
} }
} }
@ -1380,22 +1370,11 @@ impl<'tcx> ProjectionCache<'tcx> {
Ok(()) Ok(())
} }
/// Indicates that `key` was normalized to `value`. If `cacheable` is false, /// Indicates that `key` was normalized to `value`.
/// then this result is sadly not cacheable. fn complete(&mut self, key: ty::ProjectionTy<'tcx>, value: &NormalizedTy<'tcx>) {
fn complete(&mut self, debug!("ProjectionCacheEntry::complete: adding cache entry: key={:?}, value={:?}",
key: ty::ProjectionTy<'tcx>, key, value);
value: &NormalizedTy<'tcx>, let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.value));
cacheable: bool) {
let fresh_key = if cacheable {
debug!("ProjectionCacheEntry::complete: adding cache entry: key={:?}, value={:?}",
key, value);
self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.value))
} else {
debug!("ProjectionCacheEntry::complete: cannot cache: key={:?}, value={:?}",
key, value);
!self.map.remove(key)
};
assert!(!fresh_key, "never started projecting `{:?}`", key); assert!(!fresh_key, "never started projecting `{:?}`", key);
} }

View File

@ -39,8 +39,8 @@ pub enum TypeError<'tcx> {
RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
RegionsNotSame(Region<'tcx>, Region<'tcx>), RegionsNotSame(Region<'tcx>, Region<'tcx>),
RegionsNoOverlap(Region<'tcx>, Region<'tcx>), RegionsNoOverlap(Region<'tcx>, Region<'tcx>),
RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>, Option<Box<ty::Issue32330>>), RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>),
RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>, Option<Box<ty::Issue32330>>), RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>),
Sorts(ExpectedFound<Ty<'tcx>>), Sorts(ExpectedFound<Ty<'tcx>>),
IntMismatch(ExpectedFound<ty::IntVarValue>), IntMismatch(ExpectedFound<ty::IntVarValue>),
FloatMismatch(ExpectedFound<ast::FloatTy>), FloatMismatch(ExpectedFound<ast::FloatTy>),
@ -116,13 +116,13 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
RegionsNoOverlap(..) => { RegionsNoOverlap(..) => {
write!(f, "lifetimes do not intersect") write!(f, "lifetimes do not intersect")
} }
RegionsInsufficientlyPolymorphic(br, _, _) => { RegionsInsufficientlyPolymorphic(br, _) => {
write!(f, write!(f,
"expected bound lifetime parameter{}{}, found concrete lifetime", "expected bound lifetime parameter{}{}, found concrete lifetime",
if br.is_named() { " " } else { "" }, if br.is_named() { " " } else { "" },
br) br)
} }
RegionsOverlyPolymorphic(br, _, _) => { RegionsOverlyPolymorphic(br, _) => {
write!(f, write!(f,
"expected concrete lifetime, found bound lifetime parameter{}{}", "expected concrete lifetime, found bound lifetime parameter{}{}",
if br.is_named() { " " } else { "" }, if br.is_named() { " " } else { "" },
@ -257,15 +257,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.note_and_explain_region(db, "...does not overlap ", self.note_and_explain_region(db, "...does not overlap ",
region2, ""); region2, "");
} }
RegionsInsufficientlyPolymorphic(_, conc_region, _) => { RegionsInsufficientlyPolymorphic(_, conc_region) => {
self.note_and_explain_region(db, "concrete lifetime that was found is ", self.note_and_explain_region(db, "concrete lifetime that was found is ",
conc_region, ""); conc_region, "");
} }
RegionsOverlyPolymorphic(_, &ty::ReVar(_), _) => { RegionsOverlyPolymorphic(_, &ty::ReVar(_)) => {
// don't bother to print out the message below for // don't bother to print out the message below for
// inference variables, it's not very illuminating. // inference variables, it's not very illuminating.
} }
RegionsOverlyPolymorphic(_, conc_region, _) => { RegionsOverlyPolymorphic(_, conc_region) => {
self.note_and_explain_region(db, "expected concrete lifetime is ", self.note_and_explain_region(db, "expected concrete lifetime is ",
conc_region, ""); conc_region, "");
} }

View File

@ -67,7 +67,6 @@ pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
pub use self::sty::{ExistentialProjection, PolyExistentialProjection}; pub use self::sty::{ExistentialProjection, PolyExistentialProjection};
pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
pub use self::sty::RegionKind; pub use self::sty::RegionKind;
pub use self::sty::Issue32330;
pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid}; pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
pub use self::sty::BoundRegion::*; pub use self::sty::BoundRegion::*;
pub use self::sty::InferTy::*; pub use self::sty::InferTy::*;
@ -676,7 +675,6 @@ pub struct RegionParameterDef {
pub name: Name, pub name: Name,
pub def_id: DefId, pub def_id: DefId,
pub index: u32, pub index: u32,
pub issue_32330: Option<ty::Issue32330>,
/// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
/// on generic parameter `'a`, asserts data of lifetime `'a` /// on generic parameter `'a`, asserts data of lifetime `'a`

View File

@ -346,13 +346,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
RegionsNoOverlap(a, b) => { RegionsNoOverlap(a, b) => {
return tcx.lift(&(a, b)).map(|(a, b)| RegionsNoOverlap(a, b)) return tcx.lift(&(a, b)).map(|(a, b)| RegionsNoOverlap(a, b))
} }
RegionsInsufficientlyPolymorphic(a, b, ref c) => { RegionsInsufficientlyPolymorphic(a, b) => {
let c = c.clone(); return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b))
return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b, c))
} }
RegionsOverlyPolymorphic(a, b, ref c) => { RegionsOverlyPolymorphic(a, b) => {
let c = c.clone(); return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b))
return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b, c))
} }
IntMismatch(x) => IntMismatch(x), IntMismatch(x) => IntMismatch(x),
FloatMismatch(x) => FloatMismatch(x), FloatMismatch(x) => FloatMismatch(x),
@ -1004,13 +1002,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
RegionsNoOverlap(a, b) => { RegionsNoOverlap(a, b) => {
RegionsNoOverlap(a.fold_with(folder), b.fold_with(folder)) RegionsNoOverlap(a.fold_with(folder), b.fold_with(folder))
}, },
RegionsInsufficientlyPolymorphic(a, b, ref c) => { RegionsInsufficientlyPolymorphic(a, b) => {
let c = c.clone(); RegionsInsufficientlyPolymorphic(a, b.fold_with(folder))
RegionsInsufficientlyPolymorphic(a, b.fold_with(folder), c)
}, },
RegionsOverlyPolymorphic(a, b, ref c) => { RegionsOverlyPolymorphic(a, b) => {
let c = c.clone(); RegionsOverlyPolymorphic(a, b.fold_with(folder))
RegionsOverlyPolymorphic(a, b.fold_with(folder), c)
}, },
IntMismatch(x) => IntMismatch(x), IntMismatch(x) => IntMismatch(x),
FloatMismatch(x) => FloatMismatch(x), FloatMismatch(x) => FloatMismatch(x),
@ -1036,8 +1032,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
RegionsNoOverlap(a, b) => { RegionsNoOverlap(a, b) => {
a.visit_with(visitor) || b.visit_with(visitor) a.visit_with(visitor) || b.visit_with(visitor)
}, },
RegionsInsufficientlyPolymorphic(_, b, _) | RegionsInsufficientlyPolymorphic(_, b) |
RegionsOverlyPolymorphic(_, b, _) => { RegionsOverlyPolymorphic(_, b) => {
b.visit_with(visitor) b.visit_with(visitor)
}, },
Sorts(x) => x.visit_with(visitor), Sorts(x) => x.visit_with(visitor),

View File

@ -77,20 +77,6 @@ impl BoundRegion {
} }
} }
/// When a region changed from late-bound to early-bound when #32330
/// was fixed, its `RegionParameterDef` will have one of these
/// structures that we can use to give nicer errors.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash,
RustcEncodable, RustcDecodable)]
pub struct Issue32330 {
/// fn where is region declared
pub fn_def_id: DefId,
/// name of region; duplicates the info in BrNamed but convenient
/// to have it here, and this code is only temporary
pub region_name: ast::Name,
}
/// NB: If you change this, you'll probably want to change the corresponding /// NB: If you change this, you'll probably want to change the corresponding
/// AST structure in libsyntax/ast.rs as well. /// AST structure in libsyntax/ast.rs as well.
#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] #[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]

View File

@ -1110,46 +1110,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
} }
hir::TyBareFn(ref bf) => { hir::TyBareFn(ref bf) => {
require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
let bare_fn_ty = self.ty_of_fn(bf.unsafety, bf.abi, &bf.decl); tcx.mk_fn_ptr(self.ty_of_fn(bf.unsafety, bf.abi, &bf.decl))
// Find any late-bound regions declared in return type that do
// not appear in the arguments. These are not wellformed.
//
// Example:
//
// for<'a> fn() -> &'a str <-- 'a is bad
// for<'a> fn(&'a String) -> &'a str <-- 'a is ok
//
// Note that we do this check **here** and not in
// `ty_of_bare_fn` because the latter is also used to make
// the types for fn items, and we do not want to issue a
// warning then. (Once we fix #32330, the regions we are
// checking for here would be considered early bound
// anyway.)
let inputs = bare_fn_ty.inputs();
let late_bound_in_args = tcx.collect_constrained_late_bound_regions(
&inputs.map_bound(|i| i.to_owned()));
let output = bare_fn_ty.output();
let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
for br in late_bound_in_ret.difference(&late_bound_in_args) {
let br_name = match *br {
ty::BrNamed(_, name) => name,
_ => {
span_bug!(
bf.decl.output.span(),
"anonymous bound region {:?} in return but not args",
br);
}
};
struct_span_err!(tcx.sess,
ast_ty.span,
E0581,
"return type references lifetime `{}`, \
which does not appear in the fn input types",
br_name)
.emit();
}
tcx.mk_fn_ptr(bare_fn_ty)
} }
hir::TyTraitObject(ref bounds, ref lifetime) => { hir::TyTraitObject(ref bounds, ref lifetime) => {
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime) self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
@ -1269,23 +1230,56 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
-> ty::PolyFnSig<'tcx> { -> ty::PolyFnSig<'tcx> {
debug!("ty_of_fn"); debug!("ty_of_fn");
let tcx = self.tcx();
let input_tys: Vec<Ty> = let input_tys: Vec<Ty> =
decl.inputs.iter().map(|a| self.ty_of_arg(a, None)).collect(); decl.inputs.iter().map(|a| self.ty_of_arg(a, None)).collect();
let output_ty = match decl.output { let output_ty = match decl.output {
hir::Return(ref output) => self.ast_ty_to_ty(output), hir::Return(ref output) => self.ast_ty_to_ty(output),
hir::DefaultReturn(..) => self.tcx().mk_nil(), hir::DefaultReturn(..) => tcx.mk_nil(),
}; };
debug!("ty_of_fn: output_ty={:?}", output_ty); debug!("ty_of_fn: output_ty={:?}", output_ty);
ty::Binder(self.tcx().mk_fn_sig( let bare_fn_ty = ty::Binder(tcx.mk_fn_sig(
input_tys.into_iter(), input_tys.into_iter(),
output_ty, output_ty,
decl.variadic, decl.variadic,
unsafety, unsafety,
abi abi
)) ));
// Find any late-bound regions declared in return type that do
// not appear in the arguments. These are not wellformed.
//
// Example:
// for<'a> fn() -> &'a str <-- 'a is bad
// for<'a> fn(&'a String) -> &'a str <-- 'a is ok
let inputs = bare_fn_ty.inputs();
let late_bound_in_args = tcx.collect_constrained_late_bound_regions(
&inputs.map_bound(|i| i.to_owned()));
let output = bare_fn_ty.output();
let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
for br in late_bound_in_ret.difference(&late_bound_in_args) {
let br_name = match *br {
ty::BrNamed(_, name) => name,
_ => {
span_bug!(
decl.output.span(),
"anonymous bound region {:?} in return but not args",
br);
}
};
struct_span_err!(tcx.sess,
decl.output.span(),
E0581,
"return type references lifetime `{}`, \
which does not appear in the fn input types",
br_name)
.emit();
}
bare_fn_ty
} }
pub fn ty_of_closure(&self, pub fn ty_of_closure(&self,

View File

@ -1607,7 +1607,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>) fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
-> Option<ty::Region<'tcx>> { -> Option<ty::Region<'tcx>> {
let v = match def { let v = match def {
Some(def) => infer::EarlyBoundRegion(span, def.name, def.issue_32330), Some(def) => infer::EarlyBoundRegion(span, def.name),
None => infer::MiscVariable(span) None => infer::MiscVariable(span)
}; };
Some(self.next_region_var(v)) Some(self.next_region_var(v))

View File

@ -979,13 +979,11 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics); let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
let regions = early_lifetimes.enumerate().map(|(i, l)| { let regions = early_lifetimes.enumerate().map(|(i, l)| {
let issue_32330 = tcx.named_region_map.issue_32330.get(&l.lifetime.id).cloned();
ty::RegionParameterDef { ty::RegionParameterDef {
name: l.lifetime.name, name: l.lifetime.name,
index: own_start + i as u32, index: own_start + i as u32,
def_id: tcx.hir.local_def_id(l.lifetime.id), def_id: tcx.hir.local_def_id(l.lifetime.id),
pure_wrt_drop: l.pure_wrt_drop, pure_wrt_drop: l.pure_wrt_drop,
issue_32330: issue_32330,
} }
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();

View File

@ -43,23 +43,19 @@ fn baz<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
(a, b) (a, b)
} }
// FIXME(#32330) #[cfg(transmute)] // one instantiations: BAD
//#[cfg(transmute)] // one instantiations: BAD fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
//fn baz<'a,'b>(x: &'a u32) -> &'static u32 { bar(foo, x) //[transmute]~ ERROR E0495
// bar(foo, x) //[transmute] ERROR E0495 }
//}
// FIXME(#32330) #[cfg(krisskross)] // two instantiations, mixing and matching: BAD
//#[cfg(krisskross)] // two instantiations, mixing and matching: BAD fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
//fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) { let a = bar(foo, y); //[krisskross]~ ERROR E0495
// let a = bar(foo, y); //[krisskross] ERROR E0495 let b = bar(foo, x); //[krisskross]~ ERROR E0495
// let b = bar(foo, x); //[krisskross] ERROR E0495 (a, b)
// (a, b) }
//}
#[rustc_error] #[rustc_error]
fn main() { } fn main() { }
//[ok]~^ ERROR compilation successful //[ok]~^ ERROR compilation successful
//[oneuse]~^^ ERROR compilation successful //[oneuse]~^^ ERROR compilation successful
//[transmute]~^^^ ERROR compilation successful
//[krisskross]~^^^^ ERROR compilation successful

View File

@ -42,35 +42,29 @@ fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
(a, b) (a, b)
} }
// FIXME(#32330) #[cfg(oneuse)] // one instantiation: BAD
//#[cfg(oneuse)] // one instantiation: BAD fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
//fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { let f = foo; // <-- No consistent type can be inferred for `f` here.
// let f = foo; // <-- No consistent type can be inferred for `f` here. let a = bar(f, x); //[oneuse]~^ ERROR E0495
// let a = bar(f, x); //[oneuse] ERROR E0495 let b = bar(f, y);
// let b = bar(f, y); (a, b)
// (a, b) }
//}
// FIXME(#32330) #[cfg(transmute)] // one instantiations: BAD
//#[cfg(transmute)] // one instantiations: BAD fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
//fn baz<'a,'b>(x: Type<'a>) -> Type<'static> { // Cannot instantiate `foo` with any lifetime other than `'a`,
// // Cannot instantiate `foo` with any lifetime other than `'a`, // since it is provided as input.
// // since it is provided as input.
//
// bar(foo, x) //[transmute] ERROR E0495
//}
// FIXME(#32330) bar(foo, x) //[transmute]~ ERROR E0495
//#[cfg(krisskross)] // two instantiations, mixing and matching: BAD }
//fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
// let a = bar(foo, y); //[krisskross] ERROR E0495 #[cfg(krisskross)] // two instantiations, mixing and matching: BAD
// let b = bar(foo, x); //[krisskross] ERROR E0495 fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
// (a, b) let a = bar(foo, y); //[krisskross]~ ERROR E0495
//} let b = bar(foo, x); //[krisskross]~ ERROR E0495
(a, b)
}
#[rustc_error] #[rustc_error]
fn main() { } fn main() { }
//[ok]~^ ERROR compilation successful //[ok]~^ ERROR compilation successful
//[oneuse]~^^ ERROR compilation successful
//[transmute]~^^^ ERROR compilation successful
//[krisskross]~^^^^ ERROR compilation successful

View File

@ -91,9 +91,6 @@ check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
// - if we are covariant, then 'a and 'b can be set to the call-site // - if we are covariant, then 'a and 'b can be set to the call-site
// intersection; // intersection;
// - if we are contravariant, then 'a can be inferred to 'static. // - if we are contravariant, then 'a can be inferred to 'static.
//
// FIXME(#32330) this is true, but we are not currently impl'ing this
// full semantics
check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32), check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
for<'a> fn(&'a u32, &'a u32)) } for<'a> fn(&'a u32, &'a u32)) }
check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>), check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),

View File

@ -6,8 +6,6 @@ error[E0308]: mismatched types
| |
= note: expected type `fn(&'cx S) -> &'cx S` = note: expected type `fn(&'cx S) -> &'cx S`
found type `fn(&'a S) -> &S {bar::<'_>}` found type `fn(&'a S) -> &S {bar::<'_>}`
= note: lifetime parameter `'b` declared on fn `bar` appears only in the return type, but here is required to be higher-ranked, which means that `'b` must appear in both argument and return types
= note: this error is the result of a recent bug fix; for more information, see issue #33685 <https://github.com/rust-lang/rust/issues/33685>
error: aborting due to previous error error: aborting due to previous error