From c5ee60e05b1fafe20f56b21cfab30e7b80cb9d42 Mon Sep 17 00:00:00 2001
From: Florian Diebold <florian.diebold@freiheit.com>
Date: Thu, 14 Mar 2019 22:03:39 +0100
Subject: Replace Display by a pretty printing trait for Ty

This allows removing the names from Adt and FnDef (and more later), as a first
step towards aligning more with chalk's Ty :)
---
 crates/ra_hir/src/lib.rs                         |  2 +-
 crates/ra_hir/src/ty.rs                          | 94 +++++++++++++++---------
 crates/ra_hir/src/ty/display.rs                  | 56 ++++++++++++++
 crates/ra_hir/src/ty/lower.rs                    | 23 ++----
 crates/ra_hir/src/ty/tests.rs                    |  5 +-
 crates/ra_ide_api/src/completion/presentation.rs | 11 ++-
 crates/ra_ide_api/src/hover.rs                   |  5 +-
 7 files changed, 136 insertions(+), 60 deletions(-)
 create mode 100644 crates/ra_hir/src/ty/display.rs

(limited to 'crates')

diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index ac5f33079..4508a873e 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -56,7 +56,7 @@ pub use self::{
     ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner},
     macros::{MacroDef, MacroInput, MacroExpansion},
     nameres::{ItemMap, PerNs, Namespace},
-    ty::{Ty, Substs},
+    ty::{Ty, Substs, display::HirDisplay},
     impl_block::{ImplBlock, ImplItem},
     docs::{Docs, Documentation},
     adt::AdtDef,
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index bad811a56..f64877f3b 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -9,16 +9,16 @@ pub(crate) mod method_resolution;
 mod op;
 mod lower;
 mod infer;
+pub(crate) mod display;
 
 use std::sync::Arc;
 use std::{fmt, mem};
 
-use join_to_string::join;
-
-use crate::{Name, AdtDef, type_ref::Mutability};
+use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase};
 
 pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field};
 pub(crate) use infer::{infer, InferenceResult, InferTy};
+use display::{HirDisplay, HirFormatter};
 
 /// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs).
 ///
@@ -42,8 +42,6 @@ pub enum Ty {
     Adt {
         /// The definition of the struct/enum.
         def_id: AdtDef,
-        /// The name, for displaying.
-        name: Name,
         /// Substitutions for the generic parameters of the type.
         substs: Substs,
     },
@@ -79,8 +77,6 @@ pub enum Ty {
     FnDef {
         /// The definition of the function / constructor.
         def: CallableDef,
-        /// For display
-        name: Name,
         /// Parameters and return type
         sig: Arc<FnSig>,
         /// Substitutions for the generic parameters of the type
@@ -265,8 +261,8 @@ impl Ty {
     /// `Option<u32>` afterwards.)
     pub fn apply_substs(self, substs: Substs) -> Ty {
         match self {
-            Ty::Adt { def_id, name, .. } => Ty::Adt { def_id, name, substs },
-            Ty::FnDef { def, name, sig, .. } => Ty::FnDef { def, name, sig, substs },
+            Ty::Adt { def_id, .. } => Ty::Adt { def_id, substs },
+            Ty::FnDef { def, sig, .. } => Ty::FnDef { def, sig, substs },
             _ => self,
         }
     }
@@ -297,50 +293,80 @@ impl Ty {
     }
 }
 
-impl fmt::Display for Ty {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+impl HirDisplay for &Ty {
+    fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
+        HirDisplay::hir_fmt(*self, f)
+    }
+}
+
+impl HirDisplay for Ty {
+    fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
         match self {
-            Ty::Bool => write!(f, "bool"),
-            Ty::Char => write!(f, "char"),
-            Ty::Int(t) => write!(f, "{}", t.ty_to_string()),
-            Ty::Float(t) => write!(f, "{}", t.ty_to_string()),
-            Ty::Str => write!(f, "str"),
-            Ty::Slice(t) | Ty::Array(t) => write!(f, "[{}]", t),
-            Ty::RawPtr(t, m) => write!(f, "*{}{}", m.as_keyword_for_ptr(), t),
-            Ty::Ref(t, m) => write!(f, "&{}{}", m.as_keyword_for_ref(), t),
-            Ty::Never => write!(f, "!"),
+            Ty::Bool => write!(f, "bool")?,
+            Ty::Char => write!(f, "char")?,
+            Ty::Int(t) => write!(f, "{}", t.ty_to_string())?,
+            Ty::Float(t) => write!(f, "{}", t.ty_to_string())?,
+            Ty::Str => write!(f, "str")?,
+            Ty::Slice(t) | Ty::Array(t) => {
+                write!(f, "[{}]", t.display(f.db))?;
+            }
+            Ty::RawPtr(t, m) => {
+                write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?;
+            }
+            Ty::Ref(t, m) => {
+                write!(f, "&{}{}", m.as_keyword_for_ref(), t.display(f.db))?;
+            }
+            Ty::Never => write!(f, "!")?,
             Ty::Tuple(ts) => {
                 if ts.len() == 1 {
-                    write!(f, "({},)", ts[0])
+                    write!(f, "({},)", ts[0].display(f.db))?;
                 } else {
-                    join(ts.iter()).surround_with("(", ")").separator(", ").to_fmt(f)
+                    write!(f, "(")?;
+                    f.write_joined(&**ts, ", ")?;
+                    write!(f, ")")?;
                 }
             }
             Ty::FnPtr(sig) => {
-                join(sig.input.iter()).surround_with("fn(", ")").separator(", ").to_fmt(f)?;
-                write!(f, " -> {}", sig.output)
+                write!(f, "fn(")?;
+                f.write_joined(&sig.input, ", ")?;
+                write!(f, ") -> {}", sig.output.display(f.db))?;
             }
-            Ty::FnDef { def, name, substs, sig, .. } => {
+            Ty::FnDef { def, substs, sig, .. } => {
+                let name = match def {
+                    CallableDef::Function(ff) => ff.name(f.db),
+                    CallableDef::Struct(s) => s.name(f.db).unwrap_or_else(Name::missing),
+                    CallableDef::EnumVariant(e) => e.name(f.db).unwrap_or_else(Name::missing),
+                };
                 match def {
                     CallableDef::Function(_) => write!(f, "fn {}", name)?,
                     CallableDef::Struct(_) | CallableDef::EnumVariant(_) => write!(f, "{}", name)?,
                 }
                 if substs.0.len() > 0 {
-                    join(substs.0.iter()).surround_with("<", ">").separator(", ").to_fmt(f)?;
+                    write!(f, "<")?;
+                    f.write_joined(&*substs.0, ", ")?;
+                    write!(f, ">")?;
                 }
-                join(sig.input.iter()).surround_with("(", ")").separator(", ").to_fmt(f)?;
-                write!(f, " -> {}", sig.output)
+                write!(f, "(")?;
+                f.write_joined(&sig.input, ", ")?;
+                write!(f, ") -> {}", sig.output.display(f.db))?;
             }
-            Ty::Adt { name, substs, .. } => {
+            Ty::Adt { def_id, substs, .. } => {
+                let name = match def_id {
+                    AdtDef::Struct(s) => s.name(f.db),
+                    AdtDef::Enum(e) => e.name(f.db),
+                }
+                .unwrap_or_else(Name::missing);
                 write!(f, "{}", name)?;
                 if substs.0.len() > 0 {
-                    join(substs.0.iter()).surround_with("<", ">").separator(", ").to_fmt(f)?;
+                    write!(f, "<")?;
+                    f.write_joined(&*substs.0, ", ")?;
+                    write!(f, ">")?;
                 }
-                Ok(())
             }
-            Ty::Param { name, .. } => write!(f, "{}", name),
-            Ty::Unknown => write!(f, "{{unknown}}"),
-            Ty::Infer(..) => write!(f, "_"),
+            Ty::Param { name, .. } => write!(f, "{}", name)?,
+            Ty::Unknown => write!(f, "{{unknown}}")?,
+            Ty::Infer(..) => write!(f, "_")?,
         }
+        Ok(())
     }
 }
diff --git a/crates/ra_hir/src/ty/display.rs b/crates/ra_hir/src/ty/display.rs
new file mode 100644
index 000000000..63ec9d7e1
--- /dev/null
+++ b/crates/ra_hir/src/ty/display.rs
@@ -0,0 +1,56 @@
+use std::fmt;
+
+use crate::db::HirDatabase;
+
+pub struct HirFormatter<'a, 'b, DB> {
+    pub db: &'a DB,
+    fmt: &'a mut fmt::Formatter<'b>,
+}
+
+pub trait HirDisplay {
+    fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result;
+    fn display<'a, DB>(&'a self, db: &'a DB) -> HirDisplayWrapper<'a, DB, Self>
+    where
+        Self: Sized,
+    {
+        HirDisplayWrapper(db, self)
+    }
+}
+
+impl<'a, 'b, DB> HirFormatter<'a, 'b, DB>
+where
+    DB: HirDatabase,
+{
+    pub fn write_joined<T: HirDisplay>(
+        &mut self,
+        iter: impl IntoIterator<Item = T>,
+        sep: &str,
+    ) -> fmt::Result {
+        let mut first = true;
+        for e in iter {
+            if !first {
+                write!(self, "{}", sep)?;
+            }
+            first = false;
+            e.hir_fmt(self)?;
+        }
+        Ok(())
+    }
+
+    /// This allows using the `write!` macro directly with a `HirFormatter`.
+    pub fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
+        fmt::write(self.fmt, args)
+    }
+}
+
+pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T);
+
+impl<'a, DB, T> fmt::Display for HirDisplayWrapper<'a, DB, T>
+where
+    DB: HirDatabase,
+    T: HirDisplay,
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.1.hir_fmt(&mut HirFormatter { db: self.0, fmt: f })
+    }
+}
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index f4e055feb..ee4508bb2 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -9,7 +9,7 @@
 use std::sync::Arc;
 
 use crate::{
-    Function, Struct, StructField, Enum, EnumVariant, Path, Name,
+    Function, Struct, StructField, Enum, EnumVariant, Path,
     ModuleDef, TypeAlias,
     Const, Static,
     HirDatabase,
@@ -232,13 +232,12 @@ fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
     let signature = def.signature(db);
     let resolver = def.resolver(db);
     let generics = def.generic_params(db);
-    let name = def.name(db);
     let input =
         signature.params().iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>();
     let output = Ty::from_hir(db, &resolver, signature.ret_type());
     let sig = Arc::new(FnSig { input, output });
     let substs = make_substs(&generics);
-    Ty::FnDef { def: def.into(), sig, name, substs }
+    Ty::FnDef { def: def.into(), sig, substs }
 }
 
 /// Build the declared type of a const.
@@ -266,7 +265,6 @@ fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
     };
     let resolver = def.resolver(db);
     let generics = def.generic_params(db);
-    let name = def.name(db).unwrap_or_else(Name::missing);
     let input = fields
         .iter()
         .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
@@ -274,7 +272,7 @@ fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
     let output = type_for_struct(db, def);
     let sig = Arc::new(FnSig { input, output });
     let substs = make_substs(&generics);
-    Ty::FnDef { def: def.into(), sig, name, substs }
+    Ty::FnDef { def: def.into(), sig, substs }
 }
 
 /// Build the type of a tuple enum variant constructor.
@@ -286,7 +284,6 @@ fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) ->
     };
     let resolver = def.parent_enum(db).resolver(db);
     let generics = def.parent_enum(db).generic_params(db);
-    let name = def.name(db).unwrap_or_else(Name::missing);
     let input = fields
         .iter()
         .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
@@ -294,7 +291,7 @@ fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) ->
     let substs = make_substs(&generics);
     let output = type_for_enum(db, def.parent_enum(db)).subst(&substs);
     let sig = Arc::new(FnSig { input, output });
-    Ty::FnDef { def: def.into(), sig, name, substs }
+    Ty::FnDef { def: def.into(), sig, substs }
 }
 
 fn make_substs(generics: &GenericParams) -> Substs {
@@ -310,20 +307,12 @@ fn make_substs(generics: &GenericParams) -> Substs {
 
 fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty {
     let generics = s.generic_params(db);
-    Ty::Adt {
-        def_id: s.into(),
-        name: s.name(db).unwrap_or_else(Name::missing),
-        substs: make_substs(&generics),
-    }
+    Ty::Adt { def_id: s.into(), substs: make_substs(&generics) }
 }
 
 fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty {
     let generics = s.generic_params(db);
-    Ty::Adt {
-        def_id: s.into(),
-        name: s.name(db).unwrap_or_else(Name::missing),
-        substs: make_substs(&generics),
-    }
+    Ty::Adt { def_id: s.into(), substs: make_substs(&generics) }
 }
 
 fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty {
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index c7d409e6d..acae71c26 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -10,6 +10,7 @@ use test_utils::covers;
 use crate::{
     source_binder,
     mock::MockDatabase,
+    ty::display::HirDisplay,
 };
 
 // These tests compare the inference results for all expressions in a file
@@ -2142,7 +2143,7 @@ fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
     let node = algo::find_node_at_offset::<ast::Expr>(syntax.syntax(), pos.offset).unwrap();
     let expr = body_source_map.node_expr(node).unwrap();
     let ty = &inference_result[expr];
-    ty.to_string()
+    ty.display(db).to_string()
 }
 
 fn infer(content: &str) -> String {
@@ -2178,7 +2179,7 @@ fn infer(content: &str) -> String {
                 "{} '{}': {}\n",
                 syntax_ptr.range(),
                 ellipsize(node.text().to_string().replace("\n", " "), 15),
-                ty
+                ty.display(&db)
             )
             .unwrap();
         }
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index 71003104b..28c8f83ab 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -1,7 +1,7 @@
 //! This modules takes care of rendering various defenitions as completion items.
 use join_to_string::join;
 use test_utils::tested_by;
-use hir::{Docs, PerNs, Resolution};
+use hir::{Docs, PerNs, Resolution, HirDisplay};
 use ra_syntax::ast::NameOwner;
 
 use crate::completion::{
@@ -22,7 +22,7 @@ impl Completions {
             field.name(ctx.db).to_string(),
         )
         .kind(CompletionItemKind::Field)
-        .detail(field.ty(ctx.db).subst(substs).to_string())
+        .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string())
         .set_documentation(field.docs(ctx.db))
         .add_to(self);
     }
@@ -30,7 +30,7 @@ impl Completions {
     pub(crate) fn add_pos_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) {
         CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
             .kind(CompletionItemKind::Field)
-            .detail(ty.to_string())
+            .detail(ty.display(ctx.db).to_string())
             .add_to(self);
     }
 
@@ -154,7 +154,10 @@ impl Completions {
             None => return,
         };
         let detail_types = variant.fields(ctx.db).into_iter().map(|field| field.ty(ctx.db));
-        let detail = join(detail_types).separator(", ").surround_with("(", ")").to_string();
+        let detail = join(detail_types.map(|t| t.display(ctx.db).to_string()))
+            .separator(", ")
+            .surround_with("(", ")")
+            .to_string();
 
         CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
             .kind(CompletionItemKind::EnumVariant)
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 66a625c6c..f6a83dd93 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -3,6 +3,7 @@ use ra_syntax::{
     AstNode, SyntaxNode, TreeArc, ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner},
     algo::{find_covering_node, find_node_at_offset, find_leaf_at_offset, visit::{visitor, Visitor}},
 };
+use hir::HirDisplay;
 
 use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget};
 
@@ -134,9 +135,9 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
     let infer = function.infer(db);
     let source_map = function.body_source_map(db);
     if let Some(expr) = ast::Expr::cast(node).and_then(|e| source_map.node_expr(e)) {
-        Some(infer[expr].to_string())
+        Some(infer[expr].display(db).to_string())
     } else if let Some(pat) = ast::Pat::cast(node).and_then(|p| source_map.node_pat(p)) {
-        Some(infer[pat].to_string())
+        Some(infer[pat].display(db).to_string())
     } else {
         None
     }
-- 
cgit v1.2.3