diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 0940c9b9ff4..1be99a8e569 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -298,17 +298,9 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { fn closure_to_string<'tcx>(cx: &ctxt<'tcx>, cty: &ty::ClosureTy<'tcx>) -> String { let mut s = String::new(); - - match cty.unsafety { - ast::Unsafety::Normal => {} - ast::Unsafety::Unsafe => { - s.push_str(cty.unsafety.to_string().as_slice()); - s.push(' '); - } - }; - - push_sig_to_string(cx, &mut s, '|', '|', &cty.sig); - + s.push_str("[closure"); + push_sig_to_string(cx, &mut s, '(', ')', &cty.sig); + s.push(']'); s } @@ -399,18 +391,10 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { ty_enum(did, substs) | ty_struct(did, substs) => { let base = ty::item_path_str(cx, did); let generics = ty::lookup_item_type(cx, did).generics; - parameterized(cx, base.as_slice(), substs, &generics, did) + parameterized(cx, base.as_slice(), substs, &generics, did, &[]) } - ty_trait(box ty::TyTrait { - ref principal, ref bounds - }) => { - let principal = principal.user_string(cx); - let bound_str = bounds.user_string(cx); - let bound_sep = if bound_str.is_empty() { "" } else { " + " }; - format!("{}{}{}", - principal, - bound_sep, - bound_str) + ty_trait(ref data) => { + data.user_string(cx) } ty::ty_projection(ref data) => { format!("<{} as {}>::{}", @@ -420,14 +404,15 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { } ty_str => "str".to_string(), ty_closure(ref did, _, substs) => { - cx.closures.borrow().get(did).map(|cl| { + let closures = cx.closures.borrow(); + closures.get(did).map(|cl| { closure_to_string(cx, &cl.closure_type.subst(cx, substs)) }).unwrap_or_else(|| { if did.krate == ast::LOCAL_CRATE { let span = cx.map.span(did.node); - format!("closure[{}]", span.repr(cx)) + format!("[closure {}]", span.repr(cx)) } else { - format!("closure") + format!("[closure]") } }) } @@ -458,7 +443,8 @@ pub fn parameterized<'tcx>(cx: &ctxt<'tcx>, base: &str, substs: &subst::Substs<'tcx>, generics: &ty::Generics<'tcx>, - did: ast::DefId) + did: ast::DefId, + projections: &[ty::ProjectionPredicate<'tcx>]) -> String { if cx.sess.verbose() { @@ -511,8 +497,21 @@ pub fn parameterized<'tcx>(cx: &ctxt<'tcx>, strs.push(ty_to_string(cx, *t)) } - if cx.lang_items.fn_trait_kind(did).is_some() { - format!("{}({})", // TODO + for projection in projections.iter() { + strs.push(format!("{}={}", + projection.projection_ty.item_name.user_string(cx), + projection.ty.user_string(cx))); + } + + if cx.lang_items.fn_trait_kind(did).is_some() && projections.len() == 1 { + let projection_ty = projections[0].ty; + let tail = + if ty::type_is_nil(projection_ty) { + format!("") + } else { + format!(" -> {}", projection_ty.user_string(cx)) + }; + format!("{}({}){}", base, if strs[0].starts_with("(") && strs[0].ends_with(",)") { &strs[0][1 .. strs[0].len() - 2] // Remove '(' and ',)' @@ -520,7 +519,8 @@ pub fn parameterized<'tcx>(cx: &ctxt<'tcx>, &strs[0][1 .. strs[0].len() - 1] // Remove '(' and ')' } else { &strs[0][] - }) + }, + tail) } else if strs.len() > 0 { format!("{}<{}>", base, strs.connect(", ")) } else { @@ -622,6 +622,65 @@ impl<'tcx> Repr<'tcx> for def::Def { } } +/// This curious type is here to help pretty-print trait objects. In +/// a trait object, the projections are stored separately from the +/// main trait bound, but in fact we want to package them together +/// when printing out; they also have separate binders, but we want +/// them to share a binder when we print them out. (And the binder +/// pretty-printing logic is kind of clever and we don't want to +/// reproduce it.) So we just repackage up the structure somewhat. +/// +/// Right now there is only one trait in an object that can have +/// projection bounds, so we just stuff them altogether. But in +/// reality we should eventually sort things out better. +type TraitAndProjections<'tcx> = + (Rc>, Vec>); + +impl<'tcx> UserString<'tcx> for TraitAndProjections<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + let &(ref trait_ref, ref projection_bounds) = self; + let base = ty::item_path_str(tcx, trait_ref.def_id); + let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id); + parameterized(tcx, + base.as_slice(), + trait_ref.substs, + &trait_def.generics, + trait_ref.def_id, + &projection_bounds[]) + } +} + +impl<'tcx> UserString<'tcx> for ty::TyTrait<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + let &ty::TyTrait { ref principal, ref bounds } = self; + + let mut components = vec![]; + + let tap: ty::Binder> = + ty::Binder((principal.0.clone(), + bounds.projection_bounds.iter().map(|x| x.0.clone()).collect())); + + // Generate the main trait ref, including associated types. + components.push(tap.user_string(tcx)); + + // Builtin bounds. + for bound in bounds.builtin_bounds.iter() { + components.push(bound.user_string(tcx)); + } + + // Region, if not obviously implied by builtin bounds. + if bounds.region_bound != ty::ReStatic || + !bounds.builtin_bounds.contains(&ty::BoundSend) + { // Region bound is implied by builtin bounds: + components.push(bounds.region_bound.user_string(tcx)); + } + + components.retain(|s| !s.is_empty()); + + components.connect(" + ") + } +} + impl<'tcx> Repr<'tcx> for ty::TypeParameterDef<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { format!("TypeParameterDef({:?}, {}, {:?}/{})", @@ -700,12 +759,6 @@ impl<'tcx> Repr<'tcx> for ty::BuiltinBounds { } } -impl<'tcx> Repr<'tcx> for ty::ExistentialBounds<'tcx> { - fn repr(&self, tcx: &ctxt<'tcx>) -> String { - self.user_string(tcx) - } -} - impl<'tcx> Repr<'tcx> for ty::ParamBounds<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { let mut res = Vec::new(); @@ -726,7 +779,8 @@ impl<'tcx> Repr<'tcx> for ty::TraitRef<'tcx> { let trait_def = ty::lookup_trait_def(tcx, self.def_id); format!("TraitRef({}, {})", self.substs.self_ty().repr(tcx), - parameterized(tcx, base.as_slice(), self.substs, &trait_def.generics, self.def_id)) + parameterized(tcx, base.as_slice(), self.substs, + &trait_def.generics, self.def_id, &[])) } } @@ -1109,14 +1163,8 @@ impl<'tcx> UserString<'tcx> for ty::ParamBounds<'tcx> { } } -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: - return self.builtin_bounds.repr(tcx); - } - +impl<'tcx> Repr<'tcx> for ty::ExistentialBounds<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { let mut res = Vec::new(); let region_str = self.region_bound.user_string(tcx); @@ -1128,6 +1176,10 @@ impl<'tcx> UserString<'tcx> for ty::ExistentialBounds<'tcx> { res.push(bound.user_string(tcx)); } + for projection_bound in self.projection_bounds.iter() { + res.push(projection_bound.user_string(tcx)); + } + res.connect("+") } } @@ -1183,7 +1235,7 @@ impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { let path_str = ty::item_path_str(tcx, self.def_id); let trait_def = ty::lookup_trait_def(tcx, self.def_id); parameterized(tcx, path_str.as_slice(), self.substs, - &trait_def.generics, self.def_id) + &trait_def.generics, self.def_id, &[]) } }