Combine lifetime parameters when instantiating default methods
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
This commit is contained in:
parent
72869b6579
commit
daa1f5099f
@ -42,6 +42,7 @@ use syntax::ast_map::NodeItem;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util::{def_id_of_def, local_def};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
use syntax::parse::token;
|
||||
use syntax::visit;
|
||||
|
||||
@ -346,7 +347,8 @@ impl<'a> CoherenceChecker<'a> {
|
||||
Rc::new(Vec::from_slice(impl_poly_type.generics.type_param_defs()).append(
|
||||
new_method_ty.generics.type_param_defs())),
|
||||
region_param_defs:
|
||||
impl_poly_type.generics.region_param_defs.clone()
|
||||
Rc::new(Vec::from_slice(impl_poly_type.generics.region_param_defs()).append(
|
||||
new_method_ty.generics.region_param_defs()))
|
||||
};
|
||||
let new_polytype = ty::ty_param_bounds_and_ty {
|
||||
generics: new_generics,
|
||||
@ -741,39 +743,35 @@ pub fn make_substs_for_receiver_types(tcx: &ty::ctxt,
|
||||
* receiver and method generics.
|
||||
*/
|
||||
|
||||
// determine how many type parameters were declared on the impl
|
||||
let num_impl_type_parameters = {
|
||||
let impl_polytype = ty::lookup_item_type(tcx, impl_id);
|
||||
impl_polytype.generics.type_param_defs().len()
|
||||
let impl_polytype = ty::lookup_item_type(tcx, impl_id);
|
||||
let num_impl_tps = impl_polytype.generics.type_param_defs().len();
|
||||
let num_impl_regions = impl_polytype.generics.region_param_defs().len();
|
||||
let meth_tps: Vec<ty::t> =
|
||||
method.generics.type_param_defs().iter().enumerate()
|
||||
.map(|(i, t)| ty::mk_param(tcx, i + num_impl_tps, t.def_id))
|
||||
.collect();
|
||||
let meth_regions: Vec<ty::Region> =
|
||||
method.generics.region_param_defs().iter().enumerate()
|
||||
.map(|(i, l)| ty::ReEarlyBound(l.def_id.node, i + num_impl_regions, l.name))
|
||||
.collect();
|
||||
let mut combined_tps = trait_ref.substs.tps.clone();
|
||||
combined_tps.push_all_move(meth_tps);
|
||||
let combined_regions = match &trait_ref.substs.regions {
|
||||
&ty::ErasedRegions =>
|
||||
fail!("make_substs_for_receiver_types: unexpected ErasedRegions"),
|
||||
|
||||
&ty::NonerasedRegions(ref rs) => {
|
||||
let mut rs = rs.clone().into_vec();
|
||||
rs.push_all_move(meth_regions);
|
||||
ty::NonerasedRegions(OwnedSlice::from_vec(rs))
|
||||
}
|
||||
};
|
||||
|
||||
// determine how many type parameters appear on the trait
|
||||
let num_trait_type_parameters = trait_ref.substs.tps.len();
|
||||
|
||||
// the current method type has the type parameters from the trait + method
|
||||
let num_method_type_parameters =
|
||||
num_trait_type_parameters + method.generics.type_param_defs().len();
|
||||
|
||||
// the new method type will have the type parameters from the impl + method
|
||||
let combined_tps = Vec::from_fn(num_method_type_parameters, |i| {
|
||||
if i < num_trait_type_parameters {
|
||||
// replace type parameters that come from trait with new value
|
||||
*trait_ref.substs.tps.get(i)
|
||||
} else {
|
||||
// replace type parameters that belong to method with another
|
||||
// type parameter, this time with the index adjusted
|
||||
let method_index = i - num_trait_type_parameters;
|
||||
let type_param_def = &method.generics.type_param_defs()[method_index];
|
||||
let new_index = num_impl_type_parameters + method_index;
|
||||
ty::mk_param(tcx, new_index, type_param_def.def_id)
|
||||
}
|
||||
});
|
||||
|
||||
return ty::substs {
|
||||
regions: trait_ref.substs.regions.clone(),
|
||||
ty::substs {
|
||||
regions: combined_regions,
|
||||
self_ty: trait_ref.substs.self_ty,
|
||||
tps: combined_tps
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn subst_receiver_types_in_method_ty(tcx: &ty::ctxt,
|
||||
|
32
src/test/run-pass/issue-13204.rs
Normal file
32
src/test/run-pass/issue-13204.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2012-2014 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.
|
||||
|
||||
// Test that when instantiating trait default methods, typeck handles
|
||||
// lifetime parameters defined on the method bound correctly.
|
||||
|
||||
pub trait Foo {
|
||||
fn bar<'a, I: Iterator<&'a ()>>(&self, it: I) -> uint {
|
||||
let mut xs = it.filter(|_| true);
|
||||
xs.len()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Baz;
|
||||
|
||||
impl Foo for Baz {
|
||||
// When instantiating `Foo::bar` for `Baz` here, typeck used to
|
||||
// ICE due to the lifetime parameter of `bar`.
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Baz;
|
||||
let y = vec!((), (), ());
|
||||
assert_eq!(x.bar(y.iter()), 3);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user