Skip to content

Commit

Permalink
Fix incorrect subst index
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
petrochenkov committed Jul 17, 2017
1 parent e40cedb commit 46f427b
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 22 deletions.
17 changes: 10 additions & 7 deletions src/librustc_typeck/check/method/confirm.rs
Expand Up @@ -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
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/mod.rs
Expand Up @@ -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;
}

Expand Down
9 changes: 6 additions & 3 deletions src/librustc_typeck/collect.rs
Expand Up @@ -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,
}

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

match self.tcx.named_region_map.defs.get(&lt.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,
}
}
}
Expand All @@ -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) {
Expand Down
20 changes: 20 additions & 0 deletions src/test/compile-fail/method-call-lifetime-args-lint.rs
Expand Up @@ -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<for<'late> Fn(&'late u8)>)
-> &'a u8 { loop {} }
fn early_tricky_implicit<'a>(_: fn(&u8),
_: Box<Fn(&u8)>)
-> &'a u8 { loop {} }
}

fn method_call() {
Expand Down Expand Up @@ -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() {
Expand All @@ -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() {}
25 changes: 25 additions & 0 deletions 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 <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.

#![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::<u16>();
}

#[rustc_error]
fn main() {} //~ ERROR compilation successful
11 changes: 0 additions & 11 deletions src/test/compile-fail/method-call-lifetime-args.rs
Expand Up @@ -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<for<'late> Fn(&'late u8)>)
-> &'a u8 { loop {} }
fn early_tricky_implicit<'a>(_: fn(&u8),
_: Box<Fn(&u8)>)
-> &'a u8 { loop {} }
}

fn method_call() {
Expand Down Expand Up @@ -85,9 +77,6 @@ fn ufcs() {
let _: &u8 = S::life_and_type::<'static>(S);
S::life_and_type::<u8>(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() {}

0 comments on commit 46f427b

Please sign in to comment.