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;
30pub mod cstore;
31pub mod def_id;
32pub mod fhir;
33pub mod global_env;
34pub mod pretty;
35pub mod queries;
36pub mod rty;
37mod sort_of;
38pub mod timings;
39
40use std::sync::LazyLock;
41
42use flux_arc_interner::List;
43use flux_macros::fluent_messages;
44pub use flux_rustc_bridge::def_id_to_string;
45use flux_rustc_bridge::{
46 mir::{LocalDecls, PlaceElem},
47 ty::{self, GenericArgsExt},
48};
49use flux_syntax::surface::{self, NodeId};
50use global_env::GlobalEnv;
51use liquid_fixpoint::ThyFunc;
52use queries::QueryResult;
53use rty::VariantIdx;
54use rustc_abi::FieldIdx;
55use rustc_data_structures::{
56 fx::FxIndexMap,
57 unord::{UnordMap, UnordSet},
58};
59use rustc_hir::OwnerId;
60use rustc_macros::extension;
61use rustc_middle::ty::TyCtxt;
62use rustc_span::{
63 Symbol,
64 def_id::{DefId, LocalDefId},
65 symbol::Ident,
66};
67
68fluent_messages! { "../locales/en-US.ftl" }
69
70pub struct TheoryFunc {
71 pub name: Symbol,
72 pub sort: rty::PolyFuncSort,
73 pub itf: liquid_fixpoint::ThyFunc,
74}
75
76pub static THEORY_FUNCS: LazyLock<UnordMap<liquid_fixpoint::ThyFunc, TheoryFunc>> =
77 LazyLock::new(|| {
78 use rty::{BvSize, Sort::*};
79 liquid_fixpoint::ThyFunc::ALL
80 .into_iter()
81 .filter_map(|func| {
82 let func = TheoryFunc {
83 name: Symbol::intern(name_of_thy_func(func)?),
84 itf: func,
85 sort: sort_of_thy_func(func)?,
86 };
87 Some(func)
88 })
89 .chain([
90 TheoryFunc {
92 name: Symbol::intern("bv_zero_extend_32_to_64"),
93 itf: liquid_fixpoint::ThyFunc::BvZeroExtend(32),
94 sort: rty::PolyFuncSort::new(
95 List::empty(),
96 rty::FuncSort::new(
97 vec![BitVec(BvSize::Fixed(32))],
98 BitVec(BvSize::Fixed(64)),
99 ),
100 ),
101 },
102 TheoryFunc {
103 name: Symbol::intern("bv_sign_extend_32_to_64"),
104 itf: liquid_fixpoint::ThyFunc::BvSignExtend(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 ])
114 .map(|func| (func.itf, func))
115 .collect()
116 });
117
118pub fn name_of_thy_func(func: liquid_fixpoint::ThyFunc) -> Option<&'static str> {
119 let name = match func {
120 ThyFunc::BvZeroExtend(_) | ThyFunc::BvSignExtend(_) => return None,
121 ThyFunc::StrLen => "str_len",
122 ThyFunc::IntToBv8 => "bv_int_to_bv8",
123 ThyFunc::Bv8ToInt => "bv_bv8_to_int",
124 ThyFunc::IntToBv32 => "bv_int_to_bv32",
125 ThyFunc::Bv32ToInt => "bv_bv32_to_int",
126 ThyFunc::IntToBv64 => "bv_int_to_bv64",
127 ThyFunc::Bv64ToInt => "bv_bv64_to_int",
128 ThyFunc::BvUge => "bv_uge",
129 ThyFunc::BvSge => "bv_sge",
130 ThyFunc::BvUdiv => "bv_udiv",
131 ThyFunc::BvSdiv => "bv_sdiv",
132 ThyFunc::BvSrem => "bv_srem",
133 ThyFunc::BvUrem => "bv_urem",
134 ThyFunc::BvLshr => "bv_lshr",
135 ThyFunc::BvAshr => "bv_ashr",
136 ThyFunc::BvAnd => "bv_and",
137 ThyFunc::BvOr => "bv_or",
138 ThyFunc::BvXor => "bv_xor",
139 ThyFunc::BvNot => "bv_not",
140 ThyFunc::BvAdd => "bv_add",
141 ThyFunc::BvNeg => "bv_neg",
142 ThyFunc::BvSub => "bv_sub",
143 ThyFunc::BvMul => "bv_mul",
144 ThyFunc::BvShl => "bv_shl",
145 ThyFunc::BvUle => "bv_ule",
146 ThyFunc::BvSle => "bv_sle",
147 ThyFunc::BvUgt => "bv_ugt",
148 ThyFunc::BvSgt => "bv_sgt",
149 ThyFunc::BvUlt => "bv_ult",
150 ThyFunc::BvSlt => "bv_slt",
151 ThyFunc::SetEmpty => "set_empty",
152 ThyFunc::SetSng => "set_singleton",
153 ThyFunc::SetCup => "set_union",
154 ThyFunc::SetCap => "set_intersection",
155 ThyFunc::SetDif => "set_difference",
156 ThyFunc::SetSub => "set_subset",
157 ThyFunc::SetMem => "set_is_in",
158 ThyFunc::MapDefault => "map_default",
159 ThyFunc::MapSelect => "map_select",
160 ThyFunc::MapStore => "map_store",
161 };
162 Some(name)
163}
164
165fn sort_of_thy_func(func: liquid_fixpoint::ThyFunc) -> Option<rty::PolyFuncSort> {
166 use rty::{
167 BvSize, ParamSort,
168 Sort::{self, *},
169 SortCtor::*,
170 SortParamKind,
171 };
172 let param0 = ParamSort::from_u32(0);
173 let param1 = ParamSort::from_u32(1);
174 let bv_param0 = BvSize::Param(ParamSort::from_u32(0));
175
176 let sort = match func {
177 ThyFunc::BvZeroExtend(_) | ThyFunc::BvSignExtend(_) => return None,
178 ThyFunc::StrLen => {
179 rty::PolyFuncSort::new(List::empty(), rty::FuncSort::new(vec![rty::Sort::Str], Int))
181 }
182 ThyFunc::IntToBv8 => {
183 rty::PolyFuncSort::new(
185 List::empty(),
186 rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(8))),
187 )
188 }
189 ThyFunc::Bv8ToInt => {
190 rty::PolyFuncSort::new(
192 List::empty(),
193 rty::FuncSort::new(vec![BitVec(BvSize::Fixed(8))], Int),
194 )
195 }
196 ThyFunc::IntToBv32 => {
197 rty::PolyFuncSort::new(
199 List::empty(),
200 rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(32))),
201 )
202 }
203 ThyFunc::Bv32ToInt => {
204 rty::PolyFuncSort::new(
206 List::empty(),
207 rty::FuncSort::new(vec![BitVec(BvSize::Fixed(32))], Int),
208 )
209 }
210 ThyFunc::IntToBv64 => {
211 rty::PolyFuncSort::new(
213 List::empty(),
214 rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(64))),
215 )
216 }
217 ThyFunc::Bv64ToInt => {
218 rty::PolyFuncSort::new(
220 List::empty(),
221 rty::FuncSort::new(vec![BitVec(BvSize::Fixed(64))], Int),
222 )
223 }
224 ThyFunc::BvUdiv
225 | ThyFunc::BvSdiv
226 | ThyFunc::BvSrem
227 | ThyFunc::BvUrem
228 | ThyFunc::BvLshr
229 | ThyFunc::BvAshr
230 | ThyFunc::BvAnd
231 | ThyFunc::BvOr
232 | ThyFunc::BvXor
233 | ThyFunc::BvAdd
234 | ThyFunc::BvSub
235 | ThyFunc::BvMul
236 | ThyFunc::BvShl => {
237 rty::PolyFuncSort::new(
239 List::singleton(SortParamKind::BvSize),
240 rty::FuncSort::new(vec![BitVec(bv_param0), BitVec(bv_param0)], BitVec(bv_param0)),
241 )
242 }
243 ThyFunc::BvNot | ThyFunc::BvNeg => {
244 rty::PolyFuncSort::new(
246 List::singleton(SortParamKind::BvSize),
247 rty::FuncSort::new(vec![BitVec(bv_param0)], BitVec(bv_param0)),
248 )
249 }
250 ThyFunc::BvUgt
251 | ThyFunc::BvSgt
252 | ThyFunc::BvUlt
253 | ThyFunc::BvSlt
254 | ThyFunc::BvSle
255 | ThyFunc::BvUge
256 | ThyFunc::BvSge
257 | ThyFunc::BvUle => {
258 rty::PolyFuncSort::new(
260 List::singleton(SortParamKind::BvSize),
261 rty::FuncSort::new(vec![BitVec(bv_param0), BitVec(bv_param0)], Bool),
262 )
263 }
264 ThyFunc::SetEmpty => {
265 rty::PolyFuncSort::new(
267 List::singleton(SortParamKind::Sort),
268 rty::FuncSort::new(vec![Int], Sort::app(Set, List::singleton(Var(param0)))),
269 )
270 }
271 ThyFunc::SetSng => {
272 rty::PolyFuncSort::new(
274 List::singleton(SortParamKind::Sort),
275 rty::FuncSort::new(vec![Var(param0)], Sort::app(Set, List::singleton(Var(param0)))),
276 )
277 }
278 ThyFunc::SetCup | ThyFunc::SetCap | ThyFunc::SetDif => {
279 rty::PolyFuncSort::new(
281 List::singleton(SortParamKind::Sort),
282 rty::FuncSort::new(
283 vec![
284 Sort::app(Set, List::singleton(Var(param0))),
285 Sort::app(Set, List::singleton(Var(param0))),
286 ],
287 Sort::app(Set, List::singleton(Var(param0))),
288 ),
289 )
290 }
291 ThyFunc::SetMem => {
292 rty::PolyFuncSort::new(
294 List::singleton(SortParamKind::Sort),
295 rty::FuncSort::new(
296 vec![Var(param0), Sort::app(Set, List::singleton(Var(param0)))],
297 Bool,
298 ),
299 )
300 }
301 ThyFunc::SetSub => {
302 rty::PolyFuncSort::new(
304 List::singleton(SortParamKind::Sort),
305 rty::FuncSort::new(
306 vec![
307 Sort::app(Set, List::singleton(Var(param0))),
308 Sort::app(Set, List::singleton(Var(param0))),
309 ],
310 Bool,
311 ),
312 )
313 }
314
315 ThyFunc::MapDefault => {
316 rty::PolyFuncSort::new(
318 List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
319 rty::FuncSort::new(
320 vec![Var(param1)],
321 Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
322 ),
323 )
324 }
325 ThyFunc::MapSelect => {
326 rty::PolyFuncSort::new(
328 List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
329 rty::FuncSort::new(
330 vec![Sort::app(Map, List::from_arr([Var(param0), Var(param1)])), Var(param0)],
331 Var(param1),
332 ),
333 )
334 }
335 ThyFunc::MapStore => {
336 rty::PolyFuncSort::new(
338 List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
339 rty::FuncSort::new(
340 vec![
341 Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
342 Var(param0),
343 Var(param1),
344 ],
345 Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
346 ),
347 )
348 }
349 };
350 Some(sort)
351}
352
353#[derive(Default)]
354pub struct Specs {
355 items: UnordMap<OwnerId, surface::Item>,
356 trait_items: UnordMap<OwnerId, surface::TraitItemFn>,
357 impl_items: UnordMap<OwnerId, surface::ImplItemFn>,
358 pub flux_items_by_parent: FxIndexMap<OwnerId, Vec<surface::FluxItem>>,
359 dummy_extern: UnordSet<LocalDefId>,
368 extern_id_to_local_id: UnordMap<DefId, LocalDefId>,
369 local_id_to_extern_id: UnordMap<LocalDefId, DefId>,
370}
371
372impl Specs {
373 pub fn insert_extern_spec_id_mapping(
374 &mut self,
375 local_id: LocalDefId,
376 extern_id: DefId,
377 ) -> Result<(), ExternSpecMappingErr> {
378 #[expect(
379 clippy::disallowed_methods,
380 reason = "we are inserting the extern spec mapping and we want to ensure it doesn't point to a local item"
381 )]
382 if let Some(local) = extern_id.as_local() {
383 return Err(ExternSpecMappingErr::IsLocal(local));
384 }
385 if let Err(err) = self.extern_id_to_local_id.try_insert(extern_id, local_id) {
386 return Err(ExternSpecMappingErr::Dup(*err.entry.get()));
387 }
388 self.local_id_to_extern_id.insert(local_id, extern_id);
389 Ok(())
390 }
391
392 pub fn insert_dummy(&mut self, def_id: LocalDefId) {
393 self.dummy_extern.insert(def_id);
394 }
395
396 pub fn get_item(&self, owner_id: OwnerId) -> Option<&surface::Item> {
397 self.items.get(&owner_id)
398 }
399
400 pub fn insert_item(&mut self, owner_id: OwnerId, item: surface::Item) -> Option<surface::Item> {
401 if let Some(old) = self.items.insert(owner_id, item) {
402 return Some(old);
403 }
404 None
405 }
406
407 pub fn get_trait_item(&self, owner_id: OwnerId) -> Option<&surface::TraitItemFn> {
408 self.trait_items.get(&owner_id)
409 }
410
411 pub fn insert_trait_item(
412 &mut self,
413 owner_id: OwnerId,
414 trait_item: surface::TraitItemFn,
415 ) -> Option<surface::TraitItemFn> {
416 if let Some(old) = self.trait_items.insert(owner_id, trait_item) {
417 return Some(old);
418 }
419 None
420 }
421
422 pub fn get_impl_item(&self, owner_id: OwnerId) -> Option<&surface::ImplItemFn> {
423 self.impl_items.get(&owner_id)
424 }
425
426 pub fn insert_impl_item(
427 &mut self,
428 owner_id: OwnerId,
429 impl_item: surface::ImplItemFn,
430 ) -> Option<surface::ImplItemFn> {
431 if let Some(old) = self.impl_items.insert(owner_id, impl_item) {
432 return Some(old);
433 }
434 None
435 }
436}
437
438pub enum ExternSpecMappingErr {
441 IsLocal(LocalDefId),
444
445 Dup(LocalDefId),
454}
455
456#[derive(Default)]
457pub struct ResolverOutput {
458 pub path_res_map: UnordMap<NodeId, fhir::PartialRes>,
459 pub param_res_map: UnordMap<NodeId, (fhir::ParamId, fhir::ParamKind)>,
464 pub implicit_params: UnordMap<NodeId, Vec<(Ident, NodeId)>>,
468 pub sort_path_res_map: UnordMap<NodeId, fhir::SortRes>,
469 pub expr_path_res_map: UnordMap<NodeId, fhir::PartialRes<fhir::ParamId>>,
470 pub qualifier_res_map: UnordMap<NodeId, Vec<def_id::FluxLocalDefId>>,
473 pub reveal_res_map: UnordMap<NodeId, Vec<def_id::FluxDefId>>,
476}
477
478#[extension(pub trait PlaceExt)]
479impl flux_rustc_bridge::mir::Place {
480 fn ty(&self, genv: GlobalEnv, local_decls: &LocalDecls) -> QueryResult<PlaceTy> {
481 self.projection
482 .iter()
483 .try_fold(PlaceTy::from_ty(local_decls[self.local].ty.clone()), |place_ty, elem| {
484 place_ty.projection_ty(genv, *elem)
485 })
486 }
487
488 fn behind_raw_ptr(&self, genv: GlobalEnv, local_decls: &LocalDecls) -> QueryResult<bool> {
489 let mut place_ty = PlaceTy::from_ty(local_decls[self.local].ty.clone());
490 for elem in &self.projection {
491 if let (PlaceElem::Deref, ty::TyKind::RawPtr(..)) = (elem, place_ty.ty.kind()) {
492 return Ok(true);
493 }
494 place_ty = place_ty.projection_ty(genv, *elem)?;
495 }
496 Ok(false)
497 }
498}
499
500#[derive(Debug)]
501pub struct PlaceTy {
502 pub ty: ty::Ty,
503 pub variant_index: Option<VariantIdx>,
505}
506
507impl PlaceTy {
508 fn from_ty(ty: ty::Ty) -> PlaceTy {
509 PlaceTy { ty, variant_index: None }
510 }
511
512 fn projection_ty(&self, genv: GlobalEnv, elem: PlaceElem) -> QueryResult<PlaceTy> {
513 if self.variant_index.is_some() && !matches!(elem, PlaceElem::Field(..)) {
514 Err(query_bug!("cannot use non field projection on downcasted place"))?;
515 }
516 let place_ty = match elem {
517 PlaceElem::Deref => PlaceTy::from_ty(self.ty.deref()),
518 PlaceElem::Field(fld) => PlaceTy::from_ty(self.field_ty(genv, fld)?),
519 PlaceElem::Downcast(_, variant_idx) => {
520 PlaceTy { ty: self.ty.clone(), variant_index: Some(variant_idx) }
521 }
522 PlaceElem::Index(_) | PlaceElem::ConstantIndex { .. } => {
523 if let ty::TyKind::Array(ty, _) | ty::TyKind::Slice(ty) = self.ty.kind() {
524 PlaceTy::from_ty(ty.clone())
525 } else {
526 return Err(query_bug!("cannot use non field projection on downcasted place"));
527 }
528 }
529 };
530 Ok(place_ty)
531 }
532
533 fn field_ty(&self, genv: GlobalEnv, f: FieldIdx) -> QueryResult<ty::Ty> {
534 match self.ty.kind() {
535 ty::TyKind::Adt(adt_def, args) => {
536 let variant_def = match self.variant_index {
537 None => adt_def.non_enum_variant(),
538 Some(variant_index) => {
539 assert!(adt_def.is_enum());
540 adt_def.variant(variant_index)
541 }
542 };
543 let field_def = &variant_def.fields[f];
544 let ty = genv.lower_type_of(field_def.did)?;
545 Ok(ty.subst(args))
546 }
547 ty::TyKind::Tuple(tys) => Ok(tys[f.index()].clone()),
548 ty::TyKind::Closure(_, args) => Ok(args.as_closure().upvar_tys()[f.index()].clone()),
549 _ => Err(query_bug!("extracting field of non-tuple non-adt non-closure: {self:?}")),
550 }
551 }
552}
553
554#[derive(Debug, Hash, Clone, Copy)]
559pub enum FixpointQueryKind {
560 Impl,
562 Body,
564 Invariant,
566}
567
568impl FixpointQueryKind {
569 pub fn ext(self) -> &'static str {
570 match self {
571 FixpointQueryKind::Impl => "sub.fluxc",
572 FixpointQueryKind::Body => "fluxc",
573 FixpointQueryKind::Invariant => "fluxc",
574 }
575 }
576
577 pub fn task_key(self, tcx: TyCtxt, def_id: DefId) -> String {
579 format!("{}###{:?}", tcx.def_path_str(def_id), self)
580 }
581}