]> git.lizzy.rs Git - rust.git/commitdiff
rustc: support overriding region printing in ty::print::Printer.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Mon, 14 Jan 2019 15:55:57 +0000 (17:55 +0200)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Fri, 15 Mar 2019 11:25:10 +0000 (13:25 +0200)
src/librustc/infer/error_reporting/mod.rs
src/librustc/ty/print.rs
src/librustc/util/ppaux.rs
src/librustc_codegen_utils/symbol_names.rs
src/librustdoc/clean/mod.rs

index 974b9c59ea42cb8f7f481f460fc4538994ce0549..768839bf60fdcaca1fe47bcb17cea2ebece963b7 100644 (file)
@@ -457,6 +457,14 @@ impl Printer for AbsolutePathPrinter {
             type Error = NonTrivialPath;
 
             type Path = Vec<String>;
+            type Region = !;
+
+            fn print_region(
+                self: PrintCx<'_, '_, '_, Self>,
+                _region: ty::Region<'_>,
+            ) -> Result<Self::Region, Self::Error> {
+                Err(NonTrivialPath)
+            }
 
             fn path_crate(
                 self: PrintCx<'_, '_, '_, Self>,
index 4e1fdf657bd5f25dcd6e69eba3f17b6606126b4a..cf47840b022ee02aae6a4624dd01608b45584305 100644 (file)
@@ -1,6 +1,7 @@
 use crate::hir::def::Namespace;
 use crate::hir::map::DefPathData;
 use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use crate::middle::region;
 use crate::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
 use crate::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind};
 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
@@ -67,7 +68,7 @@ pub struct RegionHighlightMode {
     /// This is used when you have a signature like `fn foo(x: &u32,
     /// y: &'a u32)` and we want to give a name to the region of the
     /// reference `x`.
-    pub(crate) highlight_bound_region: Option<(ty::BoundRegion, usize)>,
+    highlight_bound_region: Option<(ty::BoundRegion, usize)>,
 }
 
 impl RegionHighlightMode {
@@ -114,7 +115,7 @@ pub fn highlighting_region_vid(
     }
 
     /// Returns `Some(n)` with the number to use for the given region, if any.
-    pub(crate) fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> {
+    fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> {
         self
             .highlight_regions
             .iter()
@@ -250,6 +251,7 @@ pub trait Printer: Sized {
     type Error;
 
     type Path;
+    type Region;
 
     fn print_def_path(
         self: PrintCx<'_, '_, 'tcx, Self>,
@@ -271,6 +273,11 @@ fn print_impl_path(
         self.default_print_impl_path(impl_def_id, substs, ns, self_ty, trait_ref)
     }
 
+    fn print_region(
+        self: PrintCx<'_, '_, '_, Self>,
+        region: ty::Region<'_>,
+    ) -> Result<Self::Region, Self::Error>;
+
     fn path_crate(
         self: PrintCx<'_, '_, '_, Self>,
         cnum: CrateNum,
@@ -310,7 +317,7 @@ fn path_generic_args<'gcx, 'tcx>(
 }
 
 /// Trait for printers that pretty-print using `fmt::Write` to the printer.
-pub trait PrettyPrinter: Printer<Error = fmt::Error, Path = Self> + fmt::Write {
+pub trait PrettyPrinter: Printer<Error = fmt::Error, Path = Self, Region = Self> + fmt::Write {
     /// Enter a nested print context, for pretty-printing
     /// nested components in some larger context.
     fn nest<'a, 'gcx, 'tcx, E>(
@@ -329,9 +336,26 @@ fn nest<'a, 'gcx, 'tcx, E>(
         })
     }
 
-    fn region_highlight_mode(&self) -> RegionHighlightMode {
-        RegionHighlightMode::default()
+    /// Return `true` if the region should be printed in path generic args
+    /// even when it's `'_`, such as in e.g. `Foo<'_, '_, '_>`.
+    fn always_print_region_in_paths(
+        self: &PrintCx<'_, '_, '_, Self>,
+        _region: ty::Region<'_>,
+    ) -> bool {
+        false
     }
+
+    // HACK(eddyb) Trying to print a lifetime might not print anything, which
+    // may need special handling in the caller (of `ty::RegionKind::print`).
+    // To avoid printing to a temporary string (which isn't even supported),
+    // the `print_region_outputs_anything` method can instead be used to
+    // determine this, ahead of time.
+    //
+    // NB: this must be kept in sync with the implementation of `print_region`.
+    fn print_region_outputs_anything(
+        self: &PrintCx<'_, '_, '_, Self>,
+        region: ty::Region<'_>,
+    ) -> bool;
 }
 
 macro_rules! nest {
@@ -795,10 +819,13 @@ pub fn pretty_path_generic_args(
 
         let start = if ns == Namespace::ValueNS { "::<" } else { "<" };
 
-        // Don't print any regions if they're all erased.
+        // Don't print `'_` if there's no printed region.
         let print_regions = params.iter().any(|param| {
             match substs[param.index as usize].unpack() {
-                UnpackedKind::Lifetime(r) => *r != ty::ReErased,
+                UnpackedKind::Lifetime(r) => {
+                    self.always_print_region_in_paths(r) ||
+                    self.print_region_outputs_anything(r)
+                }
                 _ => false,
             }
         });
@@ -827,7 +854,7 @@ pub fn pretty_path_generic_args(
                         continue;
                     }
                     start_or_continue(&mut self, start, ", ")?;
-                    if !region.display_outputs_anything(&self) {
+                    if !self.print_region_outputs_anything(region) {
                         // 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,
@@ -873,6 +900,7 @@ impl<F: fmt::Write> Printer for FmtPrinter<F> {
     type Error = fmt::Error;
 
     type Path = Self;
+    type Region = Self;
 
     fn print_def_path(
         mut self: PrintCx<'_, '_, 'tcx, Self>,
@@ -929,6 +957,80 @@ fn print_def_path(
         self.default_print_def_path(def_id, substs, ns, projections)
     }
 
+    fn print_region(
+        mut self: PrintCx<'_, '_, '_, Self>,
+        region: ty::Region<'_>,
+    ) -> Result<Self::Region, Self::Error> {
+        // Watch out for region highlights.
+        let highlight = self.printer.region_highlight_mode;
+        if let Some(n) = highlight.region_highlighted(region) {
+            write!(self.printer, "'{}", n)?;
+            return Ok(self.printer);
+        }
+
+        if self.config.is_verbose {
+            return region.print_debug(self);
+        }
+
+        // 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 *region {
+            ty::ReEarlyBound(ref data) => {
+                if data.name != "'_" {
+                    write!(self.printer, "{}", data.name)?;
+                }
+            }
+            ty::ReLateBound(_, br) |
+            ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
+            ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
+                if let ty::BrNamed(_, name) = br {
+                    if name != "" && name != "'_" {
+                        write!(self.printer, "{}", name)?;
+                        return Ok(self.printer);
+                    }
+                }
+
+                if let Some((region, counter)) = highlight.highlight_bound_region {
+                    if br == region {
+                        write!(self.printer, "'{}", counter)?;
+                    }
+                }
+            }
+            ty::ReScope(scope) if self.config.identify_regions => {
+                match scope.data {
+                    region::ScopeData::Node =>
+                        write!(self.printer, "'{}s", scope.item_local_id().as_usize())?,
+                    region::ScopeData::CallSite =>
+                        write!(self.printer, "'{}cs", scope.item_local_id().as_usize())?,
+                    region::ScopeData::Arguments =>
+                        write!(self.printer, "'{}as", scope.item_local_id().as_usize())?,
+                    region::ScopeData::Destruction =>
+                        write!(self.printer, "'{}ds", scope.item_local_id().as_usize())?,
+                    region::ScopeData::Remainder(first_statement_index) => write!(self.printer,
+                        "'{}_{}rs",
+                        scope.item_local_id().as_usize(),
+                        first_statement_index.index()
+                    )?,
+                }
+            }
+            ty::ReVar(region_vid) if self.config.identify_regions => {
+                write!(self.printer, "{:?}", region_vid)?;
+            }
+            ty::ReVar(_) => {}
+            ty::ReScope(_) |
+            ty::ReErased => {}
+            ty::ReStatic => write!(self.printer, "'static")?,
+            ty::ReEmpty => write!(self.printer, "'<empty>")?,
+
+            // The user should never encounter these in unsubstituted form.
+            ty::ReClosureBound(vid) => write!(self.printer, "{:?}", vid)?,
+        }
+
+        Ok(self.printer)
+    }
+
     fn path_crate(
         mut self: PrintCx<'_, '_, '_, Self>,
         cnum: CrateNum,
@@ -1018,7 +1120,59 @@ fn nest<'a, 'gcx, 'tcx, E>(
         })
     }
 
-    fn region_highlight_mode(&self) -> RegionHighlightMode {
-        self.region_highlight_mode
+    fn always_print_region_in_paths(
+        self: &PrintCx<'_, '_, '_, Self>,
+        region: ty::Region<'_>,
+    ) -> bool {
+        *region != ty::ReErased
+    }
+
+    fn print_region_outputs_anything(
+        self: &PrintCx<'_, '_, '_, Self>,
+        region: ty::Region<'_>,
+    ) -> bool {
+        let highlight = self.printer.region_highlight_mode;
+        if highlight.region_highlighted(region).is_some() {
+            return true;
+        }
+
+        if self.config.is_verbose {
+            return true;
+        }
+
+        match *region {
+            ty::ReEarlyBound(ref data) => {
+                data.name != "" && data.name != "'_"
+            }
+
+            ty::ReLateBound(_, br) |
+            ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
+            ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
+                if let ty::BrNamed(_, name) = br {
+                    if name != "" && name != "'_" {
+                        return true;
+                    }
+                }
+
+                if let Some((region, _)) = highlight.highlight_bound_region {
+                    if br == region {
+                        return true;
+                    }
+                }
+
+                false
+            }
+
+            ty::ReScope(_) |
+            ty::ReVar(_) if self.config.identify_regions => true,
+
+            ty::ReVar(_) |
+            ty::ReScope(_) |
+            ty::ReErased => false,
+
+            ty::ReStatic |
+            ty::ReEmpty |
+            ty::ReClosureBound(_) => true,
+        }
     }
 }
index 1ac6f3fea4c5a46044cbb6ff54e5c7d21cd250ad..e14741f55ef194a32213e1bbb5400343be3b1290 100644 (file)
@@ -1,6 +1,5 @@
 use crate::hir::def::Namespace;
 use crate::hir::def_id::DefId;
-use crate::middle::region;
 use crate::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind};
 use crate::ty::{Bool, Char, Adt};
 use crate::ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr};
@@ -487,72 +486,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 define_print! {
     () ty::RegionKind, (self, cx) {
         display {
-            // Watch out for region highlights.
-            let highlight = cx.printer.region_highlight_mode();
-            if let Some(n) = highlight.region_highlighted(self) {
-                p!(write("'{}", n));
-                return Ok(cx.printer);
-            }
-
-            if cx.config.is_verbose {
-                return self.print_debug(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) => {
-                    if data.name != "'_" {
-                        p!(write("{}", data.name))
-                    }
-                }
-                ty::ReLateBound(_, br) |
-                ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
-                ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
-                    if let ty::BrNamed(_, name) = br {
-                        if name != "" && name != "'_" {
-                            p!(write("{}", name));
-                            return Ok(cx.printer);
-                        }
-                    }
-
-                    if let Some((region, counter)) = highlight.highlight_bound_region {
-                        if br == region {
-                            p!(write("'{}", counter));
-                        }
-                    }
-                }
-                ty::ReScope(scope) if cx.config.identify_regions => {
-                    match scope.data {
-                        region::ScopeData::Node =>
-                            p!(write("'{}s", scope.item_local_id().as_usize())),
-                        region::ScopeData::CallSite =>
-                            p!(write("'{}cs", scope.item_local_id().as_usize())),
-                        region::ScopeData::Arguments =>
-                            p!(write("'{}as", scope.item_local_id().as_usize())),
-                        region::ScopeData::Destruction =>
-                            p!(write("'{}ds", scope.item_local_id().as_usize())),
-                        region::ScopeData::Remainder(first_statement_index) => p!(write(
-                            "'{}_{}rs",
-                            scope.item_local_id().as_usize(),
-                            first_statement_index.index()
-                        )),
-                    }
-                }
-                ty::ReVar(region_vid) if cx.config.identify_regions => {
-                    p!(write("{:?}", region_vid));
-                }
-                ty::ReVar(_) => {}
-                ty::ReScope(_) |
-                ty::ReErased => {}
-                ty::ReStatic => p!(write("'static")),
-                ty::ReEmpty => p!(write("'<empty>")),
-
-                // The user should never encounter these in unsubstituted form.
-                ty::ReClosureBound(vid) => p!(write("{:?}", vid)),
-            }
+            return cx.print_region(self);
         }
         debug {
             match *self {
@@ -594,63 +528,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-// HACK(eddyb) Trying to print a lifetime might not print anything, which
-// may need special handling in the caller (of `ty::RegionKind::print`).
-// To avoid printing to a temporary string, the `display_outputs_anything`
-// method can instead be used to determine this, ahead of time.
-//
-// NB: this must be kept in sync with the printing logic above.
-impl ty::RegionKind {
-    // HACK(eddyb) `pub(crate)` only for `ty::print`.
-    pub(crate) fn display_outputs_anything<P>(&self, cx: &PrintCx<'_, '_, '_, P>) -> bool
-        where P: PrettyPrinter
-    {
-        let highlight = cx.printer.region_highlight_mode();
-        if highlight.region_highlighted(self).is_some() {
-            return true;
-        }
-
-        if cx.config.is_verbose {
-            return true;
-        }
-
-        match *self {
-            ty::ReEarlyBound(ref data) => {
-                data.name != "" && data.name != "'_"
-            }
-
-            ty::ReLateBound(_, br) |
-            ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
-            ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
-                if let ty::BrNamed(_, name) = br {
-                    if name != "" && name != "'_" {
-                        return true;
-                    }
-                }
-
-                if let Some((region, _)) = highlight.highlight_bound_region {
-                    if br == region {
-                        return true;
-                    }
-                }
-
-                false
-            }
-
-            ty::ReScope(_) |
-            ty::ReVar(_) if cx.config.identify_regions => true,
-
-            ty::ReVar(_) |
-            ty::ReScope(_) |
-            ty::ReErased => false,
-
-            ty::ReStatic |
-            ty::ReEmpty |
-            ty::ReClosureBound(_) => true,
-        }
-    }
-}
-
 define_print! {
     () ty::FreeRegion, (self, cx) {
         debug {
@@ -830,7 +707,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 }
                 Ref(r, ty, mutbl) => {
                     p!(write("&"));
-                    if r.display_outputs_anything(&cx) {
+                    if cx.print_region_outputs_anything(r) {
                         p!(print_display(r), write(" "));
                     }
                     p!(print(ty::TypeAndMut { ty, mutbl }))
@@ -889,7 +766,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                     ));
                 }
                 Dynamic(data, r) => {
-                    let print_r = r.display_outputs_anything(&cx);
+                    let print_r = cx.print_region_outputs_anything(r);
                     if print_r {
                         p!(write("("));
                     }
index 2f9627331189f7e3faec2f4bb11644ec4a300005..912f8149513c620b1fe747905249243aec6e2d7a 100644 (file)
@@ -409,6 +409,14 @@ impl Printer for SymbolPath {
     type Error = fmt::Error;
 
     type Path = Self;
+    type Region = Self;
+
+    fn print_region(
+        self: PrintCx<'_, '_, '_, Self>,
+        _region: ty::Region<'_>,
+    ) -> Result<Self::Region, Self::Error> {
+        Ok(self.printer)
+    }
 
     fn path_crate(
         mut self: PrintCx<'_, '_, '_, Self>,
@@ -511,7 +519,14 @@ fn path_generic_args<'gcx, 'tcx>(
     }
 }
 
-impl PrettyPrinter for SymbolPath {}
+impl PrettyPrinter for SymbolPath {
+    fn print_region_outputs_anything(
+        self: &PrintCx<'_, '_, '_, Self>,
+        _region: ty::Region<'_>,
+    ) -> bool {
+        false
+    }
+}
 
 impl fmt::Write for SymbolPath {
     fn write_str(&mut self, s: &str) -> fmt::Result {
index 536ee3d58d65ff1b1f444d2402af32f85dd24a13..bceae24b1b44fc184eddd5b424763ca99fea0112 100644 (file)
@@ -4233,6 +4233,14 @@ impl Printer for AbsolutePathPrinter {
         type Error = !;
 
         type Path = Vec<String>;
+        type Region = ();
+
+        fn print_region(
+            self: PrintCx<'_, '_, '_, Self>,
+            _region: ty::Region<'_>,
+        ) -> Result<Self::Region, Self::Error> {
+            Ok(())
+        }
 
         fn path_crate(
             self: PrintCx<'_, '_, '_, Self>,