1use crate::display::format_ty;
2use crate::env::{TypeEnv, collect_free_vars, generalize, instantiate, scheme, substitute_var};
3use crate::types::{InferContext, InferredSig, Scheme, Ty, is_arith_bound};
4use crate::unify::{UnifyError, unify};
5use crate::warning::TypeWarning;
6use crisp_ast::Span;
7use crisp_ast::count_holes;
8use crisp_ast::expr::{BinaryOp, Block, Expr, ExprKind, FieldInit, Stmt, UnaryOp};
9use crisp_ast::ident::Ident;
10use crisp_ast::is_hole_ident;
11use crisp_ast::item::{ExternBlock, FunctionDef, ImplBlock, Item, SourceFile, TypeBody};
12use crisp_ast::lift_holes;
13use crisp_ast::pat::{Pat, PatKind};
14use crisp_ast::ty::{Type, TypeKind};
15use crisp_resolve::module::load_module_graph;
16use crisp_resolve::{ResolvedRustImport, Resolver};
17use std::collections::{BTreeMap, BTreeSet, HashMap};
18use std::path::Path;
19use thiserror::Error;
20
21#[derive(Debug, Error)]
22pub enum TypeError {
23 #[error("unification error: {0}")]
24 Unify(#[from] UnifyError),
25 #[error("[E0040] unknown type `{name}`")]
26 UnknownType { name: String, span: Span },
27 #[error("[E0041] unknown name `{name}`")]
28 UnknownName { name: String, span: Span },
29 #[error("[E0042] resolve error: {0}")]
30 Resolve(#[from] crisp_resolve::ResolveError),
31 #[error(
32 "[E0043] ambiguous field `{field}` on unresolved type; annotate the parameter (candidates: {candidates})"
33 )]
34 AmbiguousField {
35 field: String,
36 candidates: String,
37 span: Span,
38 },
39 #[error("[E0084] cannot instantiate `{func}` with `{ty}`: `{ty}` does not implement `{bound}`")]
40 UnsatisfiedBound {
41 func: String,
42 ty: String,
43 bound: String,
44 span: Span,
45 },
46 #[error(
47 "[E0085] implicit closure has {found} hole(s) `_` but a function of {expected} parameter(s) is expected; write `|x, y| …`"
48 )]
49 HoleArity {
50 expected: usize,
51 found: usize,
52 span: Span,
53 },
54 #[error(
55 "[E0086] hole `_` is only valid where a function value is expected; write `|x| …` or use `_` as a call argument"
56 )]
57 HoleMisplaced { span: Span },
58 #[error("[E0087] cannot cast `{from}` as `{to}`; only `int` and `float`")]
59 InvalidCast {
60 from: String,
61 to: String,
62 span: Span,
63 },
64 #[error(
65 "[E0088] cannot infer element type of `vec`; pin it (`xs: vec<float> := new()`, or `-> vec<int> = new()`)"
66 )]
67 UninferredVec { span: Span },
68 #[error(
69 "[E0089] `{item}` is not declared in `extern rust {crate_name}`; add a scalar signature (`float`/`int`/`str`/`bool`)"
70 )]
71 UndeclaredRustImport {
72 crate_name: String,
73 item: String,
74 span: Span,
75 },
76 #[error(
77 "[E0090] `extern rust` types must be `float`, `int`, `str`, or `bool` (`{found}` is not allowed)"
78 )]
79 InvalidExternRustTy { found: String, span: Span },
80 #[error("unification error: {message}")]
81 UnifyAt { message: String, span: Span },
82}
83
84#[derive(Debug, Clone)]
86pub struct NumericCoercion {
87 pub span: Span,
88 pub literal: bool,
90 pub explicit: bool,
92 pub to_float: bool,
93}
94
95#[derive(Debug, Clone)]
96pub struct TypedCrate {
97 pub signatures: BTreeMap<String, InferredSig>,
98 pub inherent_methods: BTreeMap<String, BTreeMap<String, String>>,
100 pub rust_imports: Vec<ResolvedRustImport>,
102 pub impl_trait_args: BTreeMap<String, Vec<Ty>>,
104 pub coercions: Vec<NumericCoercion>,
106 pub warnings: Vec<crate::warning::TypeWarning>,
107 pub expr_tys: HashMap<Span, Ty>,
109 pub rust_externs: Vec<RustExternSig>,
111}
112
113#[derive(Debug, Clone)]
115pub struct RustExternSig {
116 pub crate_name: String,
117 pub item: String,
118 pub params: Vec<Ty>,
119 pub ret: Ty,
120 pub fallible: bool,
121 pub span: Span,
122}
123
124impl TypedCrate {
125 pub fn rust_call_fallible(&self, crate_name: &str, item: &str) -> bool {
126 rust_import_returns_result(crate_name, item)
127 || self
128 .rust_externs
129 .iter()
130 .any(|s| s.crate_name == crate_name && s.item == item && s.fallible)
131 }
132}
133
134#[derive(Debug, Clone)]
135struct TraitMethodStub {
136 params: Vec<(String, Option<Ty>)>,
137 ret: Option<Ty>,
138}
139
140#[derive(Debug, Clone)]
141struct CallInst {
142 args: Vec<Ty>,
143 span: Span,
144}
145
146pub struct TypeChecker {
147 ctx: InferContext,
148 env: TypeEnv,
149 structs: BTreeMap<String, BTreeMap<String, Ty>>,
150 shapes: BTreeSet<String>,
152 type_params: BTreeMap<String, Vec<String>>,
154 trait_generics: BTreeMap<String, Vec<String>>,
156 generic_params: BTreeMap<String, Ty>,
158 enums: BTreeMap<String, BTreeMap<String, Vec<Ty>>>,
160 traits: BTreeMap<String, BTreeMap<String, TraitMethodStub>>,
162 signatures: BTreeMap<String, InferredSig>,
163 inherent_methods: BTreeMap<String, BTreeMap<String, String>>,
165 loop_break_tys: Vec<Ty>,
167 impl_trait_fresh: BTreeMap<String, Vec<Ty>>,
169 impl_trait_args: BTreeMap<String, Vec<Ty>>,
171 fn_instantiations: BTreeMap<String, Vec<CallInst>>,
173 arith_named: BTreeMap<String, BTreeSet<String>>,
175 arith_vars: BTreeMap<u32, BTreeSet<String>>,
177 trait_impls: BTreeMap<String, BTreeSet<String>>,
179 coercions: Vec<NumericCoercion>,
180 warnings: Vec<crate::warning::TypeWarning>,
181 expr_tys: HashMap<Span, Ty>,
182 fn_vec_tys: Vec<(Span, Ty)>,
183 extern_rust: BTreeMap<(String, String), RustExternSig>,
184 undeclared_rust: BTreeMap<String, (String, String)>,
185 current_module: String,
187 imported: TypeEnv,
189}
190
191impl TypeChecker {
192 pub fn check_crate(crate_root: &Path) -> Result<TypedCrate, TypeError> {
193 let resolved = Resolver::resolve_crate(crate_root)?;
194 let graph = load_module_graph(crate_root)?;
195 let mut checker = Self::new();
196 checker.register_prelude();
197 for node in graph.modules.values() {
198 checker.collect_extern_rust(&node.ast)?;
199 }
200 checker.register_rust_imports(&resolved.rust_imports);
201 for node in graph.modules.values() {
202 checker.collect_types(&node.module_path, &node.ast);
203 }
204 for node in graph.modules.values() {
207 checker.collect_fn_stubs(&node.module_path, &node.ast)?;
208 }
209 for node in graph.modules.values() {
210 checker.check_module(&node.module_path, &node.ast)?;
211 }
212 checker.seal_open_signatures();
215 checker.specialize_internal_functions()?;
216 let expr_tys = checker
217 .expr_tys
218 .iter()
219 .map(|(s, t)| (*s, checker.ctx.apply(t)))
220 .collect();
221 Ok(TypedCrate {
222 signatures: checker.signatures,
223 inherent_methods: checker.inherent_methods,
224 rust_imports: resolved.rust_imports,
225 impl_trait_args: checker.impl_trait_args,
226 coercions: checker.coercions,
227 warnings: checker.warnings,
228 expr_tys,
229 rust_externs: checker.extern_rust.into_values().collect(),
230 })
231 }
232
233 fn new() -> Self {
234 Self {
235 ctx: InferContext::new(),
236 env: TypeEnv::new(),
237 structs: BTreeMap::new(),
238 shapes: BTreeSet::new(),
239 type_params: BTreeMap::new(),
240 trait_generics: BTreeMap::new(),
241 generic_params: BTreeMap::new(),
242 enums: BTreeMap::new(),
243 traits: BTreeMap::new(),
244 signatures: BTreeMap::new(),
245 inherent_methods: BTreeMap::new(),
246 loop_break_tys: Vec::new(),
247 impl_trait_fresh: BTreeMap::new(),
248 impl_trait_args: BTreeMap::new(),
249 fn_instantiations: BTreeMap::new(),
250 arith_named: BTreeMap::new(),
251 arith_vars: BTreeMap::new(),
252 trait_impls: BTreeMap::new(),
253 coercions: Vec::new(),
254 warnings: Vec::new(),
255 expr_tys: HashMap::new(),
256 fn_vec_tys: Vec::new(),
257 extern_rust: BTreeMap::new(),
258 undeclared_rust: BTreeMap::new(),
259 current_module: String::new(),
260 imported: TypeEnv::new(),
261 }
262 }
263
264 fn register_rust_imports(&mut self, imports: &[ResolvedRustImport]) {
266 for imp in imports {
267 let (params, ret, _fallible, span) =
268 if let Some((params, ret)) = rust_import_fn_type(&imp.crate_name, &imp.item) {
269 (
270 params,
271 ret,
272 rust_import_returns_result(&imp.crate_name, &imp.item),
273 Span::new(0, 0),
274 )
275 } else if let Some(sig) = self
276 .extern_rust
277 .get(&(imp.crate_name.clone(), imp.item.clone()))
278 {
279 (sig.params.clone(), sig.ret.clone(), sig.fallible, sig.span)
280 } else {
281 self.undeclared_rust.insert(
282 imp.local_name.clone(),
283 (imp.crate_name.clone(), imp.item.clone()),
284 );
285 continue;
286 };
287 let fn_ty = Ty::Fn {
288 params: params.clone(),
289 ret: Box::new(ret.clone()),
290 };
291 self.env.insert(imp.local_name.clone(), scheme(fn_ty));
292 let module = format!("rust.{}", imp.crate_name);
293 let key = format!("{module}::{}", imp.local_name);
294 self.signatures.insert(
295 key,
296 InferredSig {
297 module,
298 name: imp.local_name.clone(),
299 impl_ty: None,
300 params: params
301 .into_iter()
302 .enumerate()
303 .map(|(i, t)| (format!("arg{i}"), t))
304 .collect(),
305 ret,
306 span,
307 generics: Vec::new(),
308 is_pub: false,
309 inferred_from_use: false,
310 instantiations: Vec::new(),
311 mono_args: None,
312 op_bounds: BTreeMap::new(),
313 },
314 );
315 }
316 }
317
318 fn collect_extern_rust(&mut self, file: &SourceFile) -> Result<(), TypeError> {
319 for item in &file.items {
320 let Item::Extern(ext) = item else {
321 continue;
322 };
323 let Some(crate_id) = &ext.rust_crate else {
324 continue;
325 };
326 for f in &ext.functions {
327 let mut param_tys = Vec::new();
328 for p in &f.params {
329 let ty = if let Some(ast_ty) = &p.ty {
330 self.ast_type(ast_ty)?
331 } else {
332 return Err(TypeError::InvalidExternRustTy {
333 found: "unannotated".into(),
334 span: p.span,
335 });
336 };
337 if !rust_extern_scalar_ok(&ty) {
338 return Err(TypeError::InvalidExternRustTy {
339 found: format_ty(&ty),
340 span: p.span,
341 });
342 }
343 param_tys.push(ty);
344 }
345 let ret = if let Some(ast_ty) = &f.ret_type {
346 self.ast_type(ast_ty)?
347 } else {
348 Ty::Unit
349 };
350 if !rust_extern_scalar_ok(&ret) {
351 return Err(TypeError::InvalidExternRustTy {
352 found: format_ty(&ret),
353 span: f.span,
354 });
355 }
356 self.extern_rust.insert(
357 (crate_id.name.clone(), f.name.name.clone()),
358 RustExternSig {
359 crate_name: crate_id.name.clone(),
360 item: f.name.name.clone(),
361 params: param_tys,
362 ret,
363 fallible: f.fallible,
364 span: f.span,
365 },
366 );
367 }
368 }
369 Ok(())
370 }
371
372 fn register_prelude(&mut self) {
373 for (name, ty) in [
374 ("int", Ty::Int),
375 ("uint", Ty::UInt),
376 ("float", Ty::Float),
377 ("bool", Ty::Bool),
378 ("char", Ty::Char),
379 ("str", Ty::Str),
380 ("Never", Ty::Never),
381 (
382 "vec",
383 Ty::Named {
384 name: "vec".into(),
385 args: vec![],
386 },
387 ),
388 (
389 "map",
390 Ty::Named {
391 name: "map".into(),
392 args: vec![],
393 },
394 ),
395 (
396 "set",
397 Ty::Named {
398 name: "set".into(),
399 args: vec![],
400 },
401 ),
402 (
403 "log",
404 Ty::Fn {
405 params: vec![Ty::StrSlice],
406 ret: Box::new(Ty::Unit),
407 },
408 ),
409 (
410 "some",
411 Ty::Fn {
412 params: vec![self.ctx.fresh()],
413 ret: Box::new(Ty::Option(Box::new(self.ctx.fresh()))),
414 },
415 ),
416 (
417 "none",
418 Ty::Fn {
419 params: vec![],
420 ret: Box::new(Ty::Option(Box::new(self.ctx.fresh()))),
421 },
422 ),
423 ] {
424 self.env.insert(name, scheme(ty));
425 }
426 let p = self.ctx.fresh();
427 let assert_ty = Ty::Fn {
428 params: vec![p.clone(), p],
429 ret: Box::new(Ty::Unit),
430 };
431 let assert_scheme = generalize(&self.env, &mut self.ctx, &assert_ty);
432 self.env.insert("assert_eq", assert_scheme);
433
434 let pp = self.ctx.fresh();
435 let print_ty = Ty::Fn {
436 params: vec![pp.clone()],
437 ret: Box::new(Ty::Unit),
438 };
439 let print_scheme = generalize(&self.env, &mut self.ctx, &print_ty);
440 self.env.insert("print", print_scheme);
441
442 {
443 let t = self.ctx.fresh();
444 let vt = vec_of(t.clone());
445 let new_ty = Ty::Fn {
446 params: vec![],
447 ret: Box::new(vt),
448 };
449 self.env
450 .insert("new", generalize(&self.env, &mut self.ctx, &new_ty));
451 let t = self.ctx.fresh();
452 let vt = vec_of(t.clone());
453 let push_ty = Ty::Fn {
454 params: vec![vt, t],
455 ret: Box::new(Ty::Unit),
456 };
457 self.env
458 .insert("push", generalize(&self.env, &mut self.ctx, &push_ty));
459 let t = self.ctx.fresh();
460 let vt = vec_of(t);
461 let len_ty = Ty::Fn {
462 params: vec![vt],
463 ret: Box::new(Ty::Int),
464 };
465 self.env
466 .insert("len", generalize(&self.env, &mut self.ctx, &len_ty));
467 }
468
469 for (name, ty) in stdlib_fn_types() {
470 self.env.insert(name, scheme(ty));
471 }
472 self.register_prelude_traits();
473 }
474
475 fn register_prelude_traits(&mut self) {
476 self.traits.entry("Show".into()).or_insert_with(|| {
477 BTreeMap::from([(
478 "show".into(),
479 TraitMethodStub {
480 params: vec![("self".into(), None)],
481 ret: Some(Ty::Str),
482 },
483 )])
484 });
485 self.traits.entry("Eq".into()).or_insert_with(|| {
486 BTreeMap::from([(
487 "equal".into(),
488 TraitMethodStub {
489 params: vec![("self".into(), None), ("other".into(), None)],
490 ret: Some(Ty::Bool),
491 },
492 )])
493 });
494 self.traits.entry("Ord".into()).or_insert_with(|| {
495 BTreeMap::from([(
496 "compare".into(),
497 TraitMethodStub {
498 params: vec![("self".into(), None), ("other".into(), None)],
499 ret: Some(Ty::Int),
500 },
501 )])
502 });
503 }
504
505 fn collect_types(&mut self, module: &str, file: &SourceFile) {
506 for item in &file.items {
507 if let Item::TypeDef(td) = item {
508 let gens: Vec<String> = td.generics.iter().map(|g| g.name.clone()).collect();
509 if !gens.is_empty() {
510 self.type_params.insert(td.name.name.clone(), gens.clone());
511 }
512 let saved = self.bind_rigid_generics(&gens);
513 if let TypeBody::Struct(fields) = &td.body {
514 let mut field_map = BTreeMap::new();
515 for f in fields {
516 if let Ok(ty) = self.ast_type(&f.ty) {
517 field_map.insert(f.name.name.clone(), self.ctx.apply(&ty));
518 }
519 }
520 self.structs.insert(td.name.name.clone(), field_map);
521 self.env.insert(
522 td.name.name.clone(),
523 scheme(Ty::Named {
524 name: td.name.name.clone(),
525 args: vec![],
526 }),
527 );
528 } else if let TypeBody::Enum(variants) = &td.body {
529 let mut variant_map = BTreeMap::new();
530 for v in variants {
531 let mut fields = Vec::new();
532 for t in &v.fields {
533 if let Ok(ty) = self.ast_type(t) {
534 fields.push(self.ctx.apply(&ty));
535 }
536 }
537 variant_map.insert(v.name.name.clone(), fields);
538 }
539 self.enums.insert(td.name.name.clone(), variant_map);
540 self.env.insert(
541 td.name.name.clone(),
542 scheme(Ty::Named {
543 name: td.name.name.clone(),
544 args: vec![],
545 }),
546 );
547 } else if let TypeBody::Alias(ty) = &td.body
548 && let Ok(t) = self.ast_type(ty)
549 {
550 self.env.insert(td.name.name.clone(), scheme(t));
551 }
552 self.generic_params = saved;
553 } else if let Item::ShapeDef(shape) = item {
554 let gens: Vec<String> = shape.generics.iter().map(|g| g.name.clone()).collect();
556 if !gens.is_empty() {
557 self.type_params
558 .insert(shape.name.name.clone(), gens.clone());
559 }
560 let saved = self.bind_rigid_generics(&gens);
561 let mut field_map = BTreeMap::new();
562 for f in &shape.fields {
563 if let crisp_ast::item::ShapeField::Data { name, ty, .. } = f
564 && let Ok(field_ty) = self.ast_type(ty)
565 {
566 field_map.insert(name.name.clone(), self.ctx.apply(&field_ty));
567 }
568 }
569 self.shapes.insert(shape.name.name.clone());
570 self.structs.insert(shape.name.name.clone(), field_map);
571 self.env.insert(
572 shape.name.name.clone(),
573 scheme(Ty::Named {
574 name: shape.name.name.clone(),
575 args: vec![],
576 }),
577 );
578 self.generic_params = saved;
579 } else if let Item::TraitDef(td) = item {
580 let gens: Vec<String> = td.generics.iter().map(|g| g.name.clone()).collect();
581 if !gens.is_empty() {
582 self.trait_generics
583 .insert(td.name.name.clone(), gens.clone());
584 }
585 let saved = self.bind_rigid_generics(&gens);
586 let mut methods = BTreeMap::new();
587 for m in &td.items {
588 let mut params = Vec::new();
589 let mut ok = true;
590 for p in &m.params {
591 let ty = if p.name.name == "self" && p.ty.is_none() {
592 None
593 } else if let Some(ast_ty) = &p.ty {
594 match self.ast_type(ast_ty) {
595 Ok(t) => Some(t),
596 Err(_) => {
597 ok = false;
598 break;
599 }
600 }
601 } else {
602 Some(self.ctx.fresh())
603 };
604 params.push((p.name.name.clone(), ty));
605 }
606 if !ok {
607 continue;
608 }
609 let ret = match &m.ret_type {
610 Some(t) => match self.ast_type(t) {
611 Ok(t) => Some(t),
612 Err(_) => continue,
613 },
614 None => None,
615 };
616 methods.insert(m.name.name.clone(), TraitMethodStub { params, ret });
617 }
618 self.traits.insert(td.name.name.clone(), methods);
619 self.generic_params = saved;
620 }
621 }
622 let _ = module;
623 }
624
625 fn collect_fn_stubs(&mut self, module: &str, file: &SourceFile) -> Result<(), TypeError> {
626 for item in &file.items {
627 match item {
628 Item::Extern(ext) if ext.rust_crate.is_none() => {
629 self.check_extern(module, ext)?;
630 }
631 Item::Function(f) => {
632 let gens: Vec<String> = f.generics.iter().map(|g| g.name.clone()).collect();
633 let saved = self.bind_rigid_generics(&gens);
634 let mut params = Vec::new();
635 for p in &f.params {
636 let ty = if let Some(ast_ty) = &p.ty {
637 self.ast_type(ast_ty)?
638 } else {
639 self.ctx.fresh()
640 };
641 params.push(ty);
642 }
643 let ret = if let Some(t) = &f.ret_type {
644 self.ast_type(t)?
645 } else {
646 self.ctx.fresh()
647 };
648 let fn_ty = Ty::Fn {
649 params,
650 ret: Box::new(ret),
651 };
652 self.env.insert(
653 format!("{}::{}", module, f.name.name),
654 generalize_named_params(&fn_ty, &gens, &mut self.ctx),
655 );
656 self.generic_params = saved;
657 }
658 Item::Impl(ib) => {
659 self.collect_impl_stubs(module, ib)?;
660 }
661 _ => {}
662 }
663 }
664 Ok(())
665 }
666
667 fn collect_impl_stubs(&mut self, module: &str, ib: &ImplBlock) -> Result<(), TypeError> {
668 let ty_name = match &ib.ty.kind {
669 TypeKind::Named(id) => id.name.clone(),
670 _ => {
671 return Err(TypeError::UnknownType {
672 name: "impl".into(),
673 span: ib.span,
674 });
675 }
676 };
677 let self_ty = Ty::Named {
678 name: ty_name.clone(),
679 args: vec![],
680 };
681 if let Some(tn) = &ib.trait_name {
682 self.trait_impls
683 .entry(ty_name.clone())
684 .or_default()
685 .insert(tn.name.clone());
686 }
687 let trait_subst = self.impl_trait_subst(module, ib, &ty_name)?;
688 for f in &ib.items {
689 let mut params = Vec::new();
690 for p in &f.params {
691 let ty = if p.name.name == "self" && p.ty.is_none() {
692 self_ty.clone()
693 } else if let Some(ast_ty) = &p.ty {
694 self.ast_type(ast_ty)?
695 } else {
696 self.ctx.fresh()
697 };
698 params.push(ty);
699 }
700 let mut ret = if let Some(t) = &f.ret_type {
701 self.ast_type(t)?
702 } else {
703 self.ctx.fresh()
704 };
705 if !trait_subst.is_empty() {
706 params = params
707 .into_iter()
708 .map(|t| subst_named_params(&t, &trait_subst))
709 .collect();
710 ret = subst_named_params(&ret, &trait_subst);
711 }
712 if let Some(tn) = &ib.trait_name
713 && let Some(methods) = self.traits.get(&tn.name)
714 && let Some(stub) = methods.get(&f.name.name)
715 && let Some(trait_ret) = &stub.ret
716 {
717 ret = subst_named_params(trait_ret, &trait_subst);
718 }
719 let key = format!("{module}::{ty_name}::{}", f.name.name);
720 self.inherent_methods
721 .entry(ty_name.clone())
722 .or_default()
723 .insert(f.name.name.clone(), key.clone());
724 self.signatures.insert(
726 key,
727 InferredSig {
728 module: module.to_string(),
729 name: f.name.name.clone(),
730 impl_ty: Some(ty_name.clone()),
731 params: f
732 .params
733 .iter()
734 .zip(params.iter())
735 .map(|(p, t)| (p.name.name.clone(), t.clone()))
736 .collect(),
737 ret,
738 span: f.span,
739 generics: Vec::new(),
740 is_pub: f.is_pub,
741 inferred_from_use: false,
742 instantiations: Vec::new(),
743 mono_args: None,
744 op_bounds: BTreeMap::new(),
745 },
746 );
747 }
748 if let Some(tn) = &ib.trait_name
750 && let Some(trait_methods) = self.traits.get(&tn.name).cloned()
751 {
752 for (mname, stub) in trait_methods {
753 let methods = self.inherent_methods.entry(ty_name.clone()).or_default();
754 if methods.contains_key(&mname) {
755 continue;
756 }
757 let key = format!("{module}::{ty_name}::{mname}");
758 methods.insert(mname.clone(), key.clone());
759 let sig_params: Vec<(String, Ty)> = stub
760 .params
761 .into_iter()
762 .map(|(pname, pty)| {
763 let ty = if pname == "self" {
764 self_ty.clone()
765 } else {
766 let t = pty.unwrap_or_else(|| self.ctx.fresh());
767 subst_named_params(&t, &trait_subst)
768 };
769 (pname, ty)
770 })
771 .collect();
772 let sig_ret =
773 subst_named_params(&stub.ret.unwrap_or_else(|| self.ctx.fresh()), &trait_subst);
774 self.signatures.insert(
775 key,
776 InferredSig {
777 module: module.to_string(),
778 name: mname,
779 impl_ty: Some(ty_name.clone()),
780 params: sig_params,
781 ret: sig_ret,
782 span: ib.span,
783 generics: Vec::new(),
784 is_pub: false,
785 inferred_from_use: false,
786 instantiations: Vec::new(),
787 mono_args: None,
788 op_bounds: BTreeMap::new(),
789 },
790 );
791 }
792 }
793 Ok(())
794 }
795
796 fn check_module(&mut self, module: &str, file: &SourceFile) -> Result<(), TypeError> {
797 let saved_mod = std::mem::replace(&mut self.current_module, module.to_string());
798 let imports = self.collect_crisp_imports(file);
799 let saved_imp = std::mem::replace(&mut self.imported, imports);
800 let result = (|| {
801 for item in &file.items {
802 match item {
803 Item::Function(f) => self.check_function(module, f)?,
804 Item::Impl(ib) => self.check_impl(module, ib)?,
805 Item::Test(t) => self.check_test_block(module, &t.name, &t.body)?,
806 Item::TestCompileFail(_) | Item::Extern(_) => {}
807 _ => {}
808 }
809 }
810 Ok(())
811 })();
812 self.current_module = saved_mod;
813 self.imported = saved_imp;
814 result
815 }
816
817 fn collect_crisp_imports(&self, file: &SourceFile) -> TypeEnv {
818 let mut env = TypeEnv::new();
819 for item in &file.items {
820 let Item::Use(u) = item else {
821 continue;
822 };
823 if u.path.first().is_some_and(|p| p.name == "rust") {
824 continue;
825 }
826 let path = u
827 .path
828 .iter()
829 .map(|p| p.name.as_str())
830 .collect::<Vec<_>>()
831 .join(".");
832 if let Some(imports) = &u.imports {
833 for imp in imports {
834 let local = imp.alias.as_ref().unwrap_or(&imp.name).name.clone();
835 let q = format!("{}::{}", path, imp.name.name);
836 if let Some(s) = self.env.get(&q) {
837 env.insert(local, s.clone());
838 }
839 }
840 } else {
841 let prefix = format!("{path}::");
842 for (k, s) in self.env.entries() {
843 if let Some(bare) = k.strip_prefix(&prefix)
844 && !bare.contains("::")
845 {
846 env.insert(bare.to_string(), s.clone());
847 }
848 }
849 }
850 }
851 env
852 }
853
854 fn env_for_generalize(&self, self_name: &str) -> TypeEnv {
858 let mut env = self.env.clone();
859 env.remove(self_name);
860 env.remove(&format!("{}::{self_name}", self.current_module));
861 for sig in self.signatures.values() {
862 if sig.impl_ty.is_some() || sig.name.starts_with("test::") {
863 continue;
864 }
865 if sig.name != self_name {
866 env.remove(&sig.name);
867 env.remove(&format!("{}::{}", sig.module, sig.name));
868 }
869 }
870 env
871 }
872
873 fn seal_open_signatures(&mut self) {
875 let keys: Vec<String> = self.signatures.keys().cloned().collect();
876 for key in keys {
877 let Some(sig) = self.signatures.get(&key).cloned() else {
878 continue;
879 };
880 let param_types: Vec<(String, Ty)> = sig
881 .params
882 .iter()
883 .map(|(n, t)| (n.clone(), self.ctx.apply(t)))
884 .collect();
885 let ret = self.ctx.apply(&sig.ret);
886 if !sig.generics.is_empty() {
887 if let Some(s) = self.signatures.get_mut(&key) {
888 s.params = param_types;
889 s.ret = ret;
890 }
891 continue;
892 }
893 let fn_ty = Ty::Fn {
894 params: param_types.iter().map(|(_, t)| t.clone()).collect(),
895 ret: Box::new(ret.clone()),
896 };
897 let (named, inferred) = name_free_vars(&fn_ty);
898 if inferred.is_empty() {
899 if let Some(s) = self.signatures.get_mut(&key) {
900 s.params = param_types;
901 s.ret = ret;
902 }
903 continue;
904 }
905 let mut named_vars = Vec::new();
906 collect_free_vars(&fn_ty, &mut named_vars);
907 named_vars.sort_unstable();
908 named_vars.dedup();
909 self.name_expr_ty_vars(&named_vars, &inferred);
910 let mut params = param_types;
911 let mut named_ret = ret;
912 if let Ty::Fn { params: ps, ret: r } = &named {
913 for (i, t) in ps.iter().enumerate() {
914 if let Some(slot) = params.get_mut(i) {
915 slot.1 = t.clone();
916 }
917 }
918 named_ret = r.as_ref().clone();
919 }
920 if let Some(s) = self.signatures.get_mut(&key) {
921 s.params = params;
922 s.ret = named_ret;
923 s.generics = inferred;
924 s.inferred_from_use = true;
925 }
926 }
927 }
928
929 fn check_impl(&mut self, module: &str, ib: &ImplBlock) -> Result<(), TypeError> {
930 let ty_name = match &ib.ty.kind {
931 TypeKind::Named(id) => id.name.clone(),
932 _ => {
933 return Err(TypeError::UnknownType {
934 name: "impl".into(),
935 span: ib.span,
936 });
937 }
938 };
939 for f in &ib.items {
940 self.check_impl_method(module, &ty_name, f)?;
941 }
942 self.finalize_impl_trait_args(module, ib, &ty_name)?;
943 Ok(())
944 }
945
946 fn check_impl_method(
947 &mut self,
948 module: &str,
949 ty_name: &str,
950 f: &FunctionDef,
951 ) -> Result<(), TypeError> {
952 let key = format!("{module}::{ty_name}::{}", f.name.name);
953 let stub = self.signatures.get(&key).cloned();
954 let (stub_params, stub_ret) = match stub {
955 Some(s) => (
956 s.params.iter().map(|(_, t)| t.clone()).collect::<Vec<_>>(),
957 Some(s.ret),
958 ),
959 None => (Vec::new(), None),
960 };
961 let self_ty = Ty::Named {
962 name: ty_name.to_string(),
963 args: vec![],
964 };
965
966 let mut local = self.env.clone();
967 let mut param_vars = Vec::new();
968 for (i, p) in f.params.iter().enumerate() {
969 let mut ty = stub_params
970 .get(i)
971 .cloned()
972 .unwrap_or_else(|| self.ctx.fresh());
973 if p.name.name == "self" && p.ty.is_none() {
974 unify(&mut self.ctx, &ty, &self_ty)?;
975 ty = self.ctx.apply(&self_ty);
976 } else if let Some(ast_ty) = &p.ty {
977 let ann = self.ast_type(ast_ty)?;
978 unify(&mut self.ctx, &ty, &ann)?;
979 ty = self.ctx.apply(&ann);
980 }
981 param_vars.push((p.name.name.clone(), ty.clone()));
982 local.insert(p.name.name.clone(), scheme(ty));
983 }
984 let ret_ann = f.ret_type.as_ref().map(|t| self.ast_type(t)).transpose()?;
985 let body_ty = self.infer_expr(&mut local, &f.body)?;
986 let param_types: Vec<(String, Ty)> = param_vars
987 .iter()
988 .map(|(n, t)| (n.clone(), self.ctx.apply(t)))
989 .collect();
990 let ret = if let Some(ann) = ret_ann {
991 self.unify_checking(&f.body, &body_ty, &ann)?;
992 if let Some(stub_r) = &stub_ret {
993 unify(&mut self.ctx, &body_ty, stub_r)?;
994 }
995 self.ctx.apply(&ann)
996 } else if let Some(stub_r) = &stub_ret {
997 unify(&mut self.ctx, &body_ty, stub_r)?;
998 self.ctx.apply(&body_ty)
999 } else {
1000 self.ctx.apply(&body_ty)
1001 };
1002 self.signatures.insert(
1003 key.clone(),
1004 InferredSig {
1005 module: module.to_string(),
1006 name: f.name.name.clone(),
1007 impl_ty: Some(ty_name.to_string()),
1008 params: param_types,
1009 ret,
1010 span: f.span,
1011 generics: Vec::new(),
1012 is_pub: f.is_pub,
1013 inferred_from_use: false,
1014 instantiations: Vec::new(),
1015 mono_args: None,
1016 op_bounds: BTreeMap::new(),
1017 },
1018 );
1019 self.inherent_methods
1020 .entry(ty_name.to_string())
1021 .or_default()
1022 .insert(f.name.name.clone(), key);
1023 Ok(())
1024 }
1025
1026 fn check_extern(&mut self, module: &str, ext: &ExternBlock) -> Result<(), TypeError> {
1027 for f in &ext.functions {
1028 let mut param_tys = Vec::new();
1029 for p in &f.params {
1030 let ty = if let Some(ast_ty) = &p.ty {
1031 self.ast_type(ast_ty)?
1032 } else {
1033 Ty::Int
1034 };
1035 param_tys.push(ty);
1036 }
1037 let ret = if let Some(ast_ty) = &f.ret_type {
1038 self.ast_type(ast_ty)?
1039 } else {
1040 Ty::Unit
1041 };
1042 let fn_ty = Ty::Fn {
1043 params: param_tys.clone(),
1044 ret: Box::new(ret.clone()),
1045 };
1046 self.env.insert(f.name.name.clone(), scheme(fn_ty));
1047 let key = format!("{}::{}", module, f.name.name);
1048 self.signatures.insert(
1049 key,
1050 InferredSig {
1051 module: module.to_string(),
1052 name: f.name.name.clone(),
1053 impl_ty: None,
1054 params: f
1055 .params
1056 .iter()
1057 .enumerate()
1058 .map(|(i, p)| (p.name.name.clone(), param_tys[i].clone()))
1059 .collect(),
1060 ret,
1061 span: f.span,
1062 generics: Vec::new(),
1063 is_pub: false,
1064 inferred_from_use: false,
1065 instantiations: Vec::new(),
1066 mono_args: None,
1067 op_bounds: BTreeMap::new(),
1068 },
1069 );
1070 }
1071 let _ = ext;
1072 Ok(())
1073 }
1074
1075 fn check_test_block(
1076 &mut self,
1077 module: &str,
1078 name: &str,
1079 body: &Block,
1080 ) -> Result<(), TypeError> {
1081 self.fn_vec_tys.clear();
1082 let mut local = self.env.clone();
1083 let body_ty = self.infer_block(&mut local, body)?;
1084 unify(&mut self.ctx, &body_ty, &Ty::Unit)?;
1085 let key = format!("{module}::test::{name}");
1086 self.signatures.insert(
1087 key,
1088 InferredSig {
1089 module: module.to_string(),
1090 name: format!("test::{name}"),
1091 impl_ty: None,
1092 params: vec![],
1093 ret: Ty::Unit,
1094 span: body.span,
1095 generics: Vec::new(),
1096 is_pub: false,
1097 inferred_from_use: false,
1098 instantiations: Vec::new(),
1099 mono_args: None,
1100 op_bounds: BTreeMap::new(),
1101 },
1102 );
1103 self.reject_uninferred_vec(&[])?;
1104 Ok(())
1105 }
1106
1107 fn check_function(&mut self, module: &str, f: &FunctionDef) -> Result<(), TypeError> {
1108 self.arith_named.clear();
1109 self.arith_vars.clear();
1110 self.fn_vec_tys.clear();
1111 let gens: Vec<String> = f.generics.iter().map(|g| g.name.clone()).collect();
1112 let saved = self.bind_rigid_generics(&gens);
1113 let stub_key = format!("{module}::{}", f.name.name);
1116 let stub = if gens.is_empty() {
1117 self.env
1118 .get(&stub_key)
1119 .map(|s| instantiate(&mut self.ctx, s))
1120 .map(|t| self.ctx.apply(&t))
1121 } else {
1122 None
1123 };
1124 let (stub_params, stub_ret) = match stub {
1125 Some(Ty::Fn { params, ret }) => (params, Some(*ret)),
1126 _ => (Vec::new(), None),
1127 };
1128
1129 let mut local = self.env.clone();
1130 let mut param_vars = Vec::new();
1131 for (i, p) in f.params.iter().enumerate() {
1132 let mut ty = stub_params
1133 .get(i)
1134 .cloned()
1135 .unwrap_or_else(|| self.ctx.fresh());
1136 if let Some(ast_ty) = &p.ty {
1137 let ann = self.ast_type(ast_ty)?;
1138 unify(&mut self.ctx, &ty, &ann)?;
1139 ty = self.ctx.apply(&ann);
1140 }
1141 param_vars.push((p.name.name.clone(), ty.clone()));
1142 local.insert(p.name.name.clone(), scheme(ty));
1143 }
1144 let ret_ann = f.ret_type.as_ref().map(|t| self.ast_type(t)).transpose()?;
1145 let body_ty = self.infer_expr(&mut local, &f.body)?;
1146 let ret = if let Some(ann) = ret_ann {
1147 self.unify_checking(&f.body, &body_ty, &ann)?;
1148 if let Some(stub_r) = &stub_ret {
1149 unify(&mut self.ctx, &body_ty, stub_r)?;
1150 }
1151 self.ctx.apply(&ann)
1152 } else if let Some(stub_r) = &stub_ret {
1153 unify(&mut self.ctx, &body_ty, stub_r)?;
1154 self.ctx.apply(&body_ty)
1155 } else {
1156 self.ctx.apply(&body_ty)
1157 };
1158 let param_types: Vec<(String, Ty)> = param_vars
1159 .iter()
1160 .map(|(n, t)| (n.clone(), self.ctx.apply(t)))
1161 .collect();
1162 let ret = self.ctx.apply(&ret);
1163 let fn_params: Vec<Ty> = param_types.iter().map(|(_, t)| t.clone()).collect();
1164 let mut fn_ty = Ty::Fn {
1165 params: fn_params,
1166 ret: Box::new(ret.clone()),
1167 };
1168 let mut gens = gens;
1169 let mut param_types = param_types;
1170 let mut ret = ret;
1171 let mut inferred_from_use = false;
1172 let pre_ty = fn_ty.clone();
1178 if gens.is_empty() {
1179 let env_wo = self.env_for_generalize(&f.name.name);
1180 let gen_scheme = generalize(&env_wo, &mut self.ctx, &fn_ty);
1181 if !gen_scheme.vars.is_empty() {
1182 let (named, inferred) = name_vars(&fn_ty, &gen_scheme.vars);
1183 if !inferred.is_empty() {
1184 fn_ty = named;
1185 gens = inferred;
1186 inferred_from_use = true;
1187 self.name_expr_ty_vars(&gen_scheme.vars, &gens);
1188 if let Ty::Fn { params, ret: r } = &fn_ty {
1189 for (i, t) in params.iter().enumerate() {
1190 if let Some(slot) = param_types.get_mut(i) {
1191 slot.1 = t.clone();
1192 }
1193 }
1194 ret = r.as_ref().clone();
1195 }
1196 }
1197 }
1198 }
1199 let op_bounds = self.take_op_bounds(&pre_ty, &gens);
1200 let key = format!("{module}::{}", f.name.name);
1201 self.signatures.insert(
1202 key,
1203 InferredSig {
1204 module: module.to_string(),
1205 name: f.name.name.clone(),
1206 impl_ty: None,
1207 params: param_types,
1208 ret: ret.clone(),
1209 span: f.span,
1210 generics: gens.clone(),
1211 is_pub: f.is_pub,
1212 inferred_from_use,
1213 instantiations: Vec::new(),
1214 mono_args: None,
1215 op_bounds,
1216 },
1217 );
1218 self.env.insert(
1219 format!("{module}::{}", f.name.name),
1220 if gens.is_empty() {
1221 scheme(fn_ty)
1222 } else {
1223 generalize_named_params(&fn_ty, &gens, &mut self.ctx)
1224 },
1225 );
1226 self.generic_params = saved;
1227 self.reject_uninferred_vec(&gens)?;
1228 Ok(())
1229 }
1230
1231 fn specialize_internal_functions(&mut self) -> Result<(), TypeError> {
1235 let insts = std::mem::take(&mut self.fn_instantiations);
1236 self.check_instantiation_bounds(&insts)?;
1237 let keys: Vec<String> = self.signatures.keys().cloned().collect();
1238 for key in keys {
1239 let Some(sig) = self.signatures.get(&key) else {
1240 continue;
1241 };
1242 if let Some(uses) = insts.get(&key).or_else(|| insts.get(&sig.name)) {
1243 let mut labels: Vec<String> = uses
1244 .iter()
1245 .map(|u| u.args.iter().map(format_ty).collect::<Vec<_>>().join(", "))
1246 .collect();
1247 labels.sort();
1248 labels.dedup();
1249 if let Some(sig) = self.signatures.get_mut(&key) {
1250 sig.instantiations = labels;
1251 }
1252 }
1253 let Some(sig) = self.signatures.get(&key) else {
1254 continue;
1255 };
1256 if sig.is_pub
1257 || !sig.inferred_from_use
1258 || sig.generics.is_empty()
1259 || sig.impl_ty.is_some()
1260 {
1261 continue;
1262 }
1263 let Some(uses) = insts.get(&key).or_else(|| insts.get(&sig.name)) else {
1264 continue;
1265 };
1266 if uses.is_empty() {
1267 continue;
1268 }
1269 let first = &uses[0].args;
1270 if !first.iter().all(ty_is_ground) {
1271 continue;
1272 }
1273 if !uses.iter().all(|u| &u.args == first) {
1274 continue;
1275 }
1276 if let Some(sig) = self.signatures.get_mut(&key) {
1277 sig.mono_args = Some(first.clone());
1278 }
1279 }
1280 Ok(())
1281 }
1282
1283 fn infer_expr(&mut self, env: &mut TypeEnv, expr: &Expr) -> Result<Ty, TypeError> {
1284 match &expr.kind {
1285 ExprKind::Int(_) => Ok(Ty::Int),
1286 ExprKind::Float(_) => Ok(Ty::Float),
1287 ExprKind::Bool(_) => Ok(Ty::Bool),
1288 ExprKind::Char(_) => Ok(Ty::Char),
1289 ExprKind::Str(_) => Ok(Ty::Str),
1290 ExprKind::Unit => Ok(Ty::Unit),
1291 ExprKind::Ident(id) if is_hole_ident(&id.name) => {
1292 Err(TypeError::HoleMisplaced { span: id.span })
1293 }
1294 ExprKind::Ident(id) => self.lookup(env, &id.name, id.span),
1295 ExprKind::Block(b) => self.infer_block(env, b),
1296 ExprKind::If {
1297 cond,
1298 then_branch,
1299 else_branch,
1300 } => {
1301 let cty = self.infer_expr(env, cond)?;
1302 unify(&mut self.ctx, &cty, &Ty::Bool)?;
1303 let t = self.infer_expr(env, then_branch)?;
1304 if let Some(e) = else_branch {
1305 let e_ty = self.infer_expr(env, e)?;
1306 unify(&mut self.ctx, &t, &e_ty)?;
1307 }
1308 Ok(self.ctx.apply(&t))
1309 }
1310 ExprKind::Match { scrutinee, arms } => {
1311 let scrut = self.infer_expr(env, scrutinee)?;
1312 let mut local = env.clone();
1313 let mut result = None;
1314 for arm in arms {
1315 self.infer_pat(&mut local, &arm.pat, &scrut)?;
1316 if let Some(g) = &arm.guard {
1317 let gty = self.infer_expr(&mut local, g)?;
1318 unify(&mut self.ctx, >y, &Ty::Bool)?;
1319 }
1320 let body = self.infer_expr(&mut local, &arm.body)?;
1321 result = Some(match result {
1322 None => body,
1323 Some(prev) => {
1324 unify(&mut self.ctx, &prev, &body)?;
1325 prev
1326 }
1327 });
1328 }
1329 Ok(result.unwrap_or(Ty::Unit))
1330 }
1331 ExprKind::Lambda { params, body } => {
1332 let mut local = env.clone();
1333 let mut ptys = Vec::new();
1334 for p in params {
1335 let ty = if let Some(ast_ty) = &p.ty {
1336 self.ast_type(ast_ty)?
1337 } else {
1338 self.ctx.fresh()
1339 };
1340 ptys.push(self.ctx.apply(&ty));
1341 local.insert(p.name.name.clone(), scheme(ty));
1342 }
1343 let ret = self.infer_expr(&mut local, body)?;
1344 Ok(Ty::Fn {
1345 params: ptys,
1346 ret: Box::new(self.ctx.apply(&ret)),
1347 })
1348 }
1349 ExprKind::Call { func, args } => {
1350 if let ExprKind::Ident(id) = &func.kind
1351 && let Some((crate_name, item)) = self.undeclared_rust.get(&id.name)
1352 {
1353 return Err(TypeError::UndeclaredRustImport {
1354 crate_name: crate_name.clone(),
1355 item: item.clone(),
1356 span: expr.span,
1357 });
1358 }
1359 if let ExprKind::Field { base, field } = &func.kind
1361 && let Some(ret) = self.try_infer_method_call(env, base, field, args)?
1362 {
1363 return Ok(ret);
1364 }
1365 let ft = self.infer_expr(env, func)?;
1366 let ft = self.ctx.apply(&ft);
1367 let (params, ret) = match ft {
1368 Ty::Fn { params, ret } => (params, ret),
1369 Ty::Var(v) => {
1370 let ps: Vec<_> = (0..args.len()).map(|_| self.ctx.fresh()).collect();
1371 let ret = self.ctx.fresh();
1372 unify(
1373 &mut self.ctx,
1374 &Ty::Var(v),
1375 &Ty::Fn {
1376 params: ps.clone(),
1377 ret: Box::new(ret.clone()),
1378 },
1379 )?;
1380 (ps, Box::new(ret))
1381 }
1382 other => {
1383 return Err(TypeError::UnifyAt {
1384 message: format!("type mismatch: expected function, found {other:?}"),
1385 span: expr.span,
1386 });
1387 }
1388 };
1389 if args.len() != params.len() {
1390 return Err(TypeError::Unify(UnifyError::Mismatch {
1391 expected: format!("{} arguments", params.len()),
1392 found: format!("{} arguments", args.len()),
1393 }));
1394 }
1395 for (arg, pty) in args.iter().zip(params.iter()) {
1396 let aty = self.infer_call_arg(env, arg, pty)?;
1397 self.unify_or_shape_checking(arg, &aty, pty)?;
1398 }
1399 if let ExprKind::Ident(id) = &func.kind {
1400 let applied: Vec<Ty> = params.iter().map(|p| self.ctx.apply(p)).collect();
1401 if applied.iter().all(ty_is_ground) {
1402 self.propagate_callee_bounds(&id.name, &applied);
1403 let inst_key = format!("{}::{}", self.current_module, id.name);
1404 self.fn_instantiations
1405 .entry(inst_key)
1406 .or_default()
1407 .push(CallInst {
1408 args: applied,
1409 span: expr.span,
1410 });
1411 }
1412 }
1413 let ret = self.ctx.apply(&ret);
1414 self.record_expr_ty(expr.span, ret.clone());
1415 Ok(ret)
1416 }
1417 ExprKind::Field { base, field } => {
1418 if let ExprKind::Ident(id) = &base.kind
1420 && let Some(variants) = self.enums.get(&id.name)
1421 {
1422 return match variants.get(&field.name) {
1423 Some(payload) if payload.is_empty() => Ok(Ty::Named {
1424 name: id.name.clone(),
1425 args: vec![],
1426 }),
1427 Some(payload) => Ok(Ty::Fn {
1428 params: payload.clone(),
1429 ret: Box::new(Ty::Named {
1430 name: id.name.clone(),
1431 args: vec![],
1432 }),
1433 }),
1434 None => Err(TypeError::UnknownName {
1435 name: format!("{}.{}", id.name, field.name),
1436 span: field.span,
1437 }),
1438 };
1439 }
1440 if let ExprKind::Ident(id) = &base.kind
1442 && self.structs.contains_key(&id.name)
1443 && let Some(sig) = self.method_sig(&id.name, &field.name)
1444 {
1445 let has_self = sig
1446 .params
1447 .first()
1448 .map(|(n, _)| n == "self")
1449 .unwrap_or(false);
1450 if !has_self {
1451 let params: Vec<Ty> = sig.params.iter().map(|(_, t)| t.clone()).collect();
1452 return Ok(Ty::Fn {
1453 params,
1454 ret: Box::new(sig.ret.clone()),
1455 });
1456 }
1457 }
1458 let base_ty = self.infer_expr(env, base)?;
1459 self.field_type(&base_ty, &field.name, field.span)
1460 }
1461 ExprKind::Unary { op, expr } => match op {
1462 UnaryOp::Not => {
1463 let t = self.infer_expr(env, expr)?;
1464 unify(&mut self.ctx, &t, &Ty::Bool)?;
1465 Ok(Ty::Bool)
1466 }
1467 UnaryOp::Neg => {
1468 let t = self.infer_expr(env, expr)?;
1469 let t = self.ctx.apply(&t);
1470 if matches!(t, Ty::Float) {
1471 Ok(Ty::Float)
1472 } else if matches!(t, Ty::Int | Ty::UInt) {
1473 Ok(Ty::Int)
1474 } else {
1475 unify(&mut self.ctx, &t, &Ty::Int)?;
1476 Ok(Ty::Int)
1477 }
1478 }
1479 },
1480 ExprKind::Cast { expr: inner, ty } => self.infer_cast(env, expr.span, inner, ty),
1481 ExprKind::Binary { op, left, right } => self.infer_binary(env, *op, left, right),
1482 ExprKind::StructLit { name, fields } => self.check_struct_lit(env, name, fields),
1483 ExprKind::Bind { pat, value, .. } => {
1484 let ty = self.infer_value(env, value)?;
1485 let mut local = env.clone();
1486 self.infer_pat(&mut local, pat, &ty)?;
1487 Ok(Ty::Unit)
1488 }
1489 ExprKind::Pipe { left, right } => {
1490 let lt = self.infer_expr(env, left)?;
1491 let mut local = env.clone();
1492 let v = self.ctx.fresh();
1493 local.insert("_pipe".to_string(), scheme(v.clone()));
1494 unify(&mut self.ctx, <, &v)?;
1495 self.infer_expr(&mut local, right)
1496 }
1497 ExprKind::Return(Some(e)) => {
1498 self.infer_expr(env, e)?;
1499 Ok(Ty::Never)
1500 }
1501 ExprKind::Return(None) => Ok(Ty::Never),
1502 ExprKind::Try(inner) => {
1503 let t = self.infer_expr(env, inner)?;
1504 match self.ctx.apply(&t) {
1505 Ty::Option(inner) => Ok(*inner),
1506 other => {
1507 let fresh = self.ctx.fresh();
1508 unify(&mut self.ctx, &other, &Ty::Option(Box::new(fresh.clone())))?;
1509 Ok(self.ctx.apply(&fresh))
1510 }
1511 }
1512 }
1513 ExprKind::Catch { body, arms } => {
1514 let _ = self.infer_expr(env, body)?;
1515 let mut result = None;
1516 for arm in arms {
1517 let body_ty = self.infer_expr(env, &arm.body)?;
1518 result = Some(match result {
1519 None => body_ty,
1520 Some(prev) => {
1521 unify(&mut self.ctx, &prev, &body_ty)?;
1522 prev
1523 }
1524 });
1525 }
1526 Ok(result.unwrap_or(Ty::Unit))
1527 }
1528 ExprKind::Async(inner) => {
1529 let inner_ty = self.infer_expr(env, inner)?;
1530 Ok(Ty::Named {
1531 name: "Future".into(),
1532 args: vec![self.ctx.apply(&inner_ty)],
1533 })
1534 }
1535 ExprKind::Await(inner) => {
1536 let t = self.infer_expr(env, inner)?;
1537 match self.ctx.apply(&t) {
1538 Ty::Named { name, args } if name == "Future" && args.len() == 1 => {
1539 Ok(args[0].clone())
1540 }
1541 other => {
1542 let fresh = self.ctx.fresh();
1543 unify(
1544 &mut self.ctx,
1545 &other,
1546 &Ty::Named {
1547 name: "Future".into(),
1548 args: vec![fresh.clone()],
1549 },
1550 )?;
1551 Ok(self.ctx.apply(&fresh))
1552 }
1553 }
1554 }
1555 ExprKind::Unsafe(inner) => self.infer_expr(env, inner),
1556 ExprKind::Spawn(inner) => {
1557 self.infer_expr(env, inner)?;
1558 Ok(Ty::Named {
1559 name: "JoinHandle".into(),
1560 args: vec![],
1561 })
1562 }
1563 ExprKind::While { cond, body } => {
1564 let cty = self.infer_expr(env, cond)?;
1565 unify(&mut self.ctx, &cty, &Ty::Bool)?;
1566 self.infer_expr(env, body)?;
1567 Ok(Ty::Unit)
1568 }
1569 ExprKind::For { pat, iter, body } => {
1570 let iter_ty = self.infer_expr(env, iter)?;
1571 let elem = self.ctx.fresh();
1572 let vec_ty = vec_of(elem.clone());
1573 unify(&mut self.ctx, &iter_ty, &vec_ty)?;
1574 let item_ty = match self.ctx.apply(&iter_ty) {
1575 Ty::Named { name, args } if name == "vec" && args.len() == 1 => args[0].clone(),
1576 _ => self.ctx.apply(&elem),
1577 };
1578 let mut local = env.clone();
1579 self.infer_pat(&mut local, pat, &item_ty)?;
1580 self.infer_expr(&mut local, body)?;
1581 Ok(Ty::Unit)
1582 }
1583 ExprKind::Loop(body) => {
1584 let break_ty = self.ctx.fresh();
1585 self.loop_break_tys.push(break_ty.clone());
1586 let _ = self.infer_expr(env, body)?;
1587 self.loop_break_tys.pop();
1588 Ok(self.ctx.apply(&break_ty))
1589 }
1590 ExprKind::Break(value) => {
1591 let vt = if let Some(v) = value {
1592 self.infer_expr(env, v)?
1593 } else {
1594 Ty::Unit
1595 };
1596 if let Some(expected) = self.loop_break_tys.last().cloned() {
1597 unify(&mut self.ctx, &vt, &expected)?;
1598 }
1599 Ok(Ty::Never)
1600 }
1601 ExprKind::Continue => Ok(Ty::Never),
1602 ExprKind::Assign { target, value } => {
1603 let expected = self.lookup(env, &target.name, target.span)?;
1604 let got = self.infer_value(env, value)?;
1605 self.unify_checking(value, &got, &expected)
1606 .map_err(|e| TypeError::UnifyAt {
1607 message: e.to_string(),
1608 span: expr.span,
1609 })?;
1610 Ok(Ty::Unit)
1611 }
1612 ExprKind::Index { base, index } => {
1613 let elem = self.infer_index(env, base, index, expr.span)?;
1614 self.record_expr_ty(expr.span, elem.clone());
1615 Ok(elem)
1616 }
1617 ExprKind::IndexAssign { base, index, value } => {
1618 let elem = self.infer_index(env, base, index, expr.span)?;
1619 let got = self.infer_value(env, value)?;
1620 self.unify_checking(value, &got, &elem)
1621 .map_err(|e| TypeError::UnifyAt {
1622 message: e.to_string(),
1623 span: expr.span,
1624 })?;
1625 Ok(Ty::Unit)
1626 }
1627 ExprKind::Array(elems) => {
1628 let elem = self.ctx.fresh();
1629 for e in elems {
1630 let et = self.infer_expr(env, e)?;
1631 self.unify_checking(e, &et, &elem)?;
1632 }
1633 let ty = vec_of(self.ctx.apply(&elem));
1634 self.record_expr_ty(expr.span, ty.clone());
1635 Ok(ty)
1636 }
1637 _ => Ok(self.ctx.fresh()),
1638 }
1639 }
1640
1641 fn infer_binary(
1642 &mut self,
1643 env: &mut TypeEnv,
1644 op: BinaryOp,
1645 left: &Expr,
1646 right: &Expr,
1647 ) -> Result<Ty, TypeError> {
1648 let lt = self.infer_expr(env, left)?;
1649 let rt = self.infer_expr(env, right)?;
1650 match op {
1651 BinaryOp::Concat => {
1652 unify(&mut self.ctx, <, &Ty::Str)?;
1653 unify(&mut self.ctx, &rt, &Ty::StrSlice)?;
1654 Ok(Ty::Str)
1655 }
1656 BinaryOp::Mod => {
1657 unify(&mut self.ctx, <, &rt)?;
1658 unify(&mut self.ctx, <, &Ty::Int)?;
1659 Ok(Ty::Int)
1660 }
1661 BinaryOp::Add | BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div => {
1662 let l = self.ctx.apply(<);
1663 let r = self.ctx.apply(&rt);
1664 if matches!(l, Ty::Float) && matches!(r, Ty::Int | Ty::UInt) {
1665 self.record_int_to_float(right, false);
1666 return Ok(Ty::Float);
1667 }
1668 if matches!(r, Ty::Float) && matches!(l, Ty::Int | Ty::UInt) {
1669 self.record_int_to_float(left, false);
1670 return Ok(Ty::Float);
1671 }
1672 unify(&mut self.ctx, <, &rt)?;
1673 let t = self.ctx.apply(<);
1674 let r = self.ctx.apply(&rt);
1675 if matches!(t, Ty::Float) || matches!(r, Ty::Float) {
1676 unify(&mut self.ctx, &t, &Ty::Float)?;
1677 Ok(Ty::Float)
1678 } else if matches!(t, Ty::Int | Ty::UInt) || matches!(r, Ty::Int | Ty::UInt) {
1679 unify(&mut self.ctx, &t, &Ty::Int)?;
1680 Ok(Ty::Int)
1681 } else if let Some(op) = arith_trait_name(op) {
1682 self.record_arith(&t, op);
1683 Ok(t)
1684 } else {
1685 unify(&mut self.ctx, &t, &Ty::Int)?;
1686 Ok(Ty::Int)
1687 }
1688 }
1689 BinaryOp::Pow => {
1690 self.unify_checking(left, <, &Ty::Float)?;
1691 self.unify_checking(right, &rt, &Ty::Float)?;
1692 Ok(Ty::Float)
1693 }
1694 BinaryOp::Eq
1695 | BinaryOp::Ne
1696 | BinaryOp::Lt
1697 | BinaryOp::Le
1698 | BinaryOp::Gt
1699 | BinaryOp::Ge => {
1700 let l = self.ctx.apply(<);
1701 let r = self.ctx.apply(&rt);
1702 if matches!(l, Ty::Float) && matches!(r, Ty::Int | Ty::UInt) {
1703 self.record_int_to_float(right, false);
1704 return Ok(Ty::Bool);
1705 }
1706 if matches!(r, Ty::Float) && matches!(l, Ty::Int | Ty::UInt) {
1707 self.record_int_to_float(left, false);
1708 return Ok(Ty::Bool);
1709 }
1710 unify(&mut self.ctx, <, &rt)?;
1711 Ok(Ty::Bool)
1712 }
1713 BinaryOp::And | BinaryOp::Or => {
1714 unify(&mut self.ctx, <, &Ty::Bool)?;
1715 unify(&mut self.ctx, &rt, &Ty::Bool)?;
1716 Ok(Ty::Bool)
1717 }
1718 _ => Ok(self.ctx.fresh()),
1719 }
1720 }
1721
1722 fn infer_value(&mut self, env: &mut TypeEnv, expr: &Expr) -> Result<Ty, TypeError> {
1723 if count_holes(expr) > 0 {
1724 self.infer_hole_lambda(env, expr, None)
1725 } else {
1726 self.infer_expr(env, expr)
1727 }
1728 }
1729
1730 fn infer_call_arg(
1731 &mut self,
1732 env: &mut TypeEnv,
1733 arg: &Expr,
1734 expected: &Ty,
1735 ) -> Result<Ty, TypeError> {
1736 let expected = self.ctx.apply(expected);
1737 if count_holes(arg) > 0 {
1738 return self.infer_hole_lambda(env, arg, Some(&expected));
1739 }
1740 self.infer_expr(env, arg)
1741 }
1742
1743 fn infer_hole_lambda(
1744 &mut self,
1745 env: &mut TypeEnv,
1746 expr: &Expr,
1747 expected: Option<&Ty>,
1748 ) -> Result<Ty, TypeError> {
1749 let found = count_holes(expr);
1750 if found == 0 {
1751 return self.infer_expr(env, expr);
1752 }
1753 if let Some(exp) = expected {
1754 match self.ctx.apply(exp) {
1755 Ty::Fn { params, .. } if params.len() != found => {
1756 return Err(TypeError::HoleArity {
1757 expected: params.len(),
1758 found,
1759 span: expr.span,
1760 });
1761 }
1762 Ty::Fn { .. } => {}
1763 _ => return Err(TypeError::HoleMisplaced { span: expr.span }),
1764 }
1765 }
1766 let lifted = lift_holes(expr).expect("count_holes > 0");
1767 self.infer_expr(env, &lifted)
1768 }
1769
1770 fn infer_block(&mut self, env: &mut TypeEnv, block: &Block) -> Result<Ty, TypeError> {
1771 let mut local = env.clone();
1772 for stmt in &block.stmts {
1773 match stmt {
1774 Stmt::Bind { pat, value, .. } => {
1775 let ty = self.infer_value(&mut local, value)?;
1776 self.infer_pat(&mut local, pat, &ty)?;
1777 }
1778 Stmt::Assign { target, value } => {
1779 let expected = self.lookup(&local, &target.name, target.span)?;
1780 let got = self.infer_value(&mut local, value)?;
1781 self.unify_checking(value, &got, &expected)?;
1782 }
1783 Stmt::Expr(e) => {
1784 self.infer_expr(&mut local, e)?;
1785 }
1786 }
1787 }
1788 if let Some(tail) = &block.tail {
1789 self.infer_expr(&mut local, tail)
1790 } else {
1791 Ok(Ty::Unit)
1792 }
1793 }
1794
1795 fn infer_pat(&mut self, env: &mut TypeEnv, pat: &Pat, ty: &Ty) -> Result<(), TypeError> {
1796 match &pat.kind {
1797 PatKind::Wildcard => Ok(()),
1798 PatKind::Ident(id) => {
1799 env.insert(id.name.clone(), scheme(self.ctx.apply(ty)));
1801 Ok(())
1802 }
1803 PatKind::Tuple(pats) => {
1804 if let Ty::Tuple(ts) = self.ctx.apply(ty) {
1805 for (p, t) in pats.iter().zip(ts) {
1806 self.infer_pat(env, p, &t)?;
1807 }
1808 Ok(())
1809 } else {
1810 let vars: Vec<_> = (0..pats.len()).map(|_| self.ctx.fresh()).collect();
1811 unify(&mut self.ctx, ty, &Ty::Tuple(vars.clone()))?;
1812 for (p, t) in pats.iter().zip(vars) {
1813 self.infer_pat(env, p, &t)?;
1814 }
1815 Ok(())
1816 }
1817 }
1818 PatKind::Enum {
1819 name,
1820 variant,
1821 args,
1822 } => {
1823 let enum_ty = Ty::Named {
1824 name: name.name.clone(),
1825 args: vec![],
1826 };
1827 unify(&mut self.ctx, ty, &enum_ty)?;
1828 let Some(variants) = self.enums.get(&name.name) else {
1829 return Err(TypeError::UnknownType {
1830 name: name.name.clone(),
1831 span: name.span,
1832 });
1833 };
1834 let Some(payload) = variants.get(&variant.name) else {
1835 return Err(TypeError::UnknownName {
1836 name: format!("{}.{}", name.name, variant.name),
1837 span: variant.span,
1838 });
1839 };
1840 if args.len() != payload.len() {
1841 return Err(TypeError::Unify(UnifyError::Mismatch {
1842 expected: format!("{} payload fields", payload.len()),
1843 found: format!("{} pattern args", args.len()),
1844 }));
1845 }
1846 let payload = payload.clone();
1847 for (arg, field_ty) in args.iter().zip(payload) {
1848 self.infer_pat(env, arg, &field_ty)?;
1849 }
1850 Ok(())
1851 }
1852 _ => Ok(()),
1853 }
1854 }
1855
1856 fn check_struct_lit(
1857 &mut self,
1858 env: &mut TypeEnv,
1859 name: &Ident,
1860 fields: &[FieldInit],
1861 ) -> Result<Ty, TypeError> {
1862 let schema =
1863 self.structs
1864 .get(&name.name)
1865 .cloned()
1866 .ok_or_else(|| TypeError::UnknownType {
1867 name: name.name.clone(),
1868 span: name.span,
1869 })?;
1870 let gens = self
1871 .type_params
1872 .get(&name.name)
1873 .cloned()
1874 .unwrap_or_default();
1875 let subst: BTreeMap<String, Ty> =
1876 gens.iter().map(|g| (g.clone(), self.ctx.fresh())).collect();
1877 let schema: BTreeMap<String, Ty> = schema
1878 .iter()
1879 .map(|(k, v)| (k.clone(), subst_named_params(v, &subst)))
1880 .collect();
1881 let field_types: Vec<_> = fields
1882 .iter()
1883 .map(|field| {
1884 schema
1885 .get(&field.name.name)
1886 .cloned()
1887 .ok_or_else(|| TypeError::UnknownType {
1888 name: field.name.name.clone(),
1889 span: field.name.span,
1890 })
1891 })
1892 .collect::<Result<_, _>>()?;
1893 for (field, expected) in fields.iter().zip(field_types) {
1894 let got = self.infer_expr(env, &field.value)?;
1895 self.unify_checking(&field.value, &got, &expected)?;
1896 }
1897 let args: Vec<Ty> = gens
1898 .iter()
1899 .map(|g| self.ctx.apply(subst.get(g).expect("generic subst")))
1900 .collect();
1901 Ok(Ty::Named {
1902 name: name.name.clone(),
1903 args,
1904 })
1905 }
1906
1907 fn method_sig(&self, ty_name: &str, method: &str) -> Option<&InferredSig> {
1908 let key = self.inherent_methods.get(ty_name)?.get(method)?;
1909 self.signatures.get(key)
1910 }
1911
1912 fn try_infer_method_call(
1915 &mut self,
1916 env: &mut TypeEnv,
1917 base: &Expr,
1918 field: &Ident,
1919 args: &[Expr],
1920 ) -> Result<Option<Ty>, TypeError> {
1921 if let ExprKind::Ident(id) = &base.kind
1923 && self.structs.contains_key(&id.name)
1924 && !self.enums.contains_key(&id.name)
1925 && let Some(sig) = self.method_sig(&id.name, &field.name).cloned()
1926 {
1927 let has_self = sig
1928 .params
1929 .first()
1930 .map(|(n, _)| n == "self")
1931 .unwrap_or(false);
1932 if has_self {
1933 return Err(TypeError::Unify(UnifyError::Mismatch {
1934 expected: format!("instance method `{}.{}(self, …)`", id.name, field.name),
1935 found: "associated call on type name".into(),
1936 }));
1937 }
1938 if args.len() != sig.params.len() {
1939 return Err(TypeError::Unify(UnifyError::Mismatch {
1940 expected: format!("{} arguments", sig.params.len()),
1941 found: format!("{} arguments", args.len()),
1942 }));
1943 }
1944 for (arg, (_, pty)) in args.iter().zip(sig.params.iter()) {
1945 let aty = self.infer_expr(env, arg)?;
1946 self.unify_checking(arg, &aty, pty)?;
1947 }
1948 return Ok(Some(self.ctx.apply(&sig.ret)));
1949 }
1950
1951 let base_ty = self.infer_expr(env, base)?;
1953 let base_ty = self.ctx.apply(&base_ty);
1954 if self.is_bound_subject(&base_ty)
1955 && let Some(ret) = self.try_infer_bound_method(env, &base_ty, field, args)?
1956 {
1957 return Ok(Some(ret));
1958 }
1959
1960 let candidate_tys: Vec<String> = self
1961 .inherent_methods
1962 .iter()
1963 .filter_map(|(ty, methods)| {
1964 if methods.contains_key(&field.name) {
1965 Some(ty.clone())
1966 } else {
1967 None
1968 }
1969 })
1970 .collect();
1971 if candidate_tys.is_empty() {
1972 return Ok(None);
1973 }
1974
1975 let ty_name = match &base_ty {
1976 Ty::Named { name, .. } => name.clone(),
1977 Ty::Var(v) if candidate_tys.len() == 1 => {
1978 let name = candidate_tys[0].clone();
1979 unify(
1980 &mut self.ctx,
1981 &Ty::Var(*v),
1982 &Ty::Named {
1983 name: name.clone(),
1984 args: vec![],
1985 },
1986 )?;
1987 name
1988 }
1989 _ => return Ok(None),
1990 };
1991
1992 let Some(sig) = self.method_sig(&ty_name, &field.name).cloned() else {
1993 return Ok(None);
1994 };
1995 let has_self = sig
1996 .params
1997 .first()
1998 .map(|(n, _)| n == "self")
1999 .unwrap_or(false);
2000 if !has_self {
2001 return Ok(None);
2003 }
2004 let self_ty = Ty::Named {
2005 name: ty_name,
2006 args: vec![],
2007 };
2008 unify(&mut self.ctx, &base_ty, &self_ty)?;
2009 let param_tys: Vec<&Ty> = sig.params.iter().skip(1).map(|(_, t)| t).collect();
2010 if args.len() != param_tys.len() {
2011 return Err(TypeError::Unify(UnifyError::Mismatch {
2012 expected: format!("{} arguments", param_tys.len()),
2013 found: format!("{} arguments", args.len()),
2014 }));
2015 }
2016 for (arg, pty) in args.iter().zip(param_tys) {
2017 let aty = self.infer_expr(env, arg)?;
2018 self.unify_checking(arg, &aty, pty)?;
2019 }
2020 Ok(Some(self.ctx.apply(&sig.ret)))
2021 }
2022
2023 fn field_type(&mut self, base: &Ty, field: &str, span: Span) -> Result<Ty, TypeError> {
2024 let base = self.ctx.apply(base);
2025 if let Ty::Named { name, args } = &base
2026 && let Some(fields) = self.instantiate_schema(name, args)
2027 {
2028 return fields.get(field).cloned().ok_or(TypeError::UnknownType {
2029 name: field.to_string(),
2030 span,
2031 });
2032 }
2033 if let Ty::Var(v) = base {
2037 let mut candidates: Vec<(&String, &Ty)> = self
2038 .structs
2039 .iter()
2040 .filter(|(name, _)| !self.shapes.contains(*name))
2041 .filter_map(|(name, fields)| fields.get(field).map(|ty| (name, ty)))
2042 .collect();
2043 candidates.sort_by(|a, b| a.0.cmp(b.0));
2044 match candidates.as_slice() {
2045 [(name, field_ty)] => {
2046 unify(
2047 &mut self.ctx,
2048 &Ty::Var(v),
2049 &Ty::Named {
2050 name: (*name).clone(),
2051 args: vec![],
2052 },
2053 )?;
2054 return Ok((*field_ty).clone());
2055 }
2056 [] => {}
2057 many => {
2058 let names = many
2059 .iter()
2060 .map(|(n, _)| n.as_str())
2061 .collect::<Vec<_>>()
2062 .join(", ");
2063 return Err(TypeError::AmbiguousField {
2064 field: field.to_string(),
2065 candidates: names,
2066 span,
2067 });
2068 }
2069 }
2070 }
2071 Err(TypeError::UnknownType {
2072 name: field.to_string(),
2073 span,
2074 })
2075 }
2076
2077 fn is_int_literal(expr: &Expr) -> bool {
2078 match &expr.kind {
2079 ExprKind::Int(_) => true,
2080 ExprKind::Unary {
2081 op: UnaryOp::Neg,
2082 expr,
2083 } => Self::is_int_literal(expr),
2084 _ => false,
2085 }
2086 }
2087
2088 fn record_int_to_float(&mut self, expr: &Expr, explicit: bool) {
2089 let literal = Self::is_int_literal(expr);
2090 self.coercions.push(NumericCoercion {
2091 span: expr.span,
2092 literal,
2093 explicit,
2094 to_float: true,
2095 });
2096 if !literal && !explicit {
2097 self.warnings
2098 .push(TypeWarning::IntToFloat { span: expr.span });
2099 }
2100 }
2101
2102 fn unify_checking(&mut self, expr: &Expr, got: &Ty, expected: &Ty) -> Result<(), TypeError> {
2103 let got = self.ctx.apply(got);
2104 let expected = self.ctx.apply(expected);
2105 if matches!(expected, Ty::Float) && matches!(got, Ty::Int | Ty::UInt) {
2106 self.record_int_to_float(expr, false);
2107 return Ok(());
2108 }
2109 unify(&mut self.ctx, &got, &expected)?;
2110 Ok(())
2111 }
2112
2113 fn unify_or_shape_checking(
2114 &mut self,
2115 expr: &Expr,
2116 actual: &Ty,
2117 expected: &Ty,
2118 ) -> Result<(), TypeError> {
2119 let got = self.ctx.apply(actual);
2120 let expected_ty = self.ctx.apply(expected);
2121 if matches!(expected_ty, Ty::Float) && matches!(got, Ty::Int | Ty::UInt) {
2122 self.record_int_to_float(expr, false);
2123 return Ok(());
2124 }
2125 self.unify_or_shape(actual, expected)
2126 }
2127
2128 fn infer_cast(
2129 &mut self,
2130 env: &mut TypeEnv,
2131 span: Span,
2132 inner: &Expr,
2133 ty: &Type,
2134 ) -> Result<Ty, TypeError> {
2135 let from = self.infer_expr(env, inner)?;
2136 let to = self.ast_type(ty)?;
2137 let from = self.ctx.apply(&from);
2138 let to = self.ctx.apply(&to);
2139 match (&from, &to) {
2140 (Ty::Int | Ty::UInt | Ty::Float, Ty::Float) => {
2141 if matches!(from, Ty::Int | Ty::UInt) {
2142 self.record_int_to_float(inner, true);
2143 }
2144 Ok(Ty::Float)
2145 }
2146 (Ty::Int | Ty::UInt | Ty::Float, Ty::Int) => {
2147 if matches!(from, Ty::Float) {
2148 self.coercions.push(NumericCoercion {
2149 span: inner.span,
2150 literal: false,
2151 explicit: true,
2152 to_float: false,
2153 });
2154 }
2155 Ok(Ty::Int)
2156 }
2157 _ => Err(TypeError::InvalidCast {
2158 from: format_ty(&from),
2159 to: format_ty(&to),
2160 span,
2161 }),
2162 }
2163 }
2164
2165 fn unify_or_shape(&mut self, actual: &Ty, expected: &Ty) -> Result<(), TypeError> {
2167 let expected = self.ctx.apply(expected);
2168 if let Ty::Named { name, args } = &expected
2169 && self.shapes.contains(name)
2170 {
2171 return self.check_shape_arg(actual, name, args);
2172 }
2173 unify(&mut self.ctx, actual, &expected)?;
2174 Ok(())
2175 }
2176
2177 fn check_shape_arg(
2178 &mut self,
2179 actual: &Ty,
2180 shape_name: &str,
2181 shape_args: &[Ty],
2182 ) -> Result<(), TypeError> {
2183 let actual = self.ctx.apply(actual);
2184 let Some(shape_fields) = self.instantiate_schema(shape_name, shape_args) else {
2185 return Err(TypeError::UnknownType {
2186 name: shape_name.to_string(),
2187 span: Span::new(0, 0),
2188 });
2189 };
2190 match &actual {
2191 Ty::Named { name, args } if name == shape_name => {
2192 if args.len() == shape_args.len() {
2193 for (a, b) in args.iter().zip(shape_args) {
2194 unify(&mut self.ctx, a, b)?;
2195 }
2196 }
2197 Ok(())
2198 }
2199 Ty::Named { name, args } => {
2200 let Some(fields) = self.instantiate_schema(name, args) else {
2201 return Err(TypeError::Unify(UnifyError::Mismatch {
2202 expected: format!("type satisfying shape `{shape_name}`"),
2203 found: name.clone(),
2204 }));
2205 };
2206 for (fname, fty) in &shape_fields {
2207 let Some(aty) = fields.get(fname) else {
2208 return Err(TypeError::Unify(UnifyError::Mismatch {
2209 expected: format!("shape `{shape_name}` (field `{fname}: {fty:?}`)"),
2210 found: name.clone(),
2211 }));
2212 };
2213 unify(&mut self.ctx, aty, fty).map_err(|err| {
2214 TypeError::Unify(UnifyError::Mismatch {
2215 expected: format!("shape `{shape_name}` (field `{fname}: {fty:?}`)"),
2216 found: format!("{name} ({err})"),
2217 })
2218 })?;
2219 }
2220 Ok(())
2221 }
2222 other => Err(TypeError::Unify(UnifyError::Mismatch {
2223 expected: format!("type satisfying shape `{shape_name}`"),
2224 found: format!("{other:?}"),
2225 })),
2226 }
2227 }
2228
2229 fn lookup(&mut self, env: &TypeEnv, name: &str, span: Span) -> Result<Ty, TypeError> {
2230 let scheme = env
2231 .get(name)
2232 .or_else(|| self.imported.get(name))
2233 .or_else(|| {
2234 let q = format!("{}::{name}", self.current_module);
2235 env.get(&q).or_else(|| self.env.get(&q))
2236 })
2237 .ok_or_else(|| TypeError::UnknownName {
2238 name: name.to_string(),
2239 span,
2240 })?;
2241 Ok(instantiate(&mut self.ctx, scheme))
2242 }
2243
2244 fn infer_index(
2245 &mut self,
2246 env: &mut TypeEnv,
2247 base: &Expr,
2248 index: &Expr,
2249 span: Span,
2250 ) -> Result<Ty, TypeError> {
2251 let bt = self.infer_expr(env, base)?;
2252 let it = self.infer_expr(env, index)?;
2253 unify(&mut self.ctx, &it, &Ty::Int).map_err(|e| TypeError::UnifyAt {
2254 message: e.to_string(),
2255 span: index.span,
2256 })?;
2257 let elem = self.ctx.fresh();
2258 self.unify_checking(base, &bt, &vec_of(elem.clone()))
2259 .map_err(|e| TypeError::UnifyAt {
2260 message: e.to_string(),
2261 span,
2262 })?;
2263 Ok(match self.ctx.apply(&bt) {
2264 Ty::Named { name, args } if name == "vec" && args.len() == 1 => args[0].clone(),
2265 _ => self.ctx.apply(&elem),
2266 })
2267 }
2268
2269 fn record_expr_ty(&mut self, span: Span, ty: Ty) {
2270 if matches!(&ty, Ty::Named { name, .. } if name == "vec") {
2271 self.fn_vec_tys.push((span, ty.clone()));
2272 }
2273 self.expr_tys.insert(span, ty);
2274 }
2275
2276 fn name_expr_ty_vars(&mut self, vars: &[u32], names: &[String]) {
2279 for ty in self.expr_tys.values_mut() {
2280 *ty = self.ctx.apply(ty);
2281 for (v, name) in vars.iter().zip(names) {
2282 *ty = substitute_var(
2283 ty,
2284 *v,
2285 &Ty::Named {
2286 name: name.clone(),
2287 args: vec![],
2288 },
2289 );
2290 }
2291 }
2292 }
2293
2294 fn reject_uninferred_vec(&mut self, gens: &[String]) -> Result<(), TypeError> {
2295 let pending = std::mem::take(&mut self.fn_vec_tys);
2296 if !gens.is_empty() {
2297 return Ok(());
2298 }
2299 for (span, ty) in pending {
2300 let t = self.ctx.apply(&ty);
2301 if vec_elem_uninferred(&t) {
2302 return Err(TypeError::UninferredVec { span });
2303 }
2304 }
2305 Ok(())
2306 }
2307
2308 fn record_arith(&mut self, ty: &Ty, op: &str) {
2309 self.record_bound(ty, op);
2310 }
2311
2312 fn record_bound(&mut self, ty: &Ty, bound: &str) {
2313 match self.ctx.apply(ty) {
2314 Ty::Named { name, args } if args.is_empty() => {
2315 self.arith_named
2316 .entry(name)
2317 .or_default()
2318 .insert(bound.into());
2319 }
2320 Ty::Var(v) => {
2321 self.arith_vars.entry(v).or_default().insert(bound.into());
2322 }
2323 _ => {}
2324 }
2325 }
2326
2327 fn take_op_bounds(&mut self, pre_ty: &Ty, gens: &[String]) -> BTreeMap<String, Vec<String>> {
2328 let mut named = std::mem::take(&mut self.arith_named);
2329 let vars = std::mem::take(&mut self.arith_vars);
2330 let mut applied_vars: BTreeMap<u32, BTreeSet<String>> = BTreeMap::new();
2331 for (v, ops) in vars {
2333 match self.ctx.apply(&Ty::Var(v)) {
2334 Ty::Named { name, args } if args.is_empty() => {
2335 named.entry(name).or_default().extend(ops);
2336 }
2337 Ty::Var(w) => {
2338 applied_vars.entry(w).or_default().extend(ops);
2339 }
2340 _ => {}
2341 }
2342 }
2343 let mut free = Vec::new();
2344 collect_free_vars(pre_ty, &mut free);
2345 free.sort_unstable();
2346 free.dedup();
2347 for (i, v) in free.iter().enumerate() {
2348 if let Some(ops) = applied_vars.get(v) {
2349 named
2350 .entry(generic_name(i))
2351 .or_default()
2352 .extend(ops.iter().cloned());
2353 }
2354 }
2355 let mut out = BTreeMap::new();
2356 for g in gens {
2357 if let Some(ops) = named.remove(g) {
2358 let mut list: Vec<String> = ops.into_iter().collect();
2359 list.sort();
2360 out.insert(g.clone(), list);
2361 }
2362 }
2363 out
2364 }
2365
2366 fn is_bound_subject(&self, ty: &Ty) -> bool {
2367 match ty {
2368 Ty::Var(_) => true,
2369 Ty::Named { name, args } if args.is_empty() => self.generic_params.contains_key(name),
2370 _ => false,
2371 }
2372 }
2373
2374 fn try_infer_bound_method(
2375 &mut self,
2376 env: &mut TypeEnv,
2377 base_ty: &Ty,
2378 field: &Ident,
2379 args: &[Expr],
2380 ) -> Result<Option<Ty>, TypeError> {
2381 let mut candidates: Vec<String> = self
2382 .traits
2383 .iter()
2384 .filter(|(name, methods)| {
2385 methods.contains_key(&field.name)
2386 && self
2387 .trait_generics
2388 .get(*name)
2389 .map(|g| g.is_empty())
2390 .unwrap_or(true)
2391 })
2392 .map(|(name, _)| name.clone())
2393 .collect();
2394 candidates.sort();
2395 match candidates.as_slice() {
2396 [] => Ok(None),
2397 [trait_name] => {
2398 let stub = self
2399 .traits
2400 .get(trait_name)
2401 .and_then(|m| m.get(&field.name))
2402 .cloned()
2403 .ok_or_else(|| TypeError::UnknownName {
2404 name: field.name.clone(),
2405 span: field.span,
2406 })?;
2407 self.record_bound(base_ty, trait_name);
2408 let param_tys: Vec<Ty> = stub
2409 .params
2410 .iter()
2411 .skip(1)
2412 .map(|(_, t)| t.clone().unwrap_or_else(|| base_ty.clone()))
2413 .collect();
2414 if args.len() != param_tys.len() {
2415 return Err(TypeError::Unify(UnifyError::Mismatch {
2416 expected: format!("{} arguments", param_tys.len()),
2417 found: format!("{} arguments", args.len()),
2418 }));
2419 }
2420 for (arg, pty) in args.iter().zip(param_tys.iter()) {
2421 let aty = self.infer_expr(env, arg)?;
2422 unify(&mut self.ctx, &aty, pty)?;
2423 }
2424 Ok(Some(stub.ret.unwrap_or_else(|| base_ty.clone())))
2425 }
2426 many => Err(TypeError::Unify(UnifyError::Mismatch {
2427 expected: format!("unique trait providing `{}`", field.name),
2428 found: many.join(", "),
2429 })),
2430 }
2431 }
2432
2433 fn free_fn_sig(&self, name: &str) -> Option<&InferredSig> {
2434 let q = format!("{}::{name}", self.current_module);
2435 if let Some(s) = self.signatures.get(&q).filter(|s| s.impl_ty.is_none()) {
2436 return Some(s);
2437 }
2438 self.signatures
2439 .values()
2440 .find(|s| s.name == name && s.impl_ty.is_none())
2441 }
2442
2443 fn propagate_callee_bounds(&mut self, fname: &str, applied: &[Ty]) {
2444 let Some(sig) = self.free_fn_sig(fname) else {
2445 return;
2446 };
2447 if sig.op_bounds.is_empty() {
2448 return;
2449 }
2450 let bounds = sig.op_bounds.clone();
2451 let gens = sig.generics.clone();
2452 let params = sig.params.clone();
2453 let mut subst = BTreeMap::new();
2454 for ((_, scheme_ty), inst_ty) in params.iter().zip(applied.iter()) {
2455 collect_generic_subst(scheme_ty, inst_ty, &gens, &mut subst);
2456 }
2457 for (g, bs) in &bounds {
2458 if let Some(ty) = subst.get(g) {
2459 for b in bs {
2460 self.record_bound(ty, b);
2461 }
2462 }
2463 }
2464 }
2465
2466 fn check_instantiation_bounds(
2467 &self,
2468 insts: &BTreeMap<String, Vec<CallInst>>,
2469 ) -> Result<(), TypeError> {
2470 for (fname, uses) in insts {
2471 let Some(sig) = self
2472 .signatures
2473 .get(fname)
2474 .or_else(|| self.free_fn_sig(fname))
2475 else {
2476 continue;
2477 };
2478 if sig.op_bounds.is_empty() || sig.generics.is_empty() {
2479 continue;
2480 }
2481 for use_site in uses {
2482 let mut subst = BTreeMap::new();
2483 for ((_, scheme_ty), inst_ty) in sig.params.iter().zip(use_site.args.iter()) {
2484 collect_generic_subst(scheme_ty, inst_ty, &sig.generics, &mut subst);
2485 }
2486 for g in &sig.generics {
2487 let Some(bounds) = sig.op_bounds.get(g) else {
2488 continue;
2489 };
2490 let Some(ty) = subst.get(g) else {
2491 continue;
2492 };
2493 if !self.ty_is_checkable(ty) {
2494 continue;
2495 }
2496 for bound in bounds {
2497 if !self.ty_implements(ty, bound) {
2498 return Err(TypeError::UnsatisfiedBound {
2499 func: fname.clone(),
2500 ty: format_ty(ty),
2501 bound: bound.clone(),
2502 span: use_site.span,
2503 });
2504 }
2505 }
2506 }
2507 }
2508 }
2509 Ok(())
2510 }
2511
2512 fn ty_is_checkable(&self, ty: &Ty) -> bool {
2513 match ty {
2514 Ty::Int
2515 | Ty::UInt
2516 | Ty::Float
2517 | Ty::Bool
2518 | Ty::Char
2519 | Ty::Str
2520 | Ty::StrSlice
2521 | Ty::Unit
2522 | Ty::Never => true,
2523 Ty::Named { name, args } => {
2524 (self.structs.contains_key(name) || self.enums.contains_key(name))
2525 && !self.shapes.contains(name)
2526 && args.iter().all(|a| self.ty_is_checkable(a))
2527 }
2528 Ty::Option(inner) | Ty::Slice(inner) | Ty::Ref { inner, .. } => {
2529 self.ty_is_checkable(inner)
2530 }
2531 Ty::Tuple(ts) => ts.iter().all(|t| self.ty_is_checkable(t)),
2532 _ => false,
2533 }
2534 }
2535
2536 fn ty_implements(&self, ty: &Ty, bound: &str) -> bool {
2537 if is_arith_bound(bound) {
2538 return matches!(ty, Ty::Int | Ty::UInt | Ty::Float);
2539 }
2540 match ty {
2541 Ty::Named { name, args } if args.is_empty() => self
2542 .trait_impls
2543 .get(name)
2544 .is_some_and(|s| s.contains(bound)),
2545 _ => false,
2546 }
2547 }
2548
2549 fn bind_rigid_generics(&mut self, gens: &[String]) -> BTreeMap<String, Ty> {
2550 let saved = self.generic_params.clone();
2551 for g in gens {
2552 self.generic_params.insert(
2553 g.clone(),
2554 Ty::Named {
2555 name: g.clone(),
2556 args: vec![],
2557 },
2558 );
2559 }
2560 saved
2561 }
2562
2563 fn instantiate_schema(&self, name: &str, args: &[Ty]) -> Option<BTreeMap<String, Ty>> {
2564 let fields = self.structs.get(name)?.clone();
2565 let Some(gens) = self.type_params.get(name) else {
2566 return Some(fields);
2567 };
2568 if args.len() != gens.len() {
2569 return Some(fields);
2570 }
2571 let subst: BTreeMap<String, Ty> = gens.iter().cloned().zip(args.iter().cloned()).collect();
2572 Some(
2573 fields
2574 .iter()
2575 .map(|(k, v)| (k.clone(), subst_named_params(v, &subst)))
2576 .collect(),
2577 )
2578 }
2579
2580 fn impl_trait_key(module: &str, trait_name: &str, ty_name: &str) -> String {
2581 format!("{module}::{trait_name} for {ty_name}")
2582 }
2583
2584 fn impl_trait_subst(
2585 &mut self,
2586 module: &str,
2587 ib: &ImplBlock,
2588 ty_name: &str,
2589 ) -> Result<BTreeMap<String, Ty>, TypeError> {
2590 let Some(tn) = &ib.trait_name else {
2591 return Ok(BTreeMap::new());
2592 };
2593 let gens = self
2594 .trait_generics
2595 .get(&tn.name)
2596 .cloned()
2597 .unwrap_or_default();
2598 if gens.is_empty() {
2599 return Ok(BTreeMap::new());
2600 }
2601 if ib.trait_args.is_empty() {
2602 let mut subst = BTreeMap::new();
2603 let mut fresh = Vec::new();
2604 for g in &gens {
2605 let v = self.ctx.fresh();
2606 subst.insert(g.clone(), v.clone());
2607 fresh.push(v);
2608 }
2609 self.impl_trait_fresh
2610 .insert(Self::impl_trait_key(module, &tn.name, ty_name), fresh);
2611 return Ok(subst);
2612 }
2613 self.trait_arg_subst(&tn.name, &ib.trait_args)
2614 }
2615
2616 fn finalize_impl_trait_args(
2617 &mut self,
2618 module: &str,
2619 ib: &ImplBlock,
2620 ty_name: &str,
2621 ) -> Result<(), TypeError> {
2622 let Some(tn) = &ib.trait_name else {
2623 return Ok(());
2624 };
2625 let key = Self::impl_trait_key(module, &tn.name, ty_name);
2626 let Some(fresh) = self.impl_trait_fresh.remove(&key) else {
2627 return Ok(());
2628 };
2629 let mut args = Vec::new();
2630 for t in fresh {
2631 let applied = self.ctx.apply(&t);
2632 if matches!(applied, Ty::Var(_)) {
2633 return Err(TypeError::UnknownType {
2634 name: format!(
2635 "cannot infer `{}` type arguments for `{ty_name}`; write `impl {}<...> for {ty_name}`",
2636 tn.name, tn.name
2637 ),
2638 span: ib.span,
2639 });
2640 }
2641 args.push(applied);
2642 }
2643 self.impl_trait_args.insert(key, args);
2644 Ok(())
2645 }
2646
2647 fn trait_arg_subst(
2648 &mut self,
2649 trait_name: &str,
2650 args: &[Type],
2651 ) -> Result<BTreeMap<String, Ty>, TypeError> {
2652 let Some(gens) = self.trait_generics.get(trait_name).cloned() else {
2653 return Ok(BTreeMap::new());
2654 };
2655 if gens.is_empty() || args.is_empty() {
2656 return Ok(BTreeMap::new());
2657 }
2658 let mut subst = BTreeMap::new();
2659 for (g, ast_ty) in gens.iter().zip(args.iter()) {
2660 subst.insert(g.clone(), self.ast_type(ast_ty)?);
2661 }
2662 Ok(subst)
2663 }
2664
2665 fn ast_type(&mut self, ty: &Type) -> Result<Ty, TypeError> {
2666 match &ty.kind {
2667 TypeKind::Named(id) => {
2668 if let Some(bound) = self.generic_params.get(&id.name) {
2669 return Ok(bound.clone());
2670 }
2671 match id.name.as_str() {
2672 "Never" => Ok(Ty::Never),
2673 "()" => Ok(Ty::Unit),
2674 "int" => Ok(Ty::Int),
2675 "uint" => Ok(Ty::UInt),
2676 "float" => Ok(Ty::Float),
2677 "bool" => Ok(Ty::Bool),
2678 "char" => Ok(Ty::Char),
2679 "str" => Ok(Ty::Str),
2680 other => Ok(Ty::Named {
2681 name: other.to_string(),
2682 args: vec![],
2683 }),
2684 }
2685 }
2686 TypeKind::Never => Ok(Ty::Never),
2687 TypeKind::Unit => Ok(Ty::Unit),
2688 TypeKind::Option(inner) => Ok(Ty::Option(Box::new(self.ast_type(inner)?))),
2689 TypeKind::Ref { mutable, inner } => Ok(Ty::Ref {
2690 mutable: *mutable,
2691 inner: Box::new(self.ast_type(inner)?),
2692 }),
2693 TypeKind::Tuple(ts) => Ok(Ty::Tuple(
2694 ts.iter()
2695 .map(|t| self.ast_type(t))
2696 .collect::<Result<_, _>>()?,
2697 )),
2698 TypeKind::Array { elem, len } => Ok(Ty::Array {
2699 elem: Box::new(self.ast_type(elem)?),
2700 len: *len,
2701 }),
2702 TypeKind::Slice(inner) => Ok(Ty::Slice(Box::new(self.ast_type(inner)?))),
2703 TypeKind::Fn { params, ret } => Ok(Ty::Fn {
2704 params: params
2705 .iter()
2706 .map(|p| self.ast_type(p))
2707 .collect::<Result<_, _>>()?,
2708 ret: Box::new(self.ast_type(ret)?),
2709 }),
2710 TypeKind::Generic { base, args } => {
2711 let base_ty = self.ast_type(base)?;
2712 if let Ty::Named { name, .. } = base_ty {
2713 Ok(Ty::Named {
2714 name,
2715 args: args
2716 .iter()
2717 .map(|a| self.ast_type(a))
2718 .collect::<Result<_, _>>()?,
2719 })
2720 } else {
2721 Ok(base_ty)
2722 }
2723 }
2724 TypeKind::Constrained { inner, .. } => self.ast_type(inner),
2725 }
2726 }
2727}
2728
2729fn arith_trait_name(op: BinaryOp) -> Option<&'static str> {
2730 match op {
2731 BinaryOp::Add => Some("Add"),
2732 BinaryOp::Sub => Some("Sub"),
2733 BinaryOp::Mul => Some("Mul"),
2734 BinaryOp::Div => Some("Div"),
2735 _ => None,
2736 }
2737}
2738
2739fn subst_named_params(ty: &Ty, subst: &BTreeMap<String, Ty>) -> Ty {
2740 match ty {
2741 Ty::Named { name, args } if args.is_empty() => {
2742 subst.get(name).cloned().unwrap_or_else(|| ty.clone())
2743 }
2744 Ty::Named { name, args } => Ty::Named {
2745 name: name.clone(),
2746 args: args.iter().map(|a| subst_named_params(a, subst)).collect(),
2747 },
2748 Ty::Fn { params, ret } => Ty::Fn {
2749 params: params
2750 .iter()
2751 .map(|p| subst_named_params(p, subst))
2752 .collect(),
2753 ret: Box::new(subst_named_params(ret, subst)),
2754 },
2755 Ty::Option(inner) => Ty::Option(Box::new(subst_named_params(inner, subst))),
2756 Ty::Slice(inner) => Ty::Slice(Box::new(subst_named_params(inner, subst))),
2757 Ty::Array { elem, len } => Ty::Array {
2758 elem: Box::new(subst_named_params(elem, subst)),
2759 len: *len,
2760 },
2761 Ty::Ref { mutable, inner } => Ty::Ref {
2762 mutable: *mutable,
2763 inner: Box::new(subst_named_params(inner, subst)),
2764 },
2765 Ty::Tuple(ts) => Ty::Tuple(ts.iter().map(|t| subst_named_params(t, subst)).collect()),
2766 other => other.clone(),
2767 }
2768}
2769
2770fn ty_is_ground(ty: &Ty) -> bool {
2771 let mut vars = Vec::new();
2772 collect_free_vars(ty, &mut vars);
2773 vars.is_empty()
2774}
2775
2776fn collect_generic_subst(scheme: &Ty, inst: &Ty, gens: &[String], out: &mut BTreeMap<String, Ty>) {
2777 match (scheme, inst) {
2778 (Ty::Named { name, args }, inst) if args.is_empty() && gens.iter().any(|g| g == name) => {
2779 out.entry(name.clone()).or_insert_with(|| inst.clone());
2780 }
2781 (Ty::Named { name: n1, args: a1 }, Ty::Named { name: n2, args: a2 })
2782 if n1 == n2 && a1.len() == a2.len() =>
2783 {
2784 for (s, i) in a1.iter().zip(a2.iter()) {
2785 collect_generic_subst(s, i, gens, out);
2786 }
2787 }
2788 (
2789 Ty::Fn {
2790 params: p1,
2791 ret: r1,
2792 },
2793 Ty::Fn {
2794 params: p2,
2795 ret: r2,
2796 },
2797 ) if p1.len() == p2.len() => {
2798 for (s, i) in p1.iter().zip(p2.iter()) {
2799 collect_generic_subst(s, i, gens, out);
2800 }
2801 collect_generic_subst(r1, r2, gens, out);
2802 }
2803 (Ty::Option(a), Ty::Option(b)) | (Ty::Slice(a), Ty::Slice(b)) => {
2804 collect_generic_subst(a, b, gens, out);
2805 }
2806 (Ty::Array { elem: a, .. }, Ty::Array { elem: b, .. }) => {
2807 collect_generic_subst(a, b, gens, out);
2808 }
2809 (Ty::Ref { inner: a, .. }, Ty::Ref { inner: b, .. }) => {
2810 collect_generic_subst(a, b, gens, out);
2811 }
2812 (Ty::Tuple(a), Ty::Tuple(b)) if a.len() == b.len() => {
2813 for (s, i) in a.iter().zip(b.iter()) {
2814 collect_generic_subst(s, i, gens, out);
2815 }
2816 }
2817 _ => {}
2818 }
2819}
2820
2821fn generic_name(i: usize) -> String {
2822 match i {
2823 0 => "T".into(),
2824 1 => "U".into(),
2825 2 => "V".into(),
2826 3 => "W".into(),
2827 n => format!("T{n}"),
2828 }
2829}
2830
2831fn name_free_vars(ty: &Ty) -> (Ty, Vec<String>) {
2832 let mut vars = Vec::new();
2833 collect_free_vars(ty, &mut vars);
2834 vars.sort_unstable();
2835 vars.dedup();
2836 name_vars(ty, &vars)
2837}
2838
2839fn name_vars(ty: &Ty, vars: &[u32]) -> (Ty, Vec<String>) {
2840 let mut vars = vars.to_vec();
2841 vars.sort_unstable();
2842 vars.dedup();
2843 if vars.is_empty() {
2844 return (ty.clone(), Vec::new());
2845 }
2846 let names: Vec<String> = vars
2847 .iter()
2848 .enumerate()
2849 .map(|(i, _)| generic_name(i))
2850 .collect();
2851 let mut named = ty.clone();
2852 for (v, name) in vars.iter().zip(&names) {
2853 named = substitute_var(
2854 &named,
2855 *v,
2856 &Ty::Named {
2857 name: name.clone(),
2858 args: vec![],
2859 },
2860 );
2861 }
2862 (named, names)
2863}
2864
2865fn generalize_named_params(ty: &Ty, gens: &[String], ctx: &mut InferContext) -> Scheme {
2866 if gens.is_empty() {
2867 return scheme(ty.clone());
2868 }
2869 let mut subst = BTreeMap::new();
2870 let mut vars = Vec::new();
2871 for g in gens {
2872 let fresh = ctx.fresh();
2873 if let Ty::Var(v) = &fresh {
2874 vars.push(*v);
2875 }
2876 subst.insert(g.clone(), fresh);
2877 }
2878 Scheme {
2879 vars,
2880 ty: subst_named_params(ty, &subst),
2881 }
2882}
2883
2884fn vec_of(elem: Ty) -> Ty {
2885 Ty::Named {
2886 name: "vec".into(),
2887 args: vec![elem],
2888 }
2889}
2890
2891fn vec_elem_uninferred(ty: &Ty) -> bool {
2892 matches!(
2893 ty,
2894 Ty::Named { name, args }
2895 if name == "vec"
2896 && (args.is_empty() || matches!(args.first(), Some(Ty::Var(_))))
2897 )
2898}
2899
2900fn float_unop() -> Ty {
2901 Ty::Fn {
2902 params: vec![Ty::Float],
2903 ret: Box::new(Ty::Float),
2904 }
2905}
2906
2907fn stdlib_fn_types() -> Vec<(&'static str, Ty)> {
2908 vec![
2909 (
2910 "read_to_string",
2911 Ty::Fn {
2912 params: vec![Ty::StrSlice],
2913 ret: Box::new(Ty::Str),
2914 },
2915 ),
2916 (
2917 "sleep_ms",
2918 Ty::Fn {
2919 params: vec![Ty::Int],
2920 ret: Box::new(Ty::Unit),
2921 },
2922 ),
2923 (
2924 "parse_ip",
2925 Ty::Fn {
2926 params: vec![Ty::Str],
2927 ret: Box::new(Ty::Str),
2928 },
2929 ),
2930 ("exp", float_unop()),
2931 ("sin", float_unop()),
2932 ("cos", float_unop()),
2933 ("tanh", float_unop()),
2934 ("sqrt", float_unop()),
2935 ]
2936}
2937
2938fn rust_import_fn_type(crate_name: &str, item: &str) -> Option<(Vec<Ty>, Ty)> {
2940 let json_value = Ty::Named {
2941 name: "serde_json::Value".into(),
2942 args: vec![],
2943 };
2944 match (crate_name, item) {
2945 ("serde_json", "from_str") => Some((vec![Ty::Str], json_value)),
2946 ("serde_json", "to_string" | "to_string_pretty" | "to_vec") => {
2947 Some((vec![json_value], Ty::Str))
2948 }
2949 ("serde_json", "from_value") => Some((vec![json_value.clone()], json_value)),
2950 ("serde_json", "Value") => Some((vec![], json_value)),
2952 ("ureq", "get") => Some((vec![Ty::Str], Ty::Str)),
2953 _ => None,
2954 }
2955}
2956
2957fn rust_extern_scalar_ok(ty: &Ty) -> bool {
2958 matches!(
2959 ty,
2960 Ty::Float | Ty::Int | Ty::UInt | Ty::Bool | Ty::Str | Ty::StrSlice | Ty::Unit
2961 )
2962}
2963
2964pub fn rust_import_returns_result(crate_name: &str, item: &str) -> bool {
2967 matches!(
2968 (crate_name, item),
2969 (
2970 "serde_json",
2971 "from_str" | "to_string" | "to_string_pretty" | "to_vec" | "from_value"
2972 ) | ("ureq", "get")
2973 )
2974}