From c5ee60e05b1fafe20f56b21cfab30e7b80cb9d42 Mon Sep 17 00:00:00 2001 From: Florian Diebold 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 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, /// Substitutions for the generic parameters of the type @@ -265,8 +261,8 @@ impl Ty { /// `Option` 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) -> fmt::Result { + HirDisplay::hir_fmt(*self, f) + } +} + +impl HirDisplay for Ty { + fn hir_fmt(&self, f: &mut HirFormatter) -> 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) -> 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( + &mut self, + iter: impl IntoIterator, + 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::>(); 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::(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 { 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