From daa1f5099f96170a290b5a5249041a8c6a8beaed Mon Sep 17 00:00:00 2001 From: Edward Wang Date: Mon, 14 Apr 2014 08:33:04 +0800 Subject: [PATCH] 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 --- src/librustc/middle/typeck/coherence.rs | 58 ++++++++++++------------- src/test/run-pass/issue-13204.rs | 32 ++++++++++++++ 2 files changed, 60 insertions(+), 30 deletions(-) create mode 100644 src/test/run-pass/issue-13204.rs diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 73e1bc7864142..c0fd73f4a36a4 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -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() - }; - - // 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) + 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 = + 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 = + 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)) } - }); + }; - 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, diff --git a/src/test/run-pass/issue-13204.rs b/src/test/run-pass/issue-13204.rs new file mode 100644 index 0000000000000..5fb9119849cab --- /dev/null +++ b/src/test/run-pass/issue-13204.rs @@ -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 or the MIT license +// , 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); +}