From 20d9014bf570ef22d3362bd98bd6f243cc4ae384 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sun, 22 Sep 2013 16:16:42 -0400 Subject: [PATCH 1/3] allow 'self lifetime in static trait methods --- src/librustc/middle/typeck/collect.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 9c69e6fd85cc7..2df18409e7e10 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -312,7 +312,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, // Self => D' // D,E,F => E',F',G' let substs = substs { - regions: ty::NonerasedRegions(opt_vec::Empty), + regions: ty::NonerasedRegions(opt_vec::with(ty::re_bound(ty::br_self))), self_ty: Some(self_param), tps: non_shifted_trait_tps + shifted_method_tps }; From 564835a69e84ca32fed3802b7844d1b07ed32d9f Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sun, 6 Oct 2013 10:43:08 -0400 Subject: [PATCH 2/3] add test case --- src/test/run-pass/issue-7331.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/run-pass/issue-7331.rs diff --git a/src/test/run-pass/issue-7331.rs b/src/test/run-pass/issue-7331.rs new file mode 100644 index 0000000000000..0f0103eeb6428 --- /dev/null +++ b/src/test/run-pass/issue-7331.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait Interner<'self, T> { + fn new() -> Self; + fn get(&'self self, tag: uint) -> Option<&'self T>; +} + +pub trait FromVec<'self> { + fn fromVec(&'self [u8]) -> Self; +} + +fn main() {} From dfd245dbbc58d9eda67dd77f925539b8b09b66f8 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sun, 13 Oct 2013 11:56:25 -0400 Subject: [PATCH 3/3] constrain 'self in static trait method to equal enclosing 'self --- src/librustc/middle/typeck/check/mod.rs | 30 +++++++++++++++------- src/librustc/middle/typeck/check/vtable.rs | 28 ++++++++++++++++++++ src/librustc/middle/typeck/collect.rs | 4 +-- src/test/run-pass/issue-7331.rs | 11 ++++++++ 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 4514564ff1f6c..9a810dea04f58 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -115,6 +115,7 @@ use std::result; use std::util::replace; use std::vec; use extra::list::Nil; +use extra::list; use syntax::abi::AbiSet; use syntax::ast::{provided, required}; use syntax::ast; @@ -3342,19 +3343,30 @@ pub fn instantiate_path(fcx: @mut FnCtxt, } }; - // Special case: If there is a self parameter, omit it from the list of - // type parameters. - // - // Here we calculate the "user type parameter count", which is the number - // of type parameters actually manifest in the AST. This will differ from - // the internal type parameter count when there are self types involved. - let (user_type_parameter_count, self_parameter_index) = match def { + // Special case for static trait methods: omit the self parameter + // from the list of type parameters and constrain the 'self + // lifetime to be equal to the enclosing 'self lifetime. + let (user_type_parameter_count, self_parameter_index, regions) = match def { ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => { let generics = generics_of_static_method_container(fcx.ccx.tcx, provenance); - (ty_param_count - 1, Some(generics.type_param_defs.len())) + + // If 'self is in scope, then use the free region it is already + // associated with. If 'self is not in scope then + // `regions` won't be used anyway. + let constrained_regions = + match list::find(fcx.in_scope_regions, + |&(br, _)| br == ty::br_self) { + Some((_, r)) => opt_vec::with(r), + None => regions + }; + + (ty_param_count - 1, + Some(generics.type_param_defs.len()), + constrained_regions) } - _ => (ty_param_count, None), + _ => { + (ty_param_count, None, regions)} }; // determine values for type parameters, using the values given by diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 3c4ff35b768db..6522d6fe8f5e7 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -28,6 +28,7 @@ use std::result; use syntax::ast; use syntax::ast_util; use syntax::codemap::Span; +use syntax::opt_vec; use syntax::print::pprust::expr_to_str; use syntax::visit; use syntax::visit::Visitor; @@ -295,6 +296,33 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext, bound_trait_ref.repr(vcx.tcx())); if bound_trait_ref.def_id == trait_ref.def_id { + + // Replace any instances of br_self with a new region + // variable in order to avoid asking region inference to + // relate a bound region to a free region. Strictly + // speaking, instead of a new region variable, we should + // use the free region associated with br_self, if it + // exists. However, bound_trait_ref does not play an + // important role in the main phase of region checking, so + // precisely what we choose here shouldn't matter. + let substs = ty::substs { + self_ty : None, + tps : ~[], + regions: ty::NonerasedRegions(opt_vec::with( + vcx.infcx.next_region_var( + infer::BoundRegionInTypeOrImpl( + location_info.span)))) + }; + + let bound_trait_ref = @ty::TraitRef { + def_id : bound_trait_ref.def_id, + substs : ty::substs { + self_ty : bound_trait_ref.substs.self_ty.clone(), + tps : bound_trait_ref.substs.tps.clone(), + regions : bound_trait_ref.substs.regions.subst(vcx.ccx.tcx, + &substs) + }}; + relate_trait_refs(vcx, location_info, bound_trait_ref, diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 2df18409e7e10..0c206b07552bf 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -268,7 +268,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, // fn foo(...) -> Self; // } // - // and we will create a function like + // then we will create a function like // // fn foo(...) -> D' {} // @@ -357,7 +357,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: trait_ty_generics.region_param + region_param: None }, ty: ty }); diff --git a/src/test/run-pass/issue-7331.rs b/src/test/run-pass/issue-7331.rs index 0f0103eeb6428..e57aba5e23ad8 100644 --- a/src/test/run-pass/issue-7331.rs +++ b/src/test/run-pass/issue-7331.rs @@ -17,4 +17,15 @@ pub trait FromVec<'self> { fn fromVec(&'self [u8]) -> Self; } +struct Reader<'self> { + v : &'self [u8] +} + +impl <'self, T : FromVec<'self>> Reader<'self> { + fn get(&self) -> T { + FromVec::fromVec(self.v) + } +} + + fn main() {}