1use crate::types::*;
4use indexmap::IndexMap;
5
6#[derive(Debug, Clone)]
7pub struct TypeDef {
8 pub params: Vec<String>,
9 pub kind: TypeDefKind,
10}
11
12#[derive(Debug, Clone)]
13pub enum TypeDefKind {
14 Union(IndexMap<String, Option<Ty>>),
16 Alias(Ty),
18 Opaque,
20}
21
22#[derive(Debug, Clone, Default)]
23pub struct TypeEnv {
24 pub types: IndexMap<String, TypeDef>,
26 pub ctor_to_type: IndexMap<String, String>,
28}
29
30impl TypeEnv {
31 pub fn new_with_builtins() -> Self {
32 let mut e = TypeEnv::default();
33 let mut r_variants = IndexMap::new();
35 r_variants.insert("Ok".into(), Some(Ty::Var(0))); r_variants.insert("Err".into(), Some(Ty::Var(1))); e.types.insert("Result".into(), TypeDef {
38 params: vec!["T".into(), "E".into()],
39 kind: TypeDefKind::Union(r_variants),
40 });
41 e.ctor_to_type.insert("Ok".into(), "Result".into());
42 e.ctor_to_type.insert("Err".into(), "Result".into());
43
44 let mut o_variants = IndexMap::new();
46 o_variants.insert("Some".into(), Some(Ty::Var(0))); o_variants.insert("None".into(), None);
48 e.types.insert("Option".into(), TypeDef {
49 params: vec!["T".into()],
50 kind: TypeDefKind::Union(o_variants),
51 });
52 e.ctor_to_type.insert("Some".into(), "Option".into());
53 e.ctor_to_type.insert("None".into(), "Option".into());
54
55 e.types.insert("Nil".into(), TypeDef {
57 params: vec![],
58 kind: TypeDefKind::Alias(Ty::Unit),
59 });
60
61 e.types.insert("Map".into(), TypeDef { params: vec!["K".into(), "V".into()], kind: TypeDefKind::Opaque });
63 e.types.insert("Set".into(), TypeDef { params: vec!["T".into()], kind: TypeDefKind::Opaque });
64
65 let mut sp_variants = IndexMap::new();
69 sp_variants.insert("PStr".into(), Some(Ty::str()));
70 sp_variants.insert("PInt".into(), Some(Ty::int()));
71 sp_variants.insert("PFloat".into(), Some(Ty::float()));
72 sp_variants.insert("PBool".into(), Some(Ty::bool()));
73 sp_variants.insert("PNull".into(), None);
74 e.types.insert("SqlParam".into(), TypeDef {
75 params: vec![],
76 kind: TypeDefKind::Union(sp_variants),
77 });
78 for ctor in &["PStr", "PInt", "PFloat", "PBool", "PNull"] {
79 e.ctor_to_type.insert((*ctor).into(), "SqlParam".into());
80 }
81
82 e.types.insert("SqlTx".into(), TypeDef { params: vec![], kind: TypeDefKind::Opaque });
87
88 let mut se_fields = IndexMap::new();
96 se_fields.insert("message".into(), Ty::str());
97 se_fields.insert("code".into(), Ty::Con("Option".into(), vec![Ty::str()]));
98 se_fields.insert("detail".into(), Ty::Con("Option".into(), vec![Ty::str()]));
99 e.types.insert("SqlError".into(), TypeDef {
100 params: vec![],
101 kind: TypeDefKind::Alias(Ty::Record(se_fields)),
102 });
103
104 let mut ar_fields = IndexMap::new();
111 ar_fields.insert("ciphertext".into(), Ty::bytes());
112 ar_fields.insert("tag".into(), Ty::bytes());
113 e.types.insert("AeadResult".into(), TypeDef {
114 params: vec![],
115 kind: TypeDefKind::Alias(Ty::Record(ar_fields)),
116 });
117
118 let mut dg_fields = IndexMap::new();
127 dg_fields.insert("data".into(), Ty::bytes());
128 dg_fields.insert("host".into(), Ty::str());
129 dg_fields.insert("port".into(), Ty::int());
130 e.types.insert("UdpDatagram".into(), TypeDef {
131 params: vec![],
132 kind: TypeDefKind::Alias(Ty::Record(dg_fields)),
133 });
134
135 e.types.insert("Iter".into(), TypeDef { params: vec!["T".into()], kind: TypeDefKind::Opaque });
139
140 e.types.insert("Stream".into(), TypeDef { params: vec!["T".into()], kind: TypeDefKind::Opaque });
147
148 let mut tz_variants = IndexMap::new();
154 tz_variants.insert("Utc".into(), None);
155 tz_variants.insert("Local".into(), None);
156 tz_variants.insert("Offset".into(), Some(Ty::int()));
157 tz_variants.insert("Iana".into(), Some(Ty::str()));
158 e.types.insert("Tz".into(), TypeDef {
159 params: vec![],
160 kind: TypeDefKind::Union(tz_variants),
161 });
162 for ctor in &["Utc", "Local", "Offset", "Iana"] {
163 e.ctor_to_type.insert((*ctor).into(), "Tz".into());
164 }
165
166 let mut http_err_variants = IndexMap::new();
172 http_err_variants.insert("NetworkError".into(), Some(Ty::str()));
173 http_err_variants.insert("TimeoutError".into(), None);
174 http_err_variants.insert("TlsError".into(), Some(Ty::str()));
175 http_err_variants.insert("DecodeError".into(), Some(Ty::str()));
176 e.types.insert("HttpError".into(), TypeDef {
177 params: vec![],
178 kind: TypeDefKind::Union(http_err_variants),
179 });
180 for ctor in &["NetworkError", "TimeoutError", "TlsError", "DecodeError"] {
181 e.ctor_to_type.insert((*ctor).into(), "HttpError".into());
182 }
183
184 let json_ty = || Ty::Con("Json".into(), vec![]);
194 let mut json_variants = IndexMap::new();
195 json_variants.insert("JNull".into(), None);
196 json_variants.insert("JBool".into(), Some(Ty::bool()));
197 json_variants.insert("JInt".into(), Some(Ty::int()));
198 json_variants.insert("JFloat".into(), Some(Ty::float()));
199 json_variants.insert("JStr".into(), Some(Ty::str()));
200 json_variants.insert("JList".into(), Some(Ty::List(Box::new(json_ty()))));
201 json_variants.insert(
202 "JObj".into(),
203 Some(Ty::List(Box::new(Ty::Tuple(vec![Ty::str(), json_ty()])))),
204 );
205 e.types.insert("Json".into(), TypeDef {
206 params: vec![],
207 kind: TypeDefKind::Union(json_variants),
208 });
209 for ctor in &["JNull", "JBool", "JInt", "JFloat", "JStr", "JList", "JObj"] {
210 e.ctor_to_type.insert((*ctor).into(), "Json".into());
211 }
212
213 let mut req_fields = IndexMap::new();
222 req_fields.insert("method".into(), Ty::str());
223 req_fields.insert("url".into(), Ty::str());
224 req_fields.insert("headers".into(), Ty::Con("Map".into(), vec![Ty::str(), Ty::str()]));
225 req_fields.insert("body".into(), Ty::Con("Option".into(), vec![Ty::bytes()]));
226 req_fields.insert("timeout_ms".into(), Ty::Con("Option".into(), vec![Ty::int()]));
227 e.types.insert("HttpRequest".into(), TypeDef {
228 params: vec![],
229 kind: TypeDefKind::Alias(Ty::Record(req_fields)),
230 });
231
232 let mut resp_fields = IndexMap::new();
236 resp_fields.insert("status".into(), Ty::int());
237 resp_fields.insert("headers".into(), Ty::Con("Map".into(), vec![Ty::str(), Ty::str()]));
238 resp_fields.insert("body".into(), Ty::bytes());
239 e.types.insert("HttpResponse".into(), TypeDef {
240 params: vec![],
241 kind: TypeDefKind::Alias(Ty::Record(resp_fields)),
242 });
243
244 let mut mat_fields = IndexMap::new();
251 mat_fields.insert("rows".into(), Ty::int());
252 mat_fields.insert("cols".into(), Ty::int());
253 mat_fields.insert("data".into(), Ty::List(Box::new(Ty::float())));
254 e.types.insert("Matrix".into(), TypeDef {
255 params: vec![],
256 kind: TypeDefKind::Alias(Ty::Record(mat_fields)),
257 });
258
259 let mut net_req_fields = IndexMap::new();
265 net_req_fields.insert("method".into(), Ty::str());
266 net_req_fields.insert("path".into(), Ty::str());
267 net_req_fields.insert("query".into(), Ty::str());
268 net_req_fields.insert("body".into(), Ty::str());
269 net_req_fields.insert("headers".into(), Ty::Con("Map".into(), vec![Ty::str(), Ty::str()]));
270 net_req_fields.insert("path_params".into(), Ty::Con("Map".into(), vec![Ty::str(), Ty::str()]));
271 e.types.insert("Request".into(), TypeDef {
272 params: vec![],
273 kind: TypeDefKind::Alias(Ty::Record(net_req_fields)),
274 });
275
276 let mut rb_variants = IndexMap::new();
282 rb_variants.insert("BodyStr".into(), Some(Ty::str()));
283 rb_variants.insert(
284 "BodyStream".into(),
285 Some(Ty::Con("Iter".into(), vec![Ty::str()])),
286 );
287 rb_variants.insert(
288 "BodyBytes".into(),
289 Some(Ty::Con("Iter".into(), vec![Ty::List(Box::new(Ty::int()))])),
290 );
291 e.types.insert("ResponseBody".into(), TypeDef {
292 params: vec![],
293 kind: TypeDefKind::Union(rb_variants),
294 });
295 for ctor in &["BodyStr", "BodyStream", "BodyBytes"] {
296 e.ctor_to_type.insert((*ctor).into(), "ResponseBody".into());
297 }
298
299 let mut net_resp_fields = IndexMap::new();
300 net_resp_fields.insert("status".into(), Ty::int());
301 net_resp_fields.insert("body".into(), Ty::Con("ResponseBody".into(), vec![]));
302 net_resp_fields.insert("headers".into(), Ty::Con("Map".into(), vec![Ty::str(), Ty::str()]));
303 e.types.insert("Response".into(), TypeDef {
304 params: vec![],
305 kind: TypeDefKind::Alias(Ty::Record(net_resp_fields)),
306 });
307
308 let mut ws_conn_fields = IndexMap::new();
311 ws_conn_fields.insert("id".into(), Ty::str());
312 ws_conn_fields.insert("path".into(), Ty::str());
313 ws_conn_fields.insert("subprotocol".into(), Ty::str());
314 e.types.insert("WsConn".into(), TypeDef {
315 params: vec![],
316 kind: TypeDefKind::Alias(Ty::Record(ws_conn_fields)),
317 });
318
319 let mut ws_msg_variants = IndexMap::new();
321 ws_msg_variants.insert("WsText".into(), Some(Ty::str()));
322 ws_msg_variants.insert("WsBinary".into(), Some(Ty::List(Box::new(Ty::int()))));
323 ws_msg_variants.insert("WsPing".into(), None);
324 ws_msg_variants.insert("WsClose".into(), None);
325 e.types.insert("WsMessage".into(), TypeDef {
326 params: vec![],
327 kind: TypeDefKind::Union(ws_msg_variants),
328 });
329 for ctor in &["WsText", "WsBinary", "WsPing", "WsClose"] {
330 e.ctor_to_type.insert((*ctor).into(), "WsMessage".into());
331 }
332
333 let mut ws_act_variants = IndexMap::new();
338 ws_act_variants.insert("WsSend".into(), Some(Ty::str()));
339 ws_act_variants.insert("WsSendBinary".into(), Some(Ty::List(Box::new(Ty::int()))));
340 ws_act_variants.insert("WsNoOp".into(), None);
341 e.types.insert("WsAction".into(), TypeDef {
342 params: vec![],
343 kind: TypeDefKind::Union(ws_act_variants),
344 });
345 for ctor in &["WsSend", "WsSendBinary", "WsNoOp"] {
346 e.ctor_to_type.insert((*ctor).into(), "WsAction".into());
347 }
348
349 let mut ce_variants = IndexMap::new();
355 ce_variants.insert("AlreadyRegistered".into(), Some(Ty::str()));
356 ce_variants.insert("NotRegistered".into(), Some(Ty::str()));
357 e.types.insert("ConcError".into(), TypeDef {
358 params: vec![],
359 kind: TypeDefKind::Union(ce_variants),
360 });
361 for ctor in &["AlreadyRegistered", "NotRegistered"] {
362 e.ctor_to_type.insert((*ctor).into(), "ConcError".into());
363 }
364
365 e.types.insert("ConnRedis".into(), TypeDef { params: vec![], kind: TypeDefKind::Opaque });
369
370 e
371 }
372
373 pub fn add_user_type(&mut self, name: &str, decl: lex_ast::TypeDecl) -> Result<(), String> {
374 match &decl.definition {
375 lex_ast::TypeExpr::Union { variants } => {
376 let mut vmap = IndexMap::new();
377 for v in variants {
378 let payload = v.payload.as_ref().map(|p| ty_from_canon(p, &decl.params));
379 vmap.insert(v.name.clone(), payload);
380 self.ctor_to_type.insert(v.name.clone(), name.to_string());
381 }
382 self.types.insert(name.to_string(), TypeDef {
383 params: decl.params.clone(),
384 kind: TypeDefKind::Union(vmap),
385 });
386 }
387 other => {
388 let ty = ty_from_canon_env(other, &decl.params, self);
389 self.types.insert(name.to_string(), TypeDef {
390 params: decl.params.clone(),
391 kind: TypeDefKind::Alias(ty),
392 });
393 }
394 }
395 Ok(())
396 }
397}
398
399pub fn ty_from_canon(t: &lex_ast::TypeExpr, params: &[String]) -> Ty {
403 match t {
404 lex_ast::TypeExpr::Named { name, args } => {
405 if let Some(idx) = params.iter().position(|p| p == name) {
407 if !args.is_empty() {
408 return Ty::Con(name.clone(), args.iter().map(|a| ty_from_canon(a, params)).collect());
410 }
411 return Ty::Var(idx as u32);
412 }
413 match name.as_str() {
415 "Int" => return Ty::int(),
416 "Float" => return Ty::float(),
417 "Bool" => return Ty::bool(),
418 "Str" => return Ty::str(),
419 "Bytes" => return Ty::bytes(),
420 "Unit" | "Nil" => return Ty::Unit,
421 "Never" => return Ty::Never,
422 "List" if args.len() == 1 => return Ty::List(Box::new(ty_from_canon(&args[0], params))),
423 "Tuple" => return Ty::Tuple(args.iter().map(|a| ty_from_canon(a, params)).collect()),
428 _ => {}
429 }
430 Ty::Con(name.clone(), args.iter().map(|a| ty_from_canon(a, params)).collect())
431 }
432 lex_ast::TypeExpr::Record { fields } => {
433 let mut m = IndexMap::new();
434 for f in fields { m.insert(f.name.clone(), ty_from_canon(&f.ty, params)); }
435 Ty::Record(m)
436 }
437 lex_ast::TypeExpr::Tuple { items } => Ty::Tuple(items.iter().map(|t| ty_from_canon(t, params)).collect()),
438 lex_ast::TypeExpr::Function { params: ps, effects, effect_row_var, ret } => {
439 let effs = EffectSet {
441 concrete: {
442 let mut s = std::collections::BTreeSet::new();
443 for e in effects {
444 let arg = e.arg.as_ref().map(|a| match a {
445 lex_ast::EffectArg::Str { value } => crate::types::EffectArg::Str(value.clone()),
446 lex_ast::EffectArg::Int { value } => crate::types::EffectArg::Int(*value),
447 lex_ast::EffectArg::Ident { value } => crate::types::EffectArg::Ident(value.clone()),
448 });
449 s.insert(crate::types::EffectKind { name: e.name.clone(), arg });
450 }
451 s
452 },
453 var: effect_row_var
459 .as_ref()
460 .and_then(|name| params.iter().position(|p| p == name))
461 .map(|i| i as u32),
462 };
463 Ty::Function {
464 params: ps.iter().map(|t| ty_from_canon(t, params)).collect(),
465 effects: effs,
466 ret: Box::new(ty_from_canon(ret, params)),
467 }
468 }
469 lex_ast::TypeExpr::Union { .. } => {
470 Ty::Unit
472 }
473 lex_ast::TypeExpr::Refined { base, .. } => {
474 ty_from_canon(base, params)
484 }
485 lex_ast::TypeExpr::RecordWithSpreads { .. } => {
486 Ty::Unit
488 }
489 }
490}
491
492pub fn ty_from_canon_env(t: &lex_ast::TypeExpr, params: &[String], env: &TypeEnv) -> Ty {
496 match t {
497 lex_ast::TypeExpr::RecordWithSpreads { spreads, fields } => {
498 let mut m = IndexMap::new();
499 for spread_name in spreads {
500 if let Some(td) = env.types.get(spread_name.as_str()) {
501 if let TypeDefKind::Alias(Ty::Record(spread_fields)) = &td.kind {
502 for (k, v) in spread_fields {
503 m.insert(k.clone(), v.clone());
504 }
505 }
506 }
507 }
508 for f in fields {
509 m.insert(f.name.clone(), ty_from_canon_env(&f.ty, params, env));
510 }
511 Ty::Record(m)
512 }
513 other => ty_from_canon(other, params),
514 }
515}