diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 2a4d5f36a17..7dccc49dcbb 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -200,9 +200,9 @@ pub fn parse_bounds_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, parse_bounds(&mut st, conv) } -pub fn parse_existential_bounds_data(data: &[u8], crate_num: ast::CrateNum, - pos: uint, tcx: &ty::ctxt, conv: conv_did) - -> ty::ExistentialBounds { +pub fn parse_existential_bounds_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, + pos: uint, tcx: &ty::ctxt<'tcx>, conv: conv_did) + -> ty::ExistentialBounds<'tcx> { let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_existential_bounds(&mut st, conv) } @@ -744,10 +744,18 @@ fn parse_type_param_def<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) } } -fn parse_existential_bounds(st: &mut PState, conv: conv_did) -> ty::ExistentialBounds { - let r = parse_region(st, |x,y| conv(x,y)); - let bb = parse_builtin_bounds(st, conv); - return ty::ExistentialBounds { region_bound: r, builtin_bounds: bb }; +fn parse_existential_bounds<'a,'tcx>(st: &mut PState<'a,'tcx>, + conv: conv_did) + -> ty::ExistentialBounds<'tcx> +{ + let ty::ParamBounds { trait_bounds, mut region_bounds, builtin_bounds, projection_bounds } = + parse_bounds(st, conv); + assert_eq!(region_bounds.len(), 1); + assert_eq!(trait_bounds.len(), 0); + let region_bound = region_bounds.pop().unwrap(); + return ty::ExistentialBounds { region_bound: region_bound, + builtin_bounds: builtin_bounds, + projection_bounds: projection_bounds }; } fn parse_builtin_bounds(st: &mut PState, _conv: conv_did) -> ty::BuiltinBounds { diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 015724d38ee..b6d05882dce 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -392,9 +392,14 @@ pub fn enc_builtin_bounds(w: &mut SeekableMemWriter, _cx: &ctxt, bs: &ty::Builti mywrite!(w, "."); } -pub fn enc_existential_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ExistentialBounds) { - enc_region(w, cx, bs.region_bound); - enc_builtin_bounds(w, cx, &bs.builtin_bounds); +pub fn enc_existential_bounds<'a,'tcx>(w: &mut SeekableMemWriter, + cx: &ctxt<'a,'tcx>, + bs: &ty::ExistentialBounds<'tcx>) { + let param_bounds = ty::ParamBounds { trait_bounds: vec!(), + region_bounds: vec!(bs.region_bound), + builtin_bounds: bs.builtin_bounds, + projection_bounds: bs.projection_bounds.clone() }; + enc_bounds(w, cx, ¶m_bounds); } pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 4dee3ee4713..0b78f2b1cfc 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -842,7 +842,8 @@ trait rbml_writer_helpers<'tcx> { type_scheme: ty::TypeScheme<'tcx>); fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, substs: &subst::Substs<'tcx>); - fn emit_existential_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::ExistentialBounds); + fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>, + bounds: &ty::ExistentialBounds<'tcx>); fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds); fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, adj: &ty::AutoAdjustment<'tcx>); @@ -982,7 +983,8 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { }); } - fn emit_existential_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::ExistentialBounds) { + fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>, + bounds: &ty::ExistentialBounds<'tcx>) { self.emit_opaque(|this| Ok(tyencode::enc_existential_bounds(this.writer, &ecx.ty_str_ctxt(), bounds))); @@ -1372,7 +1374,7 @@ trait rbml_decoder_decoder_helpers<'tcx> { fn read_type_scheme<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::TypeScheme<'tcx>; fn read_existential_bounds<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::ExistentialBounds; + -> ty::ExistentialBounds<'tcx>; fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> subst::Substs<'tcx>; fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -1626,7 +1628,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { } fn read_existential_bounds<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::ExistentialBounds + -> ty::ExistentialBounds<'tcx> { self.read_opaque(|this, doc| { Ok(tydecode::parse_existential_bounds_data(doc.data, diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs index 13017da508d..11ca202971e 100644 --- a/src/librustc/middle/infer/coercion.rs +++ b/src/librustc/middle/infer/coercion.rs @@ -351,11 +351,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { (&ty::ty_trait(..), &ty::ty_trait(..)) => { None } - (_, &ty::ty_trait(box ty::TyTrait { ref principal, bounds })) => { + (_, &ty::ty_trait(box ty::TyTrait { ref principal, ref bounds })) => { // FIXME what is the purpose of `ty`? - let ty = ty::mk_trait(tcx, principal.clone(), bounds); - Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: (*principal).clone(), - bounds: bounds }, + let ty = ty::mk_trait(tcx, principal.clone(), bounds.clone()); + Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: principal.clone(), + bounds: bounds.clone() }, ty_a))) } (&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b)) @@ -458,10 +458,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match a.sty { ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty.sty { - ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { + ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl); - // FIXME what is purpose of this type `tr`? - let tr = ty::mk_trait(tcx, principal.clone(), bounds); + let tr = ty::mk_trait(tcx, principal.clone(), bounds.clone()); try!(self.subtype(mk_ty(tr), b)); Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 4114394041d..e0bcdfc6d8d 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -222,7 +222,7 @@ pub trait Combine<'tcx> { }; let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety)); let onceness = try!(self.oncenesses(a.onceness, b.onceness)); - let bounds = try!(self.existential_bounds(a.bounds, b.bounds)); + let bounds = try!(self.existential_bounds(&a.bounds, &b.bounds)); let sig = try!(self.binders(&a.sig, &b.sig)); let abi = try!(self.abi(a.abi, b.abi)); Ok(ty::ClosureTy { @@ -289,15 +289,61 @@ pub trait Combine<'tcx> { fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<'tcx, Onceness>; + fn projection_tys(&self, + a: &ty::ProjectionTy<'tcx>, + b: &ty::ProjectionTy<'tcx>) + -> cres<'tcx, ty::ProjectionTy<'tcx>> + { + if a.item_name != b.item_name { + Err(ty::terr_projection_name_mismatched( + expected_found(self, a.item_name, b.item_name))) + } else { + let trait_ref = try!(self.trait_refs(&*a.trait_ref, &*b.trait_ref)); + Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name }) + } + } + + fn projection_predicates(&self, + a: &ty::ProjectionPredicate<'tcx>, + b: &ty::ProjectionPredicate<'tcx>) + -> cres<'tcx, ty::ProjectionPredicate<'tcx>> + { + let projection_ty = try!(self.projection_tys(&a.projection_ty, &b.projection_ty)); + let ty = try!(self.tys(a.ty, b.ty)); + Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty }) + } + + fn projection_bounds(&self, + a: &Vec>, + b: &Vec>) + -> cres<'tcx, Vec>> + { + // To be compatible, `a` and `b` must be for precisely the + // same set of traits and item names. We always require that + // projection bounds lists are sorted by trait-def-id and item-name, + // so we can just iterate through the lists pairwise, so long as they are the + // same length. + if a.len() != b.len() { + Err(ty::terr_projection_bounds_length(expected_found(self, a.len(), b.len()))) + } else { + a.iter() + .zip(b.iter()) + .map(|(a, b)| self.binders(a, b)) + .collect() + } + } + fn existential_bounds(&self, - a: ty::ExistentialBounds, - b: ty::ExistentialBounds) - -> cres<'tcx, ty::ExistentialBounds> + a: &ty::ExistentialBounds<'tcx>, + b: &ty::ExistentialBounds<'tcx>) + -> cres<'tcx, ty::ExistentialBounds<'tcx>> { let r = try!(self.contraregions(a.region_bound, b.region_bound)); let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds)); + let pb = try!(self.projection_bounds(&a.projection_bounds, &b.projection_bounds)); Ok(ty::ExistentialBounds { region_bound: r, - builtin_bounds: nb }) + builtin_bounds: nb, + projection_bounds: pb }) } fn builtin_bounds(&self, @@ -381,6 +427,16 @@ impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> { } } +impl<'tcx> Combineable<'tcx> for ty::ProjectionPredicate<'tcx> { + fn combine>(combiner: &C, + a: &ty::ProjectionPredicate<'tcx>, + b: &ty::ProjectionPredicate<'tcx>) + -> cres<'tcx, ty::ProjectionPredicate<'tcx>> + { + combiner.projection_predicates(a, b) + } +} + impl<'tcx> Combineable<'tcx> for ty::FnSig<'tcx> { fn combine>(combiner: &C, a: &ty::FnSig<'tcx>, @@ -496,7 +552,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, &ty::ty_trait(ref b_)) => { debug!("Trying to match traits {} and {}", a, b); let principal = try!(this.binders(&a_.principal, &b_.principal)); - let bounds = try!(this.existential_bounds(a_.bounds, b_.bounds)); + let bounds = try!(this.existential_bounds(&a_.bounds, &b_.bounds)); Ok(ty::mk_trait(tcx, principal, bounds)) } @@ -595,12 +651,8 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, } (&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => { - if a_data.item_name == b_data.item_name { - let trait_ref = try!(this.trait_refs(&*a_data.trait_ref, &*b_data.trait_ref)); - Ok(ty::mk_projection(tcx, Rc::new(trait_ref), a_data.item_name)) - } else { - Err(ty::terr_sorts(expected_found(this, a, b))) - } + let projection_ty = try!(this.projection_tys(a_data, b_data)); + Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name)) } _ => Err(ty::terr_sorts(expected_found(this, a, b))) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 6b2ac04f5ce..e989f5a2cc2 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -396,14 +396,14 @@ pub fn type_of_adjust<'tcx>(cx: &ctxt<'tcx>, adj: &AutoAdjustment<'tcx>) -> Opti fn type_of_autoref<'tcx>(cx: &ctxt<'tcx>, autoref: &AutoRef<'tcx>) -> Option> { match autoref { &AutoUnsize(ref k) => match k { - &UnsizeVtable(TyTrait { ref principal, bounds }, _) => { - Some(mk_trait(cx, (*principal).clone(), bounds)) + &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { + Some(mk_trait(cx, principal.clone(), bounds.clone())) } _ => None }, &AutoUnsizeUniq(ref k) => match k { - &UnsizeVtable(TyTrait { ref principal, bounds }, _) => { - Some(mk_uniq(cx, mk_trait(cx, (*principal).clone(), bounds))) + &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { + Some(mk_uniq(cx, mk_trait(cx, principal.clone(), bounds.clone()))) } _ => None }, @@ -1040,7 +1040,7 @@ pub struct ClosureTy<'tcx> { pub unsafety: ast::Unsafety, pub onceness: ast::Onceness, pub store: TraitStore, - pub bounds: ExistentialBounds, + pub bounds: ExistentialBounds<'tcx>, pub sig: PolyFnSig<'tcx>, pub abi: abi::Abi, } @@ -1376,7 +1376,7 @@ pub enum sty<'tcx> { #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct TyTrait<'tcx> { pub principal: ty::PolyTraitRef<'tcx>, - pub bounds: ExistentialBounds + pub bounds: ExistentialBounds<'tcx>, } impl<'tcx> TyTrait<'tcx> { @@ -1510,7 +1510,9 @@ pub enum type_err<'tcx> { terr_builtin_bounds(expected_found), terr_variadic_mismatch(expected_found), terr_cyclic_ty, - terr_convergence_mismatch(expected_found) + terr_convergence_mismatch(expected_found), + terr_projection_name_mismatched(expected_found), + terr_projection_bounds_length(expected_found), } /// Bounds suitable for a named type parameter like `A` in `fn foo` @@ -1528,10 +1530,11 @@ pub struct ParamBounds<'tcx> { /// major difference between this case and `ParamBounds` is that /// general purpose trait bounds are omitted and there must be /// *exactly one* region. -#[deriving(Copy, PartialEq, Eq, Hash, Clone, Show)] -pub struct ExistentialBounds { +#[deriving(PartialEq, Eq, Hash, Clone, Show)] +pub struct ExistentialBounds<'tcx> { pub region_bound: ty::Region, - pub builtin_bounds: BuiltinBounds + pub builtin_bounds: BuiltinBounds, + pub projection_bounds: Vec>, } pub type BuiltinBounds = EnumSet; @@ -1559,9 +1562,10 @@ pub fn all_builtin_bounds() -> BuiltinBounds { } /// An existential bound that does not implement any traits. -pub fn region_existential_bound(r: ty::Region) -> ExistentialBounds { +pub fn region_existential_bound<'tcx>(r: ty::Region) -> ExistentialBounds<'tcx> { ty::ExistentialBounds { region_bound: r, - builtin_bounds: empty_builtin_bounds() } + builtin_bounds: empty_builtin_bounds(), + projection_bounds: Vec::new() } } impl CLike for BuiltinBound { @@ -1820,12 +1824,24 @@ pub struct ProjectionPredicate<'tcx> { pub type PolyProjectionPredicate<'tcx> = Binder>; +impl<'tcx> PolyProjectionPredicate<'tcx> { + pub fn sort_key(&self) -> (ast::DefId, ast::Name) { + self.0.projection_ty.sort_key() + } +} + #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct ProjectionTy<'tcx> { pub trait_ref: Rc>, pub item_name: ast::Name, } +impl<'tcx> ProjectionTy<'tcx> { + pub fn sort_key(&self) -> (ast::DefId, ast::Name) { + (self.trait_ref.def_id, self.item_name) + } +} + pub trait ToPolyTraitRef<'tcx> { fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; } @@ -2675,8 +2691,11 @@ pub fn mk_ctor_fn<'tcx>(cx: &ctxt<'tcx>, pub fn mk_trait<'tcx>(cx: &ctxt<'tcx>, principal: ty::PolyTraitRef<'tcx>, - bounds: ExistentialBounds) - -> Ty<'tcx> { + bounds: ExistentialBounds<'tcx>) + -> Ty<'tcx> +{ + assert!(bound_list_is_sorted(bounds.projection_bounds.as_slice())); + let inner = box TyTrait { principal: principal, bounds: bounds @@ -2684,6 +2703,16 @@ pub fn mk_trait<'tcx>(cx: &ctxt<'tcx>, mk_t(cx, ty_trait(inner)) } +fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool { + bounds.len() == 0 || + bounds[1..].iter().enumerate().all( + |(index, bound)| bounds[index].sort_key() <= bound.sort_key()) +} + +pub fn sort_bounds_list(bounds: &mut [ty::PolyProjectionPredicate]) { + bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key())) +} + pub fn mk_projection<'tcx>(cx: &ctxt<'tcx>, trait_ref: Rc>, item_name: ast::Name) @@ -3226,7 +3255,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { } } - ty_trait(box TyTrait { bounds, .. }) => { + ty_trait(box TyTrait { ref bounds, .. }) => { object_contents(bounds) | TC::ReachesFfiUnsafe | TC::Nonsized } @@ -3391,7 +3420,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { fn closure_contents(cty: &ClosureTy) -> TypeContents { // Closure contents are just like trait contents, but with potentially // even more stuff. - let st = object_contents(cty.bounds); + let st = object_contents(&cty.bounds); let st = match cty.store { UniqTraitStore => { @@ -3405,7 +3434,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { st } - fn object_contents(bounds: ExistentialBounds) -> TypeContents { + fn object_contents(bounds: &ExistentialBounds) -> TypeContents { // These are the type contents of the (opaque) interior. We // make no assumptions (other than that it cannot have an // in-scope type parameter within, which makes no sense). @@ -4205,6 +4234,7 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, let bounds = ty::ExistentialBounds { region_bound: ReStatic, builtin_bounds: all_builtin_bounds(), + projection_bounds: vec!(), }; ty::mk_closure( @@ -4339,8 +4369,8 @@ pub fn unsize_ty<'tcx>(cx: &ctxt<'tcx>, format!("UnsizeStruct with bad sty: {}", ty_to_string(cx, ty))[]) }, - &UnsizeVtable(TyTrait { ref principal, bounds }, _) => { - mk_trait(cx, (*principal).clone(), bounds) + &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { + mk_trait(cx, principal.clone(), bounds.clone()) } } } @@ -4760,6 +4790,16 @@ pub fn type_err_to_str<'tcx>(cx: &ctxt<'tcx>, err: &type_err<'tcx>) -> String { if values.expected { "converging" } else { "diverging" }, if values.found { "converging" } else { "diverging" }) } + terr_projection_name_mismatched(ref values) => { + format!("expected {}, found {}", + token::get_name(values.expected), + token::get_name(values.found)) + } + terr_projection_bounds_length(ref values) => { + format!("expected {} associated type bindings, found {}", + values.expected, + values.found) + } } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 4ef597d2108..3aff69c0178 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -121,8 +121,8 @@ pub trait TypeFolder<'tcx> { super_fold_trait_store(self, s) } - fn fold_existential_bounds(&mut self, s: ty::ExistentialBounds) - -> ty::ExistentialBounds { + fn fold_existential_bounds(&mut self, s: &ty::ExistentialBounds<'tcx>) + -> ty::ExistentialBounds<'tcx> { super_fold_existential_bounds(self, s) } @@ -349,9 +349,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds { } } -impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds { - fn fold_with>(&self, folder: &mut F) -> ty::ExistentialBounds { - folder.fold_existential_bounds(*self) +impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::ExistentialBounds<'tcx> { + folder.fold_existential_bounds(self) } } @@ -449,7 +449,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::UnsizeKind<'tcx> { match *self { ty::UnsizeLength(len) => ty::UnsizeLength(len), ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n), - ty::UnsizeVtable(ty::TyTrait{ref principal, bounds}, self_ty) => { + ty::UnsizeVtable(ty::TyTrait{ref principal, ref bounds}, self_ty) => { ty::UnsizeVtable( ty::TyTrait { principal: principal.fold_with(folder), @@ -565,9 +565,9 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, let substs = substs.fold_with(this); ty::ty_enum(tid, this.tcx().mk_substs(substs)) } - ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { + ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { ty::ty_trait(box ty::TyTrait { - principal: (*principal).fold_with(this), + principal: principal.fold_with(this), bounds: bounds.fold_with(this), }) } @@ -693,12 +693,15 @@ pub fn super_fold_trait_store<'tcx, T: TypeFolder<'tcx>>(this: &mut T, } } -pub fn super_fold_existential_bounds<'tcx, T: TypeFolder<'tcx>>(this: &mut T, - bounds: ty::ExistentialBounds) - -> ty::ExistentialBounds { +pub fn super_fold_existential_bounds<'tcx, T: TypeFolder<'tcx>>( + this: &mut T, + bounds: &ty::ExistentialBounds<'tcx>) + -> ty::ExistentialBounds<'tcx> +{ ty::ExistentialBounds { region_bound: bounds.region_bound.fold_with(this), builtin_bounds: bounds.builtin_bounds, + projection_bounds: bounds.projection_bounds.fold_with(this), } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 134a4722507..3e7b24ac93f 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -739,8 +739,8 @@ impl<'tcx> Repr<'tcx> for ty::BuiltinBounds { } } -impl<'tcx> Repr<'tcx> for ty::ExistentialBounds { - fn repr(&self, tcx: &ctxt) -> String { +impl<'tcx> Repr<'tcx> for ty::ExistentialBounds<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { self.user_string(tcx) } } @@ -1142,8 +1142,8 @@ impl<'tcx> UserString<'tcx> for ty::ParamBounds<'tcx> { } } -impl<'tcx> UserString<'tcx> for ty::ExistentialBounds { - fn user_string(&self, tcx: &ctxt) -> String { +impl<'tcx> UserString<'tcx> for ty::ExistentialBounds<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { if self.builtin_bounds.contains(&ty::BoundSend) && self.region_bound == ty::ReStatic { // Region bound is implied by builtin bounds: diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 26959dfd1d5..26fadb0dfb1 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -810,11 +810,13 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( } } +type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec>); + fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, rscope: &RS, ty: &ast::Ty, bounds: &[ast::TyParamBound]) - -> Result, ErrorReported> + -> Result, ErrorReported> where AC : AstConv<'tcx>, RS : RegionScope { /*! @@ -832,14 +834,17 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, ast::TyPath(ref path, id) => { match this.tcx().def_map.borrow().get(&id) { Some(&def::DefTrait(trait_def_id)) => { - // TODO do something with this - let mut projections = Vec::new(); - Ok(ty::Binder(ast_path_to_trait_ref(this, - rscope, - trait_def_id, - None, - path, - Some(&mut projections)))) + 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(); + Ok((trait_ref, projection_bounds)) } _ => { span_err!(this.tcx().sess, ty.span, E0172, "expected a reference to a trait"); @@ -882,6 +887,7 @@ fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC, rscope: &RS, span: Span, trait_ref: ty::PolyTraitRef<'tcx>, + projection_bounds: Vec>, bounds: &[ast::TyParamBound]) -> Ty<'tcx> where AC : AstConv<'tcx>, RS : RegionScope @@ -890,6 +896,7 @@ fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC, rscope, span, Some(trait_ref.clone()), + projection_bounds, bounds); let result = ty::mk_trait(this.tcx(), trait_ref, existential_bounds); @@ -1019,9 +1026,9 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( } ast::TyObjectSum(ref ty, ref bounds) => { match ast_ty_to_trait_ref(this, rscope, &**ty, bounds[]) { - Ok(trait_ref) => { + Ok((trait_ref, projection_bounds)) => { trait_ref_to_object_type(this, rscope, ast_ty.span, - trait_ref, bounds[]) + trait_ref, projection_bounds, bounds[]) } Err(ErrorReported) => { this.tcx().types.err @@ -1062,13 +1069,15 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( rscope, ast_ty.span, None, + Vec::new(), f.bounds.as_slice()); + let region_bound = bounds.region_bound; let fn_decl = ty_of_closure(this, f.unsafety, f.onceness, bounds, ty::RegionTraitStore( - bounds.region_bound, + region_bound, ast::MutMutable), &*f.decl, abi::Rust, @@ -1092,15 +1101,19 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( def::DefTrait(trait_def_id) => { // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details - let mut projections = Vec::new(); // TODO + let mut projection_bounds = Vec::new(); let trait_ref = ast_path_to_trait_ref(this, rscope, trait_def_id, None, path, - Some(&mut projections)); + Some(&mut projection_bounds)); let trait_ref = ty::Binder(trait_ref); - trait_ref_to_object_type(this, rscope, path.span, trait_ref, &[]) + let projection_bounds = projection_bounds.into_iter() + .map(ty::Binder) + .collect(); + trait_ref_to_object_type(this, rscope, path.span, + trait_ref, projection_bounds, &[]) } def::DefTy(did, _) | def::DefStruct(did) => { ast_path_to_ty(this, rscope, did, path).ty @@ -1437,7 +1450,7 @@ pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>( this: &AC, unsafety: ast::Unsafety, onceness: ast::Onceness, - bounds: ty::ExistentialBounds, + bounds: ty::ExistentialBounds<'tcx>, store: ty::TraitStore, decl: &ast::FnDecl, abi: abi::Abi, @@ -1500,14 +1513,15 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( rscope: &RS, span: Span, principal_trait_ref: Option>, // None for boxed closures + projection_bounds: Vec>, ast_bounds: &[ast::TyParamBound]) - -> ty::ExistentialBounds + -> ty::ExistentialBounds<'tcx> { let partitioned_bounds = partition_bounds(this.tcx(), span, ast_bounds); conv_existential_bounds_from_partitioned_bounds( - this, rscope, span, principal_trait_ref, partitioned_bounds) + this, rscope, span, principal_trait_ref, projection_bounds, partitioned_bounds) } fn conv_ty_poly_trait_ref<'tcx, AC, RS>( @@ -1520,14 +1534,14 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>( { let mut partitioned_bounds = partition_bounds(this.tcx(), span, ast_bounds[]); - let mut projections = Vec::new(); + let mut projection_bounds = Vec::new(); let main_trait_bound = match partitioned_bounds.trait_bounds.remove(0) { Some(trait_bound) => { let ptr = instantiate_poly_trait_ref(this, rscope, trait_bound, None, - &mut projections); + &mut projection_bounds); Some(ptr) } None => { @@ -1538,13 +1552,12 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>( } }; - // TODO use projections somewhere - let bounds = conv_existential_bounds_from_partitioned_bounds(this, rscope, span, main_trait_bound.clone(), + projection_bounds, partitioned_bounds); match main_trait_bound { @@ -1558,8 +1571,9 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( rscope: &RS, span: Span, principal_trait_ref: Option>, // None for boxed closures + mut projection_bounds: Vec>, // Empty for boxed closures partitioned_bounds: PartitionedBounds) - -> ty::ExistentialBounds + -> ty::ExistentialBounds<'tcx> where AC: AstConv<'tcx>, RS:RegionScope { let PartitionedBounds { builtin_bounds, @@ -1582,9 +1596,12 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( principal_trait_ref, builtin_bounds); + ty::sort_bounds_list(projection_bounds.as_mut_slice()); + ty::ExistentialBounds { region_bound: region_bound, builtin_bounds: builtin_bounds, + projection_bounds: projection_bounds, } } diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs index fbc6d49d6e9..e737bb1b237 100644 --- a/src/librustc_typeck/check/assoc.rs +++ b/src/librustc_typeck/check/assoc.rs @@ -15,7 +15,6 @@ use middle::ty::{mod, HasProjectionTypes, Ty}; use middle::ty_fold::{mod, TypeFoldable, TypeFolder}; use syntax::ast; use syntax::codemap::Span; -use std::rc::Rc; pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, fulfillment_cx: &mut FulfillmentContext<'tcx>, diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index ec964ab638f..19108ca710b 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -289,7 +289,7 @@ fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, (&ty::UniqTraitStore, _) => ast::Once, (&ty::RegionTraitStore(..), _) => ast::Many, }; - (Some(sig), onceness, cenv.bounds) + (Some(sig), onceness, cenv.bounds.clone()) } _ => { // Not an error! Means we're inferring the closure type diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index b8cf215f89e..1da8852c9b2 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -768,7 +768,7 @@ fn constrain_cast(rcx: &mut Rcx, } /*From:*/ (_, - /*To: */ &ty::ty_trait(box ty::TyTrait { bounds, .. })) => { + /*To: */ &ty::ty_trait(box ty::TyTrait { ref bounds, .. })) => { // When T is existentially quantified as a trait // `Foo+'to`, it must outlive the region bound `'to`. type_must_outlive(rcx, infer::RelateObjectBound(cast_expr.span), @@ -851,7 +851,7 @@ fn check_expr_fn_block(rcx: &mut Rcx, } match function_type.sty { - ty::ty_closure(box ty::ClosureTy {bounds, ..}) => { + ty::ty_closure(box ty::ClosureTy {ref bounds, ..}) => { ty::with_freevars(tcx, expr.id, |freevars| { ensure_free_variable_types_outlive_closure_bound(rcx, bounds, expr, freevars); }) @@ -859,7 +859,7 @@ fn check_expr_fn_block(rcx: &mut Rcx, ty::ty_unboxed_closure(_, region, _) => { ty::with_freevars(tcx, expr.id, |freevars| { let bounds = ty::region_existential_bound(*region); - ensure_free_variable_types_outlive_closure_bound(rcx, bounds, expr, freevars); + ensure_free_variable_types_outlive_closure_bound(rcx, &bounds, expr, freevars); }) } _ => {} @@ -870,7 +870,7 @@ fn check_expr_fn_block(rcx: &mut Rcx, /// over values outliving the object's lifetime bound. fn ensure_free_variable_types_outlive_closure_bound( rcx: &mut Rcx, - bounds: ty::ExistentialBounds, + bounds: &ty::ExistentialBounds, expr: &ast::Expr, freevars: &[ty::Freevar]) { diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 98badf9c049..5cf759a4dce 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -244,7 +244,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let object_trait_ty = ty::mk_trait(fcx.tcx(), object_trait.principal.clone(), - object_trait.bounds); + object_trait.bounds.clone()); debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}", referent_ty.repr(fcx.tcx()), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d5ffce8db78..5063ce36019 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -500,13 +500,14 @@ impl Clean for ast::TyParamBound { } } -impl Clean> for ty::ExistentialBounds { +impl<'tcx> Clean> for ty::ExistentialBounds<'tcx> { fn clean(&self, cx: &DocContext) -> Vec { let mut vec = vec![]; self.region_bound.clean(cx).map(|b| vec.push(RegionBound(b))); for bb in self.builtin_bounds.iter() { vec.push(bb.clean(cx)); } + // TODO projection bounds vec } } @@ -1441,18 +1442,11 @@ impl<'tcx> Clean for ty::Ty<'tcx> { } } ty::ty_struct(did, substs) | - ty::ty_enum(did, substs) | - ty::ty_trait(box ty::TyTrait { - principal: ty::Binder(ty::TraitRef { def_id: did, substs }), - .. }) => - { + ty::ty_enum(did, substs) => { let fqn = csearch::get_item_path(cx.tcx(), did); - let fqn: Vec = fqn.into_iter().map(|i| { - i.to_string() - }).collect(); + let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect(); let kind = match self.sty { ty::ty_struct(..) => TypeStruct, - ty::ty_trait(..) => TypeTrait, _ => TypeEnum, }; let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(), @@ -1464,11 +1458,24 @@ impl<'tcx> Clean for ty::Ty<'tcx> { did: did, } } + ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { + let did = principal.def_id(); + let fqn = csearch::get_item_path(cx.tcx(), did); + let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect(); + let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(), + Some(did), principal.substs()); + cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeTrait)); + ResolvedPath { + path: path, + typarams: Some(bounds.clean(cx)), + did: did, + } + } ty::ty_tup(ref t) => Tuple(t.clean(cx)), ty::ty_projection(ref data) => { let trait_ref = match data.trait_ref.clean(cx) { - TyParamBound::TraitBound(t) => t, + TyParamBound::TraitBound(t) => t.trait_, TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"), }; Type::QPath {