Skip to content

Commit

Permalink
Make trait lifetime parameters early bound in static fn type. This is…
Browse files Browse the repository at this point in the history
… related

to rust-lang#5121.

Fixes rust-lang#10391.
  • Loading branch information
nikomatsakis committed Dec 3, 2013
1 parent 69186ef commit 23d95f6
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 12 deletions.
1 change: 0 additions & 1 deletion src/librustc/middle/typeck/check/vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
36 changes: 25 additions & 11 deletions src/librustc/middle/typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,21 +236,31 @@ pub fn ensure_trait_methods(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).
Expand Down Expand Up @@ -280,13 +290,17 @@ pub fn ensure_trait_methods(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'
Expand Down Expand Up @@ -336,7 +350,7 @@ pub fn ensure_trait_methods(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
});
Expand Down
39 changes: 39 additions & 0 deletions src/test/run-pass/regions-early-bound-lifetime-in-assoc-fn.rs
Original file line number Diff line number Diff line change
@@ -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() { }

1 comment on commit 23d95f6

@nikomatsakis
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r=pnkfelix

Please sign in to comment.