1mod check;
17mod infer;
18mod usefulness;
19
20pub use check::{check, check_with};
21
22use nova_hir::Ty;
23use nova_resolver::Definitions;
24
25#[derive(Debug)]
27pub struct CheckResult {
28 pub module: nova_hir::Module,
31 pub diagnostics: Vec<nova_diagnostics::Diagnostic>,
32 pub probe: ProbeResult,
34 pub index: Option<nova_resolver::Index>,
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub struct ProbePoint {
42 pub file: nova_diagnostics::FileId,
43 pub offset: u32,
44}
45
46#[derive(Debug, Clone, Copy, Default)]
48pub struct CheckOptions<'a> {
49 pub probe: Option<ProbePoint>,
50 pub index: bool,
54 pub sources: Option<&'a nova_diagnostics::FileDb>,
58}
59
60#[derive(Debug, Clone, Default, PartialEq)]
63pub struct ProbeResult {
64 pub receiver: Option<Ty>,
67 pub members: Vec<Member>,
69 pub locals: Vec<(String, Ty)>,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct Member {
76 pub name: String,
77 pub kind: MemberKind,
78 pub decl: Option<nova_diagnostics::Span>,
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq)]
84pub enum MemberKind {
85 Field,
86 Method,
87}
88
89pub fn display_ty(ty: &Ty, defs: &Definitions) -> String {
91 match ty {
92 Ty::Int => "Int".to_string(),
93 Ty::Float => "Float".to_string(),
94 Ty::Bool => "Bool".to_string(),
95 Ty::Char => "Char".to_string(),
96 Ty::String => "String".to_string(),
97 Ty::Bytes => "Bytes".to_string(),
98 Ty::Unit => "()".to_string(),
99 Ty::Fn { params, ret } => {
100 let params = params
101 .iter()
102 .map(|p| display_ty(p, defs))
103 .collect::<Vec<_>>()
104 .join(", ");
105 format!("fn({params}) -> {}", display_ty(ret, defs))
106 }
107 Ty::Sum { def_id, args } | Ty::Record { def_id, args } => {
108 let name = &defs.def(*def_id).name;
109 if args.is_empty() {
110 name.clone()
111 } else {
112 let args = args
113 .iter()
114 .map(|a| display_ty(a, defs))
115 .collect::<Vec<_>>()
116 .join(", ");
117 format!("{name}<{args}>")
118 }
119 }
120 Ty::Array(elem) => format!("[{}]", display_ty(elem, defs)),
121 Ty::Future(out) => format!("Future<{}>", display_ty(out, defs)),
122 Ty::Param(i) => format!("T{i}"),
123 Ty::Assoc { on, assoc } => {
124 format!("{}::{}", display_ty(on, defs), defs.def(*assoc).name)
125 }
126 Ty::Var(v) => format!("?{v}"),
127 Ty::Never => "!".to_string(),
128 Ty::Error => "{error}".to_string(),
129 }
130}
131
132pub fn display_ty_named(ty: &Ty, defs: &Definitions, names: &[String]) -> String {
135 let show = |t: &Ty| display_ty_named(t, defs, names);
136 let list = |ts: &[Ty]| ts.iter().map(show).collect::<Vec<_>>().join(", ");
137 match ty {
138 Ty::Fn { params, ret } => format!("fn({}) -> {}", list(params.as_slice()), show(ret)),
139 Ty::Sum { def_id, args } | Ty::Record { def_id, args } => {
140 let name = &defs.def(*def_id).name;
141 if args.is_empty() {
142 name.clone()
143 } else {
144 format!("{name}<{}>", list(args.as_slice()))
145 }
146 }
147 Ty::Array(elem) => format!("[{}]", show(elem)),
148 Ty::Future(out) => format!("Future<{}>", show(out)),
149 Ty::Param(i) => names
150 .get(*i as usize)
151 .filter(|n| !n.is_empty())
152 .cloned()
153 .unwrap_or_else(|| format!("T{i}")),
154 Ty::Assoc { on, assoc } => format!("{}::{}", show(on), defs.def(*assoc).name),
155 Ty::Var(_) | Ty::Error => "_".to_string(),
156 other => display_ty(other, defs),
157 }
158}
159
160pub fn builtin_text(builtin: nova_resolver::Builtin, defs: &Definitions) -> String {
163 let (params, ret) = check::builtin_signature(builtin);
164 let names: Vec<String> = ["T", "U", "V", "W"].iter().map(|s| s.to_string()).collect();
165 let params = params
166 .iter()
167 .map(|p| display_ty_named(p, defs, &names))
168 .collect::<Vec<_>>()
169 .join(", ");
170 format!(
171 "fn {}({params}) -> {}",
172 builtin.name(),
173 display_ty_named(&ret, defs, &names)
174 )
175}