1use std::iter;
2
3use derive_where::derive_where;
4use ena::unify::InPlaceUnificationTable;
5use flux_common::{bug, iter::IterExt, span_bug, tracked_span_bug};
6use flux_errors::{ErrorGuaranteed, Errors};
7use flux_infer::projections::NormalizeExt;
8use flux_middle::{
9 fhir::{self, FhirId, FluxOwnerId, QPathExpr, visit::Visitor as _},
10 global_env::GlobalEnv,
11 queries::QueryResult,
12 rty::{
13 self, AdtSortDef, FuncSort, List, RecordCtor, WfckResults,
14 fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable},
15 },
16};
17use itertools::{Itertools, izip};
18use rustc_data_structures::unord::UnordMap;
19use rustc_errors::Diagnostic;
20use rustc_hash::FxHashMap;
21use rustc_hir::def::DefKind;
22use rustc_middle::ty::TypingMode;
23use rustc_span::{Span, def_id::DefId, symbol::Ident};
24
25use super::errors;
26use crate::rustc_infer::infer::TyCtxtInferExt;
27
28type Result<T = ()> = std::result::Result<T, ErrorGuaranteed>;
29
30pub(super) struct InferCtxt<'genv, 'tcx> {
31 pub genv: GlobalEnv<'genv, 'tcx>,
32 pub owner: FluxOwnerId,
33 pub wfckresults: WfckResults,
34 sort_unification_table: InPlaceUnificationTable<rty::SortVid>,
35 bv_size_unification_table: InPlaceUnificationTable<rty::BvSizeVid>,
36 params: FxHashMap<fhir::ParamId, (fhir::RefineParam<'genv>, rty::Sort)>,
37 node_sort: FxHashMap<FhirId, rty::Sort>,
38 path_args: UnordMap<FhirId, rty::GenericArgs>,
39 sort_of_alias_reft: FxHashMap<FhirId, rty::FuncSort>,
40 sort_of_literal: NodeMap<'genv, rty::Sort>,
41 sort_of_bin_op: NodeMap<'genv, rty::Sort>,
42 sort_args_of_app: NodeMap<'genv, List<rty::SortArg>>,
43}
44
45pub fn prim_op_sort(op: &fhir::BinOp) -> Option<(Vec<rty::Sort>, rty::Sort)> {
46 match op {
47 fhir::BinOp::BitAnd
48 | fhir::BinOp::BitOr
49 | fhir::BinOp::BitXor
50 | fhir::BinOp::BitShl
51 | fhir::BinOp::BitShr => Some((vec![rty::Sort::Int, rty::Sort::Int], rty::Sort::Int)),
52 _ => None,
53 }
54}
55
56fn prim_app_sort(op: &fhir::BinOp) -> Option<(Vec<rty::Sort>, rty::Sort)> {
60 match op {
61 fhir::BinOp::Add
62 | fhir::BinOp::Sub
63 | fhir::BinOp::Mul
64 | fhir::BinOp::Div
65 | fhir::BinOp::Mod => Some((vec![rty::Sort::Int, rty::Sort::Int], rty::Sort::Int)),
66 _ => prim_op_sort(op),
67 }
68}
69
70impl<'genv, 'tcx> InferCtxt<'genv, 'tcx> {
71 pub(super) fn new(genv: GlobalEnv<'genv, 'tcx>, owner: FluxOwnerId) -> Self {
72 let mut sort_unification_table = InPlaceUnificationTable::new();
74 sort_unification_table.new_key(Default::default());
75 Self {
76 genv,
77 owner,
78 wfckresults: WfckResults::new(owner),
79 sort_unification_table,
80 bv_size_unification_table: InPlaceUnificationTable::new(),
81 params: Default::default(),
82 node_sort: Default::default(),
83 path_args: Default::default(),
84 sort_of_alias_reft: Default::default(),
85 sort_of_literal: Default::default(),
86 sort_of_bin_op: Default::default(),
87 sort_args_of_app: Default::default(),
88 }
89 }
90
91 fn check_abs(
92 &mut self,
93 expr: &fhir::Expr<'genv>,
94 params: &[fhir::RefineParam],
95 body: &fhir::Expr<'genv>,
96 expected: &rty::Sort,
97 ) -> Result {
98 let Some(fsort) = self.is_coercible_from_func(expected, expr.fhir_id) else {
99 return Err(self.emit_err(errors::UnexpectedFun::new(expr.span, expected)));
100 };
101
102 let fsort = fsort.expect_mono();
103
104 if params.len() != fsort.inputs().len() {
105 return Err(self.emit_err(errors::ParamCountMismatch::new(
106 expr.span,
107 fsort.inputs().len(),
108 params.len(),
109 )));
110 }
111 iter::zip(params, fsort.inputs()).try_for_each_exhaust(|(param, expected)| {
112 let found = self.param_sort(param.id);
113 if self.try_equate(&found, expected).is_none() {
114 return Err(self.emit_sort_mismatch(param.span, expected, &found));
115 }
116 Ok(())
117 })?;
118 self.check_expr(body, fsort.output())?;
119 self.wfckresults
120 .node_sorts_mut()
121 .insert(body.fhir_id, fsort.output().clone());
122 Ok(())
123 }
124
125 fn check_field_exprs(
126 &mut self,
127 expr_span: Span,
128 sort_def: &AdtSortDef,
129 sort_args: &[rty::Sort],
130 field_exprs: &[fhir::FieldExpr<'genv>],
131 spread: Option<&fhir::Spread<'genv>>,
132 expected: &rty::Sort,
133 ) -> Result {
134 let sort_by_field_name = sort_def.struct_variant().sort_by_field_name(sort_args);
135 let mut used_fields = FxHashMap::default();
136 for expr in field_exprs {
137 let Some(sort) = sort_by_field_name.get(&expr.ident.name) else {
139 return Err(self.emit_err(errors::FieldNotFound::new(expected.clone(), expr.ident)));
140 };
141 if let Some(old_field) = used_fields.insert(expr.ident.name, expr.ident) {
142 return Err(self.emit_err(errors::DuplicateFieldUsed::new(expr.ident, old_field)));
143 }
144 self.check_expr(&expr.expr, sort)?;
145 }
146 if let Some(spread) = spread {
147 self.check_expr(&spread.expr, expected)
149 } else if sort_by_field_name.len() != used_fields.len() {
150 let missing_fields = sort_by_field_name
152 .into_keys()
153 .filter(|x| !used_fields.contains_key(x))
154 .collect();
155 Err(self.emit_err(errors::ConstructorMissingFields::new(expr_span, missing_fields)))
156 } else {
157 Ok(())
158 }
159 }
160
161 fn check_constructor(
162 &mut self,
163 expr: &fhir::Expr,
164 field_exprs: &[fhir::FieldExpr<'genv>],
165 spread: Option<&fhir::Spread<'genv>>,
166 expected: &rty::Sort,
167 ) -> Result {
168 let expected = self.resolve_vars_if_possible(expected);
169 if let rty::Sort::App(rty::SortCtor::Adt(sort_def), sort_args) = &expected {
170 self.wfckresults
171 .record_ctors_mut()
172 .insert(expr.fhir_id, RecordCtor::Struct(sort_def.did()));
173 self.check_field_exprs(expr.span, sort_def, sort_args, field_exprs, spread, &expected)?;
174 Ok(())
175 } else {
176 Err(self.emit_err(errors::UnexpectedConstructor::new(expr.span, &expected)))
177 }
178 }
179
180 fn check_record(
181 &mut self,
182 arg: &fhir::Expr<'genv>,
183 flds: &[fhir::Expr<'genv>],
184 expected: &rty::Sort,
185 ) -> Result {
186 if let Some(sorts) = expected.field_sorts() {
187 if flds.len() != sorts.len() {
188 return Err(self.emit_err(errors::ArgCountMismatch::new(
189 Some(arg.span),
190 String::from("type"),
191 sorts.len(),
192 flds.len(),
193 )));
194 }
195 if let rty::Sort::App(rty::SortCtor::Adt(sort_def), _) = expected {
196 self.wfckresults
197 .record_ctors_mut()
198 .insert(arg.fhir_id, RecordCtor::Struct(sort_def.did()));
199 } else if matches!(expected, rty::Sort::RawPtr) {
200 self.wfckresults
201 .record_ctors_mut()
202 .insert(arg.fhir_id, RecordCtor::RawPtr);
203 }
204
205 izip!(flds, &sorts)
206 .map(|(arg, expected)| self.check_expr(arg, expected))
207 .try_collect_exhaust()
208 } else {
209 Err(self.emit_err(errors::ArgCountMismatch::new(
210 Some(arg.span),
211 String::from("type"),
212 1,
213 flds.len(),
214 )))
215 }
216 }
217
218 pub(super) fn check_expr(&mut self, expr: &fhir::Expr<'genv>, expected: &rty::Sort) -> Result {
219 match expr.kind {
220 fhir::ExprKind::IfThenElse(p, e1, e2) => {
221 self.check_expr(p, &rty::Sort::Bool)?;
222 self.check_expr(e1, expected)?;
223 self.check_expr(e2, expected)?;
224 return Ok(());
225 }
226 fhir::ExprKind::Abs(params, body) => {
227 self.check_abs(expr, params, body, expected)?;
228 return Ok(());
229 }
230 fhir::ExprKind::Record(fields) => {
231 self.check_record(expr, fields, expected)?;
232 return Ok(());
233 }
234 fhir::ExprKind::Constructor(None, exprs, spread) => {
235 self.check_constructor(expr, exprs, spread, expected)?;
236 return Ok(());
237 }
238 fhir::ExprKind::Tuple(exprs) => {
239 if let rty::Sort::Tuple(expected_sorts) = expected
241 && exprs.len() == expected_sorts.len()
242 {
243 for (expr, expected_sort) in iter::zip(exprs, expected_sorts) {
244 self.check_expr(expr, expected_sort)?;
245 }
246 return Ok(());
247 }
248 }
249 fhir::ExprKind::Err(_) => {
250 return Ok(());
252 }
253 fhir::ExprKind::UnaryOp(..)
254 | fhir::ExprKind::SetLiteral(..)
255 | fhir::ExprKind::BinaryOp(..)
256 | fhir::ExprKind::Dot(..)
257 | fhir::ExprKind::App(..)
258 | fhir::ExprKind::Alias(..)
259 | fhir::ExprKind::Var(..)
260 | fhir::ExprKind::Literal(..)
261 | fhir::ExprKind::Quant(..)
262 | fhir::ExprKind::Block(..)
263 | fhir::ExprKind::Constructor(..)
264 | fhir::ExprKind::PrimApp(..) => {}
265 }
266 let found = self.synth_expr(expr)?;
268 let found = self.resolve_vars_if_possible(&found);
269 let expected = self.resolve_vars_if_possible(expected);
270 if !self.is_coercible(&found, &expected, expr.fhir_id) {
271 return Err(self.emit_sort_mismatch(expr.span, &expected, &found));
272 }
273 Ok(())
274 }
275
276 pub(super) fn check_loc(&mut self, loc: &fhir::PathExpr) -> Result {
277 let found = self.synth_path(loc);
278 if found == rty::Sort::Loc {
279 Ok(())
280 } else {
281 Err(self.emit_sort_mismatch(loc.span, &rty::Sort::Loc, &found))
282 }
283 }
284
285 fn synth_lit(&mut self, lit: fhir::Lit, expr: &fhir::Expr<'genv>) -> rty::Sort {
286 match lit {
287 fhir::Lit::Int(_) => {
288 let sort = self.next_sort_var_with_cstr(rty::SortCstr::NUMERIC);
289 self.sort_of_literal.insert(*expr, sort.clone());
290 sort
291 }
292 fhir::Lit::Real(_) => rty::Sort::Real,
293 fhir::Lit::Bool(_) => rty::Sort::Bool,
294 fhir::Lit::Str(_) => rty::Sort::Str,
295 fhir::Lit::Char(_) => rty::Sort::Char,
296 }
297 }
298
299 fn synth_prim_app(
300 &mut self,
301 op: &fhir::BinOp,
302 e1: &fhir::Expr<'genv>,
303 e2: &fhir::Expr<'genv>,
304 span: Span,
305 ) -> Result<rty::Sort> {
306 let Some((inputs, output)) = prim_app_sort(op) else {
307 return Err(self.emit_err(errors::UnsupportedPrimOp::new(span, *op)));
308 };
309 let [sort1, sort2] = &inputs[..] else {
310 return Err(self.emit_err(errors::ArgCountMismatch::new(
311 Some(span),
312 String::from("primop app"),
313 inputs.len(),
314 2,
315 )));
316 };
317 self.check_expr(e1, sort1)?;
318 self.check_expr(e2, sort2)?;
319 Ok(output)
320 }
321
322 fn synth_expr(&mut self, expr: &fhir::Expr<'genv>) -> Result<rty::Sort> {
323 match expr.kind {
324 fhir::ExprKind::Var(QPathExpr::Resolved(path, _)) => Ok(self.synth_path(&path)),
325 fhir::ExprKind::Var(QPathExpr::TypeRelative(..)) => {
326 Ok(self.synth_type_relative_path(expr))
327 }
328 fhir::ExprKind::Literal(lit) => Ok(self.synth_lit(lit, expr)),
329 fhir::ExprKind::BinaryOp(op, e1, e2) => self.synth_binary_op(expr, op, e1, e2),
330 fhir::ExprKind::PrimApp(op, e1, e2) => self.synth_prim_app(&op, e1, e2, expr.span),
331 fhir::ExprKind::UnaryOp(op, e) => self.synth_unary_op(op, e),
332 fhir::ExprKind::App(callee, args) => {
333 let sort = self.ensure_resolved_path(&callee)?;
334 let Some(poly_fsort) = self.is_coercible_to_func(&sort, callee.fhir_id) else {
335 return Err(self.emit_err(errors::ExpectedFun::new(callee.span, &sort)));
336 };
337 let fsort = self.instantiate_func_sort(expr, poly_fsort);
338 self.synth_app(fsort, args, expr.span)
339 }
340 fhir::ExprKind::Quant(_, param, dom, body) => {
341 let sort = self.param_sort(param.id);
342 if let fhir::QuantDom::Bounded { .. } = dom
343 && self.try_equate(&sort, &rty::Sort::Int).is_none()
344 {
345 return Err(self.emit_err(errors::IllSortedQuantifier::new(param.span, sort)));
346 }
347 self.check_expr(body, &rty::Sort::Bool)?;
348 Ok(rty::Sort::Bool)
349 }
350 fhir::ExprKind::Alias(_alias_reft, args) => {
351 let fsort = self.sort_of_alias_reft(expr.fhir_id);
354 self.synth_app(fsort, args, expr.span)
355 }
356 fhir::ExprKind::IfThenElse(p, e1, e2) => {
357 self.check_expr(p, &rty::Sort::Bool)?;
358 let sort = self.synth_expr(e1)?;
359 self.check_expr(e2, &sort)?;
360 Ok(sort)
361 }
362 fhir::ExprKind::Dot(base, fld) => {
363 let sort = self.synth_expr(base)?;
364 let sort = self
365 .fully_resolve(&sort)
366 .map_err(|_| self.emit_err(errors::CannotInferSort::new(base.span)))?;
367 match &sort {
368 rty::Sort::App(rty::SortCtor::Adt(sort_def), sort_args) => {
369 let (proj, sort) = sort_def
370 .struct_variant()
371 .field_by_name(sort_def.did(), sort_args, fld.name)
372 .ok_or_else(|| self.emit_field_not_found(&sort, fld))?;
373 self.wfckresults
374 .field_projs_mut()
375 .insert(expr.fhir_id, proj);
376 Ok(sort)
377 }
378 rty::Sort::Tuple(sorts) => {
379 if let Ok(field_idx) = fld.name.as_str().parse::<usize>()
381 && field_idx < sorts.len()
382 {
383 let proj = rty::FieldProj::Tuple {
384 arity: sorts.len(),
385 field: field_idx as u32,
386 };
387 self.wfckresults
388 .field_projs_mut()
389 .insert(expr.fhir_id, proj);
390 Ok(sorts[field_idx].clone())
391 } else {
392 Err(self.emit_field_not_found(&sort, fld))
393 }
394 }
395 rty::Sort::RawPtr => {
396 let field = rty::RawPtrField::from_name(fld.name)
397 .ok_or_else(|| self.emit_field_not_found(&sort, fld))?;
398 self.wfckresults
399 .field_projs_mut()
400 .insert(expr.fhir_id, rty::FieldProj::RawPtr { field });
401 Ok(rty::Sort::Int)
402 }
403 rty::Sort::Bool | rty::Sort::Int | rty::Sort::Real => {
404 Err(self.emit_err(errors::InvalidPrimitiveDotAccess::new(&sort, fld)))
405 }
406 _ => Err(self.emit_field_not_found(&sort, fld)),
407 }
408 }
409 fhir::ExprKind::Constructor(Some(path), field_exprs, spread) => {
410 let path_def_id = match path.res {
414 fhir::Res::Def(DefKind::Enum | DefKind::Struct, def_id) => def_id,
415 _ => span_bug!(expr.span, "unexpected path in constructor"),
416 };
417 let sort_def = self
418 .genv
419 .adt_sort_def_of(path_def_id)
420 .map_err(|e| self.emit_err(e))?;
421 let fresh_args: rty::List<_> = (0..sort_def.param_count())
423 .map(|_| self.next_sort_var())
424 .collect();
425 let sort = rty::Sort::App(rty::SortCtor::Adt(sort_def.clone()), fresh_args.clone());
426 self.check_field_exprs(
428 expr.span,
429 &sort_def,
430 &fresh_args,
431 field_exprs,
432 spread,
433 &sort,
434 )?;
435 Ok(sort)
436 }
437 fhir::ExprKind::Block(decls, body) => {
438 for decl in decls {
439 self.check_expr(&decl.init, &self.param_sort(decl.param.id))?;
440 }
441 self.synth_expr(body)
442 }
443 fhir::ExprKind::SetLiteral(elems) => {
444 let elem_sort = self.next_sort_var();
445 for elem in elems {
446 self.check_expr(elem, &elem_sort)?;
447 }
448 Ok(rty::Sort::App(rty::SortCtor::Set, List::singleton(elem_sort)))
449 }
450 fhir::ExprKind::Tuple(exprs) => {
451 let sorts = exprs
452 .iter()
453 .map(|expr| self.synth_expr(expr))
454 .try_collect()?;
455 Ok(rty::Sort::Tuple(sorts))
456 }
457 _ => Err(self.emit_err(errors::CannotInferSort::new(expr.span))),
458 }
459 }
460
461 fn synth_path(&mut self, path: &fhir::PathExpr) -> rty::Sort {
462 self.node_sort
463 .get(&path.fhir_id)
464 .unwrap_or_else(|| tracked_span_bug!("no sort found for path: `{path:?}`"))
465 .clone()
466 }
467
468 fn synth_type_relative_path(&mut self, expr: &fhir::Expr) -> rty::Sort {
469 self.node_sort
470 .get(&expr.fhir_id)
471 .unwrap_or_else(|| tracked_span_bug!("no sort found for: `{expr:?}`"))
472 .clone()
473 }
474
475 fn synth_binary_op(
476 &mut self,
477 expr: &fhir::Expr<'genv>,
478 op: fhir::BinOp,
479 e1: &fhir::Expr<'genv>,
480 e2: &fhir::Expr<'genv>,
481 ) -> Result<rty::Sort> {
482 match op {
483 fhir::BinOp::Or | fhir::BinOp::And | fhir::BinOp::Iff | fhir::BinOp::Imp => {
484 self.check_expr(e1, &rty::Sort::Bool)?;
485 self.check_expr(e2, &rty::Sort::Bool)?;
486 Ok(rty::Sort::Bool)
487 }
488 fhir::BinOp::Eq | fhir::BinOp::Ne => {
489 let sort = self.next_sort_var();
490 self.check_expr(e1, &sort)?;
491 self.check_expr(e2, &sort)?;
492 Ok(rty::Sort::Bool)
493 }
494 fhir::BinOp::Lt | fhir::BinOp::Le | fhir::BinOp::Gt | fhir::BinOp::Ge => {
495 let sort = self.next_sort_var();
496 self.check_expr(e1, &sort)?;
497 self.check_expr(e2, &sort)?;
498 self.sort_of_bin_op.insert(*expr, sort.clone());
499 Ok(rty::Sort::Bool)
500 }
501 fhir::BinOp::Add
502 | fhir::BinOp::Sub
503 | fhir::BinOp::Mul
504 | fhir::BinOp::Div
505 | fhir::BinOp::Mod
506 | fhir::BinOp::BitAnd
507 | fhir::BinOp::BitOr
508 | fhir::BinOp::BitXor
509 | fhir::BinOp::BitShl
510 | fhir::BinOp::BitShr => {
511 let sort = self.next_sort_var_with_cstr(rty::SortCstr::from_bin_op(op));
512 self.check_expr(e1, &sort)?;
513 self.check_expr(e2, &sort)?;
514 self.sort_of_bin_op.insert(*expr, sort.clone());
515 Ok(sort)
516 }
517 }
518 }
519
520 fn synth_unary_op(&mut self, op: fhir::UnOp, e: &fhir::Expr<'genv>) -> Result<rty::Sort> {
521 match op {
522 fhir::UnOp::Not => {
523 self.check_expr(e, &rty::Sort::Bool)?;
524 Ok(rty::Sort::Bool)
525 }
526 fhir::UnOp::Neg => {
527 self.check_expr(e, &rty::Sort::Int)?;
528 Ok(rty::Sort::Int)
529 }
530 }
531 }
532
533 fn synth_app(
534 &mut self,
535 fsort: FuncSort,
536 args: &[fhir::Expr<'genv>],
537 span: Span,
538 ) -> Result<rty::Sort> {
539 if args.len() != fsort.inputs().len() {
540 return Err(self.emit_err(errors::ArgCountMismatch::new(
541 Some(span),
542 String::from("function"),
543 fsort.inputs().len(),
544 args.len(),
545 )));
546 }
547
548 iter::zip(args, fsort.inputs())
549 .try_for_each_exhaust(|(arg, formal)| self.check_expr(arg, formal))?;
550
551 Ok(fsort.output().clone())
552 }
553
554 fn instantiate_func_sort(
555 &mut self,
556 app_expr: &fhir::Expr<'genv>,
557 fsort: rty::PolyFuncSort,
558 ) -> rty::FuncSort {
559 let args = fsort
560 .params()
561 .map(|kind| {
562 match kind {
563 rty::SortParamKind::Sort => rty::SortArg::Sort(self.next_sort_var()),
564 rty::SortParamKind::BvSize => rty::SortArg::BvSize(self.next_bv_size_var()),
565 }
566 })
567 .collect_vec();
568 self.sort_args_of_app
569 .insert(*app_expr, List::from_slice(&args));
570 fsort.instantiate(&args)
571 }
572
573 pub(crate) fn insert_node_sort(&mut self, fhir_id: FhirId, sort: rty::Sort) {
574 self.node_sort.insert(fhir_id, sort);
575 }
576
577 pub(crate) fn sort_of_bty(&self, bty: &fhir::BaseTy) -> rty::Sort {
578 self.node_sort
579 .get(&bty.fhir_id)
580 .unwrap_or_else(|| tracked_span_bug!("no sort found for bty: `{bty:?}`"))
581 .clone()
582 }
583
584 pub(crate) fn insert_path_args(&mut self, fhir_id: FhirId, args: rty::GenericArgs) {
585 self.path_args.insert(fhir_id, args);
586 }
587
588 pub(crate) fn path_args(&self, fhir_id: FhirId) -> rty::GenericArgs {
589 self.path_args
590 .get(&fhir_id)
591 .unwrap_or_else(|| tracked_span_bug!("no entry found for `{fhir_id:?}`"))
592 .clone()
593 }
594
595 pub(crate) fn insert_sort_for_alias_reft(&mut self, fhir_id: FhirId, fsort: rty::FuncSort) {
596 self.sort_of_alias_reft.insert(fhir_id, fsort);
597 }
598
599 fn sort_of_alias_reft(&self, fhir_id: FhirId) -> rty::FuncSort {
600 self.sort_of_alias_reft
601 .get(&fhir_id)
602 .unwrap_or_else(|| tracked_span_bug!("no entry found for `{fhir_id:?}`"))
603 .clone()
604 }
605
606 fn deeply_normalize_sorts<T: TypeFoldable + Clone>(
607 genv: GlobalEnv,
608 owner: FluxOwnerId,
609 t: &T,
610 ) -> QueryResult<T> {
611 let infcx = genv
612 .tcx()
613 .infer_ctxt()
614 .with_next_trait_solver(true)
615 .build(TypingMode::non_body_analysis());
616 if let Some(def_id) = owner.resolved_id() {
617 t.deeply_normalize_sorts(def_id, genv, &infcx)
618 } else {
619 Ok(t.clone())
620 }
621 }
622
623 pub(crate) fn normalize_sorts(&mut self) -> QueryResult {
628 for sort in self.node_sort.values_mut() {
629 *sort = Self::deeply_normalize_sorts(self.genv, self.owner, sort)?;
630 }
631 for fsort in self.sort_of_alias_reft.values_mut() {
632 *fsort = Self::deeply_normalize_sorts(self.genv, self.owner, fsort)?;
633 }
634 Ok(())
635 }
636}
637
638impl<'genv> InferCtxt<'genv, '_> {
639 pub(super) fn declare_param(&mut self, param: fhir::RefineParam<'genv>, sort: rty::Sort) {
640 self.params.insert(param.id, (param, sort));
641 }
642
643 fn is_coercible(&mut self, sort1: &rty::Sort, sort2: &rty::Sort, fhir_id: FhirId) -> bool {
648 if self.try_equate(sort1, sort2).is_some() {
649 return true;
650 }
651
652 let mut sort1 = sort1.clone();
653 let mut sort2 = sort2.clone();
654
655 let mut coercions = vec![];
656 if let Some((def_id, sort)) = self.is_single_field_struct(&sort1) {
657 coercions.push(rty::Coercion::Project(def_id));
658 sort1 = sort.clone();
659 }
660 if let Some((def_id, sort)) = self.is_single_field_struct(&sort2) {
661 coercions.push(rty::Coercion::Inject(def_id));
662 sort2 = sort.clone();
663 }
664 self.wfckresults.coercions_mut().insert(fhir_id, coercions);
665 self.try_equate(&sort1, &sort2).is_some()
666 }
667
668 fn is_coercible_from_func(
669 &mut self,
670 sort: &rty::Sort,
671 fhir_id: FhirId,
672 ) -> Option<rty::PolyFuncSort> {
673 if let rty::Sort::Func(fsort) = sort {
674 Some(fsort.clone())
675 } else if let Some((def_id, rty::Sort::Func(fsort))) = self.is_single_field_struct(sort) {
676 self.wfckresults
677 .coercions_mut()
678 .insert(fhir_id, vec![rty::Coercion::Inject(def_id)]);
679 Some(fsort.clone())
680 } else {
681 None
682 }
683 }
684
685 fn is_coercible_to_func(
686 &mut self,
687 sort: &rty::Sort,
688 fhir_id: FhirId,
689 ) -> Option<rty::PolyFuncSort> {
690 if let rty::Sort::Func(fsort) = sort {
691 Some(fsort.clone())
692 } else if let Some((def_id, rty::Sort::Func(fsort))) = self.is_single_field_struct(sort) {
693 self.wfckresults
694 .coercions_mut()
695 .insert(fhir_id, vec![rty::Coercion::Project(def_id)]);
696 Some(fsort.clone())
697 } else {
698 None
699 }
700 }
701
702 fn try_equate(&mut self, sort1: &rty::Sort, sort2: &rty::Sort) -> Option<rty::Sort> {
703 let sort1 = self.resolve_vars_if_possible(sort1);
704 let sort2 = self.resolve_vars_if_possible(sort2);
705 self.try_equate_inner(&sort1, &sort2)
706 }
707
708 fn try_equate_inner(&mut self, sort1: &rty::Sort, sort2: &rty::Sort) -> Option<rty::Sort> {
709 match (sort1, sort2) {
710 (rty::Sort::Infer(vid1), rty::Sort::Infer(vid2)) => {
711 self.sort_unification_table
712 .unify_var_var(*vid1, *vid2)
713 .ok()?;
714 }
715 (rty::Sort::Infer(vid), sort) | (sort, rty::Sort::Infer(vid)) => {
716 self.sort_unification_table
717 .unify_var_value(*vid, rty::SortVarVal::Solved(sort.clone()))
718 .ok()?;
719 }
720 (rty::Sort::App(ctor1, args1), rty::Sort::App(ctor2, args2)) => {
721 if ctor1 != ctor2 || args1.len() != args2.len() {
722 return None;
723 }
724 for (s1, s2) in iter::zip(args1, args2) {
725 self.try_equate_inner(s1, s2)?;
726 }
727 }
728 (rty::Sort::Tuple(sorts1), rty::Sort::Tuple(sorts2)) => {
729 if sorts1.len() != sorts2.len() {
730 return None;
731 }
732 for (s1, s2) in iter::zip(sorts1, sorts2) {
733 self.try_equate_inner(s1, s2)?;
734 }
735 }
736 (rty::Sort::BitVec(size1), rty::Sort::BitVec(size2)) => {
737 self.try_equate_bv_sizes(*size1, *size2)?;
738 }
739 _ if sort1 == sort2 => {}
740 _ => return None,
741 }
742 Some(sort1.clone())
743 }
744
745 fn try_equate_bv_sizes(
746 &mut self,
747 size1: rty::BvSize,
748 size2: rty::BvSize,
749 ) -> Option<rty::BvSize> {
750 match (size1, size2) {
751 (rty::BvSize::Infer(vid1), rty::BvSize::Infer(vid2)) => {
752 self.bv_size_unification_table
753 .unify_var_var(vid1, vid2)
754 .ok()?;
755 }
756 (rty::BvSize::Infer(vid), size) | (size, rty::BvSize::Infer(vid)) => {
757 self.bv_size_unification_table
758 .unify_var_value(vid, Some(size))
759 .ok()?;
760 }
761 _ if size1 == size2 => {}
762 _ => return None,
763 }
764 Some(size1)
765 }
766
767 fn next_sort_var(&mut self) -> rty::Sort {
768 rty::Sort::Infer(self.next_sort_vid(Default::default()))
769 }
770
771 fn next_sort_var_with_cstr(&mut self, cstr: rty::SortCstr) -> rty::Sort {
772 rty::Sort::Infer(self.next_sort_vid(rty::SortVarVal::Unsolved(cstr)))
773 }
774
775 pub(crate) fn next_sort_vid(&mut self, val: rty::SortVarVal) -> rty::SortVid {
776 self.sort_unification_table.new_key(val)
777 }
778
779 fn next_bv_size_var(&mut self) -> rty::BvSize {
780 rty::BvSize::Infer(self.next_bv_size_vid())
781 }
782
783 fn next_bv_size_vid(&mut self) -> rty::BvSizeVid {
784 self.bv_size_unification_table.new_key(None)
785 }
786
787 fn ensure_resolved_path(&mut self, path: &fhir::PathExpr) -> Result<rty::Sort> {
788 let sort = self.synth_path(path);
789 self.fully_resolve(&sort)
790 .map_err(|_| self.emit_err(errors::CannotInferSort::new(path.span)))
791 }
792
793 fn is_single_field_struct(&mut self, sort: &rty::Sort) -> Option<(DefId, rty::Sort)> {
794 if let rty::Sort::App(rty::SortCtor::Adt(sort_def), sort_args) = sort
795 && let Some(variant) = sort_def.opt_struct_variant()
796 && let [sort] = &variant.field_sorts(sort_args)[..]
797 {
798 Some((sort_def.did(), sort.clone()))
799 } else {
800 None
801 }
802 }
803
804 pub(crate) fn into_results(mut self) -> Result<WfckResults> {
805 for (node, sort) in std::mem::take(&mut self.sort_of_literal) {
808 if let rty::Sort::Infer(vid) = &sort {
814 let _ = self
815 .sort_unification_table
816 .unify_var_value(*vid, rty::SortVarVal::Solved(rty::Sort::Int));
817 }
818
819 let sort = self
820 .fully_resolve(&sort)
821 .map_err(|_| self.emit_err(errors::CannotInferSort::new(node.span)))?;
822 self.wfckresults.node_sorts_mut().insert(node.fhir_id, sort);
823 }
824
825 for (node, sort) in std::mem::take(&mut self.sort_of_bin_op) {
827 let sort = self
828 .fully_resolve(&sort)
829 .map_err(|_| self.emit_err(errors::CannotInferSort::new(node.span)))?;
830 self.wfckresults
831 .bin_op_sorts_mut()
832 .insert(node.fhir_id, sort);
833 }
834
835 let allow_uninterpreted_cast =
836 self.owner
837 .as_rust()
838 .map_or_else(flux_config::allow_uninterpreted_cast, |def_id| {
839 self.genv
840 .infer_opts(def_id.local_id().def_id)
841 .allow_uninterpreted_cast
842 });
843
844 for (node, sort_args) in std::mem::take(&mut self.sort_args_of_app) {
846 let mut res = vec![];
847 for sort_arg in &sort_args {
848 let sort_arg = match sort_arg {
849 rty::SortArg::Sort(sort) => {
850 let sort = self
851 .fully_resolve(sort)
852 .map_err(|_| self.emit_err(errors::CannotInferSort::new(node.span)))?;
853 rty::SortArg::Sort(sort)
854 }
855 rty::SortArg::BvSize(rty::BvSize::Infer(vid)) => {
856 let size = self
857 .bv_size_unification_table
858 .probe_value(*vid)
859 .ok_or_else(|| {
860 self.emit_err(errors::CannotInferSort::new(node.span))
861 })?;
862 rty::SortArg::BvSize(size)
863 }
864 _ => sort_arg.clone(),
865 };
866 res.push(sort_arg);
867 }
868 if let fhir::ExprKind::App(callee, _) = node.kind
869 && matches!(callee.res, fhir::Res::GlobalFunc(fhir::SpecFuncKind::Cast))
870 {
871 let [rty::SortArg::Sort(from), rty::SortArg::Sort(to)] = &res[..] else {
872 span_bug!(node.span, "invalid sort args!")
873 };
874 if !allow_uninterpreted_cast
875 && matches!(from.cast_kind(to), rty::CastKind::Uninterpreted)
876 {
877 return Err(self.emit_err(errors::InvalidCast::new(node.span, from, to)));
878 }
879 }
880 self.wfckresults
881 .fn_app_sorts_mut()
882 .insert(node.fhir_id, res.into());
883 }
884
885 for (_, (param, sort)) in std::mem::take(&mut self.params) {
887 let sort = self
888 .fully_resolve(&sort)
889 .map_err(|_| self.emit_err(errors::SortAnnotationNeeded::new(¶m)))?;
890 self.wfckresults.param_sorts_mut().insert(param.id, sort);
891 }
892
893 Ok(self.wfckresults)
894 }
895
896 pub(crate) fn infer_mode(&self, id: fhir::ParamId) -> fhir::InferMode {
897 fhir::InferMode::from_param_kind(self.params[&id].0.kind)
898 }
899
900 #[track_caller]
901 pub(crate) fn param_sort(&self, id: fhir::ParamId) -> rty::Sort {
902 self.params
903 .get(&id)
904 .unwrap_or_else(|| bug!("no entry found for `{id:?}`"))
905 .1
906 .clone()
907 }
908
909 fn shallow_resolve(&mut self, sort: &rty::Sort) -> rty::Sort {
910 sort.fold_with(&mut ShallowResolver { infcx: self })
911 }
912
913 fn resolve_vars_if_possible(&mut self, sort: &rty::Sort) -> rty::Sort {
914 sort.fold_with(&mut OpportunisticResolver { infcx: self })
915 }
916
917 pub(crate) fn fully_resolve(&mut self, sort: &rty::Sort) -> std::result::Result<rty::Sort, ()> {
918 sort.try_fold_with(&mut FullResolver { infcx: self })
919 }
920}
921
922pub(crate) struct ImplicitParamInferer<'a, 'genv, 'tcx> {
933 infcx: &'a mut InferCtxt<'genv, 'tcx>,
934 errors: Errors<'genv>,
935}
936
937impl<'a, 'genv, 'tcx> ImplicitParamInferer<'a, 'genv, 'tcx> {
938 pub(crate) fn infer(
939 infcx: &'a mut InferCtxt<'genv, 'tcx>,
940 node: &fhir::OwnerNode<'genv>,
941 ) -> Result {
942 let errors = Errors::new(infcx.genv.sess());
943 let mut vis = Self { infcx, errors };
944 vis.visit_node(node);
945 vis.errors.to_result()
946 }
947
948 fn infer_implicit_params(&mut self, idx: &fhir::Expr, expected: &rty::Sort) {
949 match idx.kind {
950 fhir::ExprKind::Var(QPathExpr::Resolved(var, Some(_))) => {
951 let (_, id) = var.res.expect_param();
952 let found = self.infcx.param_sort(id);
953 self.infcx.try_equate(&found, expected).unwrap_or_else(|| {
954 span_bug!(idx.span, "failed to equate sorts: `{found:?}` `{expected:?}`")
955 });
956 }
957 fhir::ExprKind::Record(flds) => {
958 if let Some(sorts) = expected.field_sorts() {
959 if flds.len() != sorts.len() {
960 self.errors.emit(errors::ArgCountMismatch::new(
961 Some(idx.span),
962 String::from("type"),
963 sorts.len(),
964 flds.len(),
965 ));
966 return;
967 }
968 for (f, sort) in iter::zip(flds, &sorts) {
969 self.infer_implicit_params(f, sort);
970 }
971 } else {
972 self.errors.emit(errors::ArgCountMismatch::new(
973 Some(idx.span),
974 String::from("type"),
975 1,
976 flds.len(),
977 ));
978 }
979 }
980 _ => {}
981 }
982 }
983}
984
985impl<'genv> fhir::visit::Visitor<'genv> for ImplicitParamInferer<'_, 'genv, '_> {
986 fn visit_ty(&mut self, ty: &fhir::Ty<'genv>) {
987 if let fhir::TyKind::Indexed(bty, idx) = &ty.kind {
988 let expected = self.infcx.sort_of_bty(bty);
989 self.infer_implicit_params(idx, &expected);
990 }
991 fhir::visit::walk_ty(self, ty);
992 }
993}
994
995impl InferCtxt<'_, '_> {
996 #[track_caller]
997 fn emit_sort_mismatch(
998 &mut self,
999 span: Span,
1000 expected: &rty::Sort,
1001 found: &rty::Sort,
1002 ) -> ErrorGuaranteed {
1003 let expected = self.resolve_vars_if_possible(expected);
1004 let found = self.resolve_vars_if_possible(found);
1005 self.emit_err(errors::SortMismatch::new(span, expected, found))
1006 }
1007
1008 fn emit_field_not_found(&mut self, sort: &rty::Sort, field: Ident) -> ErrorGuaranteed {
1009 self.emit_err(errors::FieldNotFound::new(sort.clone(), field))
1010 }
1011
1012 #[track_caller]
1013 fn emit_err<'b>(&'b self, err: impl Diagnostic<'b>) -> ErrorGuaranteed {
1014 self.genv.sess().emit_err(err)
1015 }
1016}
1017
1018struct ShallowResolver<'a, 'genv, 'tcx> {
1019 infcx: &'a mut InferCtxt<'genv, 'tcx>,
1020}
1021
1022impl TypeFolder for ShallowResolver<'_, '_, '_> {
1023 fn fold_sort(&mut self, sort: &rty::Sort) -> rty::Sort {
1024 match sort {
1025 rty::Sort::Infer(vid) => {
1026 self.infcx
1032 .sort_unification_table
1033 .probe_value(*vid)
1034 .map_solved(|sort| sort.fold_with(self))
1035 .solved_or(sort)
1036 }
1037 rty::Sort::BitVec(rty::BvSize::Infer(vid)) => {
1038 self.infcx
1039 .bv_size_unification_table
1040 .probe_value(*vid)
1041 .map(rty::Sort::BitVec)
1042 .unwrap_or(sort.clone())
1043 }
1044 _ => sort.clone(),
1045 }
1046 }
1047}
1048
1049struct OpportunisticResolver<'a, 'genv, 'tcx> {
1050 infcx: &'a mut InferCtxt<'genv, 'tcx>,
1051}
1052
1053impl TypeFolder for OpportunisticResolver<'_, '_, '_> {
1054 fn fold_sort(&mut self, sort: &rty::Sort) -> rty::Sort {
1055 let s = self.infcx.shallow_resolve(sort);
1056 s.super_fold_with(self)
1057 }
1058}
1059
1060struct FullResolver<'a, 'genv, 'tcx> {
1061 infcx: &'a mut InferCtxt<'genv, 'tcx>,
1062}
1063
1064impl FallibleTypeFolder for FullResolver<'_, '_, '_> {
1065 type Error = ();
1066
1067 fn try_fold_sort(&mut self, sort: &rty::Sort) -> std::result::Result<rty::Sort, Self::Error> {
1068 let s = self.infcx.shallow_resolve(sort);
1069 match s {
1070 rty::Sort::Infer(_) | rty::Sort::BitVec(rty::BvSize::Infer(_)) => Err(()),
1071 _ => s.try_super_fold_with(self),
1072 }
1073 }
1074}
1075
1076#[derive_where(Default)]
1080struct NodeMap<'genv, T> {
1081 map: FxHashMap<FhirId, (fhir::Expr<'genv>, T)>,
1082}
1083
1084impl<'genv, T> NodeMap<'genv, T> {
1085 fn insert(&mut self, node: fhir::Expr<'genv>, data: T) {
1087 assert!(self.map.insert(node.fhir_id, (node, data)).is_none());
1088 }
1089}
1090
1091impl<'genv, T> IntoIterator for NodeMap<'genv, T> {
1092 type Item = (fhir::Expr<'genv>, T);
1093
1094 type IntoIter = std::collections::hash_map::IntoValues<FhirId, Self::Item>;
1095
1096 fn into_iter(self) -> Self::IntoIter {
1097 self.map.into_values()
1098 }
1099}