From 02aacaba8f7584ee334303840ad88fcd513e3f13 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 13 Jan 2015 14:00:59 -0500 Subject: [PATCH 1/5] 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() { } From b92ec6a78a980b567ec8e6c034e3b37caea81aaa Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 13 Jan 2015 14:01:27 -0500 Subject: [PATCH 2/5] Fix Repr output so that it does not ICE when a self-type is absent. This occurs while printing object type projections for debugging (note that the `UserString` impl is much more careful about this). --- src/librustc/util/ppaux.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 559ec533baa9e..c3b6c2178ee09 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1430,7 +1430,7 @@ impl<'tcx> UserString<'tcx> for ty::ProjectionPredicate<'tcx> { impl<'tcx> Repr<'tcx> for ty::ProjectionTy<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { format!("<{} as {}>::{}", - self.trait_ref.self_ty().repr(tcx), + self.trait_ref.substs.self_ty().repr(tcx), self.trait_ref.repr(tcx), self.item_name.repr(tcx)) } From ff6085f401844bc5cb07b804f0d2258bb5c2b9a8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 13 Jan 2015 14:49:10 -0500 Subject: [PATCH 3/5] Fix propagation of the HAS_PROJECTION flag in object types. Fixes #20831 some more. --- src/librustc/middle/ty.rs | 16 ++++++- ...ociated-types-projection-in-object-type.rs | 43 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/associated-types-projection-in-object-type.rs diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index cf30969ebefcc..fb216a5e99df1 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2604,12 +2604,17 @@ impl FlagComputation { &ty_projection(ref data) => { self.add_flags(HAS_PROJECTION); - self.add_substs(data.trait_ref.substs); + self.add_projection_ty(data); } &ty_trait(box TyTrait { ref principal, ref bounds }) => { let mut computation = FlagComputation::new(); computation.add_substs(principal.0.substs); + for projection_bound in bounds.projection_bounds.iter() { + let mut proj_computation = FlagComputation::new(); + proj_computation.add_projection_predicate(&projection_bound.0); + computation.add_bound_computation(&proj_computation); + } self.add_bound_computation(&computation); self.add_bounds(bounds); @@ -2673,6 +2678,15 @@ impl FlagComputation { } } + fn add_projection_predicate(&mut self, projection_predicate: &ProjectionPredicate) { + self.add_projection_ty(&projection_predicate.projection_ty); + self.add_ty(projection_predicate.ty); + } + + fn add_projection_ty(&mut self, projection_ty: &ProjectionTy) { + self.add_substs(projection_ty.trait_ref.substs); + } + fn add_substs(&mut self, substs: &Substs) { self.add_tys(substs.types.as_slice()); match substs.regions { diff --git a/src/test/run-pass/associated-types-projection-in-object-type.rs b/src/test/run-pass/associated-types-projection-in-object-type.rs new file mode 100644 index 0000000000000..44dd49b72976e --- /dev/null +++ b/src/test/run-pass/associated-types-projection-in-object-type.rs @@ -0,0 +1,43 @@ +// 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. + +// Corrected regression test for #20831. The original did not compile. +// When fixed, it revealed another problem concerning projections that +// appear in associated type bindings in object types, which were not +// being properly flagged. + +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 + 'a>) { + self.sub = t; + } +} + +fn main() {} From 2868404fcaed4030935ffafa87f5ea31ba4cd5bb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 13 Jan 2015 16:03:07 -0500 Subject: [PATCH 4/5] Normalize associated types in the type_is_newtype_immediate pass. Fixes #21010. --- src/librustc_trans/trans/common.rs | 11 ++++--- ...ociated-types-normalize-unifield-struct.rs | 32 +++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass/associated-types-normalize-unifield-struct.rs diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index f59e70d099a63..3eee4637de199 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -217,12 +217,15 @@ pub fn type_needs_drop<'tcx>(cx: &ty::ctxt<'tcx>, ty::type_contents(cx, ty).needs_drop(cx) } -fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - ty: Ty<'tcx>) -> bool { +fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { ty::ty_struct(def_id, substs) => { - let fields = ty::struct_fields(ccx.tcx(), def_id, substs); - fields.len() == 1 && type_is_immediate(ccx, fields[0].mt.ty) + let fields = ty::lookup_struct_fields(ccx.tcx(), def_id); + fields.len() == 1 && { + let ty = ty::lookup_field_type(ccx.tcx(), def_id, fields[0].id, substs); + let ty = monomorphize::normalize_associated_type(ccx.tcx(), &ty); + type_is_immediate(ccx, ty) + } } _ => false } diff --git a/src/test/run-pass/associated-types-normalize-unifield-struct.rs b/src/test/run-pass/associated-types-normalize-unifield-struct.rs new file mode 100644 index 0000000000000..c517f61de0c16 --- /dev/null +++ b/src/test/run-pass/associated-types-normalize-unifield-struct.rs @@ -0,0 +1,32 @@ +// 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 issue #21010: Normalize associated types in +// various special paths in the `type_is_immediate` function. + +#![allow(unstable)] + +pub trait OffsetState: Sized {} +pub trait Offset { type State: OffsetState; } + +#[derive(Copy)] pub struct X; +impl Offset for X { type State = Y; } + +#[derive(Copy)] pub struct Y; +impl OffsetState for Y {} + +pub fn now() -> DateTime { from_utc(Y) } + +pub struct DateTime { pub offset: Off::State } +pub fn from_utc(offset: Off::State) -> DateTime { DateTime { offset: offset } } + +pub fn main() { + let _x = now(); +} From 2479dfcbf7abc401e5925bf5d53b7ac2e0eed694 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 14 Jan 2015 12:44:21 -0500 Subject: [PATCH 5/5] Revert "rustc_trans: Fix type projection debuginfo" -- it potentially papers over a lack of normalization that should have taken place. This reverts commit f7745a9be3eb2d9438f08b383156f0a33cbb0cdf. --- src/librustc_trans/trans/debuginfo.rs | 80 +++++++------------------- src/test/debuginfo/associated_types.rs | 28 --------- 2 files changed, 22 insertions(+), 86 deletions(-) delete mode 100644 src/test/debuginfo/associated_types.rs diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 5b974d234c08c..2f58baab7fca9 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -323,28 +323,26 @@ impl<'tcx> TypeMap<'tcx> { fn get_unique_type_id_of_type<'a>(&mut self, cx: &CrateContext<'a, 'tcx>, type_: Ty<'tcx>) -> UniqueTypeId { - // basic type -> {:name of the type:} - // tuple -> {tuple_(:param-uid:)*} - // struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> } - // enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> } - // enum variant -> {variant_:variant-name:_:enum-uid:} - // reference (&) -> {& :pointee-uid:} - // mut reference (&mut) -> {&mut :pointee-uid:} - // ptr (*) -> {* :pointee-uid:} - // mut ptr (*mut) -> {*mut :pointee-uid:} - // unique ptr (~) -> {~ :pointee-uid:} - // @-ptr (@) -> {@ :pointee-uid:} - // sized vec ([T; x]) -> {[:size:] :element-uid:} - // unsized vec ([T]) -> {[] :element-uid:} - // trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> } - // closure -> { :store-sigil: - // |(:param-uid:),* <,_...>| -> \ - // :return-type-uid: : (:bounds:)*} - // function -> { fn( (:param-uid:)* <,_...> ) -> \ - // :return-type-uid:} - // unique vec box (~[]) -> {HEAP_VEC_BOX<:pointee-uid:>} - // gc box -> {GC_BOX<:pointee-uid:>} - // projection (::V) -> {<:ty-uid: as :trait-uid:> :: :name-uid: } + // basic type -> {:name of the type:} + // tuple -> {tuple_(:param-uid:)*} + // struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> } + // enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> } + // enum variant -> {variant_:variant-name:_:enum-uid:} + // reference (&) -> {& :pointee-uid:} + // mut reference (&mut) -> {&mut :pointee-uid:} + // ptr (*) -> {* :pointee-uid:} + // mut ptr (*mut) -> {*mut :pointee-uid:} + // unique ptr (~) -> {~ :pointee-uid:} + // @-ptr (@) -> {@ :pointee-uid:} + // sized vec ([T; x]) -> {[:size:] :element-uid:} + // unsized vec ([T]) -> {[] :element-uid:} + // trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> } + // closure -> { :store-sigil: |(:param-uid:),* <,_...>| -> \ + // :return-type-uid: : (:bounds:)*} + // function -> { fn( (:param-uid:)* <,_...> ) -> \ + // :return-type-uid:} + // unique vec box (~[]) -> {HEAP_VEC_BOX<:pointee-uid:>} + // gc box -> {GC_BOX<:pointee-uid:>} match self.type_to_unique_id.get(&type_).cloned() { Some(unique_type_id) => return unique_type_id, @@ -437,25 +435,6 @@ impl<'tcx> TypeMap<'tcx> { principal.substs, &mut unique_type_id); }, - ty::ty_projection(ref projection) => { - unique_type_id.push_str("<"); - - let self_ty = projection.trait_ref.self_ty(); - let self_type_id = self.get_unique_type_id_of_type(cx, self_ty); - let self_type_id = self.get_unique_type_id_as_string(self_type_id); - unique_type_id.push_str(&self_type_id[]); - - unique_type_id.push_str(" as "); - - from_def_id_and_substs(self, - cx, - projection.trait_ref.def_id, - projection.trait_ref.substs, - &mut unique_type_id); - - unique_type_id.push_str(">::"); - unique_type_id.push_str(token::get_name(projection.item_name).get()); - }, ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => { if unsafety == ast::Unsafety::Unsafe { unique_type_id.push_str("unsafe "); @@ -499,10 +478,7 @@ impl<'tcx> TypeMap<'tcx> { closure_ty, &mut unique_type_id); }, - ty::ty_err | - ty::ty_infer(_) | - ty::ty_open(_) | - ty::ty_param(_) => { + _ => { cx.sess().bug(&format!("get_unique_type_id_of_type() - unexpected type: {}, {:?}", &ppaux::ty_to_string(cx.tcx(), type_)[], type_.sty)[]) @@ -3879,22 +3855,10 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::ty_unboxed_closure(..) => { output.push_str("closure"); } - ty::ty_projection(ref projection) => { - output.push_str("<"); - let self_ty = projection.trait_ref.self_ty(); - push_debuginfo_type_name(cx, self_ty, true, output); - - output.push_str(" as "); - - push_item_name(cx, projection.trait_ref.def_id, false, output); - push_type_params(cx, projection.trait_ref.substs, output); - - output.push_str(">::"); - output.push_str(token::get_name(projection.item_name).get()); - } ty::ty_err | ty::ty_infer(_) | ty::ty_open(_) | + ty::ty_projection(..) | ty::ty_param(_) => { cx.sess().bug(&format!("debuginfo: Trying to create type name for \ unexpected type: {}", ppaux::ty_to_string(cx.tcx(), t))[]); diff --git a/src/test/debuginfo/associated_types.rs b/src/test/debuginfo/associated_types.rs deleted file mode 100644 index 92336e9b34b79..0000000000000 --- a/src/test/debuginfo/associated_types.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2013-2014 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. - -// ignore-android: FIXME(#10381) -// min-lldb-version: 310 - -// compile-flags:-g - -struct Peekable where I: Iterator { - _iter: I, - _next: Option<::Item>, -} - -fn main() { - let mut iter = Vec::::new().into_iter(); - let next = iter.next(); - let _v = Peekable { - _iter: iter, - _next : next, - }; -}