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::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
71pub struct TheoryFunc {
72 pub name: Symbol,
73 pub sort: rty::PolyFuncSort,
74 pub itf: liquid_fixpoint::ThyFunc,
75}
76
77pub static THEORY_FUNCS: LazyLock<UnordMap<liquid_fixpoint::ThyFunc, TheoryFunc>> =
78 LazyLock::new(|| {
79 use rty::{BvSize, Sort::*};
80 liquid_fixpoint::ThyFunc::ALL
81 .into_iter()
82 .filter_map(|func| {
83 let func = TheoryFunc {
84 name: Symbol::intern(name_of_thy_func(func)?),
85 itf: func,
86 sort: sort_of_thy_func(func)?,
87 };
88 Some(func)
89 })
90 .chain([
91 TheoryFunc {
93 name: Symbol::intern("bv_zero_extend_32_to_64"),
94 itf: liquid_fixpoint::ThyFunc::BvZeroExtend(32),
95 sort: rty::PolyFuncSort::new(
96 List::empty(),
97 rty::FuncSort::new(
98 vec![BitVec(BvSize::Fixed(32))],
99 BitVec(BvSize::Fixed(64)),
100 ),
101 ),
102 },
103 TheoryFunc {
104 name: Symbol::intern("bv_sign_extend_32_to_64"),
105 itf: liquid_fixpoint::ThyFunc::BvSignExtend(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 ])
115 .map(|func| (func.itf, func))
116 .collect()
117 });
118
119pub fn name_of_thy_func(func: liquid_fixpoint::ThyFunc) -> Option<&'static str> {
120 let name = match func {
121 ThyFunc::BvZeroExtend(_) | ThyFunc::BvSignExtend(_) => return None,
122 ThyFunc::StrLen => "str_len",
123 ThyFunc::StrConcat => "str_concat",
124 ThyFunc::StrPrefixOf => "str_prefix_of",
125 ThyFunc::StrSuffixOf => "str_suffix_of",
126 ThyFunc::StrContains => "str_contains",
127 ThyFunc::IntToBv8 => "bv_int_to_bv8",
128 ThyFunc::Bv8ToInt => "bv_bv8_to_int",
129 ThyFunc::IntToBv32 => "bv_int_to_bv32",
130 ThyFunc::Bv32ToInt => "bv_bv32_to_int",
131 ThyFunc::IntToBv64 => "bv_int_to_bv64",
132 ThyFunc::Bv64ToInt => "bv_bv64_to_int",
133 ThyFunc::BvUge => "bv_uge",
134 ThyFunc::BvSge => "bv_sge",
135 ThyFunc::BvUdiv => "bv_udiv",
136 ThyFunc::BvSdiv => "bv_sdiv",
137 ThyFunc::BvSrem => "bv_srem",
138 ThyFunc::BvUrem => "bv_urem",
139 ThyFunc::BvLshr => "bv_lshr",
140 ThyFunc::BvAshr => "bv_ashr",
141 ThyFunc::BvAnd => "bv_and",
142 ThyFunc::BvOr => "bv_or",
143 ThyFunc::BvXor => "bv_xor",
144 ThyFunc::BvNot => "bv_not",
145 ThyFunc::BvAdd => "bv_add",
146 ThyFunc::BvNeg => "bv_neg",
147 ThyFunc::BvSub => "bv_sub",
148 ThyFunc::BvMul => "bv_mul",
149 ThyFunc::BvShl => "bv_shl",
150 ThyFunc::BvUle => "bv_ule",
151 ThyFunc::BvSle => "bv_sle",
152 ThyFunc::BvUgt => "bv_ugt",
153 ThyFunc::BvSgt => "bv_sgt",
154 ThyFunc::BvUlt => "bv_ult",
155 ThyFunc::BvSlt => "bv_slt",
156 ThyFunc::SetEmpty => "set_empty",
157 ThyFunc::SetSng => "set_singleton",
158 ThyFunc::SetCup => "set_union",
159 ThyFunc::SetCap => "set_intersection",
160 ThyFunc::SetDif => "set_difference",
161 ThyFunc::SetSub => "set_subset",
162 ThyFunc::SetMem => "set_is_in",
163 ThyFunc::MapDefault => "map_default",
164 ThyFunc::MapSelect => "map_select",
165 ThyFunc::MapStore => "map_store",
166 };
167 Some(name)
168}
169
170fn sort_of_thy_func(func: liquid_fixpoint::ThyFunc) -> Option<rty::PolyFuncSort> {
171 use rty::{
172 BvSize, ParamSort,
173 Sort::{self, *},
174 SortCtor::*,
175 SortParamKind,
176 };
177 let param0 = ParamSort::from_u32(0);
178 let param1 = ParamSort::from_u32(1);
179 let bv_param0 = BvSize::Param(ParamSort::from_u32(0));
180
181 let sort = match func {
182 ThyFunc::BvZeroExtend(_) | ThyFunc::BvSignExtend(_) => return None,
183 ThyFunc::StrLen => {
184 rty::PolyFuncSort::new(List::empty(), rty::FuncSort::new(vec![rty::Sort::Str], Int))
186 }
187 ThyFunc::StrConcat => {
188 rty::PolyFuncSort::new(
190 List::empty(),
191 rty::FuncSort::new(vec![rty::Sort::Str, rty::Sort::Str], rty::Sort::Str),
192 )
193 }
194 ThyFunc::StrPrefixOf | ThyFunc::StrSuffixOf | ThyFunc::StrContains => {
195 rty::PolyFuncSort::new(
197 List::empty(),
198 rty::FuncSort::new(vec![rty::Sort::Str, rty::Sort::Str], Bool),
199 )
200 }
201 ThyFunc::IntToBv8 => {
202 rty::PolyFuncSort::new(
204 List::empty(),
205 rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(8))),
206 )
207 }
208 ThyFunc::Bv8ToInt => {
209 rty::PolyFuncSort::new(
211 List::empty(),
212 rty::FuncSort::new(vec![BitVec(BvSize::Fixed(8))], Int),
213 )
214 }
215 ThyFunc::IntToBv32 => {
216 rty::PolyFuncSort::new(
218 List::empty(),
219 rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(32))),
220 )
221 }
222 ThyFunc::Bv32ToInt => {
223 rty::PolyFuncSort::new(
225 List::empty(),
226 rty::FuncSort::new(vec![BitVec(BvSize::Fixed(32))], Int),
227 )
228 }
229 ThyFunc::IntToBv64 => {
230 rty::PolyFuncSort::new(
232 List::empty(),
233 rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(64))),
234 )
235 }
236 ThyFunc::Bv64ToInt => {
237 rty::PolyFuncSort::new(
239 List::empty(),
240 rty::FuncSort::new(vec![BitVec(BvSize::Fixed(64))], Int),
241 )
242 }
243 ThyFunc::BvUdiv
244 | ThyFunc::BvSdiv
245 | ThyFunc::BvSrem
246 | ThyFunc::BvUrem
247 | ThyFunc::BvLshr
248 | ThyFunc::BvAshr
249 | ThyFunc::BvAnd
250 | ThyFunc::BvOr
251 | ThyFunc::BvXor
252 | ThyFunc::BvAdd
253 | ThyFunc::BvSub
254 | ThyFunc::BvMul
255 | ThyFunc::BvShl => {
256 rty::PolyFuncSort::new(
258 List::singleton(SortParamKind::BvSize),
259 rty::FuncSort::new(vec![BitVec(bv_param0), BitVec(bv_param0)], BitVec(bv_param0)),
260 )
261 }
262 ThyFunc::BvNot | ThyFunc::BvNeg => {
263 rty::PolyFuncSort::new(
265 List::singleton(SortParamKind::BvSize),
266 rty::FuncSort::new(vec![BitVec(bv_param0)], BitVec(bv_param0)),
267 )
268 }
269 ThyFunc::BvUgt
270 | ThyFunc::BvSgt
271 | ThyFunc::BvUlt
272 | ThyFunc::BvSlt
273 | ThyFunc::BvSle
274 | ThyFunc::BvUge
275 | ThyFunc::BvSge
276 | ThyFunc::BvUle => {
277 rty::PolyFuncSort::new(
279 List::singleton(SortParamKind::BvSize),
280 rty::FuncSort::new(vec![BitVec(bv_param0), BitVec(bv_param0)], Bool),
281 )
282 }
283 ThyFunc::SetEmpty => {
284 rty::PolyFuncSort::new(
286 List::singleton(SortParamKind::Sort),
287 rty::FuncSort::new(vec![Int], Sort::app(Set, List::singleton(Var(param0)))),
288 )
289 }
290 ThyFunc::SetSng => {
291 rty::PolyFuncSort::new(
293 List::singleton(SortParamKind::Sort),
294 rty::FuncSort::new(vec![Var(param0)], Sort::app(Set, List::singleton(Var(param0)))),
295 )
296 }
297 ThyFunc::SetCup | ThyFunc::SetCap | ThyFunc::SetDif => {
298 rty::PolyFuncSort::new(
300 List::singleton(SortParamKind::Sort),
301 rty::FuncSort::new(
302 vec![
303 Sort::app(Set, List::singleton(Var(param0))),
304 Sort::app(Set, List::singleton(Var(param0))),
305 ],
306 Sort::app(Set, List::singleton(Var(param0))),
307 ),
308 )
309 }
310 ThyFunc::SetMem => {
311 rty::PolyFuncSort::new(
313 List::singleton(SortParamKind::Sort),
314 rty::FuncSort::new(
315 vec![Var(param0), Sort::app(Set, List::singleton(Var(param0)))],
316 Bool,
317 ),
318 )
319 }
320 ThyFunc::SetSub => {
321 rty::PolyFuncSort::new(
323 List::singleton(SortParamKind::Sort),
324 rty::FuncSort::new(
325 vec![
326 Sort::app(Set, List::singleton(Var(param0))),
327 Sort::app(Set, List::singleton(Var(param0))),
328 ],
329 Bool,
330 ),
331 )
332 }
333
334 ThyFunc::MapDefault => {
335 rty::PolyFuncSort::new(
337 List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
338 rty::FuncSort::new(
339 vec![Var(param1)],
340 Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
341 ),
342 )
343 }
344 ThyFunc::MapSelect => {
345 rty::PolyFuncSort::new(
347 List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
348 rty::FuncSort::new(
349 vec![Sort::app(Map, List::from_arr([Var(param0), Var(param1)])), Var(param0)],
350 Var(param1),
351 ),
352 )
353 }
354 ThyFunc::MapStore => {
355 rty::PolyFuncSort::new(
357 List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
358 rty::FuncSort::new(
359 vec![
360 Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
361 Var(param0),
362 Var(param1),
363 ],
364 Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
365 ),
366 )
367 }
368 };
369 Some(sort)
370}
371
372#[derive(Default)]
373pub struct Specs {
374 items: UnordMap<OwnerId, surface::Item>,
375 trait_items: UnordMap<OwnerId, surface::TraitItemFn>,
376 impl_items: UnordMap<OwnerId, surface::ImplItemFn>,
377 pub flux_items_by_parent: FxIndexMap<OwnerId, Vec<surface::FluxItem>>,
378 dummy_extern: UnordSet<LocalDefId>,
387 extern_id_to_local_id: UnordMap<DefId, LocalDefId>,
388 local_id_to_extern_id: UnordMap<LocalDefId, DefId>,
389}
390
391impl Specs {
392 pub fn insert_extern_spec_id_mapping(
393 &mut self,
394 local_id: LocalDefId,
395 extern_id: DefId,
396 ) -> Result<(), ExternSpecMappingErr> {
397 #[expect(
398 clippy::disallowed_methods,
399 reason = "we are inserting the extern spec mapping and we want to ensure it doesn't point to a local item"
400 )]
401 if let Some(local) = extern_id.as_local() {
402 return Err(ExternSpecMappingErr::IsLocal(local));
403 }
404 if let Err(err) = self.extern_id_to_local_id.try_insert(extern_id, local_id) {
405 return Err(ExternSpecMappingErr::Dup(*err.entry.get()));
406 }
407 self.local_id_to_extern_id.insert(local_id, extern_id);
408 Ok(())
409 }
410
411 pub fn insert_dummy(&mut self, def_id: LocalDefId) {
412 self.dummy_extern.insert(def_id);
413 }
414
415 pub fn get_item(&self, owner_id: OwnerId) -> Option<&surface::Item> {
416 self.items.get(&owner_id)
417 }
418
419 pub fn insert_item(&mut self, owner_id: OwnerId, item: surface::Item) -> Option<surface::Item> {
420 if let Some(old) = self.items.insert(owner_id, item) {
421 return Some(old);
422 }
423 None
424 }
425
426 pub fn get_trait_item(&self, owner_id: OwnerId) -> Option<&surface::TraitItemFn> {
427 self.trait_items.get(&owner_id)
428 }
429
430 pub fn insert_trait_item(
431 &mut self,
432 owner_id: OwnerId,
433 trait_item: surface::TraitItemFn,
434 ) -> Option<surface::TraitItemFn> {
435 if let Some(old) = self.trait_items.insert(owner_id, trait_item) {
436 return Some(old);
437 }
438 None
439 }
440
441 pub fn get_impl_item(&self, owner_id: OwnerId) -> Option<&surface::ImplItemFn> {
442 self.impl_items.get(&owner_id)
443 }
444
445 pub fn insert_impl_item(
446 &mut self,
447 owner_id: OwnerId,
448 impl_item: surface::ImplItemFn,
449 ) -> Option<surface::ImplItemFn> {
450 if let Some(old) = self.impl_items.insert(owner_id, impl_item) {
451 return Some(old);
452 }
453 None
454 }
455}
456
457pub enum ExternSpecMappingErr {
460 IsLocal(LocalDefId),
463
464 Dup(LocalDefId),
473}
474
475#[derive(Default)]
476pub struct ResolverOutput {
477 pub path_res_map: UnordMap<NodeId, fhir::PartialRes>,
478 pub param_res_map: UnordMap<NodeId, (fhir::ParamId, fhir::ParamKind)>,
483 pub implicit_params: UnordMap<NodeId, Vec<(Ident, NodeId)>>,
487 pub sort_path_res_map: UnordMap<NodeId, fhir::SortRes>,
488 pub expr_path_res_map: UnordMap<NodeId, fhir::PartialRes<fhir::ParamId>>,
489 pub qualifier_res_map: UnordMap<NodeId, Vec<def_id::FluxLocalDefId>>,
492 pub reveal_res_map: UnordMap<NodeId, Vec<def_id::FluxDefId>>,
495}
496
497#[extension(pub trait PlaceExt)]
498impl flux_rustc_bridge::mir::Place {
499 fn ty(&self, genv: GlobalEnv, local_decls: &LocalDecls) -> QueryResult<PlaceTy> {
500 self.projection
501 .iter()
502 .try_fold(PlaceTy::from_ty(local_decls[self.local].ty.clone()), |place_ty, elem| {
503 place_ty.projection_ty(genv, *elem)
504 })
505 }
506
507 fn behind_raw_ptr(&self, genv: GlobalEnv, local_decls: &LocalDecls) -> QueryResult<bool> {
508 let mut place_ty = PlaceTy::from_ty(local_decls[self.local].ty.clone());
509 for elem in &self.projection {
510 if let (PlaceElem::Deref, ty::TyKind::RawPtr(..)) = (elem, place_ty.ty.kind()) {
511 return Ok(true);
512 }
513 place_ty = place_ty.projection_ty(genv, *elem)?;
514 }
515 Ok(false)
516 }
517}
518
519#[derive(Debug)]
520pub struct PlaceTy {
521 pub ty: ty::Ty,
522 pub variant_index: Option<VariantIdx>,
524}
525
526impl PlaceTy {
527 fn from_ty(ty: ty::Ty) -> PlaceTy {
528 PlaceTy { ty, variant_index: None }
529 }
530
531 fn projection_ty(&self, genv: GlobalEnv, elem: PlaceElem) -> QueryResult<PlaceTy> {
532 if self.variant_index.is_some() && !matches!(elem, PlaceElem::Field(..)) {
533 Err(query_bug!("cannot use non field projection on downcasted place"))?;
534 }
535 let place_ty = match elem {
536 PlaceElem::Deref => PlaceTy::from_ty(self.ty.deref()),
537 PlaceElem::Field(fld) => PlaceTy::from_ty(self.field_ty(genv, fld)?),
538 PlaceElem::Downcast(_, variant_idx) => {
539 PlaceTy { ty: self.ty.clone(), variant_index: Some(variant_idx) }
540 }
541 PlaceElem::Index(_) | PlaceElem::ConstantIndex { .. } => {
542 if let ty::TyKind::Array(ty, _) | ty::TyKind::Slice(ty) = self.ty.kind() {
543 PlaceTy::from_ty(ty.clone())
544 } else {
545 return Err(query_bug!("cannot use non field projection on downcasted place"));
546 }
547 }
548 };
549 Ok(place_ty)
550 }
551
552 fn field_ty(&self, genv: GlobalEnv, f: FieldIdx) -> QueryResult<ty::Ty> {
553 match self.ty.kind() {
554 ty::TyKind::Adt(adt_def, args) => {
555 let variant_def = match self.variant_index {
556 None => adt_def.non_enum_variant(),
557 Some(variant_index) => {
558 assert!(adt_def.is_enum());
559 adt_def.variant(variant_index)
560 }
561 };
562 let field_def = &variant_def.fields[f];
563 let ty = genv.lower_type_of(field_def.did)?;
564 Ok(ty.subst(args))
565 }
566 ty::TyKind::Tuple(tys) => Ok(tys[f.index()].clone()),
567 ty::TyKind::Closure(_, args) => Ok(args.as_closure().upvar_tys()[f.index()].clone()),
568 _ => Err(query_bug!("extracting field of non-tuple non-adt non-closure: {self:?}")),
569 }
570 }
571}
572
573#[derive(Debug, Hash, Clone, Copy)]
578pub enum FixpointQueryKind {
579 Impl,
581 Body,
583 Invariant,
585}
586
587impl FixpointQueryKind {
588 pub fn ext(self) -> &'static str {
589 match self {
590 FixpointQueryKind::Impl => "sub.fluxc",
591 FixpointQueryKind::Body => "fluxc",
592 FixpointQueryKind::Invariant => "fluxc",
593 }
594 }
595
596 pub fn task_key(self, tcx: TyCtxt, def_id: DefId) -> String {
598 format!("{}###{:?}", tcx.def_path_str(def_id), self)
599 }
600
601 #[must_use]
605 pub fn is_body(&self) -> bool {
606 matches!(self, Self::Body)
607 }
608}