Auto merge of #37057 - brson:nosuggest, r=nikomatsakis

rustc: Remove all "consider using an explicit lifetime parameter" suggestions

These give so many incorrect suggestions that having them is
detrimental to the user experience. The compiler should not be
suggesting changes to the code that are wrong - it is infuriating: not
only is the compiler telling you that _you don't understand_ borrowing,
_the compiler itself_ appears to not understand borrowing. It does not
inspire confidence.

r? @nikomatsakis
This commit is contained in:
bors 2017-01-27 22:13:41 +00:00
commit 154c202afb
7 changed files with 4 additions and 893 deletions

View File

@ -55,8 +55,6 @@
//! ported to this system, and which relies on string concatenation at the
//! time of error detection.
use self::FreshOrKept::*;
use super::InferCtxt;
use super::TypeTrace;
use super::SubregionOrigin;
@ -71,13 +69,10 @@ use super::region_inference::ProcessedErrors;
use super::region_inference::ProcessedErrorOrigin;
use super::region_inference::SameRegions;
use std::collections::HashSet;
use hir::map as hir_map;
use hir;
use lint;
use hir::def::Def;
use hir::def_id::DefId;
use infer;
use middle::region;
@ -86,13 +81,9 @@ use ty::{self, TyCtxt, TypeFoldable};
use ty::{Region, ReFree};
use ty::error::TypeError;
use std::cell::{Cell, RefCell};
use std::char::from_u32;
use std::fmt;
use syntax::ast;
use syntax::ptr::P;
use syntax::symbol::Symbol;
use syntax_pos::{self, Pos, Span};
use syntax_pos::{Pos, Span};
use errors::DiagnosticBuilder;
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
@ -292,7 +283,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ProcessedErrors(ref origins,
ref same_regions) => {
if !same_regions.is_empty() {
self.report_processed_errors(origins, same_regions);
self.report_processed_errors(origins);
}
}
}
@ -1050,9 +1041,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
fn report_processed_errors(&self,
origins: &[ProcessedErrorOrigin<'tcx>],
same_regions: &[SameRegions]) {
for (i, origin) in origins.iter().enumerate() {
origins: &[ProcessedErrorOrigin<'tcx>]) {
for origin in origins.iter() {
let mut err = match *origin {
ProcessedErrorOrigin::VariableFailure(ref var_origin) =>
self.report_inference_failure(var_origin.clone()),
@ -1060,78 +1050,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.report_concrete_failure(sr_origin.clone(), sub, sup),
};
// attach the suggestion to the last such error
if i == origins.len() - 1 {
self.give_suggestion(&mut err, same_regions);
}
err.emit();
}
}
fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegions]) {
let scope_id = same_regions[0].scope_id;
let parent = self.tcx.hir.get_parent(scope_id);
let parent_node = self.tcx.hir.find(parent);
let taken = lifetimes_in_scope(self.tcx, scope_id);
let life_giver = LifeGiver::with_taken(&taken[..]);
let node_inner = match parent_node {
Some(ref node) => match *node {
hir_map::NodeItem(ref item) => {
match item.node {
hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, body) => {
Some((fn_decl, gen, unsafety, constness, item.name, item.span, body))
}
_ => None,
}
}
hir_map::NodeImplItem(item) => {
let id = self.tcx.hir.get_parent(item.id);
if let Some(hir_map::NodeItem(parent_scope)) = self.tcx.hir.find(id) {
if let hir::ItemImpl(_, _, _, None, _, _) = parent_scope.node {
// this impl scope implements a trait, do not recomend
// using explicit lifetimes (#37363)
return;
}
}
if let hir::ImplItemKind::Method(ref sig, body) = item.node {
Some((&sig.decl,
&sig.generics,
sig.unsafety,
sig.constness,
item.name,
item.span,
body))
} else {
None
}
},
hir_map::NodeTraitItem(item) => {
match item.node {
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
Some((&sig.decl,
&sig.generics,
sig.unsafety,
sig.constness,
item.name,
item.span,
body))
}
_ => None,
}
}
_ => None,
},
None => None,
};
let (fn_decl, generics, unsafety, constness, name, span, body)
= node_inner.expect("expect item fn");
let rebuilder = Rebuilder::new(self.tcx, fn_decl, generics, same_regions, &life_giver);
let (fn_decl, generics) = rebuilder.rebuild();
self.give_expl_lifetime_param(
err, &fn_decl, unsafety, constness, name, &generics, span, body);
}
pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) {
for issue32330 in issue32330s {
match *issue32330 {
@ -1154,530 +1076,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}
struct RebuildPathInfo<'a> {
path: &'a hir::Path,
// indexes to insert lifetime on path.lifetimes
indexes: Vec<u32>,
// number of lifetimes we expect to see on the type referred by `path`
// (e.g., expected=1 for struct Foo<'a>)
expected: u32,
anon_nums: &'a HashSet<u32>,
region_names: &'a HashSet<ast::Name>
}
struct Rebuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
fn_decl: &'a hir::FnDecl,
generics: &'a hir::Generics,
same_regions: &'a [SameRegions],
life_giver: &'a LifeGiver,
cur_anon: Cell<u32>,
inserted_anons: RefCell<HashSet<u32>>,
}
enum FreshOrKept {
Fresh,
Kept
}
impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
fn_decl: &'a hir::FnDecl,
generics: &'a hir::Generics,
same_regions: &'a [SameRegions],
life_giver: &'a LifeGiver)
-> Rebuilder<'a, 'gcx, 'tcx> {
Rebuilder {
tcx: tcx,
fn_decl: fn_decl,
generics: generics,
same_regions: same_regions,
life_giver: life_giver,
cur_anon: Cell::new(0),
inserted_anons: RefCell::new(HashSet::new()),
}
}
fn rebuild(&self) -> (hir::FnDecl, hir::Generics) {
let mut inputs = self.fn_decl.inputs.clone();
let mut output = self.fn_decl.output.clone();
let mut ty_params = self.generics.ty_params.clone();
let where_clause = self.generics.where_clause.clone();
let mut kept_lifetimes = HashSet::new();
for sr in self.same_regions {
self.cur_anon.set(0);
self.offset_cur_anon();
let (anon_nums, region_names) =
self.extract_anon_nums_and_names(sr);
let (lifetime, fresh_or_kept) = self.pick_lifetime(&region_names);
match fresh_or_kept {
Kept => { kept_lifetimes.insert(lifetime.name); }
_ => ()
}
inputs = self.rebuild_args_ty(&inputs[..], lifetime,
&anon_nums, &region_names);
output = self.rebuild_output(&output, lifetime, &anon_nums, &region_names);
ty_params = self.rebuild_ty_params(ty_params, lifetime,
&region_names);
}
let fresh_lifetimes = self.life_giver.get_generated_lifetimes();
let all_region_names = self.extract_all_region_names();
let generics = self.rebuild_generics(self.generics,
&fresh_lifetimes,
&kept_lifetimes,
&all_region_names,
ty_params,
where_clause);
let new_fn_decl = hir::FnDecl {
inputs: inputs,
output: output,
variadic: self.fn_decl.variadic
};
(new_fn_decl, generics)
}
fn pick_lifetime(&self,
region_names: &HashSet<ast::Name>)
-> (hir::Lifetime, FreshOrKept) {
if !region_names.is_empty() {
// It's not necessary to convert the set of region names to a
// vector of string and then sort them. However, it makes the
// choice of lifetime name deterministic and thus easier to test.
let mut names = Vec::new();
for rn in region_names {
let lt_name = rn.to_string();
names.push(lt_name);
}
names.sort();
let name = Symbol::intern(&names[0]);
return (name_to_dummy_lifetime(name), Kept);
}
return (self.life_giver.give_lifetime(), Fresh);
}
fn extract_anon_nums_and_names(&self, same_regions: &SameRegions)
-> (HashSet<u32>, HashSet<ast::Name>) {
let mut anon_nums = HashSet::new();
let mut region_names = HashSet::new();
for br in &same_regions.regions {
match *br {
ty::BrAnon(i) => {
anon_nums.insert(i);
}
ty::BrNamed(_, name, _) => {
region_names.insert(name);
}
_ => ()
}
}
(anon_nums, region_names)
}
fn extract_all_region_names(&self) -> HashSet<ast::Name> {
let mut all_region_names = HashSet::new();
for sr in self.same_regions {
for br in &sr.regions {
match *br {
ty::BrNamed(_, name, _) => {
all_region_names.insert(name);
}
_ => ()
}
}
}
all_region_names
}
fn inc_cur_anon(&self, n: u32) {
let anon = self.cur_anon.get();
self.cur_anon.set(anon+n);
}
fn offset_cur_anon(&self) {
let mut anon = self.cur_anon.get();
while self.inserted_anons.borrow().contains(&anon) {
anon += 1;
}
self.cur_anon.set(anon);
}
fn inc_and_offset_cur_anon(&self, n: u32) {
self.inc_cur_anon(n);
self.offset_cur_anon();
}
fn track_anon(&self, anon: u32) {
self.inserted_anons.borrow_mut().insert(anon);
}
fn rebuild_ty_params(&self,
ty_params: hir::HirVec<hir::TyParam>,
lifetime: hir::Lifetime,
region_names: &HashSet<ast::Name>)
-> hir::HirVec<hir::TyParam> {
ty_params.into_iter().map(|ty_param| {
let bounds = self.rebuild_ty_param_bounds(ty_param.bounds,
lifetime,
region_names);
hir::TyParam {
name: ty_param.name,
id: ty_param.id,
bounds: bounds,
default: ty_param.default,
span: ty_param.span,
pure_wrt_drop: ty_param.pure_wrt_drop,
}
}).collect()
}
fn rebuild_ty_param_bounds(&self,
ty_param_bounds: hir::TyParamBounds,
lifetime: hir::Lifetime,
region_names: &HashSet<ast::Name>)
-> hir::TyParamBounds {
ty_param_bounds.iter().map(|tpb| {
match tpb {
&hir::RegionTyParamBound(lt) => {
// FIXME -- it's unclear whether I'm supposed to
// substitute lifetime here. I suspect we need to
// be passing down a map.
hir::RegionTyParamBound(lt)
}
&hir::TraitTyParamBound(ref poly_tr, modifier) => {
let tr = &poly_tr.trait_ref;
let last_seg = tr.path.segments.last().unwrap();
let mut insert = Vec::new();
let lifetimes = last_seg.parameters.lifetimes();
for (i, lt) in lifetimes.iter().enumerate() {
if region_names.contains(&lt.name) {
insert.push(i as u32);
}
}
let rebuild_info = RebuildPathInfo {
path: &tr.path,
indexes: insert,
expected: lifetimes.len() as u32,
anon_nums: &HashSet::new(),
region_names: region_names
};
let new_path = self.rebuild_path(rebuild_info, lifetime);
hir::TraitTyParamBound(hir::PolyTraitRef {
bound_lifetimes: poly_tr.bound_lifetimes.clone(),
trait_ref: hir::TraitRef {
path: new_path,
ref_id: tr.ref_id,
},
span: poly_tr.span,
}, modifier)
}
}
}).collect()
}
fn rebuild_generics(&self,
generics: &hir::Generics,
add: &Vec<hir::Lifetime>,
keep: &HashSet<ast::Name>,
remove: &HashSet<ast::Name>,
ty_params: hir::HirVec<hir::TyParam>,
where_clause: hir::WhereClause)
-> hir::Generics {
let mut lifetimes = Vec::new();
for lt in add {
lifetimes.push(hir::LifetimeDef {
lifetime: *lt,
bounds: hir::HirVec::new(),
pure_wrt_drop: false,
});
}
for lt in &generics.lifetimes {
if keep.contains(&lt.lifetime.name) ||
!remove.contains(&lt.lifetime.name) {
lifetimes.push((*lt).clone());
}
}
hir::Generics {
lifetimes: lifetimes.into(),
ty_params: ty_params,
where_clause: where_clause,
span: generics.span,
}
}
fn rebuild_args_ty(&self,
inputs: &[P<hir::Ty>],
lifetime: hir::Lifetime,
anon_nums: &HashSet<u32>,
region_names: &HashSet<ast::Name>)
-> hir::HirVec<P<hir::Ty>> {
inputs.iter().map(|arg_ty| {
self.rebuild_arg_ty_or_output(arg_ty, lifetime, anon_nums, region_names)
}).collect()
}
fn rebuild_output(&self, ty: &hir::FunctionRetTy,
lifetime: hir::Lifetime,
anon_nums: &HashSet<u32>,
region_names: &HashSet<ast::Name>) -> hir::FunctionRetTy {
match *ty {
hir::Return(ref ret_ty) => hir::Return(
self.rebuild_arg_ty_or_output(&ret_ty, lifetime, anon_nums, region_names)
),
hir::DefaultReturn(span) => hir::DefaultReturn(span),
}
}
fn rebuild_arg_ty_or_output(&self,
ty: &hir::Ty,
lifetime: hir::Lifetime,
anon_nums: &HashSet<u32>,
region_names: &HashSet<ast::Name>)
-> P<hir::Ty> {
let mut new_ty = P(ty.clone());
let mut ty_queue = vec![ty];
while !ty_queue.is_empty() {
let cur_ty = ty_queue.remove(0);
match cur_ty.node {
hir::TyRptr(lt_opt, ref mut_ty) => {
let rebuild = match lt_opt {
Some(lt) => region_names.contains(&lt.name),
None => {
let anon = self.cur_anon.get();
let rebuild = anon_nums.contains(&anon);
if rebuild {
self.track_anon(anon);
}
self.inc_and_offset_cur_anon(1);
rebuild
}
};
if rebuild {
let to = hir::Ty {
id: cur_ty.id,
node: hir::TyRptr(Some(lifetime), mut_ty.clone()),
span: cur_ty.span
};
new_ty = self.rebuild_ty(new_ty, P(to));
}
ty_queue.push(&mut_ty.ty);
}
hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
match path.def {
Def::Enum(did) | Def::TyAlias(did) |
Def::Struct(did) | Def::Union(did) => {
let generics = self.tcx.item_generics(did);
let expected =
generics.regions.len() as u32;
let lifetimes =
path.segments.last().unwrap().parameters.lifetimes();
let mut insert = Vec::new();
if lifetimes.is_empty() {
let anon = self.cur_anon.get();
for (i, a) in (anon..anon+expected).enumerate() {
if anon_nums.contains(&a) {
insert.push(i as u32);
}
self.track_anon(a);
}
self.inc_and_offset_cur_anon(expected);
} else {
for (i, lt) in lifetimes.iter().enumerate() {
if region_names.contains(&lt.name) {
insert.push(i as u32);
}
}
}
let rebuild_info = RebuildPathInfo {
path: path,
indexes: insert,
expected: expected,
anon_nums: anon_nums,
region_names: region_names
};
let new_path = self.rebuild_path(rebuild_info, lifetime);
let qself = maybe_qself.as_ref().map(|qself| {
self.rebuild_arg_ty_or_output(qself, lifetime,
anon_nums, region_names)
});
let to = hir::Ty {
id: cur_ty.id,
node: hir::TyPath(hir::QPath::Resolved(qself, P(new_path))),
span: cur_ty.span
};
new_ty = self.rebuild_ty(new_ty, P(to));
}
_ => ()
}
}
hir::TyPtr(ref mut_ty) => {
ty_queue.push(&mut_ty.ty);
}
hir::TySlice(ref ty) |
hir::TyArray(ref ty, _) => {
ty_queue.push(&ty);
}
hir::TyTup(ref tys) => ty_queue.extend(tys.iter().map(|ty| &**ty)),
_ => {}
}
}
new_ty
}
fn rebuild_ty(&self,
from: P<hir::Ty>,
to: P<hir::Ty>)
-> P<hir::Ty> {
fn build_to(from: P<hir::Ty>,
to: &mut Option<P<hir::Ty>>)
-> P<hir::Ty> {
if Some(from.id) == to.as_ref().map(|ty| ty.id) {
return to.take().expect("`to` type found more than once during rebuild");
}
from.map(|hir::Ty {id, node, span}| {
let new_node = match node {
hir::TyRptr(lifetime, mut_ty) => {
hir::TyRptr(lifetime, hir::MutTy {
mutbl: mut_ty.mutbl,
ty: build_to(mut_ty.ty, to),
})
}
hir::TyPtr(mut_ty) => {
hir::TyPtr(hir::MutTy {
mutbl: mut_ty.mutbl,
ty: build_to(mut_ty.ty, to),
})
}
hir::TySlice(ty) => hir::TySlice(build_to(ty, to)),
hir::TyArray(ty, e) => {
hir::TyArray(build_to(ty, to), e)
}
hir::TyTup(tys) => {
hir::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect())
}
other => other
};
hir::Ty { id: id, node: new_node, span: span }
})
}
build_to(from, &mut Some(to))
}
fn rebuild_path(&self,
rebuild_info: RebuildPathInfo,
lifetime: hir::Lifetime)
-> hir::Path
{
let RebuildPathInfo {
path,
indexes,
expected,
anon_nums,
region_names,
} = rebuild_info;
let last_seg = path.segments.last().unwrap();
let new_parameters = match last_seg.parameters {
hir::ParenthesizedParameters(..) => {
last_seg.parameters.clone()
}
hir::AngleBracketedParameters(ref data) => {
let mut new_lts = Vec::new();
if data.lifetimes.is_empty() {
// traverse once to see if there's a need to insert lifetime
let need_insert = (0..expected).any(|i| {
indexes.contains(&i)
});
if need_insert {
for i in 0..expected {
if indexes.contains(&i) {
new_lts.push(lifetime);
} else {
new_lts.push(self.life_giver.give_lifetime());
}
}
}
} else {
for (i, lt) in data.lifetimes.iter().enumerate() {
if indexes.contains(&(i as u32)) {
new_lts.push(lifetime);
} else {
new_lts.push(*lt);
}
}
}
let new_types = data.types.iter().map(|t| {
self.rebuild_arg_ty_or_output(&t, lifetime, anon_nums, region_names)
}).collect();
let new_bindings = data.bindings.iter().map(|b| {
hir::TypeBinding {
id: b.id,
name: b.name,
ty: self.rebuild_arg_ty_or_output(&b.ty,
lifetime,
anon_nums,
region_names),
span: b.span
}
}).collect();
hir::AngleBracketedParameters(hir::AngleBracketedParameterData {
lifetimes: new_lts.into(),
types: new_types,
infer_types: data.infer_types,
bindings: new_bindings,
})
}
};
let new_seg = hir::PathSegment {
name: last_seg.name,
parameters: new_parameters
};
let mut new_segs = Vec::new();
new_segs.extend_from_slice(path.segments.split_last().unwrap().1);
new_segs.push(new_seg);
hir::Path {
span: path.span,
def: path.def,
segments: new_segs.into()
}
}
}
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
fn give_expl_lifetime_param(&self,
err: &mut DiagnosticBuilder,
decl: &hir::FnDecl,
unsafety: hir::Unsafety,
constness: hir::Constness,
name: ast::Name,
generics: &hir::Generics,
span: Span,
body: hir::BodyId) {
let s = hir::print::to_string(&self.tcx.hir, |s| {
use syntax::abi::Abi;
use syntax::print::pprust::PrintState;
s.head("")?;
s.print_fn(decl,
unsafety,
constness,
Abi::Rust,
Some(name),
generics,
&hir::Inherited,
&[],
Some(body))?;
s.end()?; // Close the head box
s.end() // Close the outer box
});
let msg = format!("consider using an explicit lifetime parameter as shown: {}", s);
err.span_help(span, &msg[..]);
}
fn report_inference_failure(&self,
var_origin: RegionVariableOrigin)
-> DiagnosticBuilder<'tcx> {
@ -1890,114 +1289,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}
fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
scope_id: ast::NodeId)
-> Vec<hir::LifetimeDef> {
let mut taken = Vec::new();
let parent = tcx.hir.get_parent(scope_id);
let method_id_opt = match tcx.hir.find(parent) {
Some(node) => match node {
hir_map::NodeItem(item) => match item.node {
hir::ItemFn(.., ref gen, _) => {
taken.extend_from_slice(&gen.lifetimes);
None
},
_ => None
},
hir_map::NodeImplItem(ii) => {
match ii.node {
hir::ImplItemKind::Method(ref sig, _) => {
taken.extend_from_slice(&sig.generics.lifetimes);
Some(ii.id)
}
_ => None,
}
}
_ => None
},
None => None
};
if let Some(method_id) = method_id_opt {
let parent = tcx.hir.get_parent(method_id);
if let Some(node) = tcx.hir.find(parent) {
match node {
hir_map::NodeItem(item) => match item.node {
hir::ItemImpl(_, _, ref gen, ..) => {
taken.extend_from_slice(&gen.lifetimes);
}
_ => ()
},
_ => ()
}
}
}
return taken;
}
// LifeGiver is responsible for generating fresh lifetime names
struct LifeGiver {
taken: HashSet<String>,
counter: Cell<usize>,
generated: RefCell<Vec<hir::Lifetime>>,
}
impl LifeGiver {
fn with_taken(taken: &[hir::LifetimeDef]) -> LifeGiver {
let mut taken_ = HashSet::new();
for lt in taken {
let lt_name = lt.lifetime.name.to_string();
taken_.insert(lt_name);
}
LifeGiver {
taken: taken_,
counter: Cell::new(0),
generated: RefCell::new(Vec::new()),
}
}
fn inc_counter(&self) {
let c = self.counter.get();
self.counter.set(c+1);
}
fn give_lifetime(&self) -> hir::Lifetime {
let lifetime;
loop {
let mut s = String::from("'");
s.push_str(&num_to_string(self.counter.get()));
if !self.taken.contains(&s) {
lifetime = name_to_dummy_lifetime(Symbol::intern(&s));
self.generated.borrow_mut().push(lifetime);
break;
}
self.inc_counter();
}
self.inc_counter();
return lifetime;
// 0 .. 25 generates a .. z, 26 .. 51 generates aa .. zz, and so on
fn num_to_string(counter: usize) -> String {
let mut s = String::new();
let (n, r) = (counter/26 + 1, counter % 26);
let letter: char = from_u32((r+97) as u32).unwrap();
for _ in 0..n {
s.push(letter);
}
s
}
}
fn get_generated_lifetimes(&self) -> Vec<hir::Lifetime> {
self.generated.borrow().clone()
}
}
fn name_to_dummy_lifetime(name: ast::Name) -> hir::Lifetime {
hir::Lifetime { id: ast::DUMMY_NODE_ID,
span: syntax_pos::DUMMY_SP,
name: name }
}
impl<'tcx> ObligationCause<'tcx> {
fn as_failure_str(&self) -> &'static str {
use traits::ObligationCauseCode::*;
@ -2038,4 +1329,3 @@ impl<'tcx> ObligationCause<'tcx> {
}
}
}

View File

@ -20,7 +20,6 @@ impl<'r> Itble<'r, usize, Range<usize>> for (usize, usize) {
}
fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &T) -> bool
//~^ HELP as shown: fn check<'r, I: Iterator<Item = usize>, T: Itble<'r, usize, I>>(cont: &'r T)
{
let cont_iter = cont.iter();
//~^ ERROR cannot infer an appropriate lifetime for autoref due to conflicting requirements

View File

@ -1,36 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-tidy-linelength
use std::ops::Range;
trait Itble<'r, T, I: Iterator<Item=T>> { fn iter(&'r self) -> I; }
impl<'r> Itble<'r, usize, Range<usize>> for (usize, usize) {
fn iter(&'r self) -> Range<usize> {
let &(min, max) = self;
min..max
}
}
fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &T) -> bool {
//~^ HELP: consider using an explicit lifetime parameter as shown: fn check<'r, I: Iterator<Item = usize>, T: Itble<'r, usize, I>>(cont: &'r T)
let cont_iter = cont.iter(); //~ ERROR: cannot infer
let result = cont_iter.fold(Some(0), |state, val| {
state.map_or(None, |mask| {
let bit = 1 << val;
if mask & bit == 0 {Some(mask|bit)} else {None}
})
});
result.is_some()
}
fn main() {}

View File

@ -1,32 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-tidy-linelength
use std::marker::PhantomData;
struct Bar<'x, 'y, 'z> { bar: &'y i32, baz: i32, marker: PhantomData<(&'x(),&'y(),&'z())> }
fn bar1<'a>(x: &Bar) -> (&'a i32, &'a i32, &'a i32) {
//~^ HELP consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a i32, &'a i32, &'a i32)
(x.bar, &x.baz, &x.baz)
//~^ ERROR E0312
//~| ERROR cannot infer
//~| ERROR cannot infer
}
fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a i32, &'a i32, &'a i32) {
//~^ HELP: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a i32, &'a i32, &'a i32)
(x.bar, &x.baz, &x.baz)
//~^ ERROR E0312
//~| ERROR cannot infer
//~| ERROR cannot infer
}
fn main() { }

View File

@ -1,57 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-tidy-linelength
use std::marker::PhantomData;
struct Foo<'x> { bar: isize, marker: PhantomData<&'x ()> }
fn foo1<'a>(x: &Foo) -> &'a isize {
//~^ HELP: consider using an explicit lifetime parameter as shown: fn foo1<'a>(x: &'a Foo) -> &'a isize
&x.bar //~ ERROR: cannot infer
}
fn foo2<'a, 'b>(x: &'a Foo) -> &'b isize {
//~^ HELP: consider using an explicit lifetime parameter as shown: fn foo2<'a>(x: &'a Foo) -> &'a isize
&x.bar //~ ERROR: cannot infer
}
fn foo3<'a>(x: &Foo) -> (&'a isize, &'a isize) {
//~^ HELP: consider using an explicit lifetime parameter as shown: fn foo3<'a>(x: &'a Foo) -> (&'a isize, &'a isize)
(&x.bar, &x.bar) //~ ERROR: cannot infer
//~^ ERROR: cannot infer
}
fn foo4<'a, 'b>(x: &'a Foo) -> (&'b isize, &'a isize, &'b isize) {
//~^ HELP: consider using an explicit lifetime parameter as shown: fn foo4<'a>(x: &'a Foo) -> (&'a isize, &'a isize, &'a isize)
(&x.bar, &x.bar, &x.bar) //~ ERROR: cannot infer
//~^ ERROR: cannot infer
}
struct Cat<'x, T> { cat: &'x isize, t: T }
struct Dog<'y> { dog: &'y isize }
fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &'x isize {
//~^ HELP consider using an explicit lifetime parameter as shown: fn cat2<'x>(x: Cat<'x, Dog<'x>>) -> &'x isize
x.t.dog //~ ERROR E0312
}
struct Baz<'x> {
bar: &'x isize
}
impl<'a> Baz<'a> {
fn baz2<'b>(&self, x: &isize) -> (&'b isize, &'b isize) {
(self.bar, x) //~ ERROR E0312
//~^ ERROR E0312
}
}
fn main() {}

View File

@ -1,28 +0,0 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::str::FromStr;
pub struct Foo<'a> {
field: &'a str,
}
impl<'a> Foo<'a> {
fn bar(path: &str) -> Result<Self, ()> {
Ok(Foo { field: path })
}
}
impl<'a> FromStr for Foo<'a> {
type Err = ();
fn from_str(path: &str) -> Result<Self, ()> {
Ok(Foo { field: path })
}
}

View File

@ -1,25 +0,0 @@
error: main function not found
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> $DIR/consider-using-explicit-lifetime.rs:19:12
|
19 | Ok(Foo { field: path })
| ^^^
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> $DIR/consider-using-explicit-lifetime.rs:26:12
|
26 | Ok(Foo { field: path })
| ^^^
|
help: consider using an explicit lifetime parameter as shown: fn from_str(path: &'a str) -> Result<Self, ()>
--> $DIR/consider-using-explicit-lifetime.rs:25:5
|
25 | fn from_str(path: &str) -> Result<Self, ()> {
| _____^ starting here...
26 | | Ok(Foo { field: path })
27 | | }
| |_____^ ...ending here
error: aborting due to 2 previous errors