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