From 02aacaba8f7584ee334303840ad88fcd513e3f13 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 13 Jan 2015 14:00:59 -0500 Subject: [PATCH] Fix DeBruijn accounting. It used to be that all trait-refs were binders, but now only poly-trait-refs are binders. Fixes #20831. --- src/librustc_typeck/astconv.rs | 74 +++++++++++-------- src/test/compile-fail/issue-20831-debruijn.rs | 49 ++++++++++++ .../run-pass/regions-debruijn-of-object.rs | 25 +++++++ 3 files changed, 119 insertions(+), 29 deletions(-) create mode 100644 src/test/compile-fail/issue-20831-debruijn.rs create mode 100644 src/test/run-pass/regions-debruijn-of-object.rs diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 45e05c12713bf..6c8ab50a99366 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -516,8 +516,15 @@ pub fn instantiate_poly_trait_ref<'tcx>( { let mut projections = Vec::new(); + // the trait reference introduces a binding level here, so + // we need to shift the `rscope`. It'd be nice if we could + // do away with this rscope stuff and work this knowledge + // into resolve_lifetimes, as we do with non-omitted + // lifetimes. Oh well, not there yet. + let shifted_rscope = ShiftedRscope::new(rscope); + let trait_ref = - instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, + instantiate_trait_ref(this, &shifted_rscope, &ast_trait_ref.trait_ref, self_ty, Some(&mut projections)); for projection in projections.into_iter() { @@ -561,6 +568,29 @@ pub fn instantiate_trait_ref<'tcx>( } } +fn object_path_to_poly_trait_ref<'a,'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, + trait_def_id: ast::DefId, + path: &ast::Path, + mut projections: &mut Vec>) + -> ty::PolyTraitRef<'tcx> +{ + // we are introducing a binder here, so shift the + // anonymous regions depth to account for that + let shifted_rscope = ShiftedRscope::new(rscope); + + let mut tmp = Vec::new(); + let trait_ref = ty::Binder(ast_path_to_trait_ref(this, + &shifted_rscope, + trait_def_id, + None, + path, + Some(&mut tmp))); + projections.extend(tmp.into_iter().map(ty::Binder)); + trait_ref +} + fn ast_path_to_trait_ref<'a,'tcx>( this: &AstConv<'tcx>, rscope: &RegionScope, @@ -573,13 +603,6 @@ fn ast_path_to_trait_ref<'a,'tcx>( debug!("ast_path_to_trait_ref {:?}", path); let trait_def = this.get_trait_def(trait_def_id); - // the trait reference introduces a binding level here, so - // we need to shift the `rscope`. It'd be nice if we could - // do away with this rscope stuff and work this knowledge - // into resolve_lifetimes, as we do with non-omitted - // lifetimes. Oh well, not there yet. - let shifted_rscope = ShiftedRscope::new(rscope); - let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters { ast::AngleBracketedParameters(ref data) => { // For now, require that parenthetical notation be used @@ -595,7 +618,7 @@ fn ast_path_to_trait_ref<'a,'tcx>( the crate attributes to enable"); } - convert_angle_bracketed_parameters(this, &shifted_rscope, data) + convert_angle_bracketed_parameters(this, rscope, data) } ast::ParenthesizedParameters(ref data) => { // For now, require that parenthetical notation be used @@ -616,7 +639,7 @@ fn ast_path_to_trait_ref<'a,'tcx>( }; let substs = create_substs_for_ast_path(this, - &shifted_rscope, + rscope, path.span, &trait_def.generics, self_ty, @@ -851,15 +874,11 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, match this.tcx().def_map.borrow().get(&id) { Some(&def::DefTrait(trait_def_id)) => { let mut projection_bounds = Vec::new(); - let trait_ref = ty::Binder(ast_path_to_trait_ref(this, - rscope, - trait_def_id, - None, - path, - Some(&mut projection_bounds))); - let projection_bounds = projection_bounds.into_iter() - .map(ty::Binder) - .collect(); + let trait_ref = object_path_to_poly_trait_ref(this, + rscope, + trait_def_id, + path, + &mut projection_bounds); Ok((trait_ref, projection_bounds)) } _ => { @@ -1095,16 +1114,13 @@ pub fn ast_ty_to_ty<'tcx>( // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details let mut projection_bounds = Vec::new(); - let trait_ref = ast_path_to_trait_ref(this, - rscope, - trait_def_id, - None, - path, - Some(&mut projection_bounds)); - let trait_ref = ty::Binder(trait_ref); - let projection_bounds = projection_bounds.into_iter() - .map(ty::Binder) - .collect(); + + let trait_ref = object_path_to_poly_trait_ref(this, + rscope, + trait_def_id, + path, + &mut projection_bounds); + trait_ref_to_object_type(this, rscope, path.span, trait_ref, projection_bounds, &[]) } diff --git a/src/test/compile-fail/issue-20831-debruijn.rs b/src/test/compile-fail/issue-20831-debruijn.rs new file mode 100644 index 0000000000000..aaf45f2739891 --- /dev/null +++ b/src/test/compile-fail/issue-20831-debruijn.rs @@ -0,0 +1,49 @@ +// Copyright 2015 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. + +// Regression test for #20831: debruijn index account was thrown off +// by the (anonymous) lifetime in `::Output` +// below. Note that changing to a named lifetime made the problem go +// away. + +use std::ops::{Shl, Shr}; +use std::cell::RefCell; + +pub trait Subscriber { + type Input; +} + +pub trait Publisher<'a> { + type Output; + fn subscribe(&mut self, Box + 'a>); +} + +pub trait Processor<'a> : Subscriber + Publisher<'a> { } + +impl<'a, P> Processor<'a> for P where P : Subscriber + Publisher<'a> { } + +struct MyStruct<'a> { + sub: Box + 'a> +} + +impl<'a> Publisher<'a> for MyStruct<'a> { + type Output = u64; + fn subscribe(&mut self, t : Box::Output> + 'a>) { + // Not obvious, but there is an implicit lifetime here -------^ + //~^^ ERROR cannot infer + // + // The fact that `Publisher` is using an implicit lifetime is + // what was causing the debruijn accounting to be off, so + // leave it that way! + self.sub = t; + } +} + +fn main() {} diff --git a/src/test/run-pass/regions-debruijn-of-object.rs b/src/test/run-pass/regions-debruijn-of-object.rs new file mode 100644 index 0000000000000..b9d3ed49c625f --- /dev/null +++ b/src/test/run-pass/regions-debruijn-of-object.rs @@ -0,0 +1,25 @@ +// Copyright 2015 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. + +struct ctxt<'tcx> { + x: &'tcx i32 +} + +trait AstConv<'tcx> { + fn tcx<'a>(&'a self) -> &'a ctxt<'tcx>; +} + +fn foo(conv: &AstConv) { } + +fn bar<'tcx>(conv: &AstConv<'tcx>) { + foo(conv) +} + +fn main() { }