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,
def_id,
index,
issue_32330: _,
pure_wrt_drop
} = *self;

View File

@ -66,8 +66,7 @@ use hir::map as hir_map;
use hir::def_id::DefId;
use middle::region;
use traits::{ObligationCause, ObligationCauseCode};
use ty::{self, TyCtxt, TypeFoldable};
use ty::{Region, Issue32330};
use ty::{self, Region, TyCtxt, TypeFoldable};
use ty::error::TypeError;
use syntax::ast::DUMMY_NODE_ID;
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);
}
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,
trace: TypeTrace<'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_issue_32330(&mut diag, terr);
diag
}
@ -934,7 +903,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
format!(" for lifetime parameter {}in trait containing associated type `{}`",
br_string(br), type_name)
}
infer::EarlyBoundRegion(_, name, _) => {
infer::EarlyBoundRegion(_, name) => {
format!(" for lifetime parameter `{}`",
name)
}

View File

@ -13,9 +13,7 @@
use super::{CombinedSnapshot,
InferCtxt,
LateBoundRegion,
HigherRankedType,
RegionVariableOrigin,
SubregionOrigin,
SkolemizationMap};
use super::combine::CombineFields;
@ -29,15 +27,6 @@ use util::nodemap::{FxHashMap, FxHashSet};
pub struct HrMatchResult<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> {
@ -108,7 +97,6 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
/// that do not appear in `T`. If that happens, those regions are
/// unconstrained, and this routine replaces them with `'static`.
pub fn higher_ranked_match<T, U>(&mut self,
span: Span,
a_pair: &Binder<(T, U)>,
b_match: &T,
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
// `skol_map`. There should always be a representative if things
// are properly well-formed.
let mut unconstrained_regions = vec![];
let skol_representatives: FxHashMap<_, _> =
skol_resolution_map
.iter()
.map(|(&skol, &(br, ref regions))| {
.map(|(&skol, &(_, ref regions))| {
let representative =
regions.iter()
.filter(|&&r| !skol_resolution_map.contains_key(r))
.cloned()
.next()
.unwrap_or_else(|| { // [1]
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).
.expect("no representative region");
(skol, representative)
})
@ -216,10 +192,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
// We are now done with these skolemized variables.
self.infcx.pop_skolemized(skol_map, snapshot);
Ok(HrMatchResult {
value: a_value,
unconstrained_regions,
})
Ok(HrMatchResult { value: a_value })
});
}
@ -657,28 +630,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
skol_br,
tainted_region);
let issue_32330 = if let &ty::ReVar(vid) = tainted_region {
match self.region_vars.var_origin(vid) {
RegionVariableOrigin::EarlyBoundRegion(_, _, issue_32330) => {
issue_32330.map(Box::new)
}
_ => None
}
} else {
None
};
if overly_polymorphic {
return Err(if overly_polymorphic {
debug!("Overly polymorphic!");
return Err(TypeError::RegionsOverlyPolymorphic(skol_br,
tainted_region,
issue_32330));
TypeError::RegionsOverlyPolymorphic(skol_br, tainted_region)
} else {
debug!("Not as polymorphic!");
return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br,
tainted_region,
issue_32330));
}
TypeError::RegionsInsufficientlyPolymorphic(skol_br, tainted_region)
})
}
}

View File

@ -299,7 +299,7 @@ pub enum RegionVariableOrigin {
Coercion(Span),
// 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
// in a function or method that is called
@ -989,7 +989,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
span: Span,
def: &ty::RegionParameterDef)
-> 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
@ -1278,14 +1278,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-> InferResult<'tcx, HrMatchResult<Ty<'tcx>>>
{
let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref(self.tcx), p.ty));
let span = cause.span;
let trace = TypeTrace {
cause,
values: TraitRefs(ExpectedFound::new(true, match_pair.skip_binder().0, match_b))
};
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 })
}

View File

@ -153,10 +153,6 @@ pub struct NamedRegionMap {
// (b) it DOES appear in the arguments.
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
// to the trait object lifetime defaults computed from them.
pub object_lifetime_defaults: NodeMap<Vec<ObjectLifetimeDefault>>,
@ -261,7 +257,6 @@ pub fn krate(sess: &Session,
let mut map = NamedRegionMap {
defs: NodeMap(),
late_bound: NodeSet(),
issue_32330: NodeMap(),
object_lifetime_defaults: compute_object_lifetime_defaults(sess, hir_map),
};
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) {
match item.node {
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);
});
}
@ -355,7 +350,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
match item.node {
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);
})
}
@ -406,7 +401,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
if let hir::TraitItemKind::Method(ref sig, _) = trait_item.node {
self.visit_early_late(
trait_item.id,
Some(self.hir_map.get_parent(trait_item.id)),
&sig.decl, &sig.generics,
|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) {
if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
self.visit_early_late(
impl_item.id,
Some(self.hir_map.get_parent(impl_item.id)),
&sig.decl, &sig.generics,
|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
/// ordering is not important there.
fn visit_early_late<F>(&mut self,
fn_id: ast::NodeId,
parent_id: Option<ast::NodeId>,
decl: &'tcx hir::FnDecl,
generics: &'tcx hir::Generics,
walk: F) where
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,
fn_def_id,
decl,
generics);
insert_late_bound_lifetimes(self.map, decl, generics);
// Find the start of nested early scopes, e.g. in methods.
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
/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
fn_def_id: DefId,
decl: &hir::FnDecl,
generics: &hir::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.
if appears_in_output.impl_trait { continue; }
// does not appear in the inputs, but appears in the return
// type? eventually this will be early-bound, but for now we
// just mark it so we can issue warnings.
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,
});
// does not appear in the inputs, but appears in the return type? early-bound.
if !constrained_by_input.regions.contains(&name) &&
appears_in_output.regions.contains(&name) {
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);
match project_type(selcx, &obligation) {
Ok(ProjectedTy::Progress(Progress { ty: projected_ty,
mut obligations,
cacheable })) => {
Ok(ProjectedTy::Progress(Progress { ty: projected_ty, mut obligations })) => {
// if projection succeeded, then what we get out of this
// is also non-normalized (consider: it was derived from
// 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: \
projected_ty={:?} \
depth={} \
obligations={:?} \
cacheable={:?}",
obligations={:?}",
projected_ty,
depth,
obligations,
cacheable);
obligations);
let result = if projected_ty.has_projection_types() {
let mut normalizer = AssociatedTypeNormalizer::new(selcx,
@ -520,8 +516,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
obligations,
}
};
infcx.projection_cache.borrow_mut()
.complete(projection_ty, &result, cacheable);
infcx.projection_cache.borrow_mut().complete(projection_ty, &result);
Some(result)
}
Ok(ProjectedTy::NoProgress(projected_ty)) => {
@ -532,8 +527,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
value: projected_ty,
obligations: vec![]
};
infcx.projection_cache.borrow_mut()
.complete(projection_ty, &result, true);
infcx.projection_cache.borrow_mut().complete(projection_ty, &result);
Some(result)
}
Err(ProjectionTyError::TooManyCandidates) => {
@ -606,7 +600,6 @@ enum ProjectedTy<'tcx> {
struct Progress<'tcx> {
ty: Ty<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
cacheable: bool,
}
impl<'tcx> Progress<'tcx> {
@ -614,7 +607,6 @@ impl<'tcx> Progress<'tcx> {
Progress {
ty: tcx.types.err,
obligations: vec![],
cacheable: true
}
}
@ -1228,7 +1220,6 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
Progress {
ty: ty_match.value,
obligations,
cacheable: ty_match.unconstrained_regions.is_empty(),
}
}
Err(e) => {
@ -1272,7 +1263,6 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
Progress {
ty: ty.subst(tcx, substs),
obligations: nested,
cacheable: true
}
}
@ -1380,22 +1370,11 @@ impl<'tcx> ProjectionCache<'tcx> {
Ok(())
}
/// Indicates that `key` was normalized to `value`. If `cacheable` is false,
/// then this result is sadly not cacheable.
fn complete(&mut self,
key: ty::ProjectionTy<'tcx>,
value: &NormalizedTy<'tcx>,
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)
};
/// Indicates that `key` was normalized to `value`.
fn complete(&mut self, key: ty::ProjectionTy<'tcx>, value: &NormalizedTy<'tcx>) {
debug!("ProjectionCacheEntry::complete: adding cache entry: key={:?}, value={:?}",
key, value);
let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.value));
assert!(!fresh_key, "never started projecting `{:?}`", key);
}

View File

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

View File

@ -67,7 +67,6 @@ pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
pub use self::sty::{ExistentialProjection, PolyExistentialProjection};
pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
pub use self::sty::RegionKind;
pub use self::sty::Issue32330;
pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
pub use self::sty::BoundRegion::*;
pub use self::sty::InferTy::*;
@ -676,7 +675,6 @@ pub struct RegionParameterDef {
pub name: Name,
pub def_id: DefId,
pub index: u32,
pub issue_32330: Option<ty::Issue32330>,
/// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
/// 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) => {
return tcx.lift(&(a, b)).map(|(a, b)| RegionsNoOverlap(a, b))
}
RegionsInsufficientlyPolymorphic(a, b, ref c) => {
let c = c.clone();
return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b, c))
RegionsInsufficientlyPolymorphic(a, b) => {
return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b))
}
RegionsOverlyPolymorphic(a, b, ref c) => {
let c = c.clone();
return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b, c))
RegionsOverlyPolymorphic(a, b) => {
return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b))
}
IntMismatch(x) => IntMismatch(x),
FloatMismatch(x) => FloatMismatch(x),
@ -1004,13 +1002,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
RegionsNoOverlap(a, b) => {
RegionsNoOverlap(a.fold_with(folder), b.fold_with(folder))
},
RegionsInsufficientlyPolymorphic(a, b, ref c) => {
let c = c.clone();
RegionsInsufficientlyPolymorphic(a, b.fold_with(folder), c)
RegionsInsufficientlyPolymorphic(a, b) => {
RegionsInsufficientlyPolymorphic(a, b.fold_with(folder))
},
RegionsOverlyPolymorphic(a, b, ref c) => {
let c = c.clone();
RegionsOverlyPolymorphic(a, b.fold_with(folder), c)
RegionsOverlyPolymorphic(a, b) => {
RegionsOverlyPolymorphic(a, b.fold_with(folder))
},
IntMismatch(x) => IntMismatch(x),
FloatMismatch(x) => FloatMismatch(x),
@ -1036,8 +1032,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
RegionsNoOverlap(a, b) => {
a.visit_with(visitor) || b.visit_with(visitor)
},
RegionsInsufficientlyPolymorphic(_, b, _) |
RegionsOverlyPolymorphic(_, b, _) => {
RegionsInsufficientlyPolymorphic(_, b) |
RegionsOverlyPolymorphic(_, b) => {
b.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
/// AST structure in libsyntax/ast.rs as well.
#[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) => {
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);
// 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)
tcx.mk_fn_ptr(self.ty_of_fn(bf.unsafety, bf.abi, &bf.decl))
}
hir::TyTraitObject(ref bounds, ref 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> {
debug!("ty_of_fn");
let tcx = self.tcx();
let input_tys: Vec<Ty> =
decl.inputs.iter().map(|a| self.ty_of_arg(a, None)).collect();
let output_ty = match decl.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);
ty::Binder(self.tcx().mk_fn_sig(
let bare_fn_ty = ty::Binder(tcx.mk_fn_sig(
input_tys.into_iter(),
output_ty,
decl.variadic,
unsafety,
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,

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>)
-> Option<ty::Region<'tcx>> {
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)
};
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 regions = early_lifetimes.enumerate().map(|(i, l)| {
let issue_32330 = tcx.named_region_map.issue_32330.get(&l.lifetime.id).cloned();
ty::RegionParameterDef {
name: l.lifetime.name,
index: own_start + i as u32,
def_id: tcx.hir.local_def_id(l.lifetime.id),
pure_wrt_drop: l.pure_wrt_drop,
issue_32330: issue_32330,
}
}).collect::<Vec<_>>();

View File

@ -43,23 +43,19 @@ fn baz<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
(a, b)
}
// FIXME(#32330)
//#[cfg(transmute)] // one instantiations: BAD
//fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
// bar(foo, x) //[transmute] ERROR E0495
//}
#[cfg(transmute)] // one instantiations: BAD
fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
bar(foo, x) //[transmute]~ ERROR E0495
}
// FIXME(#32330)
//#[cfg(krisskross)] // two instantiations, mixing and matching: BAD
//fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
// let a = bar(foo, y); //[krisskross] ERROR E0495
// let b = bar(foo, x); //[krisskross] ERROR E0495
// (a, b)
//}
#[cfg(krisskross)] // two instantiations, mixing and matching: BAD
fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
let a = bar(foo, y); //[krisskross]~ ERROR E0495
let b = bar(foo, x); //[krisskross]~ ERROR E0495
(a, b)
}
#[rustc_error]
fn main() { }
//[ok]~^ 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)
}
// FIXME(#32330)
//#[cfg(oneuse)] // one instantiation: BAD
//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 a = bar(f, x); //[oneuse] ERROR E0495
// let b = bar(f, y);
// (a, b)
//}
#[cfg(oneuse)] // one instantiation: BAD
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 a = bar(f, x); //[oneuse]~^ ERROR E0495
let b = bar(f, y);
(a, b)
}
// FIXME(#32330)
//#[cfg(transmute)] // one instantiations: BAD
//fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
// // Cannot instantiate `foo` with any lifetime other than `'a`,
// // since it is provided as input.
//
// bar(foo, x) //[transmute] ERROR E0495
//}
#[cfg(transmute)] // one instantiations: BAD
fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
// Cannot instantiate `foo` with any lifetime other than `'a`,
// since it is provided as input.
// FIXME(#32330)
//#[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
// let b = bar(foo, x); //[krisskross] ERROR E0495
// (a, b)
//}
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
let b = bar(foo, x); //[krisskross]~ ERROR E0495
(a, b)
}
#[rustc_error]
fn main() { }
//[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
// intersection;
// - 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),
for<'a> fn(&'a u32, &'a u32)) }
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`
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