Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| // Copyright 2012 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 <LICENSE-APACHE or | |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
| // option. This file may not be copied, modified, or distributed | |
| // except according to those terms. | |
| use hir::def_id::DefId; | |
| use hir::map::definitions::DefPathData; | |
| use middle::const_val::ConstVal; | |
| use middle::region::{self, BlockRemainder}; | |
| use ty::subst::{self, Subst}; | |
| use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; | |
| use ty::{TyBool, TyChar, TyAdt}; | |
| use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; | |
| use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; | |
| use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, TyAnon}; | |
| use ty::{TyDynamic, TyInt, TyUint, TyInfer}; | |
| use ty::{self, Ty, TyCtxt, TypeFoldable}; | |
| use util::nodemap::FxHashSet; | |
| use std::cell::Cell; | |
| use std::fmt; | |
| use std::usize; | |
| use rustc_const_math::ConstInt; | |
| use rustc_data_structures::indexed_vec::Idx; | |
| use syntax::abi::Abi; | |
| use syntax::ast::CRATE_NODE_ID; | |
| use syntax::symbol::Symbol; | |
| use hir; | |
| macro_rules! gen_display_debug_body { | |
| ( $with:path ) => { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| let mut cx = PrintContext::new(); | |
| $with(self, f, &mut cx) | |
| } | |
| }; | |
| } | |
| macro_rules! gen_display_debug { | |
| ( ($($x:tt)+) $target:ty, display yes ) => { | |
| impl<$($x)+> fmt::Display for $target { | |
| gen_display_debug_body! { Print::print_display } | |
| } | |
| }; | |
| ( () $target:ty, display yes ) => { | |
| impl fmt::Display for $target { | |
| gen_display_debug_body! { Print::print_display } | |
| } | |
| }; | |
| ( ($($x:tt)+) $target:ty, debug yes ) => { | |
| impl<$($x)+> fmt::Debug for $target { | |
| gen_display_debug_body! { Print::print_debug } | |
| } | |
| }; | |
| ( () $target:ty, debug yes ) => { | |
| impl fmt::Debug for $target { | |
| gen_display_debug_body! { Print::print_debug } | |
| } | |
| }; | |
| ( $generic:tt $target:ty, $t:ident no ) => {}; | |
| } | |
| macro_rules! gen_print_impl { | |
| ( ($($x:tt)+) $target:ty, ($self:ident, $f:ident, $cx:ident) $disp:block $dbg:block ) => { | |
| impl<$($x)+> Print for $target { | |
| fn print<F: fmt::Write>(&$self, $f: &mut F, $cx: &mut PrintContext) -> fmt::Result { | |
| if $cx.is_debug $dbg | |
| else $disp | |
| } | |
| } | |
| }; | |
| ( () $target:ty, ($self:ident, $f:ident, $cx:ident) $disp:block $dbg:block ) => { | |
| impl Print for $target { | |
| fn print<F: fmt::Write>(&$self, $f: &mut F, $cx: &mut PrintContext) -> fmt::Result { | |
| if $cx.is_debug $dbg | |
| else $disp | |
| } | |
| } | |
| }; | |
| ( $generic:tt $target:ty, | |
| $vars:tt $gendisp:ident $disp:block $gendbg:ident $dbg:block ) => { | |
| gen_print_impl! { $generic $target, $vars $disp $dbg } | |
| gen_display_debug! { $generic $target, display $gendisp } | |
| gen_display_debug! { $generic $target, debug $gendbg } | |
| } | |
| } | |
| macro_rules! define_print { | |
| ( $generic:tt $target:ty, | |
| $vars:tt { display $disp:block debug $dbg:block } ) => { | |
| gen_print_impl! { $generic $target, $vars yes $disp yes $dbg } | |
| }; | |
| ( $generic:tt $target:ty, | |
| $vars:tt { debug $dbg:block display $disp:block } ) => { | |
| gen_print_impl! { $generic $target, $vars yes $disp yes $dbg } | |
| }; | |
| ( $generic:tt $target:ty, | |
| $vars:tt { debug $dbg:block } ) => { | |
| gen_print_impl! { $generic $target, $vars no { | |
| bug!(concat!("display not implemented for ", stringify!($target))); | |
| } yes $dbg } | |
| }; | |
| ( $generic:tt $target:ty, | |
| ($self:ident, $f:ident, $cx:ident) { display $disp:block } ) => { | |
| gen_print_impl! { $generic $target, ($self, $f, $cx) yes $disp no { | |
| write!($f, "{:?}", $self) | |
| } } | |
| }; | |
| } | |
| macro_rules! define_print_multi { | |
| ( [ $($generic:tt $target:ty),* ] $vars:tt $def:tt ) => { | |
| $(define_print! { $generic $target, $vars $def })* | |
| }; | |
| } | |
| macro_rules! print_inner { | |
| ( $f:expr, $cx:expr, write ($($data:expr),+) ) => { | |
| write!($f, $($data),+) | |
| }; | |
| ( $f:expr, $cx:expr, $kind:ident ($data:expr) ) => { | |
| $data.$kind($f, $cx) | |
| }; | |
| } | |
| macro_rules! print { | |
| ( $f:expr, $cx:expr $(, $kind:ident $data:tt)+ ) => { | |
| Ok(())$(.and_then(|_| print_inner!($f, $cx, $kind $data)))+ | |
| }; | |
| } | |
| struct LateBoundRegionNameCollector(FxHashSet<Symbol>); | |
| impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector { | |
| fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { | |
| match *r { | |
| ty::ReLateBound(_, ty::BrNamed(_, name)) => { | |
| self.0.insert(name); | |
| }, | |
| _ => {}, | |
| } | |
| r.super_visit_with(self) | |
| } | |
| } | |
| #[derive(Debug)] | |
| pub struct PrintContext { | |
| is_debug: bool, | |
| is_verbose: bool, | |
| identify_regions: bool, | |
| used_region_names: Option<FxHashSet<Symbol>>, | |
| region_index: usize, | |
| binder_depth: usize, | |
| } | |
| impl PrintContext { | |
| fn new() -> Self { | |
| ty::tls::with_opt(|tcx| { | |
| let (is_verbose, identify_regions) = tcx.map( | |
| |tcx| (tcx.sess.verbose(), tcx.sess.opts.debugging_opts.identify_regions) | |
| ).unwrap_or((false, false)); | |
| PrintContext { | |
| is_debug: false, | |
| is_verbose: is_verbose, | |
| identify_regions: identify_regions, | |
| used_region_names: None, | |
| region_index: 0, | |
| binder_depth: 0, | |
| } | |
| }) | |
| } | |
| fn prepare_late_bound_region_info<'tcx, T>(&mut self, value: &ty::Binder<T>) | |
| where T: TypeFoldable<'tcx> | |
| { | |
| let mut collector = LateBoundRegionNameCollector(FxHashSet()); | |
| value.visit_with(&mut collector); | |
| self.used_region_names = Some(collector.0); | |
| self.region_index = 0; | |
| } | |
| } | |
| pub trait Print { | |
| fn print<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result; | |
| fn print_to_string(&self, cx: &mut PrintContext) -> String { | |
| let mut result = String::new(); | |
| let _ = self.print(&mut result, cx); | |
| result | |
| } | |
| fn print_display<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result { | |
| let old_debug = cx.is_debug; | |
| cx.is_debug = false; | |
| let result = self.print(f, cx); | |
| cx.is_debug = old_debug; | |
| result | |
| } | |
| fn print_display_to_string(&self, cx: &mut PrintContext) -> String { | |
| let mut result = String::new(); | |
| let _ = self.print_display(&mut result, cx); | |
| result | |
| } | |
| fn print_debug<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result { | |
| let old_debug = cx.is_debug; | |
| cx.is_debug = true; | |
| let result = self.print(f, cx); | |
| cx.is_debug = old_debug; | |
| result | |
| } | |
| fn print_debug_to_string(&self, cx: &mut PrintContext) -> String { | |
| let mut result = String::new(); | |
| let _ = self.print_debug(&mut result, cx); | |
| result | |
| } | |
| } | |
| impl PrintContext { | |
| fn fn_sig<F: fmt::Write>(&mut self, | |
| f: &mut F, | |
| inputs: &[Ty], | |
| variadic: bool, | |
| output: Ty) | |
| -> fmt::Result { | |
| write!(f, "(")?; | |
| let mut inputs = inputs.iter(); | |
| if let Some(&ty) = inputs.next() { | |
| print!(f, self, print_display(ty))?; | |
| for &ty in inputs { | |
| print!(f, self, write(", "), print_display(ty))?; | |
| } | |
| if variadic { | |
| write!(f, ", ...")?; | |
| } | |
| } | |
| write!(f, ")")?; | |
| if !output.is_nil() { | |
| print!(f, self, write(" -> "), print_display(output))?; | |
| } | |
| Ok(()) | |
| } | |
| fn parameterized<F: fmt::Write>(&mut self, | |
| f: &mut F, | |
| substs: &subst::Substs, | |
| mut did: DefId, | |
| projections: &[ty::ProjectionPredicate]) | |
| -> fmt::Result { | |
| let key = ty::tls::with(|tcx| tcx.def_key(did)); | |
| let mut item_name = if let Some(name) = key.disambiguated_data.data.get_opt_name() { | |
| Some(name) | |
| } else { | |
| did.index = key.parent.unwrap_or_else( | |
| || bug!("finding type for {:?}, encountered def-id {:?} with no parent", | |
| did, did)); | |
| self.parameterized(f, substs, did, projections)?; | |
| return write!(f, "::{}", key.disambiguated_data.data.as_interned_str()); | |
| }; | |
| let verbose = self.is_verbose; | |
| let mut num_supplied_defaults = 0; | |
| let mut has_self = false; | |
| let mut num_regions = 0; | |
| let mut num_types = 0; | |
| let mut is_value_path = false; | |
| let fn_trait_kind = ty::tls::with(|tcx| { | |
| // Unfortunately, some kinds of items (e.g., closures) don't have | |
| // generics. So walk back up the find the closest parent that DOES | |
| // have them. | |
| let mut item_def_id = did; | |
| loop { | |
| let key = tcx.def_key(item_def_id); | |
| match key.disambiguated_data.data { | |
| DefPathData::TypeNs(_) => { | |
| break; | |
| } | |
| DefPathData::ValueNs(_) | DefPathData::EnumVariant(_) => { | |
| is_value_path = true; | |
| break; | |
| } | |
| _ => { | |
| // if we're making a symbol for something, there ought | |
| // to be a value or type-def or something in there | |
| // *somewhere* | |
| item_def_id.index = key.parent.unwrap_or_else(|| { | |
| bug!("finding type for {:?}, encountered def-id {:?} with no \ | |
| parent", did, item_def_id); | |
| }); | |
| } | |
| } | |
| } | |
| let mut generics = tcx.generics_of(item_def_id); | |
| let mut path_def_id = did; | |
| has_self = generics.has_self; | |
| let mut child_types = 0; | |
| if let Some(def_id) = generics.parent { | |
| // Methods. | |
| assert!(is_value_path); | |
| child_types = generics.types.len(); | |
| generics = tcx.generics_of(def_id); | |
| num_regions = generics.regions.len(); | |
| num_types = generics.types.len(); | |
| if has_self { | |
| print!(f, self, write("<"), print_display(substs.type_at(0)), write(" as "))?; | |
| } | |
| path_def_id = def_id; | |
| } else { | |
| item_name = None; | |
| if is_value_path { | |
| // Functions. | |
| assert_eq!(has_self, false); | |
| } else { | |
| // Types and traits. | |
| num_regions = generics.regions.len(); | |
| num_types = generics.types.len(); | |
| } | |
| } | |
| if !verbose { | |
| if generics.types.last().map_or(false, |def| def.has_default) { | |
| if let Some(substs) = tcx.lift(&substs) { | |
| let tps = substs.types().rev().skip(child_types); | |
| for (def, actual) in generics.types.iter().rev().zip(tps) { | |
| if !def.has_default { | |
| break; | |
| } | |
| if tcx.type_of(def.def_id).subst(tcx, substs) != actual { | |
| break; | |
| } | |
| num_supplied_defaults += 1; | |
| } | |
| } | |
| } | |
| } | |
| print!(f, self, write("{}", tcx.item_path_str(path_def_id)))?; | |
| Ok(tcx.lang_items().fn_trait_kind(path_def_id)) | |
| })?; | |
| if !verbose && fn_trait_kind.is_some() && projections.len() == 1 { | |
| let projection_ty = projections[0].ty; | |
| if let TyTuple(ref args, _) = substs.type_at(1).sty { | |
| return self.fn_sig(f, args, false, projection_ty); | |
| } | |
| } | |
| let empty = Cell::new(true); | |
| let start_or_continue = |f: &mut F, start: &str, cont: &str| { | |
| if empty.get() { | |
| empty.set(false); | |
| write!(f, "{}", start) | |
| } else { | |
| write!(f, "{}", cont) | |
| } | |
| }; | |
| let print_regions = |f: &mut F, start: &str, skip, count| { | |
| // Don't print any regions if they're all erased. | |
| let regions = || substs.regions().skip(skip).take(count); | |
| if regions().all(|r: ty::Region| *r == ty::ReErased) { | |
| return Ok(()); | |
| } | |
| for region in regions() { | |
| let region: ty::Region = region; | |
| start_or_continue(f, start, ", ")?; | |
| if verbose { | |
| write!(f, "{:?}", region)?; | |
| } else { | |
| let s = region.to_string(); | |
| if s.is_empty() { | |
| // This happens when the value of the region | |
| // parameter is not easily serialized. This may be | |
| // because the user omitted it in the first place, | |
| // or because it refers to some block in the code, | |
| // etc. I'm not sure how best to serialize this. | |
| write!(f, "'_")?; | |
| } else { | |
| write!(f, "{}", s)?; | |
| } | |
| } | |
| } | |
| Ok(()) | |
| }; | |
| print_regions(f, "<", 0, num_regions)?; | |
| let tps = substs.types().take(num_types - num_supplied_defaults) | |
| .skip(has_self as usize); | |
| for ty in tps { | |
| start_or_continue(f, "<", ", ")?; | |
| ty.print_display(f, self)?; | |
| } | |
| for projection in projections { | |
| start_or_continue(f, "<", ", ")?; | |
| ty::tls::with(|tcx| | |
| print!(f, self, | |
| write("{}=", | |
| tcx.associated_item(projection.projection_ty.item_def_id).name), | |
| print_display(projection.ty)) | |
| )?; | |
| } | |
| start_or_continue(f, "", ">")?; | |
| // For values, also print their name and type parameters. | |
| if is_value_path { | |
| empty.set(true); | |
| if has_self { | |
| write!(f, ">")?; | |
| } | |
| if let Some(item_name) = item_name { | |
| write!(f, "::{}", item_name)?; | |
| } | |
| print_regions(f, "::<", num_regions, usize::MAX)?; | |
| // FIXME: consider being smart with defaults here too | |
| for ty in substs.types().skip(num_types) { | |
| start_or_continue(f, "::<", ", ")?; | |
| ty.print_display(f, self)?; | |
| } | |
| start_or_continue(f, "", ">")?; | |
| } | |
| Ok(()) | |
| } | |
| fn in_binder<'a, 'gcx, 'tcx, T, U, F>(&mut self, | |
| f: &mut F, | |
| tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
| original: &ty::Binder<T>, | |
| lifted: Option<ty::Binder<U>>) -> fmt::Result | |
| where T: Print, U: Print + TypeFoldable<'tcx>, F: fmt::Write | |
| { | |
| fn name_by_region_index(index: usize) -> Symbol { | |
| match index { | |
| 0 => Symbol::intern("'r"), | |
| 1 => Symbol::intern("'s"), | |
| i => Symbol::intern(&format!("'t{}", i-2)), | |
| } | |
| } | |
| // Replace any anonymous late-bound regions with named | |
| // variants, using gensym'd identifiers, so that we can | |
| // clearly differentiate between named and unnamed regions in | |
| // the output. We'll probably want to tweak this over time to | |
| // decide just how much information to give. | |
| let value = if let Some(v) = lifted { | |
| v | |
| } else { | |
| return original.0.print_display(f, self); | |
| }; | |
| if self.binder_depth == 0 { | |
| self.prepare_late_bound_region_info(&value); | |
| } | |
| let mut empty = true; | |
| let mut start_or_continue = |f: &mut F, start: &str, cont: &str| { | |
| if empty { | |
| empty = false; | |
| write!(f, "{}", start) | |
| } else { | |
| write!(f, "{}", cont) | |
| } | |
| }; | |
| let old_region_index = self.region_index; | |
| let mut region_index = old_region_index; | |
| let new_value = tcx.replace_late_bound_regions(&value, |br| { | |
| let _ = start_or_continue(f, "for<", ", "); | |
| let br = match br { | |
| ty::BrNamed(_, name) => { | |
| let _ = write!(f, "{}", name); | |
| br | |
| } | |
| ty::BrAnon(_) | | |
| ty::BrFresh(_) | | |
| ty::BrEnv => { | |
| let name = loop { | |
| let name = name_by_region_index(region_index); | |
| region_index += 1; | |
| if !self.is_name_used(&name) { | |
| break name; | |
| } | |
| }; | |
| let _ = write!(f, "{}", name); | |
| ty::BrNamed(tcx.hir.local_def_id(CRATE_NODE_ID), | |
| name) | |
| } | |
| }; | |
| tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br)) | |
| }).0; | |
| start_or_continue(f, "", "> ")?; | |
| // Push current state to gcx, and restore after writing new_value. | |
| self.binder_depth += 1; | |
| self.region_index = region_index; | |
| let result = new_value.print_display(f, self); | |
| self.region_index = old_region_index; | |
| self.binder_depth -= 1; | |
| result | |
| } | |
| fn is_name_used(&self, name: &Symbol) -> bool { | |
| match self.used_region_names { | |
| Some(ref names) => names.contains(name), | |
| None => false, | |
| } | |
| } | |
| } | |
| pub fn verbose() -> bool { | |
| ty::tls::with(|tcx| tcx.sess.verbose()) | |
| } | |
| pub fn identify_regions() -> bool { | |
| ty::tls::with(|tcx| tcx.sess.opts.debugging_opts.identify_regions) | |
| } | |
| pub fn parameterized<F: fmt::Write>(f: &mut F, | |
| substs: &subst::Substs, | |
| did: DefId, | |
| projections: &[ty::ProjectionPredicate]) | |
| -> fmt::Result { | |
| PrintContext::new().parameterized(f, substs, did, projections) | |
| } | |
| impl<'a, T: Print> Print for &'a T { | |
| fn print<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result { | |
| (*self).print(f, cx) | |
| } | |
| } | |
| define_print! { | |
| ('tcx) &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>, (self, f, cx) { | |
| display { | |
| // Generate the main trait ref, including associated types. | |
| ty::tls::with(|tcx| { | |
| // Use a type that can't appear in defaults of type parameters. | |
| let dummy_self = tcx.mk_infer(ty::FreshTy(0)); | |
| if let Some(p) = self.principal() { | |
| let principal = tcx.lift(&p).expect("could not lift TraitRef for printing") | |
| .with_self_ty(tcx, dummy_self); | |
| let projections = self.projection_bounds().map(|p| { | |
| tcx.lift(&p) | |
| .expect("could not lift projection for printing") | |
| .with_self_ty(tcx, dummy_self) | |
| }).collect::<Vec<_>>(); | |
| cx.parameterized(f, principal.substs, principal.def_id, &projections)?; | |
| } | |
| // Builtin bounds. | |
| for did in self.auto_traits() { | |
| write!(f, " + {}", tcx.item_path_str(did))?; | |
| } | |
| Ok(()) | |
| })?; | |
| Ok(()) | |
| } | |
| } | |
| } | |
| impl fmt::Debug for ty::TypeParameterDef { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "TypeParameterDef({}, {:?}, {})", | |
| self.name, | |
| self.def_id, | |
| self.index) | |
| } | |
| } | |
| impl fmt::Debug for ty::RegionParameterDef { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "RegionParameterDef({}, {:?}, {})", | |
| self.name, | |
| self.def_id, | |
| self.index) | |
| } | |
| } | |
| impl fmt::Debug for ty::TraitDef { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| ty::tls::with(|tcx| { | |
| write!(f, "{}", tcx.item_path_str(self.def_id)) | |
| }) | |
| } | |
| } | |
| impl fmt::Debug for ty::AdtDef { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| ty::tls::with(|tcx| { | |
| write!(f, "{}", tcx.item_path_str(self.did)) | |
| }) | |
| } | |
| } | |
| impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "ClosureUpvar({:?},{:?})", | |
| self.def, | |
| self.ty) | |
| } | |
| } | |
| impl fmt::Debug for ty::UpvarId { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "UpvarId({:?};`{}`;{:?})", | |
| self.var_id, | |
| ty::tls::with(|tcx| tcx.hir.name(tcx.hir.hir_to_node_id(self.var_id))), | |
| self.closure_expr_id) | |
| } | |
| } | |
| impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "UpvarBorrow({:?}, {:?})", | |
| self.kind, self.region) | |
| } | |
| } | |
| define_print! { | |
| ('tcx) &'tcx ty::Slice<Ty<'tcx>>, (self, f, cx) { | |
| display { | |
| write!(f, "{{")?; | |
| let mut tys = self.iter(); | |
| if let Some(&ty) = tys.next() { | |
| print!(f, cx, print(ty))?; | |
| for &ty in tys { | |
| print!(f, cx, write(", "), print(ty))?; | |
| } | |
| } | |
| write!(f, "}}") | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::TypeAndMut<'tcx>, (self, f, cx) { | |
| display { | |
| print!(f, cx, | |
| write("{}", if self.mutbl == hir::MutMutable { "mut " } else { "" }), | |
| print(self.ty)) | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::ExistentialTraitRef<'tcx>, (self, f, cx) { | |
| debug { | |
| ty::tls::with(|tcx| { | |
| let dummy_self = tcx.mk_infer(ty::FreshTy(0)); | |
| let trait_ref = tcx.lift(&ty::Binder(*self)) | |
| .expect("could not lift TraitRef for printing") | |
| .with_self_ty(tcx, dummy_self).0; | |
| cx.parameterized(f, trait_ref.substs, trait_ref.def_id, &[]) | |
| }) | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::adjustment::Adjustment<'tcx>, (self, f, cx) { | |
| debug { | |
| print!(f, cx, write("{:?} -> ", self.kind), print(self.target)) | |
| } | |
| } | |
| } | |
| define_print! { | |
| () ty::BoundRegion, (self, f, cx) { | |
| display { | |
| if cx.is_verbose { | |
| return self.print_debug(f, cx); | |
| } | |
| match *self { | |
| BrNamed(_, name) => write!(f, "{}", name), | |
| BrAnon(_) | BrFresh(_) | BrEnv => Ok(()) | |
| } | |
| } | |
| debug { | |
| return match *self { | |
| BrAnon(n) => write!(f, "BrAnon({:?})", n), | |
| BrFresh(n) => write!(f, "BrFresh({:?})", n), | |
| BrNamed(did, name) => { | |
| write!(f, "BrNamed({:?}:{:?}, {:?})", | |
| did.krate, did.index, name) | |
| } | |
| BrEnv => write!(f, "BrEnv"), | |
| }; | |
| } | |
| } | |
| } | |
| define_print! { | |
| () ty::RegionKind, (self, f, cx) { | |
| display { | |
| if cx.is_verbose { | |
| return self.print_debug(f, cx); | |
| } | |
| // These printouts are concise. They do not contain all the information | |
| // the user might want to diagnose an error, but there is basically no way | |
| // to fit that into a short string. Hence the recommendation to use | |
| // `explain_region()` or `note_and_explain_region()`. | |
| match *self { | |
| ty::ReEarlyBound(ref data) => { | |
| write!(f, "{}", data.name) | |
| } | |
| ty::ReLateBound(_, br) | | |
| ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | | |
| ty::ReSkolemized(_, br) => { | |
| write!(f, "{}", br) | |
| } | |
| ty::ReScope(scope) if cx.identify_regions => { | |
| match scope.data() { | |
| region::ScopeData::Node(id) => | |
| write!(f, "'{}s", id.as_usize()), | |
| region::ScopeData::CallSite(id) => | |
| write!(f, "'{}cs", id.as_usize()), | |
| region::ScopeData::Arguments(id) => | |
| write!(f, "'{}as", id.as_usize()), | |
| region::ScopeData::Destruction(id) => | |
| write!(f, "'{}ds", id.as_usize()), | |
| region::ScopeData::Remainder(BlockRemainder | |
| { block, first_statement_index }) => | |
| write!(f, "'{}_{}rs", block.as_usize(), first_statement_index.index()), | |
| } | |
| } | |
| ty::ReVar(region_vid) if cx.identify_regions => { | |
| write!(f, "'{}rv", region_vid.index()) | |
| } | |
| ty::ReScope(_) | | |
| ty::ReVar(_) | | |
| ty::ReErased => Ok(()), | |
| ty::ReStatic => write!(f, "'static"), | |
| ty::ReEmpty => write!(f, "'<empty>"), | |
| // The user should never encounter these in unsubstituted form. | |
| ty::ReClosureBound(vid) => write!(f, "{:?}", vid), | |
| } | |
| } | |
| debug { | |
| match *self { | |
| ty::ReEarlyBound(ref data) => { | |
| write!(f, "ReEarlyBound({}, {})", | |
| data.index, | |
| data.name) | |
| } | |
| ty::ReClosureBound(ref vid) => { | |
| write!(f, "ReClosureBound({:?})", | |
| vid) | |
| } | |
| ty::ReLateBound(binder_id, ref bound_region) => { | |
| write!(f, "ReLateBound({:?}, {:?})", | |
| binder_id, | |
| bound_region) | |
| } | |
| ty::ReFree(ref fr) => write!(f, "{:?}", fr), | |
| ty::ReScope(id) => { | |
| write!(f, "ReScope({:?})", id) | |
| } | |
| ty::ReStatic => write!(f, "ReStatic"), | |
| ty::ReVar(ref vid) => { | |
| write!(f, "{:?}", vid) | |
| } | |
| ty::ReSkolemized(id, ref bound_region) => { | |
| write!(f, "ReSkolemized({}, {:?})", id.index, bound_region) | |
| } | |
| ty::ReEmpty => write!(f, "ReEmpty"), | |
| ty::ReErased => write!(f, "ReErased") | |
| } | |
| } | |
| } | |
| } | |
| define_print! { | |
| () ty::FreeRegion, (self, f, cx) { | |
| debug { | |
| write!(f, "ReFree({:?}, {:?})", self.scope, self.bound_region) | |
| } | |
| } | |
| } | |
| define_print! { | |
| () ty::Variance, (self, f, cx) { | |
| debug { | |
| f.write_str(match *self { | |
| ty::Covariant => "+", | |
| ty::Contravariant => "-", | |
| ty::Invariant => "o", | |
| ty::Bivariant => "*", | |
| }) | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::GenericPredicates<'tcx>, (self, f, cx) { | |
| debug { | |
| write!(f, "GenericPredicates({:?})", self.predicates) | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::InstantiatedPredicates<'tcx>, (self, f, cx) { | |
| debug { | |
| write!(f, "InstantiatedPredicates({:?})", self.predicates) | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::FnSig<'tcx>, (self, f, cx) { | |
| display { | |
| if self.unsafety == hir::Unsafety::Unsafe { | |
| write!(f, "unsafe ")?; | |
| } | |
| if self.abi != Abi::Rust { | |
| write!(f, "extern {} ", self.abi)?; | |
| } | |
| write!(f, "fn")?; | |
| cx.fn_sig(f, self.inputs(), self.variadic, self.output()) | |
| } | |
| debug { | |
| write!(f, "({:?}; variadic: {})->{:?}", self.inputs(), self.variadic, self.output()) | |
| } | |
| } | |
| } | |
| impl fmt::Debug for ty::TyVid { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "_#{}t", self.index) | |
| } | |
| } | |
| impl fmt::Debug for ty::IntVid { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "_#{}i", self.index) | |
| } | |
| } | |
| impl fmt::Debug for ty::FloatVid { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "_#{}f", self.index) | |
| } | |
| } | |
| impl fmt::Debug for ty::RegionVid { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "'_#{}r", self.index()) | |
| } | |
| } | |
| define_print! { | |
| () ty::InferTy, (self, f, cx) { | |
| display { | |
| if cx.is_verbose { | |
| print!(f, cx, print_debug(self)) | |
| } else { | |
| match *self { | |
| ty::TyVar(_) => write!(f, "_"), | |
| ty::IntVar(_) => write!(f, "{}", "{integer}"), | |
| ty::FloatVar(_) => write!(f, "{}", "{float}"), | |
| ty::FreshTy(v) => write!(f, "FreshTy({})", v), | |
| ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v), | |
| ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v) | |
| } | |
| } | |
| } | |
| debug { | |
| match *self { | |
| ty::TyVar(ref v) => write!(f, "{:?}", v), | |
| ty::IntVar(ref v) => write!(f, "{:?}", v), | |
| ty::FloatVar(ref v) => write!(f, "{:?}", v), | |
| ty::FreshTy(v) => write!(f, "FreshTy({:?})", v), | |
| ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v), | |
| ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v) | |
| } | |
| } | |
| } | |
| } | |
| impl fmt::Debug for ty::IntVarValue { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| match *self { | |
| ty::IntType(ref v) => v.fmt(f), | |
| ty::UintType(ref v) => v.fmt(f), | |
| } | |
| } | |
| } | |
| // The generic impl doesn't work yet because projections are not | |
| // normalized under HRTB. | |
| /*impl<T> fmt::Display for ty::Binder<T> | |
| where T: fmt::Display + for<'a> ty::Lift<'a>, | |
| for<'a> <T as ty::Lift<'a>>::Lifted: fmt::Display + TypeFoldable<'a> | |
| { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) | |
| } | |
| }*/ | |
| define_print_multi! { | |
| [ | |
| ('tcx) ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>, | |
| ('tcx) ty::Binder<ty::TraitRef<'tcx>>, | |
| ('tcx) ty::Binder<ty::FnSig<'tcx>>, | |
| ('tcx) ty::Binder<ty::TraitPredicate<'tcx>>, | |
| ('tcx) ty::Binder<ty::EquatePredicate<'tcx>>, | |
| ('tcx) ty::Binder<ty::SubtypePredicate<'tcx>>, | |
| ('tcx) ty::Binder<ty::ProjectionPredicate<'tcx>>, | |
| ('tcx) ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>, | |
| ('tcx) ty::Binder<ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>> | |
| ] | |
| (self, f, cx) { | |
| display { | |
| ty::tls::with(|tcx| cx.in_binder(f, tcx, self, tcx.lift(self))) | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::TraitRef<'tcx>, (self, f, cx) { | |
| display { | |
| cx.parameterized(f, self.substs, self.def_id, &[]) | |
| } | |
| debug { | |
| // when printing out the debug representation, we don't need | |
| // to enumerate the `for<...>` etc because the debruijn index | |
| // tells you everything you need to know. | |
| print!(f, cx, | |
| write("<"), | |
| print(self.self_ty()), | |
| write(" as "))?; | |
| cx.parameterized(f, self.substs, self.def_id, &[])?; | |
| write!(f, ">") | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::GeneratorInterior<'tcx>, (self, f, cx) { | |
| display { | |
| self.witness.print(f, cx) | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::TypeVariants<'tcx>, (self, f, cx) { | |
| display { | |
| match *self { | |
| TyBool => write!(f, "bool"), | |
| TyChar => write!(f, "char"), | |
| TyInt(t) => write!(f, "{}", t.ty_to_string()), | |
| TyUint(t) => write!(f, "{}", t.ty_to_string()), | |
| TyFloat(t) => write!(f, "{}", t.ty_to_string()), | |
| TyRawPtr(ref tm) => { | |
| write!(f, "*{} ", match tm.mutbl { | |
| hir::MutMutable => "mut", | |
| hir::MutImmutable => "const", | |
| })?; | |
| tm.ty.print(f, cx) | |
| } | |
| TyRef(r, ref tm) => { | |
| write!(f, "&")?; | |
| let s = r.print_to_string(cx); | |
| write!(f, "{}", s)?; | |
| if !s.is_empty() { | |
| write!(f, " ")?; | |
| } | |
| tm.print(f, cx) | |
| } | |
| TyNever => write!(f, "!"), | |
| TyTuple(ref tys, _) => { | |
| write!(f, "(")?; | |
| let mut tys = tys.iter(); | |
| if let Some(&ty) = tys.next() { | |
| print!(f, cx, print(ty), write(","))?; | |
| if let Some(&ty) = tys.next() { | |
| print!(f, cx, write(" "), print(ty))?; | |
| for &ty in tys { | |
| print!(f, cx, write(", "), print(ty))?; | |
| } | |
| } | |
| } | |
| write!(f, ")") | |
| } | |
| TyFnDef(def_id, substs) => { | |
| ty::tls::with(|tcx| { | |
| let mut sig = tcx.fn_sig(def_id); | |
| if let Some(substs) = tcx.lift(&substs) { | |
| sig = sig.subst(tcx, substs); | |
| } | |
| print!(f, cx, print(sig), write(" {{")) | |
| })?; | |
| cx.parameterized(f, substs, def_id, &[])?; | |
| write!(f, "}}") | |
| } | |
| TyFnPtr(ref bare_fn) => { | |
| bare_fn.print(f, cx) | |
| } | |
| TyInfer(infer_ty) => write!(f, "{}", infer_ty), | |
| TyError => write!(f, "[type error]"), | |
| TyParam(ref param_ty) => write!(f, "{}", param_ty), | |
| TyAdt(def, substs) => cx.parameterized(f, substs, def.did, &[]), | |
| TyDynamic(data, r) => { | |
| data.print(f, cx)?; | |
| let r = r.print_to_string(cx); | |
| if !r.is_empty() { | |
| write!(f, " + {}", r) | |
| } else { | |
| Ok(()) | |
| } | |
| } | |
| TyForeign(def_id) => parameterized(f, subst::Substs::empty(), def_id, &[]), | |
| TyProjection(ref data) => data.print(f, cx), | |
| TyAnon(def_id, substs) => { | |
| if cx.is_verbose { | |
| return write!(f, "TyAnon({:?}, {:?})", def_id, substs); | |
| } | |
| ty::tls::with(|tcx| { | |
| // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, | |
| // by looking up the projections associated with the def_id. | |
| let predicates_of = tcx.predicates_of(def_id); | |
| let substs = tcx.lift(&substs).unwrap_or_else(|| { | |
| tcx.intern_substs(&[]) | |
| }); | |
| let bounds = predicates_of.instantiate(tcx, substs); | |
| let mut first = true; | |
| let mut is_sized = false; | |
| write!(f, "impl")?; | |
| for predicate in bounds.predicates { | |
| if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() { | |
| // Don't print +Sized, but rather +?Sized if absent. | |
| if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { | |
| is_sized = true; | |
| continue; | |
| } | |
| print!(f, cx, | |
| write("{}", if first { " " } else { "+" }), | |
| print(trait_ref))?; | |
| first = false; | |
| } | |
| } | |
| if !is_sized { | |
| write!(f, "{}?Sized", if first { " " } else { "+" })?; | |
| } | |
| Ok(()) | |
| }) | |
| } | |
| TyStr => write!(f, "str"), | |
| TyGenerator(did, substs, interior) => ty::tls::with(|tcx| { | |
| let upvar_tys = substs.upvar_tys(did, tcx); | |
| if interior.movable { | |
| write!(f, "[generator")?; | |
| } else { | |
| write!(f, "[static generator")?; | |
| } | |
| if let Some(node_id) = tcx.hir.as_local_node_id(did) { | |
| write!(f, "@{:?}", tcx.hir.span(node_id))?; | |
| let mut sep = " "; | |
| tcx.with_freevars(node_id, |freevars| { | |
| for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) { | |
| print!(f, cx, | |
| write("{}{}:", | |
| sep, | |
| tcx.hir.name(freevar.var_id())), | |
| print(upvar_ty))?; | |
| sep = ", "; | |
| } | |
| Ok(()) | |
| })? | |
| } else { | |
| // cross-crate closure types should only be | |
| // visible in trans bug reports, I imagine. | |
| write!(f, "@{:?}", did)?; | |
| let mut sep = " "; | |
| for (index, upvar_ty) in upvar_tys.enumerate() { | |
| print!(f, cx, | |
| write("{}{}:", sep, index), | |
| print(upvar_ty))?; | |
| sep = ", "; | |
| } | |
| } | |
| print!(f, cx, write(" "), print(interior), write("]")) | |
| }), | |
| TyGeneratorWitness(types) => { | |
| ty::tls::with(|tcx| cx.in_binder(f, tcx, &types, tcx.lift(&types))) | |
| } | |
| TyClosure(did, substs) => ty::tls::with(|tcx| { | |
| let upvar_tys = substs.upvar_tys(did, tcx); | |
| write!(f, "[closure")?; | |
| if let Some(node_id) = tcx.hir.as_local_node_id(did) { | |
| if tcx.sess.opts.debugging_opts.span_free_formats { | |
| write!(f, "@{:?}", node_id)?; | |
| } else { | |
| write!(f, "@{:?}", tcx.hir.span(node_id))?; | |
| } | |
| let mut sep = " "; | |
| tcx.with_freevars(node_id, |freevars| { | |
| for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) { | |
| print!(f, cx, | |
| write("{}{}:", | |
| sep, | |
| tcx.hir.name(freevar.var_id())), | |
| print(upvar_ty))?; | |
| sep = ", "; | |
| } | |
| Ok(()) | |
| })? | |
| } else { | |
| // cross-crate closure types should only be | |
| // visible in trans bug reports, I imagine. | |
| write!(f, "@{:?}", did)?; | |
| let mut sep = " "; | |
| for (index, upvar_ty) in upvar_tys.enumerate() { | |
| print!(f, cx, | |
| write("{}{}:", sep, index), | |
| print(upvar_ty))?; | |
| sep = ", "; | |
| } | |
| } | |
| write!(f, "]") | |
| }), | |
| TyArray(ty, sz) => { | |
| print!(f, cx, write("["), print(ty), write("; "))?; | |
| match sz.val { | |
| ConstVal::Integral(ConstInt::Usize(sz)) => { | |
| write!(f, "{}", sz)?; | |
| } | |
| ConstVal::Unevaluated(_def_id, substs) => { | |
| write!(f, "<unevaluated{:?}>", &substs[..])?; | |
| } | |
| _ => { | |
| write!(f, "{:?}", sz)?; | |
| } | |
| } | |
| write!(f, "]") | |
| } | |
| TySlice(ty) => { | |
| print!(f, cx, write("["), print(ty), write("]")) | |
| } | |
| } | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::TyS<'tcx>, (self, f, cx) { | |
| display { | |
| self.sty.print(f, cx) | |
| } | |
| debug { | |
| self.sty.print_display(f, cx) | |
| } | |
| } | |
| } | |
| define_print! { | |
| () ty::ParamTy, (self, f, cx) { | |
| display { | |
| write!(f, "{}", self.name) | |
| } | |
| debug { | |
| write!(f, "{}/#{}", self.name, self.idx) | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx, T: Print + fmt::Debug, U: Print + fmt::Debug) ty::OutlivesPredicate<T, U>, | |
| (self, f, cx) { | |
| display { | |
| print!(f, cx, print(self.0), write(" : "), print(self.1)) | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::EquatePredicate<'tcx>, (self, f, cx) { | |
| display { | |
| print!(f, cx, print(self.0), write(" == "), print(self.1)) | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::SubtypePredicate<'tcx>, (self, f, cx) { | |
| display { | |
| print!(f, cx, print(self.a), write(" <: "), print(self.b)) | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::TraitPredicate<'tcx>, (self, f, cx) { | |
| debug { | |
| write!(f, "TraitPredicate({:?})", | |
| self.trait_ref) | |
| } | |
| display { | |
| print!(f, cx, print(self.trait_ref.self_ty()), write(": "), print(self.trait_ref)) | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::ProjectionPredicate<'tcx>, (self, f, cx) { | |
| debug { | |
| print!(f, cx, | |
| write("ProjectionPredicate("), | |
| print(self.projection_ty), | |
| write(", "), | |
| print(self.ty), | |
| write(")")) | |
| } | |
| display { | |
| print!(f, cx, print(self.projection_ty), write(" == "), print(self.ty)) | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::ProjectionTy<'tcx>, (self, f, cx) { | |
| display { | |
| // FIXME(tschottdorf): use something like | |
| // parameterized(f, self.substs, self.item_def_id, &[]) | |
| // (which currently ICEs). | |
| let (trait_ref, item_name) = ty::tls::with(|tcx| | |
| (self.trait_ref(tcx), tcx.associated_item(self.item_def_id).name) | |
| ); | |
| print!(f, cx, print_debug(trait_ref), write("::{}", item_name)) | |
| } | |
| } | |
| } | |
| define_print! { | |
| () ty::ClosureKind, (self, f, cx) { | |
| display { | |
| match *self { | |
| ty::ClosureKind::Fn => write!(f, "Fn"), | |
| ty::ClosureKind::FnMut => write!(f, "FnMut"), | |
| ty::ClosureKind::FnOnce => write!(f, "FnOnce"), | |
| } | |
| } | |
| } | |
| } | |
| define_print! { | |
| ('tcx) ty::Predicate<'tcx>, (self, f, cx) { | |
| display { | |
| match *self { | |
| ty::Predicate::Trait(ref data) => data.print(f, cx), | |
| ty::Predicate::Equate(ref predicate) => predicate.print(f, cx), | |
| ty::Predicate::Subtype(ref predicate) => predicate.print(f, cx), | |
| ty::Predicate::RegionOutlives(ref predicate) => predicate.print(f, cx), | |
| ty::Predicate::TypeOutlives(ref predicate) => predicate.print(f, cx), | |
| ty::Predicate::Projection(ref predicate) => predicate.print(f, cx), | |
| ty::Predicate::WellFormed(ty) => print!(f, cx, print(ty), write(" well-formed")), | |
| ty::Predicate::ObjectSafe(trait_def_id) => | |
| ty::tls::with(|tcx| { | |
| write!(f, "the trait `{}` is object-safe", tcx.item_path_str(trait_def_id)) | |
| }), | |
| ty::Predicate::ClosureKind(closure_def_id, _closure_substs, kind) => | |
| ty::tls::with(|tcx| { | |
| write!(f, "the closure `{}` implements the trait `{}`", | |
| tcx.item_path_str(closure_def_id), kind) | |
| }), | |
| ty::Predicate::ConstEvaluatable(def_id, substs) => { | |
| write!(f, "the constant `")?; | |
| cx.parameterized(f, substs, def_id, &[])?; | |
| write!(f, "` can be evaluated") | |
| } | |
| } | |
| } | |
| debug { | |
| match *self { | |
| ty::Predicate::Trait(ref a) => a.print(f, cx), | |
| ty::Predicate::Equate(ref pair) => pair.print(f, cx), | |
| ty::Predicate::Subtype(ref pair) => pair.print(f, cx), | |
| ty::Predicate::RegionOutlives(ref pair) => pair.print(f, cx), | |
| ty::Predicate::TypeOutlives(ref pair) => pair.print(f, cx), | |
| ty::Predicate::Projection(ref pair) => pair.print(f, cx), | |
| ty::Predicate::WellFormed(ty) => ty.print(f, cx), | |
| ty::Predicate::ObjectSafe(trait_def_id) => { | |
| write!(f, "ObjectSafe({:?})", trait_def_id) | |
| } | |
| ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { | |
| write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind) | |
| } | |
| ty::Predicate::ConstEvaluatable(def_id, substs) => { | |
| write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) | |
| } | |
| } | |
| } | |
| } | |
| } |