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.
This commit is contained in:
Vadim Petrochenkov 2017-07-11 23:12:06 +03:00
parent e40cedb393
commit 46f427bee9
6 changed files with 62 additions and 22 deletions

View File

@ -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)

View File

@ -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;
}

View File

@ -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(&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,
}
}
}
@ -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) {

View File

@ -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() {
@ -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() {}

View File

@ -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

View File

@ -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() {
@ -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() {}