]> git.lizzy.rs Git - rust.git/commitdiff
rustc: rewrite ty::item_path to be more functional than mutation-oriented.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Sun, 9 Dec 2018 19:05:22 +0000 (21:05 +0200)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Fri, 15 Mar 2019 07:26:13 +0000 (09:26 +0200)
src/librustc/ty/item_path.rs
src/librustc_codegen_utils/symbol_names.rs

index 6734e264305a74bd81fa034d686bd45072e122b7..1eb3952032a6de4044f08fc3a3210ed664d0e614 100644 (file)
@@ -65,10 +65,9 @@ pub fn item_path_str(self, def_id: DefId) -> String {
                 RootMode::Local
             }
         });
-        let mut buffer = LocalPathBuffer::new(mode);
-        debug!("item_path_str: buffer={:?} def_id={:?}", buffer, def_id);
-        self.push_item_path(&mut buffer, def_id);
-        buffer.into_string()
+        let mut printer = LocalPathPrinter::new(mode);
+        debug!("item_path_str: printer={:?} def_id={:?}", printer, def_id);
+        self.print_item_path(&mut printer, def_id)
     }
 
     /// Returns a string identifying this local node-id.
@@ -79,23 +78,26 @@ pub fn node_path_str(self, id: ast::NodeId) -> String {
     /// Returns a string identifying this def-id. This string is
     /// suitable for user output. It always begins with a crate identifier.
     pub fn absolute_item_path_str(self, def_id: DefId) -> String {
-        let mut buffer = LocalPathBuffer::new(RootMode::Absolute);
-        debug!("absolute_item_path_str: buffer={:?} def_id={:?}", buffer, def_id);
-        self.push_item_path(&mut buffer, def_id);
-        buffer.into_string()
+        let mut printer = LocalPathPrinter::new(RootMode::Absolute);
+        debug!("absolute_item_path_str: printer={:?} def_id={:?}", printer, def_id);
+        self.print_item_path(&mut printer, def_id)
     }
 
     /// Returns the "path" to a particular crate. This can proceed in
-    /// various ways, depending on the `root_mode` of the `buffer`.
+    /// various ways, depending on the `root_mode` of the `printer`.
     /// (See `RootMode` enum for more details.)
-    pub fn push_krate_path<T>(self, buffer: &mut T, cnum: CrateNum)
-        where T: ItemPathBuffer + Debug
+    fn print_krate_path<P>(
+        self,
+        printer: &mut P,
+        cnum: CrateNum,
+    ) -> P::Path
+        where P: ItemPathPrinter + Debug
     {
         debug!(
-            "push_krate_path: buffer={:?} cnum={:?} LOCAL_CRATE={:?}",
-            buffer, cnum, LOCAL_CRATE
+            "print_krate_path: printer={:?} cnum={:?} LOCAL_CRATE={:?}",
+            printer, cnum, LOCAL_CRATE
         );
-        match *buffer.root_mode() {
+        match printer.root_mode() {
             RootMode::Local => {
                 // In local mode, when we encounter a crate other than
                 // LOCAL_CRATE, execution proceeds in one of two ways:
@@ -117,56 +119,60 @@ pub fn push_krate_path<T>(self, buffer: &mut T, cnum: CrateNum)
                             span,
                             ..
                         }) if !span.is_dummy() => {
-                            debug!("push_krate_path: def_id={:?}", def_id);
-                            self.push_item_path(buffer, def_id);
+                            debug!("print_krate_path: def_id={:?}", def_id);
+                            self.print_item_path(printer, def_id)
                         }
                         _ => {
                             let name = self.crate_name(cnum).as_str();
-                            debug!("push_krate_path: name={:?}", name);
-                            buffer.push(&name);
+                            debug!("print_krate_path: name={:?}", name);
+                            printer.path_crate(Some(&name))
                         }
                     }
                 } else if self.sess.rust_2018() {
                     // We add the `crate::` keyword on Rust 2018, only when desired.
                     if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
-                        buffer.push(&keywords::Crate.name().as_str())
+                        printer.path_crate(Some(&keywords::Crate.name().as_str()))
+                    } else {
+                        printer.path_crate(None)
                     }
+                } else {
+                    printer.path_crate(None)
                 }
             }
             RootMode::Absolute => {
                 // In absolute mode, just write the crate name
                 // unconditionally.
                 let name = self.original_crate_name(cnum).as_str();
-                debug!("push_krate_path: original_name={:?}", name);
-                buffer.push(&name);
+                debug!("print_krate_path: original_name={:?}", name);
+                printer.path_crate(Some(&name))
             }
         }
     }
 
-    /// If possible, this pushes a global path resolving to `external_def_id` that is visible
+    /// If possible, this returns a global path resolving to `external_def_id` that is visible
     /// from at least one local module and returns true. If the crate defining `external_def_id` is
     /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
-    pub fn try_push_visible_item_path<T>(
+    fn try_print_visible_item_path<P>(
         self,
-        buffer: &mut T,
+        printer: &mut P,
         external_def_id: DefId,
-    ) -> bool
-        where T: ItemPathBuffer + Debug
+    ) -> Option<P::Path>
+        where P: ItemPathPrinter + Debug
     {
         debug!(
-            "try_push_visible_item_path: buffer={:?} external_def_id={:?}",
-            buffer, external_def_id
+            "try_print_visible_item_path: printer={:?} external_def_id={:?}",
+            printer, external_def_id
         );
         let visible_parent_map = self.visible_parent_map(LOCAL_CRATE);
 
         let (mut cur_def, mut cur_path) = (external_def_id, Vec::<LocalInternedString>::new());
         loop {
             debug!(
-                "try_push_visible_item_path: cur_def={:?} cur_path={:?} CRATE_DEF_INDEX={:?}",
+                "try_print_visible_item_path: cur_def={:?} cur_path={:?} CRATE_DEF_INDEX={:?}",
                 cur_def, cur_path, CRATE_DEF_INDEX,
             );
-            // If `cur_def` is a direct or injected extern crate, push the path to the crate
-            // followed by the path to the item within the crate and return.
+            // If `cur_def` is a direct or injected extern crate, return the path to the crate
+            // followed by the path to the item within the crate.
             if cur_def.index == CRATE_DEF_INDEX {
                 match *self.extern_crate(cur_def) {
                     Some(ExternCrate {
@@ -175,26 +181,32 @@ pub fn try_push_visible_item_path<T>(
                         span,
                         ..
                     }) => {
-                        debug!("try_push_visible_item_path: def_id={:?}", def_id);
-                        if !span.is_dummy() {
-                            self.push_item_path(buffer, def_id);
+                        debug!("try_print_visible_item_path: def_id={:?}", def_id);
+                        let path = if !span.is_dummy() {
+                            self.print_item_path(printer, def_id)
                         } else {
-                            buffer.push(&self.crate_name(cur_def.krate).as_str());
-                        }
-                        cur_path.iter().rev().for_each(|segment| buffer.push(&segment));
-                        return true;
+                            printer.path_crate(Some(
+                                &self.crate_name(cur_def.krate).as_str(),
+                            ))
+                        };
+                        return Some(cur_path.iter().rev().fold(path, |path, segment| {
+                            printer.path_append(path, &segment)
+                        }));
                     }
                     None => {
-                        buffer.push(&self.crate_name(cur_def.krate).as_str());
-                        cur_path.iter().rev().for_each(|segment| buffer.push(&segment));
-                        return true;
+                        let path = printer.path_crate(Some(
+                            &self.crate_name(cur_def.krate).as_str(),
+                        ));
+                        return Some(cur_path.iter().rev().fold(path, |path, segment| {
+                            printer.path_append(path, &segment)
+                        }));
                     }
                     _ => {},
                 }
             }
 
             let mut cur_def_key = self.def_key(cur_def);
-            debug!("try_push_visible_item_path: cur_def_key={:?}", cur_def_key);
+            debug!("try_print_visible_item_path: cur_def_key={:?}", cur_def_key);
 
             // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
             if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
@@ -211,7 +223,7 @@ pub fn try_push_visible_item_path<T>(
 
             let data = cur_def_key.disambiguated_data.data;
             debug!(
-                "try_push_visible_item_path: data={:?} visible_parent={:?} actual_parent={:?}",
+                "try_print_visible_item_path: data={:?} visible_parent={:?} actual_parent={:?}",
                 data, visible_parent, actual_parent,
             );
             let symbol = match data {
@@ -268,39 +280,44 @@ pub fn try_push_visible_item_path<T>(
                     })
                 },
             };
-            debug!("try_push_visible_item_path: symbol={:?}", symbol);
+            debug!("try_print_visible_item_path: symbol={:?}", symbol);
             cur_path.push(symbol);
 
-            match visible_parent {
-                Some(def) => cur_def = def,
-                None => return false,
-            };
+            cur_def = visible_parent?;
         }
     }
 
-    pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId)
-        where T: ItemPathBuffer + Debug
+    pub fn print_item_path<P>(
+        self,
+        printer: &mut P,
+        def_id: DefId,
+    ) -> P::Path
+        where P: ItemPathPrinter + Debug
     {
         debug!(
-            "push_item_path: buffer={:?} def_id={:?}",
-            buffer, def_id
+            "print_item_path: printer={:?} def_id={:?}",
+            printer, def_id
         );
-        match *buffer.root_mode() {
-            RootMode::Local if !def_id.is_local() =>
-                if self.try_push_visible_item_path(buffer, def_id) { return },
+        match printer.root_mode() {
+            RootMode::Local if !def_id.is_local() => {
+                match self.try_print_visible_item_path(printer, def_id) {
+                    Some(path) => return path,
+                    None => {}
+                }
+            }
             _ => {}
         }
 
         let key = self.def_key(def_id);
-        debug!("push_item_path: key={:?}", key);
+        debug!("print_item_path: key={:?}", key);
         match key.disambiguated_data.data {
             DefPathData::CrateRoot => {
                 assert!(key.parent.is_none());
-                self.push_krate_path(buffer, def_id.krate);
+                self.print_krate_path(printer, def_id.krate)
             }
 
             DefPathData::Impl => {
-                self.push_impl_path(buffer, def_id);
+                self.print_impl_path(printer, def_id)
             }
 
             // Unclear if there is any value in distinguishing these.
@@ -325,26 +342,26 @@ pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId)
             data @ DefPathData::ClosureExpr |
             data @ DefPathData::ImplTrait |
             data @ DefPathData::GlobalMetaData(..) => {
-                let parent_def_id = self.parent_def_id(def_id).unwrap();
-                self.push_item_path(buffer, parent_def_id);
-                buffer.push(&data.as_interned_str().as_symbol().as_str());
+                let parent_did = self.parent_def_id(def_id).unwrap();
+                let path = self.print_item_path(printer, parent_did);
+                printer.path_append(path, &data.as_interned_str().as_symbol().as_str())
             },
 
             DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}`
                 let parent_def_id = self.parent_def_id(def_id).unwrap();
-                self.push_item_path(buffer, parent_def_id);
+                self.print_item_path(printer, parent_def_id)
             }
         }
     }
 
-    fn push_impl_path<T>(
+    fn print_impl_path<P>(
         self,
-        buffer: &mut T,
+        printer: &mut P,
         impl_def_id: DefId,
-    )
-        where T: ItemPathBuffer + Debug
+    ) -> P::Path
+        where P: ItemPathPrinter + Debug
     {
-        debug!("push_impl_path: buffer={:?} impl_def_id={:?}", buffer, impl_def_id);
+        debug!("print_impl_path: printer={:?} impl_def_id={:?}", printer, impl_def_id);
         let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
 
         // Always use types for non-local impls, where types are always
@@ -356,7 +373,7 @@ fn push_impl_path<T>(
         };
 
         if !use_types {
-            return self.push_impl_path_fallback(buffer, impl_def_id);
+            return self.print_impl_path_fallback(printer, impl_def_id);
         }
 
         // Decide whether to print the parent path for the impl.
@@ -380,13 +397,12 @@ fn push_impl_path<T>(
             // If the impl is not co-located with either self-type or
             // trait-type, then fallback to a format that identifies
             // the module more clearly.
-            self.push_item_path(buffer, parent_def_id);
+            let path = self.print_item_path(printer, parent_def_id);
             if let Some(trait_ref) = impl_trait_ref {
-                buffer.push(&format!("<impl {} for {}>", trait_ref, self_ty));
+                return printer.path_append(path, &format!("<impl {} for {}>", trait_ref, self_ty));
             } else {
-                buffer.push(&format!("<impl {}>", self_ty));
+                return printer.path_append(path, &format!("<impl {}>", self_ty));
             }
-            return;
         }
 
         // Otherwise, try to give a good form that would be valid language
@@ -394,8 +410,7 @@ fn push_impl_path<T>(
 
         if let Some(trait_ref) = impl_trait_ref {
             // Trait impls.
-            buffer.push(&format!("<{} as {}>", self_ty, trait_ref));
-            return;
+            return printer.path_impl(&format!("<{} as {}>", self_ty, trait_ref));
         }
 
         // Inherent impls. Try to print `Foo::bar` for an inherent
@@ -403,14 +418,15 @@ fn push_impl_path<T>(
         // anything other than a simple path.
         match self_ty.sty {
             ty::Adt(adt_def, substs) => {
+                // FIXME(eddyb) always print without <> here.
                 if substs.types().next().is_none() { // ignore regions
-                    self.push_item_path(buffer, adt_def.did);
+                    self.print_item_path(printer, adt_def.did)
                 } else {
-                    buffer.push(&format!("<{}>", self_ty));
+                    printer.path_impl(&format!("<{}>", self_ty))
                 }
             }
 
-            ty::Foreign(did) => self.push_item_path(buffer, did),
+            ty::Foreign(did) => self.print_item_path(printer, did),
 
             ty::Bool |
             ty::Char |
@@ -418,31 +434,31 @@ fn push_impl_path<T>(
             ty::Uint(_) |
             ty::Float(_) |
             ty::Str => {
-                buffer.push(&self_ty.to_string());
+                printer.path_impl(&self_ty.to_string())
             }
 
             _ => {
-                buffer.push(&format!("<{}>", self_ty));
+                printer.path_impl(&format!("<{}>", self_ty))
             }
         }
     }
 
-    fn push_impl_path_fallback<T>(
+    fn print_impl_path_fallback<P>(
         self,
-        buffer: &mut T,
+        printer: &mut P,
         impl_def_id: DefId,
-    )
-        where T: ItemPathBuffer + Debug
+    ) -> P::Path
+        where P: ItemPathPrinter + Debug
     {
         // If no type info is available, fall back to
         // pretty printing some span information. This should
         // only occur very early in the compiler pipeline.
         let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
-        self.push_item_path(buffer, parent_def_id);
+        let path = self.print_item_path(printer, parent_def_id);
         let hir_id = self.hir().as_local_hir_id(impl_def_id).unwrap();
         let item = self.hir().expect_item_by_hir_id(hir_id);
         let span_str = self.sess.source_map().span_to_string(item.span);
-        buffer.push(&format!("<impl at {}>", span_str));
+        printer.path_append(path, &format!("<impl at {}>", span_str))
     }
 
     /// Returns the `DefId` of `def_id`'s parent in the def tree. If
@@ -505,12 +521,17 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
 /// Unifying Trait for different kinds of item paths we might
 /// construct. The basic interface is that components get pushed: the
 /// instance can also customize how we handle the root of a crate.
-pub trait ItemPathBuffer {
-    fn root_mode(&self) -> &RootMode;
-    fn push(&mut self, text: &str);
+pub trait ItemPathPrinter {
+    type Path;
+
+    fn root_mode(&self) -> RootMode;
+
+    fn path_crate(&self, name: Option<&str>) -> Self::Path;
+    fn path_impl(&self, text: &str) -> Self::Path;
+    fn path_append(&self, path: Self::Path, text: &str) -> Self::Path;
 }
 
-#[derive(Debug)]
+#[derive(Copy, Clone, Debug)]
 pub enum RootMode {
     /// Try to make a path relative to the local crate. In
     /// particular, local paths have no prefix, and if the path comes
@@ -524,33 +545,36 @@ pub enum RootMode {
 }
 
 #[derive(Debug)]
-struct LocalPathBuffer {
+struct LocalPathPrinter {
     root_mode: RootMode,
-    str: String,
 }
 
-impl LocalPathBuffer {
-    fn new(root_mode: RootMode) -> LocalPathBuffer {
-        LocalPathBuffer {
+impl LocalPathPrinter {
+    fn new(root_mode: RootMode) -> LocalPathPrinter {
+        LocalPathPrinter {
             root_mode,
-            str: String::new(),
         }
     }
-
-    fn into_string(self) -> String {
-        self.str
-    }
 }
 
-impl ItemPathBuffer for LocalPathBuffer {
-    fn root_mode(&self) -> &RootMode {
-        &self.root_mode
+impl ItemPathPrinter for LocalPathPrinter {
+    type Path = String;
+
+    fn root_mode(&self) -> RootMode {
+        self.root_mode
     }
 
-    fn push(&mut self, text: &str) {
-        if !self.str.is_empty() {
-            self.str.push_str("::");
+    fn path_crate(&self, name: Option<&str>) -> Self::Path {
+        name.unwrap_or("").to_string()
+    }
+    fn path_impl(&self, text: &str) -> Self::Path {
+        text.to_string()
+    }
+    fn path_append(&self, mut path: Self::Path, text: &str) -> Self::Path {
+        if !path.is_empty() {
+            path.push_str("::");
         }
-        self.str.push_str(text);
+        path.push_str(text);
+        path
     }
 }
index 70ab185660c4c533ba66d440870e59f9639c2b1d..13f8e13c3288d163a1d6a605cf53ef69da0c57be 100644 (file)
@@ -92,7 +92,7 @@
 use rustc::hir::CodegenFnAttrFlags;
 use rustc::hir::map::definitions::DefPathData;
 use rustc::ich::NodeIdHashingMode;
-use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
+use rustc::ty::item_path::{self, ItemPathPrinter, RootMode};
 use rustc::ty::query::Providers;
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
@@ -223,11 +223,9 @@ fn get_symbol_hash<'a, 'tcx>(
 }
 
 fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::SymbolName {
-    let mut buffer = SymbolPathBuffer::new(tcx);
     item_path::with_forced_absolute_paths(|| {
-        tcx.push_item_path(&mut buffer, def_id);
-    });
-    buffer.into_interned()
+        tcx.push_item_path(&mut SymbolPath::new(tcx), def_id).into_interned()
+    })
 }
 
 fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) -> ty::SymbolName {
@@ -319,7 +317,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
 
     let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs);
 
-    let mut buf = SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id), tcx);
+    let mut buf = SymbolPath::from_interned(tcx.def_symbol_name(def_id), tcx);
 
     if instance.is_vtable_shim() {
         buf.push("{{vtable-shim}}");
@@ -342,15 +340,15 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
 // To be able to work on all platforms and get *some* reasonable output, we
 // use C++ name-mangling.
 #[derive(Debug)]
-struct SymbolPathBuffer {
+struct SymbolPath {
     result: String,
     temp_buf: String,
     strict_naming: bool,
 }
 
-impl SymbolPathBuffer {
+impl SymbolPath {
     fn new(tcx: TyCtxt<'_, '_, '_>) -> Self {
-        let mut result = SymbolPathBuffer {
+        let mut result = SymbolPath {
             result: String::with_capacity(64),
             temp_buf: String::with_capacity(16),
             strict_naming: tcx.has_strict_asm_symbol_naming(),
@@ -360,7 +358,7 @@ fn new(tcx: TyCtxt<'_, '_, '_>) -> Self {
     }
 
     fn from_interned(symbol: ty::SymbolName, tcx: TyCtxt<'_, '_, '_>) -> Self {
-        let mut result = SymbolPathBuffer {
+        let mut result = SymbolPath {
             result: String::with_capacity(64),
             temp_buf: String::with_capacity(16),
             strict_naming: tcx.has_strict_asm_symbol_naming(),
@@ -375,19 +373,6 @@ fn into_interned(self) -> ty::SymbolName {
         }
     }
 
-    fn finish(mut self, hash: u64) -> String {
-        // E = end name-sequence
-        let _ = write!(self.result, "17h{:016x}E", hash);
-        self.result
-    }
-}
-
-impl ItemPathBuffer for SymbolPathBuffer {
-    fn root_mode(&self) -> &RootMode {
-        const ABSOLUTE: &RootMode = &RootMode::Absolute;
-        ABSOLUTE
-    }
-
     fn push(&mut self, text: &str) {
         self.temp_buf.clear();
         let need_underscore = sanitize(&mut self.temp_buf, text, self.strict_naming);
@@ -401,6 +386,40 @@ fn push(&mut self, text: &str) {
         }
         self.result.push_str(&self.temp_buf);
     }
+
+    fn finish(mut self, hash: u64) -> String {
+        // E = end name-sequence
+        let _ = write!(self.result, "17h{:016x}E", hash);
+        self.result
+    }
+}
+
+#[derive(Debug)]
+struct SymbolPathPrinter;
+
+impl ItemPathPrinter for SymbolPathPrinter {
+    type Path = SymbolPath;
+
+    fn root_mode(&self) ->RootMode {
+        RootMode::Absolute
+    }
+
+    fn path_crate(&self, name: Option<&str>) -> Self::Path {
+        let mut path = SymbolPath::new();
+        if let Some(name) = name {
+            path.push(name);
+        }
+        path
+    }
+    fn path_impl(&self, text: &str) -> Self::Path {
+        let mut path = SymbolPath::new();
+        path.push(text);
+        path
+    }
+    fn path_append(&self, mut path: Self::Path, text: &str) -> Self::Path {
+        path.push(text);
+        path
+    }
 }
 
 // Name sanitation. LLVM will happily accept identifiers with weird names, but