1#![feature(
3 associated_type_defaults,
4 box_patterns,
5 closure_track_caller,
6 if_let_guard,
7 let_chains,
8 map_try_insert,
9 min_specialization,
10 never_type,
11 rustc_private,
12 unwrap_infallible,
13 new_range_api
14)]
15
16extern crate rustc_abi;
17extern crate rustc_ast;
18extern crate rustc_data_structures;
19extern crate rustc_errors;
20extern crate rustc_hir;
21extern crate rustc_index;
22extern crate rustc_macros;
23extern crate rustc_middle;
24extern crate rustc_serialize;
25extern crate rustc_span;
26extern crate rustc_type_ir;
27
28extern crate self as flux_middle;
29
30pub mod big_int;
31pub mod cstore;
32pub mod def_id;
33pub mod fhir;
34pub mod global_env;
35pub mod pretty;
36pub mod queries;
37pub mod rty;
38mod sort_of;
39pub mod timings;
40
41use std::sync::LazyLock;
42
43use flux_arc_interner::List;
44use flux_config as config;
45use flux_macros::fluent_messages;
46pub use flux_rustc_bridge::def_id_to_string;
47use flux_rustc_bridge::{
48 mir::{LocalDecls, PlaceElem},
49 ty::{self, GenericArgsExt},
50};
51use flux_syntax::surface::{self, NodeId};
52use global_env::GlobalEnv;
53use liquid_fixpoint::ThyFunc;
54use queries::QueryResult;
55use rty::VariantIdx;
56use rustc_abi::FieldIdx;
57use rustc_data_structures::{
58 fx::FxIndexMap,
59 unord::{UnordMap, UnordSet},
60};
61use rustc_hir::OwnerId;
62use rustc_macros::extension;
63use rustc_middle::ty::TyCtxt;
64use rustc_span::{
65 Symbol,
66 def_id::{DefId, LocalDefId},
67 symbol::Ident,
68};
69
70fluent_messages! { "../locales/en-US.ftl" }
71
72pub struct TheoryFunc {
73 pub name: Symbol,
74 pub sort: rty::PolyFuncSort,
75 pub itf: liquid_fixpoint::ThyFunc,
76}
77
78pub static THEORY_FUNCS: LazyLock<UnordMap<liquid_fixpoint::ThyFunc, TheoryFunc>> =
79 LazyLock::new(|| {
80 use rty::{BvSize, Sort::*};
81 liquid_fixpoint::ThyFunc::ALL
82 .into_iter()
83 .filter_map(|func| {
84 let func = TheoryFunc {
85 name: Symbol::intern(name_of_thy_func(func)?),
86 itf: func,
87 sort: sort_of_thy_func(func)?,
88 };
89 Some(func)
90 })
91 .chain([
92 TheoryFunc {
94 name: Symbol::intern("bv_zero_extend_32_to_64"),
95 itf: liquid_fixpoint::ThyFunc::BvZeroExtend(32),
96 sort: rty::PolyFuncSort::new(
97 List::empty(),
98 rty::FuncSort::new(
99 vec![BitVec(BvSize::Fixed(32))],
100 BitVec(BvSize::Fixed(64)),
101 ),
102 ),
103 },
104 TheoryFunc {
105 name: Symbol::intern("bv_sign_extend_32_to_64"),
106 itf: liquid_fixpoint::ThyFunc::BvSignExtend(32),
107 sort: rty::PolyFuncSort::new(
108 List::empty(),
109 rty::FuncSort::new(
110 vec![BitVec(BvSize::Fixed(32))],
111 BitVec(BvSize::Fixed(64)),
112 ),
113 ),
114 },
115 ])
116 .map(|func| (func.itf, func))
117 .collect()
118 });
119
120pub fn name_of_thy_func(func: liquid_fixpoint::ThyFunc) -> Option<&'static str> {
121 let name = match func {
122 ThyFunc::BvZeroExtend(_) | ThyFunc::BvSignExtend(_) => return None,
123 ThyFunc::StrLen => "str_len",
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::SetMem => "set_is_in",
155 ThyFunc::MapDefault => "map_default",
156 ThyFunc::MapSelect => "map_select",
157 ThyFunc::MapStore => "map_store",
158 };
159 Some(name)
160}
161
162fn sort_of_thy_func(func: liquid_fixpoint::ThyFunc) -> Option<rty::PolyFuncSort> {
163 use rty::{
164 BvSize, ParamSort,
165 Sort::{self, *},
166 SortCtor::*,
167 SortParamKind,
168 };
169 let param0 = ParamSort::from_u32(0);
170 let param1 = ParamSort::from_u32(1);
171 let bv_param0 = BvSize::Param(ParamSort::from_u32(0));
172
173 let sort = match func {
174 ThyFunc::BvZeroExtend(_) | ThyFunc::BvSignExtend(_) => return None,
175 ThyFunc::StrLen => {
176 rty::PolyFuncSort::new(List::empty(), rty::FuncSort::new(vec![rty::Sort::Str], Int))
178 }
179 ThyFunc::IntToBv32 => {
180 rty::PolyFuncSort::new(
182 List::empty(),
183 rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(32))),
184 )
185 }
186 ThyFunc::Bv32ToInt => {
187 rty::PolyFuncSort::new(
189 List::empty(),
190 rty::FuncSort::new(vec![BitVec(BvSize::Fixed(32))], Int),
191 )
192 }
193 ThyFunc::IntToBv64 => {
194 rty::PolyFuncSort::new(
196 List::empty(),
197 rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(64))),
198 )
199 }
200 ThyFunc::Bv64ToInt => {
201 rty::PolyFuncSort::new(
203 List::empty(),
204 rty::FuncSort::new(vec![BitVec(BvSize::Fixed(64))], Int),
205 )
206 }
207 ThyFunc::BvUdiv
208 | ThyFunc::BvSdiv
209 | ThyFunc::BvSrem
210 | ThyFunc::BvUrem
211 | ThyFunc::BvLshr
212 | ThyFunc::BvAshr
213 | ThyFunc::BvAnd
214 | ThyFunc::BvOr
215 | ThyFunc::BvXor
216 | ThyFunc::BvAdd
217 | ThyFunc::BvSub
218 | ThyFunc::BvMul
219 | ThyFunc::BvShl => {
220 rty::PolyFuncSort::new(
222 List::singleton(SortParamKind::BvSize),
223 rty::FuncSort::new(vec![BitVec(bv_param0), BitVec(bv_param0)], BitVec(bv_param0)),
224 )
225 }
226 ThyFunc::BvNot | ThyFunc::BvNeg => {
227 rty::PolyFuncSort::new(
229 List::singleton(SortParamKind::BvSize),
230 rty::FuncSort::new(vec![BitVec(bv_param0)], BitVec(bv_param0)),
231 )
232 }
233 ThyFunc::BvUgt
234 | ThyFunc::BvSgt
235 | ThyFunc::BvUlt
236 | ThyFunc::BvSlt
237 | ThyFunc::BvSle
238 | ThyFunc::BvUge
239 | ThyFunc::BvSge
240 | ThyFunc::BvUle => {
241 rty::PolyFuncSort::new(
243 List::singleton(SortParamKind::BvSize),
244 rty::FuncSort::new(vec![BitVec(bv_param0), BitVec(bv_param0)], Bool),
245 )
246 }
247 ThyFunc::SetEmpty => {
248 rty::PolyFuncSort::new(
250 List::singleton(SortParamKind::Sort),
251 rty::FuncSort::new(vec![Int], Sort::app(Set, List::singleton(Var(param0)))),
252 )
253 }
254 ThyFunc::SetSng => {
255 rty::PolyFuncSort::new(
257 List::singleton(SortParamKind::Sort),
258 rty::FuncSort::new(vec![Var(param0)], Sort::app(Set, List::singleton(Var(param0)))),
259 )
260 }
261 ThyFunc::SetCup => {
262 rty::PolyFuncSort::new(
264 List::singleton(SortParamKind::Sort),
265 rty::FuncSort::new(
266 vec![
267 Sort::app(Set, List::singleton(Var(param0))),
268 Sort::app(Set, List::singleton(Var(param0))),
269 ],
270 Sort::app(Set, List::singleton(Var(param0))),
271 ),
272 )
273 }
274 ThyFunc::SetMem => {
275 rty::PolyFuncSort::new(
277 List::singleton(SortParamKind::Sort),
278 rty::FuncSort::new(
279 vec![Var(param0), Sort::app(Set, List::singleton(Var(param0)))],
280 Bool,
281 ),
282 )
283 }
284 ThyFunc::MapDefault => {
285 rty::PolyFuncSort::new(
287 List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
288 rty::FuncSort::new(
289 vec![Var(param1)],
290 Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
291 ),
292 )
293 }
294 ThyFunc::MapSelect => {
295 rty::PolyFuncSort::new(
297 List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
298 rty::FuncSort::new(
299 vec![Sort::app(Map, List::from_arr([Var(param0), Var(param1)])), Var(param0)],
300 Var(param1),
301 ),
302 )
303 }
304 ThyFunc::MapStore => {
305 rty::PolyFuncSort::new(
307 List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
308 rty::FuncSort::new(
309 vec![
310 Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
311 Var(param0),
312 Var(param1),
313 ],
314 Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
315 ),
316 )
317 }
318 };
319 Some(sort)
320}
321
322#[derive(Default)]
323pub struct Specs {
324 pub fn_sigs: UnordMap<OwnerId, surface::FnSpec>,
325 pub constants: UnordMap<OwnerId, surface::ConstantInfo>,
326 pub structs: UnordMap<OwnerId, surface::StructDef>,
327 pub traits: UnordMap<OwnerId, surface::Trait>,
328 pub impls: UnordMap<OwnerId, surface::Impl>,
329 pub enums: UnordMap<OwnerId, surface::EnumDef>,
330 pub flux_items_by_parent: FxIndexMap<OwnerId, Vec<surface::Item>>,
331 pub ty_aliases: UnordMap<OwnerId, Option<surface::TyAlias>>,
332 pub ignores: UnordMap<LocalDefId, fhir::Ignored>,
333 pub trusted: UnordMap<LocalDefId, fhir::Trusted>,
334 pub trusted_impl: UnordMap<LocalDefId, fhir::Trusted>,
335 pub infer_opts: UnordMap<LocalDefId, config::PartialInferOpts>,
336 pub should_fail: UnordSet<LocalDefId>,
337 dummy_extern: UnordSet<LocalDefId>,
346 extern_id_to_local_id: UnordMap<DefId, LocalDefId>,
347 local_id_to_extern_id: UnordMap<LocalDefId, DefId>,
348}
349
350impl Specs {
351 pub fn insert_extern_spec_id_mapping(
352 &mut self,
353 local_id: LocalDefId,
354 extern_id: DefId,
355 ) -> Result<(), ExternSpecMappingErr> {
356 #[expect(
357 clippy::disallowed_methods,
358 reason = "we are inserting the extern spec mapping and we want to ensure it doesn't point to a local item"
359 )]
360 if let Some(local) = extern_id.as_local() {
361 return Err(ExternSpecMappingErr::IsLocal(local));
362 }
363 if let Err(err) = self.extern_id_to_local_id.try_insert(extern_id, local_id) {
364 return Err(ExternSpecMappingErr::Dup(*err.entry.get()));
365 }
366 self.local_id_to_extern_id.insert(local_id, extern_id);
367 Ok(())
368 }
369
370 pub fn insert_dummy(&mut self, owner_id: OwnerId) {
371 self.dummy_extern.insert(owner_id.def_id);
372 }
373}
374
375pub enum ExternSpecMappingErr {
378 IsLocal(LocalDefId),
381
382 Dup(LocalDefId),
391}
392
393#[derive(Default)]
394pub struct ResolverOutput {
395 pub path_res_map: UnordMap<NodeId, fhir::PartialRes>,
396 pub impl_trait_res_map: UnordMap<NodeId, LocalDefId>,
397 pub param_res_map: UnordMap<NodeId, (fhir::ParamId, fhir::ParamKind)>,
402 pub implicit_params: UnordMap<NodeId, Vec<(Ident, NodeId)>>,
406 pub sort_path_res_map: UnordMap<NodeId, fhir::SortRes>,
407 pub expr_path_res_map: UnordMap<NodeId, fhir::ExprRes>,
408 pub qualifier_res_map: UnordMap<OwnerId, Vec<def_id::FluxLocalDefId>>,
410 pub reveal_res_map: UnordMap<OwnerId, Vec<def_id::FluxDefId>>,
412}
413
414#[extension(pub trait PlaceExt)]
415impl flux_rustc_bridge::mir::Place {
416 fn ty(&self, genv: GlobalEnv, local_decls: &LocalDecls) -> QueryResult<PlaceTy> {
417 self.projection
418 .iter()
419 .try_fold(PlaceTy::from_ty(local_decls[self.local].ty.clone()), |place_ty, elem| {
420 place_ty.projection_ty(genv, *elem)
421 })
422 }
423
424 fn behind_raw_ptr(&self, genv: GlobalEnv, local_decls: &LocalDecls) -> QueryResult<bool> {
425 let mut place_ty = PlaceTy::from_ty(local_decls[self.local].ty.clone());
426 for elem in &self.projection {
427 if let (PlaceElem::Deref, ty::TyKind::RawPtr(..)) = (elem, place_ty.ty.kind()) {
428 return Ok(true);
429 }
430 place_ty = place_ty.projection_ty(genv, *elem)?;
431 }
432 Ok(false)
433 }
434}
435
436#[derive(Debug)]
437pub struct PlaceTy {
438 pub ty: ty::Ty,
439 pub variant_index: Option<VariantIdx>,
441}
442
443impl PlaceTy {
444 fn from_ty(ty: ty::Ty) -> PlaceTy {
445 PlaceTy { ty, variant_index: None }
446 }
447
448 fn projection_ty(&self, genv: GlobalEnv, elem: PlaceElem) -> QueryResult<PlaceTy> {
449 if self.variant_index.is_some() && !matches!(elem, PlaceElem::Field(..)) {
450 Err(query_bug!("cannot use non field projection on downcasted place"))?;
451 }
452 let place_ty = match elem {
453 PlaceElem::Deref => PlaceTy::from_ty(self.ty.deref()),
454 PlaceElem::Field(fld) => PlaceTy::from_ty(self.field_ty(genv, fld)?),
455 PlaceElem::Downcast(_, variant_idx) => {
456 PlaceTy { ty: self.ty.clone(), variant_index: Some(variant_idx) }
457 }
458 PlaceElem::Index(_) | PlaceElem::ConstantIndex { .. } => {
459 if let ty::TyKind::Array(ty, _) | ty::TyKind::Slice(ty) = self.ty.kind() {
460 PlaceTy::from_ty(ty.clone())
461 } else {
462 return Err(query_bug!("cannot use non field projection on downcasted place"));
463 }
464 }
465 };
466 Ok(place_ty)
467 }
468
469 fn field_ty(&self, genv: GlobalEnv, f: FieldIdx) -> QueryResult<ty::Ty> {
470 match self.ty.kind() {
471 ty::TyKind::Adt(adt_def, args) => {
472 let variant_def = match self.variant_index {
473 None => adt_def.non_enum_variant(),
474 Some(variant_index) => {
475 assert!(adt_def.is_enum());
476 adt_def.variant(variant_index)
477 }
478 };
479 let field_def = &variant_def.fields[f];
480 let ty = genv.lower_type_of(field_def.did)?;
481 Ok(ty.subst(args))
482 }
483 ty::TyKind::Tuple(tys) => Ok(tys[f.index()].clone()),
484 ty::TyKind::Closure(_, args) => Ok(args.as_closure().upvar_tys()[f.index()].clone()),
485 _ => Err(query_bug!("extracting field of non-tuple non-adt non-closure: {self:?}")),
486 }
487 }
488}
489
490#[derive(Debug, Hash, Clone, Copy)]
495pub enum FixpointQueryKind {
496 Impl,
498 Body,
500 Invariant,
502}
503
504impl FixpointQueryKind {
505 pub fn ext(self) -> &'static str {
506 match self {
507 FixpointQueryKind::Impl => "sub.fluxc",
508 FixpointQueryKind::Body => "fluxc",
509 FixpointQueryKind::Invariant => "fluxc",
510 }
511 }
512
513 pub fn task_key(self, tcx: TyCtxt, def_id: DefId) -> String {
515 format!("{}###{:?}", tcx.def_path_str(def_id), self)
516 }
517}