Skip to content

Commit b2b2bbb

Browse files
committed
auto merge of #13112 : ktt3ja/rust/issue-13058, r=pnkfelix
Previously, Rebuilder did not visit type parameters when rebuilding generics and path, so in some cases the suggestion turns out to be erroneous.
2 parents 9539be6 + 1d99d37 commit b2b2bbb

File tree

3 files changed

+157
-24
lines changed

3 files changed

+157
-24
lines changed

src/librustc/middle/typeck/infer/error_reporting.rs

+110-24
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ use syntax::ast;
8080
use syntax::ast_map;
8181
use syntax::ast_util;
8282
use syntax::ast_util::name_to_dummy_lifetime;
83+
use syntax::owned_slice::OwnedSlice;
8384
use syntax::parse::token;
8485
use syntax::print::pprust;
8586
use util::ppaux::UserString;
@@ -678,6 +679,17 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
678679
}
679680
}
680681

682+
struct RebuildPathInfo<'a> {
683+
path: &'a ast::Path,
684+
// indexes to insert lifetime on path.lifetimes
685+
indexes: Vec<uint>,
686+
// number of lifetimes we expect to see on the type referred by `path`
687+
// (e.g., expected=1 for struct Foo<'a>)
688+
expected: uint,
689+
anon_nums: &'a HashSet<uint>,
690+
region_names: &'a HashSet<ast::Name>
691+
}
692+
681693
struct Rebuilder<'a> {
682694
tcx: &'a ty::ctxt,
683695
fn_decl: ast::P<ast::FnDecl>,
@@ -708,6 +720,7 @@ impl<'a> Rebuilder<'a> {
708720
fn rebuild(&self) -> (Vec<ast::Arg>, ast::P<ast::Ty>, ast::Generics) {
709721
let mut inputs = self.fn_decl.inputs.clone();
710722
let mut output = self.fn_decl.output;
723+
let mut ty_params = self.generics.ty_params.clone();
711724
for sr in self.same_regions.iter() {
712725
self.cur_anon.set(0);
713726
self.offset_cur_anon();
@@ -718,12 +731,14 @@ impl<'a> Rebuilder<'a> {
718731
&anon_nums, &region_names);
719732
output = self.rebuild_arg_ty_or_output(output, lifetime,
720733
&anon_nums, &region_names);
734+
ty_params = self.rebuild_ty_params(ty_params, lifetime,
735+
&region_names);
721736
}
722737
let generated_lifetimes = self.life_giver.get_generated_lifetimes();
723738
let all_region_names = self.extract_all_region_names();
724739
let generics = self.rebuild_generics(self.generics,
725740
generated_lifetimes,
726-
&all_region_names);
741+
&all_region_names, ty_params);
727742
(inputs, output, generics)
728743
}
729744

@@ -782,10 +797,62 @@ impl<'a> Rebuilder<'a> {
782797
self.inserted_anons.borrow_mut().insert(anon);
783798
}
784799

800+
fn rebuild_ty_params(&self,
801+
ty_params: OwnedSlice<ast::TyParam>,
802+
lifetime: ast::Lifetime,
803+
region_names: &HashSet<ast::Name>)
804+
-> OwnedSlice<ast::TyParam> {
805+
ty_params.map(|ty_param| {
806+
let bounds = self.rebuild_ty_param_bounds(ty_param.bounds.clone(),
807+
lifetime,
808+
region_names);
809+
ast::TyParam {
810+
ident: ty_param.ident,
811+
id: ty_param.id,
812+
bounds: bounds,
813+
default: ty_param.default,
814+
}
815+
})
816+
}
817+
818+
fn rebuild_ty_param_bounds(&self,
819+
ty_param_bounds: OwnedSlice<ast::TyParamBound>,
820+
lifetime: ast::Lifetime,
821+
region_names: &HashSet<ast::Name>)
822+
-> OwnedSlice<ast::TyParamBound> {
823+
ty_param_bounds.map(|tpb| {
824+
match tpb {
825+
&ast::RegionTyParamBound => ast::RegionTyParamBound,
826+
&ast::TraitTyParamBound(ref tr) => {
827+
let last_seg = tr.path.segments.last().unwrap();
828+
let mut insert = Vec::new();
829+
for (i, lt) in last_seg.lifetimes.iter().enumerate() {
830+
if region_names.contains(&lt.name) {
831+
insert.push(i);
832+
}
833+
}
834+
let rebuild_info = RebuildPathInfo {
835+
path: &tr.path,
836+
indexes: insert,
837+
expected: last_seg.lifetimes.len(),
838+
anon_nums: &HashSet::new(),
839+
region_names: region_names
840+
};
841+
let new_path = self.rebuild_path(rebuild_info, lifetime);
842+
ast::TraitTyParamBound(ast::TraitRef {
843+
path: new_path,
844+
ref_id: tr.ref_id,
845+
})
846+
}
847+
}
848+
})
849+
}
850+
785851
fn rebuild_generics(&self,
786852
generics: &ast::Generics,
787853
add: Vec<ast::Lifetime>,
788-
remove: &HashSet<ast::Name>)
854+
remove: &HashSet<ast::Name>,
855+
ty_params: OwnedSlice<ast::TyParam>)
789856
-> ast::Generics {
790857
let mut lifetimes = Vec::new();
791858
for lt in add.iter() {
@@ -798,7 +865,7 @@ impl<'a> Rebuilder<'a> {
798865
}
799866
ast::Generics {
800867
lifetimes: lifetimes,
801-
ty_params: generics.ty_params.clone()
868+
ty_params: ty_params
802869
}
803870
}
804871

@@ -886,11 +953,16 @@ impl<'a> Rebuilder<'a> {
886953
}
887954
}
888955
}
889-
for i in insert.iter() {
890-
new_ty = self.rebuild_ty(new_ty, cur_ty,
891-
lifetime,
892-
Some((*i, expected)));
893-
}
956+
let rebuild_info = RebuildPathInfo {
957+
path: path,
958+
indexes: insert,
959+
expected: expected,
960+
anon_nums: anon_nums,
961+
region_names: region_names
962+
};
963+
new_ty = self.rebuild_ty(new_ty, cur_ty,
964+
lifetime,
965+
Some(rebuild_info));
894966
}
895967
_ => ()
896968
}
@@ -906,7 +978,7 @@ impl<'a> Rebuilder<'a> {
906978
from: ast::P<ast::Ty>,
907979
to: ast::P<ast::Ty>,
908980
lifetime: ast::Lifetime,
909-
index_opt: Option<(uint, uint)>)
981+
rebuild_path_info: Option<RebuildPathInfo>)
910982
-> ast::P<ast::Ty> {
911983

912984
fn build_to(from: ast::P<ast::Ty>,
@@ -950,13 +1022,12 @@ impl<'a> Rebuilder<'a> {
9501022

9511023
let new_ty_node = match to.node {
9521024
ast::TyRptr(_, mut_ty) => ast::TyRptr(Some(lifetime), mut_ty),
953-
ast::TyPath(ref path, ref bounds, id) => {
954-
let (index, expected) = match index_opt {
955-
Some((i, e)) => (i, e),
1025+
ast::TyPath(_, ref bounds, id) => {
1026+
let rebuild_info = match rebuild_path_info {
1027+
Some(ri) => ri,
9561028
None => fail!("expect index_opt in rebuild_ty/ast::TyPath")
9571029
};
958-
let new_path = self.rebuild_path(path, index,
959-
expected, lifetime);
1030+
let new_path = self.rebuild_path(rebuild_info, lifetime);
9601031
ast::TyPath(new_path, bounds.clone(), id)
9611032
}
9621033
_ => fail!("expect ast::TyRptr or ast::TyPath")
@@ -970,34 +1041,49 @@ impl<'a> Rebuilder<'a> {
9701041
}
9711042

9721043
fn rebuild_path(&self,
973-
path: &ast::Path,
974-
index: uint,
975-
expected: uint,
1044+
rebuild_info: RebuildPathInfo,
9761045
lifetime: ast::Lifetime)
9771046
-> ast::Path {
1047+
let RebuildPathInfo {
1048+
path: path,
1049+
indexes: indexes,
1050+
expected: expected,
1051+
anon_nums: anon_nums,
1052+
region_names: region_names,
1053+
} = rebuild_info;
1054+
9781055
let last_seg = path.segments.last().unwrap();
9791056
let mut new_lts = Vec::new();
9801057
if last_seg.lifetimes.len() == 0 {
981-
for i in range(0, expected) {
982-
if i == index {
983-
new_lts.push(lifetime);
984-
} else {
985-
new_lts.push(self.life_giver.give_lifetime());
1058+
// traverse once to see if there's a need to insert lifetime
1059+
let need_insert = range(0, expected).any(|i| {
1060+
indexes.contains(&i)
1061+
});
1062+
if need_insert {
1063+
for i in range(0, expected) {
1064+
if indexes.contains(&i) {
1065+
new_lts.push(lifetime);
1066+
} else {
1067+
new_lts.push(self.life_giver.give_lifetime());
1068+
}
9861069
}
9871070
}
9881071
} else {
9891072
for (i, lt) in last_seg.lifetimes.iter().enumerate() {
990-
if i == index {
1073+
if indexes.contains(&i) {
9911074
new_lts.push(lifetime);
9921075
} else {
9931076
new_lts.push(*lt);
9941077
}
9951078
}
9961079
}
1080+
let new_types = last_seg.types.map(|&t| {
1081+
self.rebuild_arg_ty_or_output(t, lifetime, anon_nums, region_names)
1082+
});
9971083
let new_seg = ast::PathSegment {
9981084
identifier: last_seg.identifier,
9991085
lifetimes: new_lts,
1000-
types: last_seg.types.clone(),
1086+
types: new_types,
10011087
};
10021088
let mut new_segs = Vec::new();
10031089
new_segs.push_all(path.segments.init());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2014 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+
// ignore-tidy-linelength
12+
13+
use std::iter::{Range,range};
14+
15+
trait Itble<'r, T, I: Iterator<T>> { fn iter(&'r self) -> I; }
16+
17+
impl<'r> Itble<'r, uint, Range<uint>> for (uint, uint) {
18+
fn iter(&'r self) -> Range<uint> {
19+
let &(min, max) = self;
20+
range(min, max)
21+
}
22+
}
23+
24+
fn check<'r, I: Iterator<uint>, T: Itble<'r, uint, I>>(cont: &T) -> bool {
25+
//~^ NOTE: consider using an explicit lifetime parameter as shown: fn check<'a, I: Iterator<uint>, T: Itble<'a, uint, I>>(cont: &'a T) -> bool
26+
let cont_iter = cont.iter(); //~ ERROR: cannot infer
27+
let result = cont_iter.fold(Some(0u16), |state, val| {
28+
state.map_or(None, |mask| {
29+
let bit = 1 << val;
30+
if mask & bit == 0 {Some(mask|bit)} else {None}
31+
})
32+
});
33+
result.is_some()
34+
}
35+
36+
fn main() {}

src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs

+11
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,16 @@ fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&int, &int, &int) {
5454
//~^^ ERROR: cannot infer
5555
}
5656

57+
struct Cat<'x, T> { cat: &'x int, t: T }
58+
struct Dog<'y> { dog: &'y int }
59+
fn cat<'x>(x: Cat<'x, Dog>) -> &int {
60+
//~^ NOTE: consider using an explicit lifetime parameter as shown: fn cat<'a, 'x>(x: Cat<'x, Dog<'a>>) -> &'a int
61+
x.t.dog //~ ERROR: mismatched types
62+
}
63+
64+
fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &int {
65+
//~^ NOTE: consider using an explicit lifetime parameter as shown: fn cat2<'a, 'x>(x: Cat<'x, Dog<'a>>) -> &'a int
66+
x.t.dog //~ ERROR: mismatched types
67+
}
5768

5869
fn main() {}

0 commit comments

Comments
 (0)