1#![feature(
3 associated_type_defaults,
4 closure_track_caller,
5 map_try_insert,
6 min_specialization,
7 never_type,
8 rustc_private,
9 unwrap_infallible
10)]
11
12extern crate rustc_abi;
13extern crate rustc_ast;
14extern crate rustc_data_structures;
15extern crate rustc_errors;
16extern crate rustc_hir;
17extern crate rustc_index;
18extern crate rustc_macros;
19extern crate rustc_middle;
20extern crate rustc_serialize;
21extern crate rustc_span;
22extern crate rustc_type_ir;
23
24extern crate self as flux_middle;
25
26pub mod big_int;
27mod builtin_assoc_refts;
28pub mod call_graph;
29pub mod cstore;
30pub mod def_id;
31pub mod fhir;
32pub mod global_env;
33pub mod metrics;
34pub mod pretty;
35pub mod queries;
36pub mod rty;
37mod sort_of;
38
39use std::sync::LazyLock;
40
41use flux_arc_interner::List;
42pub use flux_rustc_bridge::def_id_to_string;
43use flux_rustc_bridge::{
44 mir::{LocalDecls, PlaceElem},
45 ty::{self, GenericArgsExt},
46};
47use flux_syntax::surface::{self, NodeId};
48use global_env::GlobalEnv;
49use liquid_fixpoint::ThyFunc;
50use queries::QueryResult;
51use rty::VariantIdx;
52use rustc_abi::FieldIdx;
53use rustc_data_structures::{
54 fx::FxIndexMap,
55 unord::{UnordMap, UnordSet},
56};
57use rustc_hir::OwnerId;
58use rustc_macros::{Decodable, Encodable, extension};
59use rustc_middle::ty::TyCtxt;
60use rustc_span::{
61 Span, Symbol,
62 def_id::{DefId, LocalDefId},
63 symbol::Ident,
64};
65
66#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Encodable, Decodable)]
67pub enum PanicSpec {
68 WillNotPanic,
69 MightPanic(PanicReason),
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
73pub enum PanicReason {
74 Transitive,
75 UnresolvedCall(DefId),
76 DynamicDispatch,
77 SynthesizedPanic,
78 NotInCallGraph,
79 NoMIRAvailable,
80}
81
82pub struct TheoryFunc {
83 pub name: Symbol,
84 pub sort: rty::PolyFuncSort,
85 pub itf: liquid_fixpoint::ThyFunc,
86}
87
88pub static THEORY_FUNCS: LazyLock<UnordMap<liquid_fixpoint::ThyFunc, TheoryFunc>> =
89 LazyLock::new(|| {
90 use rty::{BvSize, Sort::*};
91 liquid_fixpoint::ThyFunc::ALL
92 .into_iter()
93 .filter_map(|func| {
94 let func = TheoryFunc {
95 name: Symbol::intern(name_of_thy_func(func)?),
96 itf: func,
97 sort: sort_of_thy_func(func)?,
98 };
99 Some(func)
100 })
101 .chain([
102 TheoryFunc {
104 name: Symbol::intern("bv_zero_extend_32_to_64"),
105 itf: liquid_fixpoint::ThyFunc::BvZeroExtend(32),
106 sort: rty::PolyFuncSort::new(
107 List::empty(),
108 rty::FuncSort::new(
109 vec![BitVec(BvSize::Fixed(32))],
110 BitVec(BvSize::Fixed(64)),
111 ),
112 ),
113 },
114 TheoryFunc {
115 name: Symbol::intern("bv_sign_extend_32_to_64"),
116 itf: liquid_fixpoint::ThyFunc::BvSignExtend(32),
117 sort: rty::PolyFuncSort::new(
118 List::empty(),
119 rty::FuncSort::new(
120 vec![BitVec(BvSize::Fixed(32))],
121 BitVec(BvSize::Fixed(64)),
122 ),
123 ),
124 },
125 ])
126 .map(|func| (func.itf, func))
127 .collect()
128 });
129
130pub fn name_of_thy_func(func: liquid_fixpoint::ThyFunc) -> Option<&'static str> {
131 let name = match func {
132 ThyFunc::BvZeroExtend(_) | ThyFunc::BvSignExtend(_) => return None,
133 ThyFunc::StrLen => "str_len",
134 ThyFunc::StrConcat => "str_concat",
135 ThyFunc::StrPrefixOf => "str_prefix_of",
136 ThyFunc::StrSuffixOf => "str_suffix_of",
137 ThyFunc::StrContains => "str_contains",
138 ThyFunc::IntToBv8 => "bv_int_to_bv8",
139 ThyFunc::Bv8ToInt => "bv_bv8_to_int",
140 ThyFunc::IntToBv32 => "bv_int_to_bv32",
141 ThyFunc::Bv32ToInt => "bv_bv32_to_int",
142 ThyFunc::IntToBv64 => "bv_int_to_bv64",
143 ThyFunc::Bv64ToInt => "bv_bv64_to_int",
144 ThyFunc::IntToBv128 => "bv_int_to_bv128",
145 ThyFunc::Bv128ToInt => "bv_bv128_to_int",
146 ThyFunc::BvUge => "bv_uge",
147 ThyFunc::BvSge => "bv_sge",
148 ThyFunc::BvUdiv => "bv_udiv",
149 ThyFunc::BvSdiv => "bv_sdiv",
150 ThyFunc::BvSrem => "bv_srem",
151 ThyFunc::BvUrem => "bv_urem",
152 ThyFunc::BvLshr => "bv_lshr",
153 ThyFunc::BvAshr => "bv_ashr",
154 ThyFunc::BvAnd => "bv_and",
155 ThyFunc::BvOr => "bv_or",
156 ThyFunc::BvXor => "bv_xor",
157 ThyFunc::BvNot => "bv_not",
158 ThyFunc::BvAdd => "bv_add",
159 ThyFunc::BvNeg => "bv_neg",
160 ThyFunc::BvSub => "bv_sub",
161 ThyFunc::BvMul => "bv_mul",
162 ThyFunc::BvShl => "bv_shl",
163 ThyFunc::BvUle => "bv_ule",
164 ThyFunc::BvSle => "bv_sle",
165 ThyFunc::BvUgt => "bv_ugt",
166 ThyFunc::BvSgt => "bv_sgt",
167 ThyFunc::BvUlt => "bv_ult",
168 ThyFunc::BvSlt => "bv_slt",
169 ThyFunc::SetEmpty => "set_empty",
170 ThyFunc::SetSng => "set_singleton",
171 ThyFunc::SetCup => "set_union",
172 ThyFunc::SetCap => "set_intersection",
173 ThyFunc::SetDif => "set_difference",
174 ThyFunc::SetSub => "set_subset",
175 ThyFunc::SetMem => "set_is_in",
176 ThyFunc::MapDefault => "map_default",
177 ThyFunc::MapSelect => "map_select",
178 ThyFunc::MapStore => "map_store",
179 };
180 Some(name)
181}
182
183fn sort_of_thy_func(func: liquid_fixpoint::ThyFunc) -> Option<rty::PolyFuncSort> {
184 use rty::{
185 BvSize, ParamSort,
186 Sort::{self, *},
187 SortCtor::*,
188 SortParamKind,
189 };
190 let param0 = ParamSort::from_u32(0);
191 let param1 = ParamSort::from_u32(1);
192 let bv_param0 = BvSize::Param(ParamSort::from_u32(0));
193
194 let sort = match func {
195 ThyFunc::BvZeroExtend(_) | ThyFunc::BvSignExtend(_) => return None,
196 ThyFunc::StrLen => {
197 rty::PolyFuncSort::new(List::empty(), rty::FuncSort::new(vec![rty::Sort::Str], Int))
199 }
200 ThyFunc::StrConcat => {
201 rty::PolyFuncSort::new(
203 List::empty(),
204 rty::FuncSort::new(vec![rty::Sort::Str, rty::Sort::Str], rty::Sort::Str),
205 )
206 }
207 ThyFunc::StrPrefixOf | ThyFunc::StrSuffixOf | ThyFunc::StrContains => {
208 rty::PolyFuncSort::new(
210 List::empty(),
211 rty::FuncSort::new(vec![rty::Sort::Str, rty::Sort::Str], Bool),
212 )
213 }
214 ThyFunc::IntToBv8 => {
215 rty::PolyFuncSort::new(
217 List::empty(),
218 rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(8))),
219 )
220 }
221 ThyFunc::Bv8ToInt => {
222 rty::PolyFuncSort::new(
224 List::empty(),
225 rty::FuncSort::new(vec![BitVec(BvSize::Fixed(8))], Int),
226 )
227 }
228 ThyFunc::IntToBv32 => {
229 rty::PolyFuncSort::new(
231 List::empty(),
232 rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(32))),
233 )
234 }
235 ThyFunc::Bv32ToInt => {
236 rty::PolyFuncSort::new(
238 List::empty(),
239 rty::FuncSort::new(vec![BitVec(BvSize::Fixed(32))], Int),
240 )
241 }
242 ThyFunc::IntToBv64 => {
243 rty::PolyFuncSort::new(
245 List::empty(),
246 rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(64))),
247 )
248 }
249 ThyFunc::Bv64ToInt => {
250 rty::PolyFuncSort::new(
252 List::empty(),
253 rty::FuncSort::new(vec![BitVec(BvSize::Fixed(64))], Int),
254 )
255 }
256 ThyFunc::IntToBv128 => {
257 rty::PolyFuncSort::new(
259 List::empty(),
260 rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(128))),
261 )
262 }
263 ThyFunc::Bv128ToInt => {
264 rty::PolyFuncSort::new(
266 List::empty(),
267 rty::FuncSort::new(vec![BitVec(BvSize::Fixed(128))], Int),
268 )
269 }
270 ThyFunc::BvUdiv
271 | ThyFunc::BvSdiv
272 | ThyFunc::BvSrem
273 | ThyFunc::BvUrem
274 | ThyFunc::BvLshr
275 | ThyFunc::BvAshr
276 | ThyFunc::BvAnd
277 | ThyFunc::BvOr
278 | ThyFunc::BvXor
279 | ThyFunc::BvAdd
280 | ThyFunc::BvSub
281 | ThyFunc::BvMul
282 | ThyFunc::BvShl => {
283 rty::PolyFuncSort::new(
285 List::singleton(SortParamKind::BvSize),
286 rty::FuncSort::new(vec![BitVec(bv_param0), BitVec(bv_param0)], BitVec(bv_param0)),
287 )
288 }
289 ThyFunc::BvNot | ThyFunc::BvNeg => {
290 rty::PolyFuncSort::new(
292 List::singleton(SortParamKind::BvSize),
293 rty::FuncSort::new(vec![BitVec(bv_param0)], BitVec(bv_param0)),
294 )
295 }
296 ThyFunc::BvUgt
297 | ThyFunc::BvSgt
298 | ThyFunc::BvUlt
299 | ThyFunc::BvSlt
300 | ThyFunc::BvSle
301 | ThyFunc::BvUge
302 | ThyFunc::BvSge
303 | ThyFunc::BvUle => {
304 rty::PolyFuncSort::new(
306 List::singleton(SortParamKind::BvSize),
307 rty::FuncSort::new(vec![BitVec(bv_param0), BitVec(bv_param0)], Bool),
308 )
309 }
310 ThyFunc::SetEmpty => {
311 rty::PolyFuncSort::new(
313 List::singleton(SortParamKind::Sort),
314 rty::FuncSort::new(vec![Int], Sort::app(Set, List::singleton(Var(param0)))),
315 )
316 }
317 ThyFunc::SetSng => {
318 rty::PolyFuncSort::new(
320 List::singleton(SortParamKind::Sort),
321 rty::FuncSort::new(vec![Var(param0)], Sort::app(Set, List::singleton(Var(param0)))),
322 )
323 }
324 ThyFunc::SetCup | ThyFunc::SetCap | ThyFunc::SetDif => {
325 rty::PolyFuncSort::new(
327 List::singleton(SortParamKind::Sort),
328 rty::FuncSort::new(
329 vec![
330 Sort::app(Set, List::singleton(Var(param0))),
331 Sort::app(Set, List::singleton(Var(param0))),
332 ],
333 Sort::app(Set, List::singleton(Var(param0))),
334 ),
335 )
336 }
337 ThyFunc::SetMem => {
338 rty::PolyFuncSort::new(
340 List::singleton(SortParamKind::Sort),
341 rty::FuncSort::new(
342 vec![Var(param0), Sort::app(Set, List::singleton(Var(param0)))],
343 Bool,
344 ),
345 )
346 }
347 ThyFunc::SetSub => {
348 rty::PolyFuncSort::new(
350 List::singleton(SortParamKind::Sort),
351 rty::FuncSort::new(
352 vec![
353 Sort::app(Set, List::singleton(Var(param0))),
354 Sort::app(Set, List::singleton(Var(param0))),
355 ],
356 Bool,
357 ),
358 )
359 }
360
361 ThyFunc::MapDefault => {
362 rty::PolyFuncSort::new(
364 List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
365 rty::FuncSort::new(
366 vec![Var(param1)],
367 Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
368 ),
369 )
370 }
371 ThyFunc::MapSelect => {
372 rty::PolyFuncSort::new(
374 List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
375 rty::FuncSort::new(
376 vec![Sort::app(Map, List::from_arr([Var(param0), Var(param1)])), Var(param0)],
377 Var(param1),
378 ),
379 )
380 }
381 ThyFunc::MapStore => {
382 rty::PolyFuncSort::new(
384 List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
385 rty::FuncSort::new(
386 vec![
387 Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
388 Var(param0),
389 Var(param1),
390 ],
391 Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
392 ),
393 )
394 }
395 };
396 Some(sort)
397}
398
399#[derive(Default)]
400pub struct Specs {
401 items: UnordMap<OwnerId, surface::Item>,
402 trait_items: UnordMap<OwnerId, surface::TraitItemFn>,
403 impl_items: UnordMap<OwnerId, surface::ImplItemFn>,
404 pub flux_items_by_parent: FxIndexMap<OwnerId, Vec<surface::FluxItem>>,
405 spec_attr_spans: UnordMap<DefId, Span>,
407 dummy_extern: UnordSet<LocalDefId>,
416 extern_id_to_local_id: UnordMap<DefId, LocalDefId>,
417 local_id_to_extern_id: UnordMap<LocalDefId, DefId>,
418}
419
420impl Specs {
421 pub fn insert_extern_spec_id_mapping(
422 &mut self,
423 local_id: LocalDefId,
424 extern_id: DefId,
425 ) -> Result<(), ExternSpecMappingErr> {
426 #[expect(
427 clippy::disallowed_methods,
428 reason = "we are inserting the extern spec mapping and we want to ensure it doesn't point to a local item"
429 )]
430 if let Some(local) = extern_id.as_local() {
431 return Err(ExternSpecMappingErr::IsLocal(local));
432 }
433 if let Err(err) = self.extern_id_to_local_id.try_insert(extern_id, local_id) {
434 return Err(ExternSpecMappingErr::Dup(*err.entry.get()));
435 }
436 self.local_id_to_extern_id.insert(local_id, extern_id);
437 Ok(())
438 }
439
440 pub fn insert_dummy(&mut self, def_id: LocalDefId) {
441 self.dummy_extern.insert(def_id);
442 }
443
444 pub fn set_spec_attr_span(&mut self, def_id: DefId, span: Span) {
445 self.spec_attr_spans.insert(def_id, span);
446 }
447
448 pub fn get_spec_attr_span(&self, def_id: DefId) -> Option<Span> {
449 self.spec_attr_spans.get(&def_id).copied()
450 }
451
452 pub fn get_item(&self, owner_id: OwnerId) -> Option<&surface::Item> {
453 self.items.get(&owner_id)
454 }
455
456 pub fn insert_item(&mut self, owner_id: OwnerId, item: surface::Item) -> Option<surface::Item> {
457 if let Some(old) = self.items.insert(owner_id, item) {
458 return Some(old);
459 }
460 None
461 }
462
463 pub fn get_trait_item(&self, owner_id: OwnerId) -> Option<&surface::TraitItemFn> {
464 self.trait_items.get(&owner_id)
465 }
466
467 pub fn insert_trait_item(
468 &mut self,
469 owner_id: OwnerId,
470 trait_item: surface::TraitItemFn,
471 ) -> Option<surface::TraitItemFn> {
472 if let Some(old) = self.trait_items.insert(owner_id, trait_item) {
473 return Some(old);
474 }
475 None
476 }
477
478 pub fn get_impl_item(&self, owner_id: OwnerId) -> Option<&surface::ImplItemFn> {
479 self.impl_items.get(&owner_id)
480 }
481
482 pub fn insert_impl_item(
483 &mut self,
484 owner_id: OwnerId,
485 impl_item: surface::ImplItemFn,
486 ) -> Option<surface::ImplItemFn> {
487 if let Some(old) = self.impl_items.insert(owner_id, impl_item) {
488 return Some(old);
489 }
490 None
491 }
492}
493
494pub enum ExternSpecMappingErr {
497 IsLocal(LocalDefId),
500
501 Dup(LocalDefId),
510}
511
512#[derive(Default)]
513pub struct ResolverOutput {
514 pub path_res_map: UnordMap<NodeId, fhir::PartialRes<NodeId>>,
516 pub param_res_map: UnordMap<NodeId, (fhir::ParamId, fhir::ParamKind)>,
521 pub implicit_params: UnordMap<NodeId, Vec<(Ident, NodeId)>>,
525 pub qualifier_res_map: UnordMap<NodeId, Vec<def_id::FluxLocalDefId>>,
528 pub reveal_res_map: UnordMap<NodeId, Vec<def_id::FluxDefId>>,
531 pub parametric_param_res_map: UnordMap<NodeId, Vec<DefId>>,
534}
535
536#[extension(pub trait PlaceExt)]
537impl flux_rustc_bridge::mir::Place {
538 fn ty(&self, genv: GlobalEnv, local_decls: &LocalDecls) -> QueryResult<PlaceTy> {
539 self.projection
540 .iter()
541 .try_fold(PlaceTy::from_ty(local_decls[self.local].ty.clone()), |place_ty, elem| {
542 place_ty.projection_ty(genv, *elem)
543 })
544 }
545
546 fn behind_raw_ptr(&self, genv: GlobalEnv, local_decls: &LocalDecls) -> QueryResult<bool> {
547 let mut place_ty = PlaceTy::from_ty(local_decls[self.local].ty.clone());
548 for elem in &self.projection {
549 if let (PlaceElem::Deref, ty::TyKind::RawPtr(..)) = (elem, place_ty.ty.kind()) {
550 return Ok(true);
551 }
552 place_ty = place_ty.projection_ty(genv, *elem)?;
553 }
554 Ok(false)
555 }
556}
557
558#[derive(Debug)]
559pub struct PlaceTy {
560 pub ty: ty::Ty,
561 pub variant_index: Option<VariantIdx>,
563}
564
565impl PlaceTy {
566 fn from_ty(ty: ty::Ty) -> PlaceTy {
567 PlaceTy { ty, variant_index: None }
568 }
569
570 fn projection_ty(&self, genv: GlobalEnv, elem: PlaceElem) -> QueryResult<PlaceTy> {
571 if self.variant_index.is_some() && !matches!(elem, PlaceElem::Field(..)) {
572 Err(query_bug!("cannot use non field projection on downcasted place"))?;
573 }
574 let place_ty = match elem {
575 PlaceElem::Deref => PlaceTy::from_ty(self.ty.deref()),
576 PlaceElem::Field(fld) => PlaceTy::from_ty(self.field_ty(genv, fld)?),
577 PlaceElem::Downcast(_, variant_idx) => {
578 PlaceTy { ty: self.ty.clone(), variant_index: Some(variant_idx) }
579 }
580 PlaceElem::Index(_) | PlaceElem::ConstantIndex { .. } => {
581 if let ty::TyKind::Array(ty, _) | ty::TyKind::Slice(ty) = self.ty.kind() {
582 PlaceTy::from_ty(ty.clone())
583 } else {
584 return Err(query_bug!("cannot use non field projection on downcasted place"));
585 }
586 }
587 };
588 Ok(place_ty)
589 }
590
591 fn field_ty(&self, genv: GlobalEnv, f: FieldIdx) -> QueryResult<ty::Ty> {
592 match self.ty.kind() {
593 ty::TyKind::Adt(adt_def, args) => {
594 let variant_def = match self.variant_index {
595 None => adt_def.non_enum_variant(),
596 Some(variant_index) => {
597 assert!(adt_def.is_enum());
598 adt_def.variant(variant_index)
599 }
600 };
601 let field_def = &variant_def.fields[f];
602 let ty = genv.lower_type_of(field_def.did)?;
603 Ok(ty.subst(args))
604 }
605 ty::TyKind::Tuple(tys) => Ok(tys[f.index()].clone()),
606 ty::TyKind::Closure(_, args) => Ok(args.as_closure().upvar_tys()[f.index()].clone()),
607 _ => Err(query_bug!("extracting field of non-tuple non-adt non-closure: {self:?}")),
608 }
609 }
610}
611
612#[derive(Debug, Hash, Clone, Copy)]
617pub enum FixpointQueryKind {
618 Impl,
620 Body,
622 Invariant,
624}
625
626impl FixpointQueryKind {
627 pub fn ext(self) -> &'static str {
628 match self {
629 FixpointQueryKind::Impl => "sub.fluxc",
630 FixpointQueryKind::Body => "fluxc",
631 FixpointQueryKind::Invariant => "fluxc",
632 }
633 }
634
635 pub fn task_key(self, tcx: TyCtxt, def_id: DefId) -> String {
637 format!("{}###{:?}", tcx.def_path_str(def_id), self)
638 }
639
640 #[must_use]
644 pub fn is_body(&self) -> bool {
645 matches!(self, Self::Body)
646 }
647}