Skip to content

Commit 1dec477

Browse files
committed
auto merge of #13503 : edwardw/rust/lifetime-ice, r=nikomatsakis
When instantiating trait default methods for certain implementation, `typeck` correctly combined type parameters from trait bound with those from method bound, but didn't do so for lifetime parameters. Applies the same logic to lifetime parameters. Closes #13204
2 parents 9f3fd93 + daa1f50 commit 1dec477

File tree

2 files changed

+60
-30
lines changed

2 files changed

+60
-30
lines changed

src/librustc/middle/typeck/coherence.rs

+28-30
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use syntax::ast_map::NodeItem;
4242
use syntax::ast_map;
4343
use syntax::ast_util::{def_id_of_def, local_def};
4444
use syntax::codemap::Span;
45+
use syntax::owned_slice::OwnedSlice;
4546
use syntax::parse::token;
4647
use syntax::visit;
4748

@@ -346,7 +347,8 @@ impl<'a> CoherenceChecker<'a> {
346347
Rc::new(Vec::from_slice(impl_poly_type.generics.type_param_defs()).append(
347348
new_method_ty.generics.type_param_defs())),
348349
region_param_defs:
349-
impl_poly_type.generics.region_param_defs.clone()
350+
Rc::new(Vec::from_slice(impl_poly_type.generics.region_param_defs()).append(
351+
new_method_ty.generics.region_param_defs()))
350352
};
351353
let new_polytype = ty::ty_param_bounds_and_ty {
352354
generics: new_generics,
@@ -741,39 +743,35 @@ pub fn make_substs_for_receiver_types(tcx: &ty::ctxt,
741743
* receiver and method generics.
742744
*/
743745

744-
// determine how many type parameters were declared on the impl
745-
let num_impl_type_parameters = {
746-
let impl_polytype = ty::lookup_item_type(tcx, impl_id);
747-
impl_polytype.generics.type_param_defs().len()
748-
};
749-
750-
// determine how many type parameters appear on the trait
751-
let num_trait_type_parameters = trait_ref.substs.tps.len();
752-
753-
// the current method type has the type parameters from the trait + method
754-
let num_method_type_parameters =
755-
num_trait_type_parameters + method.generics.type_param_defs().len();
756-
757-
// the new method type will have the type parameters from the impl + method
758-
let combined_tps = Vec::from_fn(num_method_type_parameters, |i| {
759-
if i < num_trait_type_parameters {
760-
// replace type parameters that come from trait with new value
761-
*trait_ref.substs.tps.get(i)
762-
} else {
763-
// replace type parameters that belong to method with another
764-
// type parameter, this time with the index adjusted
765-
let method_index = i - num_trait_type_parameters;
766-
let type_param_def = &method.generics.type_param_defs()[method_index];
767-
let new_index = num_impl_type_parameters + method_index;
768-
ty::mk_param(tcx, new_index, type_param_def.def_id)
746+
let impl_polytype = ty::lookup_item_type(tcx, impl_id);
747+
let num_impl_tps = impl_polytype.generics.type_param_defs().len();
748+
let num_impl_regions = impl_polytype.generics.region_param_defs().len();
749+
let meth_tps: Vec<ty::t> =
750+
method.generics.type_param_defs().iter().enumerate()
751+
.map(|(i, t)| ty::mk_param(tcx, i + num_impl_tps, t.def_id))
752+
.collect();
753+
let meth_regions: Vec<ty::Region> =
754+
method.generics.region_param_defs().iter().enumerate()
755+
.map(|(i, l)| ty::ReEarlyBound(l.def_id.node, i + num_impl_regions, l.name))
756+
.collect();
757+
let mut combined_tps = trait_ref.substs.tps.clone();
758+
combined_tps.push_all_move(meth_tps);
759+
let combined_regions = match &trait_ref.substs.regions {
760+
&ty::ErasedRegions =>
761+
fail!("make_substs_for_receiver_types: unexpected ErasedRegions"),
762+
763+
&ty::NonerasedRegions(ref rs) => {
764+
let mut rs = rs.clone().into_vec();
765+
rs.push_all_move(meth_regions);
766+
ty::NonerasedRegions(OwnedSlice::from_vec(rs))
769767
}
770-
});
768+
};
771769

772-
return ty::substs {
773-
regions: trait_ref.substs.regions.clone(),
770+
ty::substs {
771+
regions: combined_regions,
774772
self_ty: trait_ref.substs.self_ty,
775773
tps: combined_tps
776-
};
774+
}
777775
}
778776

779777
fn subst_receiver_types_in_method_ty(tcx: &ty::ctxt,

src/test/run-pass/issue-13204.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2012-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+
// Test that when instantiating trait default methods, typeck handles
12+
// lifetime parameters defined on the method bound correctly.
13+
14+
pub trait Foo {
15+
fn bar<'a, I: Iterator<&'a ()>>(&self, it: I) -> uint {
16+
let mut xs = it.filter(|_| true);
17+
xs.len()
18+
}
19+
}
20+
21+
pub struct Baz;
22+
23+
impl Foo for Baz {
24+
// When instantiating `Foo::bar` for `Baz` here, typeck used to
25+
// ICE due to the lifetime parameter of `bar`.
26+
}
27+
28+
fn main() {
29+
let x = Baz;
30+
let y = vec!((), (), ());
31+
assert_eq!(x.bar(y.iter()), 3);
32+
}

0 commit comments

Comments
 (0)