Make trait lifetime parameters early bound in static fn type. This is related

to #5121.

Fixes #10391.
This commit is contained in:
Niko Matsakis 2013-11-15 17:04:01 -05:00
parent 69186efc19
commit 23d95f6dc6
3 changed files with 64 additions and 12 deletions

View File

@ -94,7 +94,6 @@ fn lookup_vtables(vcx: &VtableContext,
location_info,
type_param_defs.repr(vcx.tcx()),
substs.repr(vcx.tcx()));
let _i = indenter();
// We do this backwards for reasons discussed above.
assert_eq!(substs.tps.len(), type_param_defs.len());

View File

@ -236,21 +236,31 @@ fn make_static_method_ty(ccx: &CrateCtxt,
trait_ty_generics: &ty::Generics) {
// If declaration is
//
// trait<'a,'b,'c,A,B,C> {
// fn foo<'d,'e,'f,D,E,F>(...) -> Self;
// trait Trait<'a,'b,'c,a,b,c> {
// fn foo<'d,'e,'f,d,e,f>(...) -> Self;
// }
//
// and we will create a function like
//
// fn foo<'a,'b,'c,'d,'e,'f,A',B',C',D',E',F',G'>(...) -> D' {}
// fn foo<'a,'b,'c, // First the lifetime params from trait
// 'd,'e,'f, // Then lifetime params from `foo()`
// a,b,c, // Then type params from trait
// D:Trait<'a,'b,'c,a,b,c>, // Then this sucker
// E,F,G // Then type params from `foo()`, offset by 1
// >(...) -> D' {}
//
// Note that `Self` is replaced with an explicit type
// parameter D' that is sandwiched in between the trait params
// parameter D that is sandwiched in between the trait params
// and the method params, and thus the indices of the method
// type parameters are offset by 1 (that is, the method
// parameters are mapped from D, E, F to E', F', and G'). The
// parameters are mapped from d, e, f to E, F, and G). The
// choice of this ordering is somewhat arbitrary.
//
// Note also that the bound for `D` is `Trait<'a,'b,'c,a,b,c>`.
// This implies that the lifetime parameters that were inherited
// from the trait (i.e., `'a`, `'b`, and `'c`) all must be early
// bound, since they appear in a trait bound.
//
// Also, this system is rather a hack that should be replaced
// with a more uniform treatment of Self (which is partly
// underway).
@ -280,13 +290,17 @@ fn make_static_method_ty(ccx: &CrateCtxt,
});
// Convert the regions 'a, 'b, 'c defined on the trait into
// bound regions on the fn.
let rps_from_trait = trait_ty_generics.region_param_defs.iter().map(|d| {
ty::ReLateBound(m.fty.sig.binder_id,
ty::BrNamed(d.def_id, d.ident))
}).collect();
// bound regions on the fn. Note that because these appear in the
// bound for `Self` they must be early bound.
let new_early_region_param_defs = trait_ty_generics.region_param_defs;
let rps_from_trait =
trait_ty_generics.region_param_defs.iter().
enumerate().
map(|(index,d)| ty::ReEarlyBound(d.def_id.node, index, d.ident)).
collect();
// build up the substitution from
// 'a,'b,'c => 'a,'b,'c
// A,B,C => A',B',C'
// Self => D'
// D,E,F => E',F',G'
@ -336,7 +350,7 @@ fn make_static_method_ty(ccx: &CrateCtxt,
ty_param_bounds_and_ty {
generics: ty::Generics {
type_param_defs: @new_type_param_defs,
region_param_defs: @[], // fn items
region_param_defs: new_early_region_param_defs
},
ty: ty
});

View File

@ -0,0 +1,39 @@
// Copyright 2013 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 we are able to compile calls to associated fns like
// `decode()` where the bound on the `Self` parameter references a
// lifetime parameter of the trait. This example indicates why trait
// lifetime parameters must be early bound in the type of the
// associated item.
pub enum Value<'v> {
A(&'v str),
B,
}
pub trait Decoder<'v> {
fn read(&mut self) -> Value<'v>;
}
pub trait Decodable<'v, D: Decoder<'v>> {
fn decode(d: &mut D) -> Self;
}
impl<'v, D: Decoder<'v>> Decodable<'v, D> for () {
fn decode(d: &mut D) -> () {
match d.read() {
A(..) => (),
B => Decodable::decode(d),
}
}
}
fn main() { }