Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make trait lifetime parameters early bound in static fn type. #10506

Merged
merged 2 commits into from
Dec 6, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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' {}
Copy link
Member

Choose a reason for hiding this comment

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

same comments as on #10556 about using a different syntax for the primed type-vars. But I assume you will fix that eventually, it need not hold up this patch...

//
// 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),
}
}
}

pub fn main() { }