From 01dee1b77e3f594256fc380c348f7ba8fcff41db Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Fri, 5 Jun 2015 20:49:23 +0300 Subject: [PATCH] Allow nested generics for the last field of structs in unsizing. --- src/librustc/middle/traits/select.rs | 46 +++++++++++++++++++--------- src/test/run-pass/dst-coerce-rc.rs | 5 +++ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index b568d40ba1c..4ea6f0cb26e 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -2523,41 +2523,57 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::lookup_field_type_unsubstituted(tcx, def_id, f.id) }).collect::>(); - // FIXME(#25351) The last field of the structure has to exist and be a - // type parameter (for now, to avoid tracking edge cases). - let i = if let Some(&ty::ty_param(p)) = fields.last().map(|ty| &ty.sty) { - assert!(p.space == TypeSpace); - p.idx as usize + // The last field of the structure has to exist and contain type parameters. + let field = if let Some(&field) = fields.last() { + field } else { return Err(Unimplemented); }; + let mut ty_params = vec![]; + ty::walk_ty(field, |ty| { + if let ty::ty_param(p) = ty.sty { + assert!(p.space == TypeSpace); + let idx = p.idx as usize; + if !ty_params.contains(&idx) { + ty_params.push(idx); + } + } + }); + if ty_params.is_empty() { + return Err(Unimplemented); + } - // Replace the type parameter chosen for unsizing with - // ty_err and ensure it does not affect any other fields. + // Replace type parameters used in unsizing with + // ty_err and ensure they do not affect any other fields. // This could be checked after type collection for any struct // with a potentially unsized trailing field. let mut new_substs = substs_a.clone(); - new_substs.types.get_mut_slice(TypeSpace)[i] = tcx.types.err; + for &i in &ty_params { + new_substs.types.get_mut_slice(TypeSpace)[i] = tcx.types.err; + } for &ty in fields.init() { if ty::type_is_error(ty.subst(tcx, &new_substs)) { return Err(Unimplemented); } } - // Extract T and U from Struct and Struct. - let inner_source = *substs_a.types.get(TypeSpace, i); - let inner_target = *substs_b.types.get(TypeSpace, i); + // Extract Field and Field from Struct and Struct. + let inner_source = field.subst(tcx, substs_a); + let inner_target = field.subst(tcx, substs_b); - // Check that all the source structure with the unsized - // type parameter is a subtype of the target. - new_substs.types.get_mut_slice(TypeSpace)[i] = inner_target; + // Check that the source structure with the target's + // type parameters is a subtype of the target. + for &i in &ty_params { + let param_b = *substs_b.types.get(TypeSpace, i); + new_substs.types.get_mut_slice(TypeSpace)[i] = param_b; + } let new_struct = ty::mk_struct(tcx, def_id, tcx.mk_substs(new_substs)); let origin = infer::Misc(obligation.cause.span); if self.infcx.sub_types(false, origin, new_struct, target).is_err() { return Err(Unimplemented); } - // Construct the nested T: Unsize predicate. + // Construct the nested Field: Unsize> predicate. nested.push(util::predicate_for_trait_def(tcx, obligation.cause.clone(), obligation.predicate.def_id(), diff --git a/src/test/run-pass/dst-coerce-rc.rs b/src/test/run-pass/dst-coerce-rc.rs index 32e7a6279c8..67dd4021cb5 100644 --- a/src/test/run-pass/dst-coerce-rc.rs +++ b/src/test/run-pass/dst-coerce-rc.rs @@ -12,6 +12,7 @@ #![feature(core)] +use std::cell::RefCell; use std::rc::Rc; trait Baz { @@ -36,4 +37,8 @@ fn main() { assert_eq!(b.get(), 42); let _c = b.clone(); + + let a: Rc> = Rc::new(RefCell::new(42)); + let b: Rc> = a.clone(); + assert_eq!(b.borrow().get(), 42); }