Skip to content

Commit 46f427b

Browse files
committed
Fix incorrect subst index
Fix treatment of lifetimes defined in nested types during detection of late bound regions in signatures. Do not replace substs with inference variables when "cannot specify lifetime arguments explicitly..." is reported as a lint.
1 parent e40cedb commit 46f427b

File tree

6 files changed

+62
-22
lines changed

6 files changed

+62
-22
lines changed

src/librustc_typeck/check/method/confirm.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
281281
fn instantiate_method_substs(&mut self,
282282
pick: &probe::Pick<'tcx>,
283283
segment: &hir::PathSegment,
284-
substs: &Substs<'tcx>)
284+
parent_substs: &Substs<'tcx>)
285285
-> &'tcx Substs<'tcx> {
286286
// Determine the values for the generic parameters of the method.
287287
// If they were not explicitly supplied, just construct fresh
@@ -296,20 +296,23 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
296296
hir::AngleBracketedParameters(ref data) => (&data.types, &data.lifetimes),
297297
_ => bug!("unexpected generic arguments: {:?}", segment.parameters),
298298
};
299+
assert_eq!(method_generics.parent_count(), parent_substs.len());
299300
Substs::for_item(self.tcx, pick.item.def_id, |def, _| {
300301
let i = def.index as usize;
301-
if i < substs.len() {
302-
substs.region_at(i)
303-
} else if let Some(lifetime) = supplied_lifetimes.get(i - substs.len()) {
302+
if i < parent_substs.len() {
303+
parent_substs.region_at(i)
304+
} else if let Some(lifetime) =
305+
supplied_lifetimes.get(i - parent_substs.len()) {
304306
AstConv::ast_region_to_region(self.fcx, lifetime, Some(def))
305307
} else {
306308
self.region_var_for_def(self.span, def)
307309
}
308310
}, |def, cur_substs| {
309311
let i = def.index as usize;
310-
if i < substs.len() {
311-
substs.type_at(i)
312-
} else if let Some(ast_ty) = supplied_types.get(i - substs.len()) {
312+
if i < parent_substs.len() {
313+
parent_substs.type_at(i)
314+
} else if let Some(ast_ty) =
315+
supplied_types.get(i - parent_substs.len() - method_generics.regions.len()) {
313316
self.to_ty(ast_ty)
314317
} else {
315318
self.type_var_for_def(self.span, def, cur_substs)

src/librustc_typeck/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4697,13 +4697,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
46974697
self.tcx.sess.span_err(lifetimes[0].span,
46984698
"cannot specify lifetime arguments explicitly \
46994699
if late bound lifetime parameters are present");
4700+
*segment = None;
47004701
} else {
47014702
self.tcx.sess.add_lint(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS,
47024703
lifetimes[0].id, lifetimes[0].span,
47034704
format!("cannot specify lifetime arguments explicitly \
47044705
if late bound lifetime parameters are present"));
47054706
}
4706-
*segment = None;
47074707
return;
47084708
}
47094709

src/librustc_typeck/collect.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
777777
-> bool {
778778
struct LateBoundRegionsDetector<'a, 'tcx: 'a> {
779779
tcx: TyCtxt<'a, 'tcx, 'tcx>,
780-
binder_depth: usize,
780+
binder_depth: u32,
781781
has_late_bound_regions: bool,
782782
}
783783

@@ -812,7 +812,10 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
812812

813813
match self.tcx.named_region_map.defs.get(&lt.id).cloned() {
814814
Some(rl::Region::Static) | Some(rl::Region::EarlyBound(..)) => {}
815-
_ => self.has_late_bound_regions = true
815+
Some(rl::Region::LateBound(debruijn, _)) |
816+
Some(rl::Region::LateBoundAnon(debruijn, _))
817+
if debruijn.depth < self.binder_depth => {}
818+
_ => self.has_late_bound_regions = true,
816819
}
817820
}
818821
}
@@ -822,7 +825,7 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
822825
decl: &'tcx hir::FnDecl)
823826
-> bool {
824827
let mut visitor = LateBoundRegionsDetector {
825-
tcx, binder_depth: 0, has_late_bound_regions: false
828+
tcx, binder_depth: 1, has_late_bound_regions: false
826829
};
827830
for lifetime in &generics.lifetimes {
828831
if tcx.named_region_map.late_bound.contains(&lifetime.lifetime.id) {

src/test/compile-fail/method-call-lifetime-args-lint.rs

+20
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ impl S {
1717
fn late_implicit(self, _: &u8, _: &u8) {}
1818
fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} }
1919
fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} }
20+
21+
// 'late lifetimes here belong to nested types not to the tested functions.
22+
fn early_tricky_explicit<'a>(_: for<'late> fn(&'late u8),
23+
_: Box<for<'late> Fn(&'late u8)>)
24+
-> &'a u8 { loop {} }
25+
fn early_tricky_implicit<'a>(_: fn(&u8),
26+
_: Box<Fn(&u8)>)
27+
-> &'a u8 { loop {} }
2028
}
2129

2230
fn method_call() {
@@ -61,6 +69,9 @@ fn method_call() {
6169
S.late_implicit_early::<'static, 'static, 'static>(&0);
6270
//~^ ERROR cannot specify lifetime arguments explicitly
6371
//~| WARN this was previously accepted
72+
73+
S::early_tricky_explicit::<'static>(loop {}, loop {}); // OK
74+
S::early_tricky_implicit::<'static>(loop {}, loop {}); // OK
6475
}
6576

6677
fn ufcs() {
@@ -73,4 +84,13 @@ fn ufcs() {
7384
//~| WARN this was previously accepted
7485
}
7586

87+
fn lint_not_inference_error() {
88+
fn f<'early, 'late, T: 'early>() {}
89+
90+
// Make sure `u8` is substituted and not replaced with an inference variable
91+
f::<'static, u8>;
92+
//~^ ERROR cannot specify lifetime arguments explicitly
93+
//~| WARN this was previously accepted
94+
}
95+
7696
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(rustc_attrs)]
12+
#![allow(unused)]
13+
14+
struct S;
15+
16+
impl S {
17+
fn early_and_type<'a, T>(self) -> &'a T { loop {} }
18+
}
19+
20+
fn test() {
21+
S.early_and_type::<u16>();
22+
}
23+
24+
#[rustc_error]
25+
fn main() {} //~ ERROR compilation successful

src/test/compile-fail/method-call-lifetime-args.rs

-11
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,6 @@ impl S {
1919
fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} }
2020
fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} }
2121
fn life_and_type<'a, T>(self) -> &'a T { loop {} }
22-
23-
// 'late lifetimes here belong to nested types not to the tested functions.
24-
fn early_tricky_explicit<'a>(_: for<'late> fn(&'late u8),
25-
_: Box<for<'late> Fn(&'late u8)>)
26-
-> &'a u8 { loop {} }
27-
fn early_tricky_implicit<'a>(_: fn(&u8),
28-
_: Box<Fn(&u8)>)
29-
-> &'a u8 { loop {} }
3022
}
3123

3224
fn method_call() {
@@ -85,9 +77,6 @@ fn ufcs() {
8577
let _: &u8 = S::life_and_type::<'static>(S);
8678
S::life_and_type::<u8>(S);
8779
S::life_and_type::<'static, u8>(S);
88-
89-
S::early_tricky_explicit::<'static>(loop {}, loop {}); // OK
90-
S::early_tricky_implicit::<'static>(loop {}, loop {}); // OK
9180
}
9281

9382
fn main() {}

0 commit comments

Comments
 (0)