1use std::collections::{BTreeMap, BTreeSet, HashMap};
9
10use yulang_typed_ir as typed_ir;
11
12use crate::diagnostic::{RuntimeError, RuntimeResult, TypeSource};
13use crate::ir::{
14 Binding, Expr, ExprKind, HandleArm, HandleEffect, MatchArm, Module, Pattern, RecordSpreadExpr,
15 RecordSpreadPattern, ResumeBinding, Root, Stmt, Type as RuntimeType, TypeInstantiation,
16};
17use crate::types::{
18 BoundsChoice, choose_bounds_type, collect_type_vars, core_types_compatible,
19 diagnostic_core_type, effect_compatible, is_qualified_runtime_path,
20 project_runtime_hir_type_with_vars, runtime_core_type, runtime_type_contains_unknown,
21 strict_core_type as core_type,
22};
23
24mod expr;
25mod helpers;
26mod pattern;
27mod types;
28
29use expr::*;
30use helpers::*;
31use pattern::*;
32use types::*;
33
34#[derive(Debug, Clone)]
35pub(super) struct BindingInfo {
36 pub(super) ty: RuntimeType,
37 pub(super) type_params: Vec<typed_ir::TypeVar>,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub(super) enum TypeArgKind {
42 Value,
43 Effect,
44}
45
46pub(super) type TypeArgKinds = HashMap<typed_ir::Path, Vec<TypeArgKind>>;
47
48pub fn validate_module(module: &Module) -> RuntimeResult<()> {
49 let mut bindings = HashMap::new();
50 for binding in &module.bindings {
51 let info = BindingInfo {
52 ty: binding.body.ty.clone(),
53 type_params: binding.type_params.clone(),
54 };
55 match bindings.get_mut(&binding.name) {
56 Some(current) if binding_info_generality(&info) > binding_info_generality(current) => {
57 *current = info;
58 }
59 Some(_) => {}
60 None => {
61 bindings.insert(binding.name.clone(), info);
62 }
63 }
64 }
65 let type_arg_kinds = infer_type_arg_kinds(&module.bindings);
66 for root in &module.roots {
67 match root {
68 Root::Binding(path) if !bindings.contains_key(path) => {
69 return Err(RuntimeError::UnboundVariable { path: path.clone() });
70 }
71 Root::Expr(index) if *index >= module.root_exprs.len() => {
72 return Err(RuntimeError::MissingRootType { index: *index });
73 }
74 Root::Binding(_) | Root::Expr(_) => {}
75 }
76 }
77 for binding in &module.bindings {
78 if let Err(error) = validate_binding(binding, &bindings, &type_arg_kinds) {
79 if std::env::var_os("YULANG_DEBUG_MONO_PIPELINE").is_some() {
80 eprintln!("runtime validation failed in binding {:?}", binding.name);
81 }
82 return Err(error);
83 }
84 }
85 for (index, expr) in module.root_exprs.iter().enumerate() {
86 if let Err(error) = validate_expr(expr, &bindings, &type_arg_kinds, &mut HashMap::new()) {
87 if std::env::var_os("YULANG_DEBUG_MONO_PIPELINE").is_some() {
88 eprintln!("runtime validation failed in root expression {index}");
89 }
90 return Err(error);
91 }
92 }
93 Ok(())
94}
95
96fn validate_binding(
97 binding: &Binding,
98 bindings: &HashMap<typed_ir::Path, BindingInfo>,
99 type_arg_kinds: &TypeArgKinds,
100) -> RuntimeResult<()> {
101 if !binding.type_params.is_empty() {
102 return Ok(());
103 }
104 validate_hir_type_no_any(&binding.body.ty, TypeSource::Validation, type_arg_kinds)?;
105 validate_expr(&binding.body, bindings, type_arg_kinds, &mut HashMap::new())?;
106 let mut vars = BTreeSet::new();
107 collect_type_vars(&binding.scheme.body, &mut vars);
108 require_same_hir_type(
109 &project_runtime_hir_type_with_vars(&binding.scheme.body, &vars),
110 &binding.body.ty,
111 TypeSource::BindingScheme,
112 )
113}
114
115fn infer_type_arg_kinds(bindings: &[Binding]) -> TypeArgKinds {
116 let mut out = TypeArgKinds::new();
117 for binding in bindings {
118 infer_type_arg_kinds_from_hir(&binding.body.ty, &mut out);
119 infer_type_arg_kinds_from_core(&binding.scheme.body, &mut out);
120 infer_type_arg_kinds_from_expr(&binding.body, &mut out);
121 }
122 for binding in bindings {
123 infer_concrete_effect_args_from_expr(&binding.body, &mut out);
124 }
125 for binding in bindings {
126 infer_concrete_effect_args_from_hir(&binding.body.ty, &mut out);
127 infer_concrete_effect_args_from_core(&binding.scheme.body, &mut out);
128 }
129 out
130}
131
132fn infer_type_arg_kinds_from_hir(ty: &RuntimeType, out: &mut TypeArgKinds) {
133 let mut vars = HashMap::<typed_ir::TypeVar, TypeArgKind>::new();
134 collect_hir_type_var_kinds(ty, TypeArgKind::Value, &mut vars);
135 collect_hir_named_arg_kinds(ty, &vars, out);
136}
137
138fn infer_type_arg_kinds_from_core(ty: &typed_ir::Type, out: &mut TypeArgKinds) {
139 let mut vars = HashMap::<typed_ir::TypeVar, TypeArgKind>::new();
140 collect_core_type_var_kinds(ty, TypeArgKind::Value, &mut vars);
141 collect_core_named_arg_kinds(ty, &vars, out);
142}
143
144fn infer_type_arg_kinds_from_expr(expr: &Expr, out: &mut TypeArgKinds) {
145 infer_type_arg_kinds_from_hir(&expr.ty, out);
146 match &expr.kind {
147 ExprKind::Lambda { body, .. }
148 | ExprKind::BindHere { expr: body }
149 | ExprKind::LocalPushId { body, .. }
150 | ExprKind::Pack { expr: body, .. } => infer_type_arg_kinds_from_expr(body, out),
151 ExprKind::Apply { callee, arg, .. } => {
152 infer_type_arg_kinds_from_expr(callee, out);
153 infer_type_arg_kinds_from_expr(arg, out);
154 }
155 ExprKind::If {
156 cond,
157 then_branch,
158 else_branch,
159 ..
160 } => {
161 infer_type_arg_kinds_from_expr(cond, out);
162 infer_type_arg_kinds_from_expr(then_branch, out);
163 infer_type_arg_kinds_from_expr(else_branch, out);
164 }
165 ExprKind::Tuple(items) => {
166 for item in items {
167 infer_type_arg_kinds_from_expr(item, out);
168 }
169 }
170 ExprKind::Record { fields, spread } => {
171 for field in fields {
172 infer_type_arg_kinds_from_expr(&field.value, out);
173 }
174 infer_type_arg_kinds_from_record_spread(spread, out);
175 }
176 ExprKind::Variant { value, .. } => {
177 if let Some(value) = value {
178 infer_type_arg_kinds_from_expr(value, out);
179 }
180 }
181 ExprKind::Select { base, .. } => infer_type_arg_kinds_from_expr(base, out),
182 ExprKind::Match {
183 scrutinee, arms, ..
184 } => {
185 infer_type_arg_kinds_from_expr(scrutinee, out);
186 for arm in arms {
187 infer_type_arg_kinds_from_pattern(&arm.pattern, out);
188 if let Some(guard) = &arm.guard {
189 infer_type_arg_kinds_from_expr(guard, out);
190 }
191 infer_type_arg_kinds_from_expr(&arm.body, out);
192 }
193 }
194 ExprKind::Block { stmts, tail } => {
195 for stmt in stmts {
196 infer_type_arg_kinds_from_stmt(stmt, out);
197 }
198 if let Some(tail) = tail {
199 infer_type_arg_kinds_from_expr(tail, out);
200 }
201 }
202 ExprKind::Handle { body, arms, .. } => {
203 infer_type_arg_kinds_from_expr(body, out);
204 for arm in arms {
205 infer_type_arg_kinds_from_pattern(&arm.payload, out);
206 if let Some(resume) = &arm.resume {
207 infer_type_arg_kinds_from_hir(&resume.ty, out);
208 }
209 if let Some(guard) = &arm.guard {
210 infer_type_arg_kinds_from_expr(guard, out);
211 }
212 infer_type_arg_kinds_from_expr(&arm.body, out);
213 }
214 }
215 ExprKind::Thunk {
216 effect,
217 value,
218 expr,
219 } => {
220 infer_type_arg_kinds_from_core(effect, out);
221 infer_type_arg_kinds_from_hir(value, out);
222 infer_type_arg_kinds_from_expr(expr, out);
223 }
224 ExprKind::AddId { allowed, thunk, .. } => {
225 infer_type_arg_kinds_from_core(allowed, out);
226 infer_type_arg_kinds_from_expr(thunk, out);
227 }
228 ExprKind::Coerce { from, to, expr } => {
229 infer_type_arg_kinds_from_core(from, out);
230 infer_type_arg_kinds_from_core(to, out);
231 infer_type_arg_kinds_from_expr(expr, out);
232 }
233 ExprKind::Var(_)
234 | ExprKind::EffectOp(_)
235 | ExprKind::PrimitiveOp(_)
236 | ExprKind::Lit(_)
237 | ExprKind::PeekId
238 | ExprKind::FindId { .. } => {}
239 }
240}
241
242fn collect_hir_type_var_kinds(
243 ty: &RuntimeType,
244 slot: TypeArgKind,
245 out: &mut HashMap<typed_ir::TypeVar, TypeArgKind>,
246) {
247 match ty {
248 RuntimeType::Unknown => {}
249 RuntimeType::Core(ty) => collect_core_type_var_kinds(ty, slot, out),
250 RuntimeType::Fun { param, ret } => {
251 collect_hir_type_var_kinds(param, TypeArgKind::Value, out);
252 collect_hir_type_var_kinds(ret, TypeArgKind::Value, out);
253 }
254 RuntimeType::Thunk { effect, value } => {
255 collect_core_type_var_kinds(effect, TypeArgKind::Effect, out);
256 collect_hir_type_var_kinds(value, TypeArgKind::Value, out);
257 }
258 }
259}
260
261fn collect_core_type_var_kinds(
262 ty: &typed_ir::Type,
263 slot: TypeArgKind,
264 out: &mut HashMap<typed_ir::TypeVar, TypeArgKind>,
265) {
266 match ty {
267 typed_ir::Type::Var(var) => merge_var_kind(out, var.clone(), slot),
268 typed_ir::Type::Named { args, .. } => {
269 for arg in args {
270 match arg {
271 typed_ir::TypeArg::Type(ty) => {
272 collect_core_type_var_kinds(ty, TypeArgKind::Value, out)
273 }
274 typed_ir::TypeArg::Bounds(bounds) => {
275 if let Some(lower) = bounds.lower.as_deref() {
276 collect_core_type_var_kinds(lower, TypeArgKind::Value, out);
277 }
278 if let Some(upper) = bounds.upper.as_deref() {
279 collect_core_type_var_kinds(upper, TypeArgKind::Value, out);
280 }
281 }
282 }
283 }
284 }
285 typed_ir::Type::Fun {
286 param,
287 param_effect,
288 ret_effect,
289 ret,
290 } => {
291 collect_core_type_var_kinds(param, TypeArgKind::Value, out);
292 collect_core_type_var_kinds(param_effect, TypeArgKind::Effect, out);
293 collect_core_type_var_kinds(ret_effect, TypeArgKind::Effect, out);
294 collect_core_type_var_kinds(ret, TypeArgKind::Value, out);
295 }
296 typed_ir::Type::Tuple(items)
297 | typed_ir::Type::Union(items)
298 | typed_ir::Type::Inter(items) => {
299 for item in items {
300 collect_core_type_var_kinds(item, slot, out);
301 }
302 }
303 typed_ir::Type::Record(record) => {
304 for field in &record.fields {
305 collect_core_type_var_kinds(&field.value, TypeArgKind::Value, out);
306 }
307 if let Some(spread) = &record.spread {
308 match spread {
309 typed_ir::RecordSpread::Head(ty) | typed_ir::RecordSpread::Tail(ty) => {
310 collect_core_type_var_kinds(ty, TypeArgKind::Value, out);
311 }
312 }
313 }
314 }
315 typed_ir::Type::Variant(variant) => {
316 for case in &variant.cases {
317 for payload in &case.payloads {
318 collect_core_type_var_kinds(payload, TypeArgKind::Value, out);
319 }
320 }
321 if let Some(tail) = variant.tail.as_deref() {
322 collect_core_type_var_kinds(tail, TypeArgKind::Value, out);
323 }
324 }
325 typed_ir::Type::Row { items, tail } => {
326 for item in items {
327 collect_core_type_var_kinds(item, TypeArgKind::Effect, out);
328 }
329 collect_core_type_var_kinds(tail, TypeArgKind::Effect, out);
330 }
331 typed_ir::Type::Recursive { body, .. } => collect_core_type_var_kinds(body, slot, out),
332 typed_ir::Type::Unknown | typed_ir::Type::Never | typed_ir::Type::Any => {}
333 }
334}
335
336fn collect_hir_named_arg_kinds(
337 ty: &RuntimeType,
338 vars: &HashMap<typed_ir::TypeVar, TypeArgKind>,
339 out: &mut TypeArgKinds,
340) {
341 match ty {
342 RuntimeType::Unknown => {}
343 RuntimeType::Core(ty) => collect_core_named_arg_kinds(ty, vars, out),
344 RuntimeType::Fun { param, ret } => {
345 collect_hir_named_arg_kinds(param, vars, out);
346 collect_hir_named_arg_kinds(ret, vars, out);
347 }
348 RuntimeType::Thunk { effect, value } => {
349 collect_core_named_arg_kinds(effect, vars, out);
350 collect_hir_named_arg_kinds(value, vars, out);
351 }
352 }
353}
354
355fn collect_core_named_arg_kinds(
356 ty: &typed_ir::Type,
357 vars: &HashMap<typed_ir::TypeVar, TypeArgKind>,
358 out: &mut TypeArgKinds,
359) {
360 match ty {
361 typed_ir::Type::Named { path, args } => {
362 for (index, arg) in args.iter().enumerate() {
363 if let Some(var) = type_arg_single_var(arg)
364 && let Some(kind) = vars.get(&var).copied()
365 {
366 merge_type_arg_kind(out, path.clone(), index, kind);
367 }
368 match arg {
369 typed_ir::TypeArg::Type(ty) => collect_core_named_arg_kinds(ty, vars, out),
370 typed_ir::TypeArg::Bounds(bounds) => {
371 if let Some(lower) = bounds.lower.as_deref() {
372 collect_core_named_arg_kinds(lower, vars, out);
373 }
374 if let Some(upper) = bounds.upper.as_deref() {
375 collect_core_named_arg_kinds(upper, vars, out);
376 }
377 }
378 }
379 }
380 }
381 typed_ir::Type::Fun {
382 param,
383 param_effect,
384 ret_effect,
385 ret,
386 } => {
387 collect_core_named_arg_kinds(param, vars, out);
388 collect_core_named_arg_kinds(param_effect, vars, out);
389 collect_core_named_arg_kinds(ret_effect, vars, out);
390 collect_core_named_arg_kinds(ret, vars, out);
391 }
392 typed_ir::Type::Tuple(items)
393 | typed_ir::Type::Union(items)
394 | typed_ir::Type::Inter(items) => {
395 for item in items {
396 collect_core_named_arg_kinds(item, vars, out);
397 }
398 }
399 typed_ir::Type::Record(record) => {
400 for field in &record.fields {
401 collect_core_named_arg_kinds(&field.value, vars, out);
402 }
403 if let Some(spread) = &record.spread {
404 match spread {
405 typed_ir::RecordSpread::Head(ty) | typed_ir::RecordSpread::Tail(ty) => {
406 collect_core_named_arg_kinds(ty, vars, out);
407 }
408 }
409 }
410 }
411 typed_ir::Type::Variant(variant) => {
412 for case in &variant.cases {
413 for payload in &case.payloads {
414 collect_core_named_arg_kinds(payload, vars, out);
415 }
416 }
417 if let Some(tail) = variant.tail.as_deref() {
418 collect_core_named_arg_kinds(tail, vars, out);
419 }
420 }
421 typed_ir::Type::Row { items, tail } => {
422 for item in items {
423 collect_core_named_arg_kinds(item, vars, out);
424 }
425 collect_core_named_arg_kinds(tail, vars, out);
426 }
427 typed_ir::Type::Recursive { body, .. } => collect_core_named_arg_kinds(body, vars, out),
428 typed_ir::Type::Unknown
429 | typed_ir::Type::Var(_)
430 | typed_ir::Type::Never
431 | typed_ir::Type::Any => {}
432 }
433}
434
435fn type_arg_single_var(arg: &typed_ir::TypeArg) -> Option<typed_ir::TypeVar> {
436 match arg {
437 typed_ir::TypeArg::Type(typed_ir::Type::Var(var)) => Some(var.clone()),
438 typed_ir::TypeArg::Bounds(bounds) => {
439 match (bounds.lower.as_deref(), bounds.upper.as_deref()) {
440 (Some(typed_ir::Type::Var(lower)), Some(typed_ir::Type::Var(upper)))
441 if lower == upper =>
442 {
443 Some(lower.clone())
444 }
445 _ => None,
446 }
447 }
448 _ => None,
449 }
450}
451
452fn merge_var_kind(
453 out: &mut HashMap<typed_ir::TypeVar, TypeArgKind>,
454 var: typed_ir::TypeVar,
455 kind: TypeArgKind,
456) {
457 let entry = out.entry(var).or_insert(kind);
458 if kind == TypeArgKind::Effect {
459 *entry = TypeArgKind::Effect;
460 }
461}
462
463fn merge_type_arg_kind(
464 out: &mut TypeArgKinds,
465 path: typed_ir::Path,
466 index: usize,
467 kind: TypeArgKind,
468) {
469 let kinds = out.entry(path).or_default();
470 if kinds.len() <= index {
471 kinds.resize(index + 1, TypeArgKind::Value);
472 }
473 if kind == TypeArgKind::Effect {
474 kinds[index] = TypeArgKind::Effect;
475 }
476}
477
478fn infer_concrete_effect_args_from_hir(ty: &RuntimeType, out: &mut TypeArgKinds) {
479 match ty {
480 RuntimeType::Unknown => {}
481 RuntimeType::Core(ty) => infer_concrete_effect_args_from_core(ty, out),
482 RuntimeType::Fun { param, ret } => {
483 infer_concrete_effect_args_from_hir(param, out);
484 infer_concrete_effect_args_from_hir(ret, out);
485 }
486 RuntimeType::Thunk { effect, value } => {
487 infer_concrete_effect_args_from_core(effect, out);
488 infer_concrete_effect_args_from_hir(value, out);
489 }
490 }
491}
492
493fn infer_concrete_effect_args_from_expr(expr: &Expr, out: &mut TypeArgKinds) {
494 infer_concrete_effect_args_from_hir(&expr.ty, out);
495 match &expr.kind {
496 ExprKind::Lambda { body, .. }
497 | ExprKind::BindHere { expr: body }
498 | ExprKind::LocalPushId { body, .. }
499 | ExprKind::Pack { expr: body, .. } => infer_concrete_effect_args_from_expr(body, out),
500 ExprKind::Apply { callee, arg, .. } => {
501 infer_concrete_effect_args_from_expr(callee, out);
502 infer_concrete_effect_args_from_expr(arg, out);
503 }
504 ExprKind::If {
505 cond,
506 then_branch,
507 else_branch,
508 ..
509 } => {
510 infer_concrete_effect_args_from_expr(cond, out);
511 infer_concrete_effect_args_from_expr(then_branch, out);
512 infer_concrete_effect_args_from_expr(else_branch, out);
513 }
514 ExprKind::Tuple(items) => {
515 for item in items {
516 infer_concrete_effect_args_from_expr(item, out);
517 }
518 }
519 ExprKind::Record { fields, spread } => {
520 for field in fields {
521 infer_concrete_effect_args_from_expr(&field.value, out);
522 }
523 infer_concrete_effect_args_from_record_spread(spread, out);
524 }
525 ExprKind::Variant { value, .. } => {
526 if let Some(value) = value {
527 infer_concrete_effect_args_from_expr(value, out);
528 }
529 }
530 ExprKind::Select { base, .. } => infer_concrete_effect_args_from_expr(base, out),
531 ExprKind::Match {
532 scrutinee, arms, ..
533 } => {
534 infer_concrete_effect_args_from_expr(scrutinee, out);
535 for arm in arms {
536 infer_concrete_effect_args_from_pattern(&arm.pattern, out);
537 if let Some(guard) = &arm.guard {
538 infer_concrete_effect_args_from_expr(guard, out);
539 }
540 infer_concrete_effect_args_from_expr(&arm.body, out);
541 }
542 }
543 ExprKind::Block { stmts, tail } => {
544 for stmt in stmts {
545 infer_concrete_effect_args_from_stmt(stmt, out);
546 }
547 if let Some(tail) = tail {
548 infer_concrete_effect_args_from_expr(tail, out);
549 }
550 }
551 ExprKind::Handle { body, arms, .. } => {
552 infer_concrete_effect_args_from_expr(body, out);
553 for arm in arms {
554 infer_concrete_effect_args_from_pattern(&arm.payload, out);
555 if let Some(resume) = &arm.resume {
556 infer_concrete_effect_args_from_hir(&resume.ty, out);
557 }
558 if let Some(guard) = &arm.guard {
559 infer_concrete_effect_args_from_expr(guard, out);
560 }
561 infer_concrete_effect_args_from_expr(&arm.body, out);
562 }
563 }
564 ExprKind::Thunk {
565 effect,
566 value,
567 expr,
568 } => {
569 infer_concrete_effect_args_from_core(effect, out);
570 infer_concrete_effect_args_from_hir(value, out);
571 infer_concrete_effect_args_from_expr(expr, out);
572 }
573 ExprKind::AddId { allowed, thunk, .. } => {
574 infer_concrete_effect_args_from_core(allowed, out);
575 infer_concrete_effect_args_from_expr(thunk, out);
576 }
577 ExprKind::Coerce { from, to, expr } => {
578 infer_concrete_effect_args_from_core(from, out);
579 infer_concrete_effect_args_from_core(to, out);
580 infer_concrete_effect_args_from_expr(expr, out);
581 }
582 ExprKind::Var(_)
583 | ExprKind::EffectOp(_)
584 | ExprKind::PrimitiveOp(_)
585 | ExprKind::Lit(_)
586 | ExprKind::PeekId
587 | ExprKind::FindId { .. } => {}
588 }
589}
590
591fn infer_concrete_effect_args_from_core(ty: &typed_ir::Type, out: &mut TypeArgKinds) {
592 match ty {
593 typed_ir::Type::Named { path, args } => {
594 for (index, arg) in args.iter().enumerate() {
595 match arg {
596 typed_ir::TypeArg::Type(arg_ty) => {
597 if matches!(arg_ty, typed_ir::Type::Row { .. }) {
598 merge_type_arg_kind(out, path.clone(), index, TypeArgKind::Effect);
599 }
600 infer_concrete_effect_args_from_core(arg_ty, out);
601 }
602 typed_ir::TypeArg::Bounds(bounds) => {
603 if let Some(lower) = bounds.lower.as_deref() {
604 infer_concrete_effect_args_from_core(lower, out);
605 }
606 if let Some(upper) = bounds.upper.as_deref() {
607 infer_concrete_effect_args_from_core(upper, out);
608 }
609 }
610 }
611 }
612 }
613 typed_ir::Type::Fun {
614 param,
615 param_effect,
616 ret_effect,
617 ret,
618 } => {
619 infer_concrete_effect_args_from_core(param, out);
620 infer_concrete_effect_args_from_core(param_effect, out);
621 infer_concrete_effect_args_from_core(ret_effect, out);
622 infer_concrete_effect_args_from_core(ret, out);
623 }
624 typed_ir::Type::Tuple(items)
625 | typed_ir::Type::Union(items)
626 | typed_ir::Type::Inter(items) => {
627 for item in items {
628 infer_concrete_effect_args_from_core(item, out);
629 }
630 }
631 typed_ir::Type::Record(record) => {
632 for field in &record.fields {
633 infer_concrete_effect_args_from_core(&field.value, out);
634 }
635 if let Some(spread) = &record.spread {
636 match spread {
637 typed_ir::RecordSpread::Head(ty) | typed_ir::RecordSpread::Tail(ty) => {
638 infer_concrete_effect_args_from_core(ty, out);
639 }
640 }
641 }
642 }
643 typed_ir::Type::Variant(variant) => {
644 for case in &variant.cases {
645 for payload in &case.payloads {
646 infer_concrete_effect_args_from_core(payload, out);
647 }
648 }
649 if let Some(tail) = variant.tail.as_deref() {
650 infer_concrete_effect_args_from_core(tail, out);
651 }
652 }
653 typed_ir::Type::Row { items, tail } => {
654 for item in items {
655 infer_concrete_effect_args_from_core(item, out);
656 }
657 infer_concrete_effect_args_from_core(tail, out);
658 }
659 typed_ir::Type::Recursive { body, .. } => infer_concrete_effect_args_from_core(body, out),
660 typed_ir::Type::Unknown
661 | typed_ir::Type::Var(_)
662 | typed_ir::Type::Never
663 | typed_ir::Type::Any => {}
664 }
665}
666
667fn infer_type_arg_kinds_from_stmt(stmt: &Stmt, out: &mut TypeArgKinds) {
668 match stmt {
669 Stmt::Let { pattern, value } => {
670 infer_type_arg_kinds_from_pattern(pattern, out);
671 infer_type_arg_kinds_from_expr(value, out);
672 }
673 Stmt::Expr(expr) => infer_type_arg_kinds_from_expr(expr, out),
674 Stmt::Module { body, .. } => infer_type_arg_kinds_from_expr(body, out),
675 }
676}
677
678fn infer_concrete_effect_args_from_stmt(stmt: &Stmt, out: &mut TypeArgKinds) {
679 match stmt {
680 Stmt::Let { pattern, value } => {
681 infer_concrete_effect_args_from_pattern(pattern, out);
682 infer_concrete_effect_args_from_expr(value, out);
683 }
684 Stmt::Expr(expr) => infer_concrete_effect_args_from_expr(expr, out),
685 Stmt::Module { body, .. } => infer_concrete_effect_args_from_expr(body, out),
686 }
687}
688
689fn infer_type_arg_kinds_from_pattern(pattern: &Pattern, out: &mut TypeArgKinds) {
690 infer_type_arg_kinds_from_hir(pattern_ty(pattern), out);
691 match pattern {
692 Pattern::Tuple { items, .. } => {
693 for item in items {
694 infer_type_arg_kinds_from_pattern(item, out);
695 }
696 }
697 Pattern::List {
698 prefix,
699 spread,
700 suffix,
701 ..
702 } => {
703 for item in prefix.iter().chain(suffix) {
704 infer_type_arg_kinds_from_pattern(item, out);
705 }
706 if let Some(spread) = spread {
707 infer_type_arg_kinds_from_pattern(spread, out);
708 }
709 }
710 Pattern::Record { fields, spread, .. } => {
711 for field in fields {
712 infer_type_arg_kinds_from_pattern(&field.pattern, out);
713 if let Some(default) = &field.default {
714 infer_type_arg_kinds_from_expr(default, out);
715 }
716 }
717 infer_type_arg_kinds_from_record_spread_pattern(spread, out);
718 }
719 Pattern::Variant { value, .. } => {
720 if let Some(value) = value {
721 infer_type_arg_kinds_from_pattern(value, out);
722 }
723 }
724 Pattern::Or { left, right, .. } => {
725 infer_type_arg_kinds_from_pattern(left, out);
726 infer_type_arg_kinds_from_pattern(right, out);
727 }
728 Pattern::As { pattern, .. } => infer_type_arg_kinds_from_pattern(pattern, out),
729 Pattern::Wildcard { .. } | Pattern::Bind { .. } | Pattern::Lit { .. } => {}
730 }
731}
732
733fn infer_concrete_effect_args_from_pattern(pattern: &Pattern, out: &mut TypeArgKinds) {
734 infer_concrete_effect_args_from_hir(pattern_ty(pattern), out);
735 match pattern {
736 Pattern::Tuple { items, .. } => {
737 for item in items {
738 infer_concrete_effect_args_from_pattern(item, out);
739 }
740 }
741 Pattern::List {
742 prefix,
743 spread,
744 suffix,
745 ..
746 } => {
747 for item in prefix.iter().chain(suffix) {
748 infer_concrete_effect_args_from_pattern(item, out);
749 }
750 if let Some(spread) = spread {
751 infer_concrete_effect_args_from_pattern(spread, out);
752 }
753 }
754 Pattern::Record { fields, spread, .. } => {
755 for field in fields {
756 infer_concrete_effect_args_from_pattern(&field.pattern, out);
757 if let Some(default) = &field.default {
758 infer_concrete_effect_args_from_expr(default, out);
759 }
760 }
761 infer_concrete_effect_args_from_record_spread_pattern(spread, out);
762 }
763 Pattern::Variant { value, .. } => {
764 if let Some(value) = value {
765 infer_concrete_effect_args_from_pattern(value, out);
766 }
767 }
768 Pattern::Or { left, right, .. } => {
769 infer_concrete_effect_args_from_pattern(left, out);
770 infer_concrete_effect_args_from_pattern(right, out);
771 }
772 Pattern::As { pattern, .. } => infer_concrete_effect_args_from_pattern(pattern, out),
773 Pattern::Wildcard { .. } | Pattern::Bind { .. } | Pattern::Lit { .. } => {}
774 }
775}
776
777fn infer_type_arg_kinds_from_record_spread(
778 spread: &Option<RecordSpreadExpr>,
779 out: &mut TypeArgKinds,
780) {
781 if let Some(RecordSpreadExpr::Head(expr) | RecordSpreadExpr::Tail(expr)) = spread {
782 infer_type_arg_kinds_from_expr(expr, out);
783 }
784}
785
786fn infer_concrete_effect_args_from_record_spread(
787 spread: &Option<RecordSpreadExpr>,
788 out: &mut TypeArgKinds,
789) {
790 if let Some(RecordSpreadExpr::Head(expr) | RecordSpreadExpr::Tail(expr)) = spread {
791 infer_concrete_effect_args_from_expr(expr, out);
792 }
793}
794
795fn infer_type_arg_kinds_from_record_spread_pattern(
796 spread: &Option<RecordSpreadPattern>,
797 out: &mut TypeArgKinds,
798) {
799 if let Some(RecordSpreadPattern::Head(pattern) | RecordSpreadPattern::Tail(pattern)) = spread {
800 infer_type_arg_kinds_from_pattern(pattern, out);
801 }
802}
803
804fn infer_concrete_effect_args_from_record_spread_pattern(
805 spread: &Option<RecordSpreadPattern>,
806 out: &mut TypeArgKinds,
807) {
808 if let Some(RecordSpreadPattern::Head(pattern) | RecordSpreadPattern::Tail(pattern)) = spread {
809 infer_concrete_effect_args_from_pattern(pattern, out);
810 }
811}