From f43380d009c72a0bdd00d5adfd080a378b5157a2 Mon Sep 17 00:00:00 2001 From: oxalica Date: Mon, 7 Nov 2022 14:47:06 +0800 Subject: [PATCH] Tweak type formatter --- crates/ide/src/ty/fmt.rs | 93 ++++++++++++++++++++++++++++++-------- crates/ide/src/ty/infer.rs | 14 +++++- crates/ide/src/ty/tests.rs | 24 ++++------ 3 files changed, 97 insertions(+), 34 deletions(-) diff --git a/crates/ide/src/ty/fmt.rs b/crates/ide/src/ty/fmt.rs index 5a27c84..93a5061 100644 --- a/crates/ide/src/ty/fmt.rs +++ b/crates/ide/src/ty/fmt.rs @@ -1,20 +1,24 @@ -//! TODO: Limit type length. use super::{InferenceResult, Ty, TyKind}; use std::fmt; +const MAX_FIELD_CNT: usize = 8; + #[derive(Clone, Copy)] pub struct TyDisplay<'a> { ty: Ty, infer: &'a InferenceResult, + depth: usize, + in_param: bool, } impl<'a> TyDisplay<'a> { - pub fn new(ty: Ty, infer: &'a InferenceResult) -> Self { - Self { ty, infer } - } - - fn with(self, ty: Ty) -> Self { - Self::new(ty, self.infer) + pub fn new(ty: Ty, infer: &'a InferenceResult, depth: usize) -> Self { + Self { + ty, + infer, + depth, + in_param: false, + } } } @@ -27,21 +31,74 @@ impl fmt::Display for TyDisplay<'_> { TyKind::Float => "float".fmt(f), TyKind::String => "string".fmt(f), TyKind::Path => "path".fmt(f), - &TyKind::List(elem) => write!(f, "[{}]", self.with(elem)), - &TyKind::Lambda(a, b) => write!(f, "{} -> {}", self.with(a), self.with(b)), + &TyKind::List(ty) => { + if self.depth == 0 { + "[…]".fmt(f) + } else { + let elem = Self { + ty, + infer: self.infer, + depth: self.depth - 1, + in_param: false, + }; + write!(f, "[{}]", elem) + } + } + &TyKind::Lambda(param, ret) => { + if self.in_param { + "(".fmt(f)?; + } + if self.depth == 0 { + "… → …".fmt(f)?; + } else { + let param = Self { + ty: param, + infer: self.infer, + // Show full lambda type. + depth: self.depth, + in_param: true, + }; + let ret = Self { + ty: ret, + infer: self.infer, + // Show full lambda type. + depth: self.depth, + in_param: false, + }; + write!(f, "{} → {}", param, ret)?; + } + if self.in_param { + ")".fmt(f)?; + } + Ok(()) + } TyKind::Attrset(set) => { - write!(f, "{{")?; - let mut first = true; - for (name, ty) in set.iter() { - if first { - first = false; + if self.depth == 0 { + "{ … }".fmt(f) + } else { + "{".fmt(f)?; + let mut first = true; + for (name, ty) in set.iter().take(MAX_FIELD_CNT) { + if first { + first = false; + } else { + ",".fmt(f)?; + } + // FIXME: Escape field names. + let value = Self { + ty, + infer: self.infer, + depth: self.depth - 1, + in_param: false, + }; + write!(f, " {}: {}", name, value)?; + } + if set.len() > MAX_FIELD_CNT { + ", … }".fmt(f) } else { - write!(f, ",")?; + " }".fmt(f) } - // FIXME: Escape field names. - write!(f, " {}: {}", name, self.with(ty))?; } - write!(f, " }}") } } } diff --git a/crates/ide/src/ty/infer.rs b/crates/ide/src/ty/infer.rs index 21555cd..55733f0 100644 --- a/crates/ide/src/ty/infer.rs +++ b/crates/ide/src/ty/infer.rs @@ -55,6 +55,14 @@ impl TyKind { pub struct Attrset(BTreeMap); impl Attrset { + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn len(&self) -> usize { + self.0.len() + } + pub fn get(&self, field: &str) -> Option { self.0.get(field).copied() } @@ -85,7 +93,11 @@ impl InferenceResult { } pub fn display_ty(&self, ty: Ty) -> TyDisplay<'_> { - TyDisplay::new(ty, self) + TyDisplay::new(ty, self, 2) + } + + pub fn debug_ty(&self, ty: Ty) -> TyDisplay<'_> { + TyDisplay::new(ty, self, usize::MAX) } } diff --git a/crates/ide/src/ty/tests.rs b/crates/ide/src/ty/tests.rs index fc36e25..5aecd11 100644 --- a/crates/ide/src/ty/tests.rs +++ b/crates/ide/src/ty/tests.rs @@ -7,7 +7,7 @@ fn check(src: &str, expect: Expect) { let module = db.module(file); let infer = db.infer(file); let ty = infer.ty_for_expr(module.entry_expr()); - let got = infer.display_ty(ty).to_string(); + let got = infer.debug_ty(ty).to_string(); expect.assert_eq(&got); } @@ -17,16 +17,10 @@ fn check_all(src: &str, expect: Expect) { let infer = db.infer(file); let got = module .names() - .map(|(i, name)| { - format!( - "{}: {}\n", - name.text, - infer.display_ty(infer.ty_for_name(i)) - ) - }) + .map(|(i, name)| format!("{}: {}\n", name.text, infer.debug_ty(infer.ty_for_name(i)))) .chain([format!( ": {}\n", - infer.display_ty(infer.ty_for_expr(module.entry_expr())) + infer.debug_ty(infer.ty_for_expr(module.entry_expr())) )]) .collect::(); expect.assert_eq(&got); @@ -116,32 +110,32 @@ fn if_then_else() { #[test] fn lambda() { - check("a: a", expect!["? -> ?"]); + check("a: a", expect!["? → ?"]); check("(a: a) 1", expect!["int"]); - check("{ }: 1", expect!["{ } -> int"]); + check("{ }: 1", expect!["{ } → int"]); check_all( "{ a ? b, b ? 42 }@c: b", expect![[r#" c: { a: int, b: int } a: int b: int - : { a: int, b: int } -> int + : { a: int, b: int } → int "#]], ); } #[test] fn select() { - check("a: a.b.c", expect!["{ b: { c: ? } } -> ?"]); - check("a: a.b.c or 42", expect!["{ b: { c: int } } -> int"]); + check("a: a.b.c", expect!["{ b: { c: ? } } → ?"]); + check("a: a.b.c or 42", expect!["{ b: { c: int } } → int"]); check_all( "a: b: a.${b}", expect![[r#" a: { } b: string - : { } -> string -> ? + : { } → string → ? "#]], ); }