diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index c28ddf876b3c..ad4ee5a9d6dc 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -281,7 +281,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn instantiate_method_substs(&mut self, pick: &probe::Pick<'tcx>, segment: &hir::PathSegment, - substs: &Substs<'tcx>) + parent_substs: &Substs<'tcx>) -> &'tcx Substs<'tcx> { // Determine the values for the generic parameters of the method. // If they were not explicitly supplied, just construct fresh @@ -296,20 +296,23 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { hir::AngleBracketedParameters(ref data) => (&data.types, &data.lifetimes), _ => bug!("unexpected generic arguments: {:?}", segment.parameters), }; + assert_eq!(method_generics.parent_count(), parent_substs.len()); Substs::for_item(self.tcx, pick.item.def_id, |def, _| { let i = def.index as usize; - if i < substs.len() { - substs.region_at(i) - } else if let Some(lifetime) = supplied_lifetimes.get(i - substs.len()) { + if i < parent_substs.len() { + parent_substs.region_at(i) + } else if let Some(lifetime) = + supplied_lifetimes.get(i - parent_substs.len()) { AstConv::ast_region_to_region(self.fcx, lifetime, Some(def)) } else { self.region_var_for_def(self.span, def) } }, |def, cur_substs| { let i = def.index as usize; - if i < substs.len() { - substs.type_at(i) - } else if let Some(ast_ty) = supplied_types.get(i - substs.len()) { + if i < parent_substs.len() { + parent_substs.type_at(i) + } else if let Some(ast_ty) = + supplied_types.get(i - parent_substs.len() - method_generics.regions.len()) { self.to_ty(ast_ty) } else { self.type_var_for_def(self.span, def, cur_substs) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 917bffbc22f0..af11cacb247b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4697,13 +4697,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.sess.span_err(lifetimes[0].span, "cannot specify lifetime arguments explicitly \ if late bound lifetime parameters are present"); + *segment = None; } else { self.tcx.sess.add_lint(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, lifetimes[0].id, lifetimes[0].span, format!("cannot specify lifetime arguments explicitly \ if late bound lifetime parameters are present")); } - *segment = None; return; } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 32ccfc511fc4..72bd084330dd 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -777,7 +777,7 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> bool { struct LateBoundRegionsDetector<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - binder_depth: usize, + binder_depth: u32, has_late_bound_regions: bool, } @@ -812,7 +812,10 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match self.tcx.named_region_map.defs.get(<.id).cloned() { Some(rl::Region::Static) | Some(rl::Region::EarlyBound(..)) => {} - _ => self.has_late_bound_regions = true + Some(rl::Region::LateBound(debruijn, _)) | + Some(rl::Region::LateBoundAnon(debruijn, _)) + if debruijn.depth < self.binder_depth => {} + _ => self.has_late_bound_regions = true, } } } @@ -822,7 +825,7 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, decl: &'tcx hir::FnDecl) -> bool { let mut visitor = LateBoundRegionsDetector { - tcx, binder_depth: 0, has_late_bound_regions: false + tcx, binder_depth: 1, has_late_bound_regions: false }; for lifetime in &generics.lifetimes { if tcx.named_region_map.late_bound.contains(&lifetime.lifetime.id) { diff --git a/src/test/compile-fail/method-call-lifetime-args-lint.rs b/src/test/compile-fail/method-call-lifetime-args-lint.rs index 9bf34de92fe8..b206924e538f 100644 --- a/src/test/compile-fail/method-call-lifetime-args-lint.rs +++ b/src/test/compile-fail/method-call-lifetime-args-lint.rs @@ -17,6 +17,14 @@ impl S { fn late_implicit(self, _: &u8, _: &u8) {} fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } + + // 'late lifetimes here belong to nested types not to the tested functions. + fn early_tricky_explicit<'a>(_: for<'late> fn(&'late u8), + _: Box Fn(&'late u8)>) + -> &'a u8 { loop {} } + fn early_tricky_implicit<'a>(_: fn(&u8), + _: Box) + -> &'a u8 { loop {} } } fn method_call() { @@ -61,6 +69,9 @@ fn method_call() { S.late_implicit_early::<'static, 'static, 'static>(&0); //~^ ERROR cannot specify lifetime arguments explicitly //~| WARN this was previously accepted + + S::early_tricky_explicit::<'static>(loop {}, loop {}); // OK + S::early_tricky_implicit::<'static>(loop {}, loop {}); // OK } fn ufcs() { @@ -73,4 +84,13 @@ fn ufcs() { //~| WARN this was previously accepted } +fn lint_not_inference_error() { + fn f<'early, 'late, T: 'early>() {} + + // Make sure `u8` is substituted and not replaced with an inference variable + f::<'static, u8>; + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted +} + fn main() {} diff --git a/src/test/compile-fail/method-call-lifetime-args-subst-index.rs b/src/test/compile-fail/method-call-lifetime-args-subst-index.rs new file mode 100644 index 000000000000..a9505e4f936a --- /dev/null +++ b/src/test/compile-fail/method-call-lifetime-args-subst-index.rs @@ -0,0 +1,25 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] +#![allow(unused)] + +struct S; + +impl S { + fn early_and_type<'a, T>(self) -> &'a T { loop {} } +} + +fn test() { + S.early_and_type::(); +} + +#[rustc_error] +fn main() {} //~ ERROR compilation successful diff --git a/src/test/compile-fail/method-call-lifetime-args.rs b/src/test/compile-fail/method-call-lifetime-args.rs index c29701804a74..f0a87c747038 100644 --- a/src/test/compile-fail/method-call-lifetime-args.rs +++ b/src/test/compile-fail/method-call-lifetime-args.rs @@ -19,14 +19,6 @@ impl S { fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} } fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} } fn life_and_type<'a, T>(self) -> &'a T { loop {} } - - // 'late lifetimes here belong to nested types not to the tested functions. - fn early_tricky_explicit<'a>(_: for<'late> fn(&'late u8), - _: Box Fn(&'late u8)>) - -> &'a u8 { loop {} } - fn early_tricky_implicit<'a>(_: fn(&u8), - _: Box) - -> &'a u8 { loop {} } } fn method_call() { @@ -85,9 +77,6 @@ fn ufcs() { let _: &u8 = S::life_and_type::<'static>(S); S::life_and_type::(S); S::life_and_type::<'static, u8>(S); - - S::early_tricky_explicit::<'static>(loop {}, loop {}); // OK - S::early_tricky_implicit::<'static>(loop {}, loop {}); // OK } fn main() {}