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