1use std::{
2 cell::{OnceCell, RefCell},
3 rc::Rc,
4};
5
6use flux_arc_interner::List;
7use flux_common::{bug, tracked_span_bug};
8use flux_errors::{E0999, ErrorGuaranteed};
9use flux_rustc_bridge::{
10 self, def_id_to_string,
11 lowering::{self, Lower, UnsupportedErr},
12 mir, ty,
13};
14use itertools::Itertools;
15use rustc_data_structures::unord::{ExtendUnord, UnordMap};
16use rustc_errors::Diagnostic;
17use rustc_hir::{
18 def::DefKind,
19 def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId},
20};
21use rustc_index::IndexVec;
22use rustc_macros::{Decodable, Encodable};
23use rustc_span::{Span, Symbol};
24
25use crate::{
26 def_id::{FluxDefId, FluxId, FluxLocalDefId, MaybeExternId, ResolvedDefId},
27 fhir,
28 global_env::GlobalEnv,
29 rty::{
30 self,
31 refining::{self, Refine, Refiner},
32 },
33};
34
35type Cache<K, V> = RefCell<UnordMap<K, V>>;
36
37pub type QueryResult<T = ()> = Result<T, QueryErr>;
38
39#[derive(Debug, Clone, Encodable, Decodable)]
64pub enum QueryErr {
65 Unsupported {
66 def_id: DefId,
67 err: UnsupportedErr,
68 },
69 Ignored {
70 def_id: DefId,
71 },
72 InvalidGenericArg {
73 def_id: DefId,
74 },
75 MissingAssocReft {
76 impl_id: DefId,
77 trait_id: DefId,
78 name: Symbol,
79 },
80 OpaqueStruct {
82 struct_id: DefId,
83 },
84 Bug {
88 def_id: Option<DefId>,
89 location: String,
90 msg: String,
91 },
92 Emitted(ErrorGuaranteed),
93}
94
95#[macro_export]
96macro_rules! query_bug {
97 ($fmt:literal $(,$args:expr)* $(,)?) => {
98 $crate::queries::QueryErr::bug(None, format_args!($fmt, $($args),*))
99 };
100 ($def_id:expr, $fmt:literal $(,$args:expr)* $(,)? ) => {{
101 $crate::queries::QueryErr::bug(Some($def_id.into()), format_args!($fmt, $($args),*))
102 }};
103}
104
105impl QueryErr {
106 pub fn unsupported(def_id: DefId, err: UnsupportedErr) -> Self {
107 QueryErr::Unsupported { def_id, err }
108 }
109
110 #[track_caller]
111 pub fn bug(def_id: Option<DefId>, msg: impl ToString) -> Self {
112 QueryErr::Bug {
113 def_id,
114 location: format!("{}", std::panic::Location::caller()),
115 msg: msg.to_string(),
116 }
117 }
118
119 pub fn at(self, cx: impl Into<ErrCtxt>) -> QueryErrAt {
120 QueryErrAt { cx: cx.into(), err: self }
121 }
122}
123
124pub struct QueryErrAt {
126 cx: ErrCtxt,
127 err: QueryErr,
128}
129
130#[derive(Clone, Copy)]
132pub enum ErrCtxt {
133 FnCheck(Span, LocalDefId),
136 Misc(Span),
138}
139
140impl From<Span> for ErrCtxt {
141 fn from(v: Span) -> Self {
142 Self::Misc(v)
143 }
144}
145
146impl ErrCtxt {
147 fn span(self) -> Span {
148 match self {
149 ErrCtxt::Misc(span) => span,
150 ErrCtxt::FnCheck(span, _) => span,
151 }
152 }
153}
154
155pub struct Providers {
156 pub collect_specs: fn(GlobalEnv) -> crate::Specs,
157 pub resolve_crate: fn(GlobalEnv) -> crate::ResolverOutput,
158 pub desugar: for<'genv> fn(
159 GlobalEnv<'genv, '_>,
160 LocalDefId,
161 ) -> QueryResult<UnordMap<LocalDefId, fhir::Node<'genv>>>,
162 pub fhir_crate: for<'genv> fn(GlobalEnv<'genv, '_>) -> fhir::FluxItems<'genv>,
163 pub qualifiers: fn(GlobalEnv) -> QueryResult<Vec<rty::Qualifier>>,
164 pub prim_rel: fn(GlobalEnv) -> QueryResult<UnordMap<rty::BinOp, rty::PrimRel>>,
165 pub normalized_defns: fn(GlobalEnv) -> rty::NormalizedDefns,
166 pub func_sort: fn(GlobalEnv, FluxLocalDefId) -> rty::PolyFuncSort,
167 pub adt_sort_def_of: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::AdtSortDef>,
168 pub check_wf: for<'genv> fn(GlobalEnv, LocalDefId) -> QueryResult<Rc<rty::WfckResults>>,
169 pub adt_def: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::AdtDef>,
170 pub constant_info: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::ConstantInfo>,
171 pub type_of: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>>,
172 pub variants_of: fn(
173 GlobalEnv,
174 LocalDefId,
175 ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>,
176 pub fn_sig: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>>,
177 pub generics_of: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::Generics>,
178 pub refinement_generics_of:
179 fn(GlobalEnv, LocalDefId) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>,
180 pub predicates_of:
181 fn(GlobalEnv, LocalDefId) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>>,
182 pub assoc_refinements_of: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::AssocRefinements>,
183 pub sort_of_assoc_reft:
184 fn(GlobalEnv, FluxId<MaybeExternId>) -> QueryResult<rty::EarlyBinder<rty::FuncSort>>,
185 pub assoc_refinement_body:
186 fn(GlobalEnv, FluxId<MaybeExternId>) -> QueryResult<rty::EarlyBinder<rty::Lambda>>,
187 #[allow(clippy::type_complexity)]
188 pub default_assoc_refinement_body:
189 fn(GlobalEnv, FluxId<MaybeExternId>) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>,
190 pub item_bounds: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>>,
191}
192
193macro_rules! empty_query {
194 () => {
195 flux_common::bug!("query not provided")
196 };
197}
198
199impl Default for Providers {
200 fn default() -> Self {
201 Self {
202 collect_specs: |_| empty_query!(),
203 resolve_crate: |_| empty_query!(),
204 desugar: |_, _| empty_query!(),
205 fhir_crate: |_| empty_query!(),
206 normalized_defns: |_| empty_query!(),
207 func_sort: |_, _| empty_query!(),
208 qualifiers: |_| empty_query!(),
209 prim_rel: |_| empty_query!(),
210 adt_sort_def_of: |_, _| empty_query!(),
211 check_wf: |_, _| empty_query!(),
212 adt_def: |_, _| empty_query!(),
213 type_of: |_, _| empty_query!(),
214 variants_of: |_, _| empty_query!(),
215 fn_sig: |_, _| empty_query!(),
216 generics_of: |_, _| empty_query!(),
217 refinement_generics_of: |_, _| empty_query!(),
218 predicates_of: |_, _| empty_query!(),
219 assoc_refinements_of: |_, _| empty_query!(),
220 assoc_refinement_body: |_, _| empty_query!(),
221 default_assoc_refinement_body: |_, _| empty_query!(),
222 sort_of_assoc_reft: |_, _| empty_query!(),
223 item_bounds: |_, _| empty_query!(),
224 constant_info: |_, _| empty_query!(),
225 }
226 }
227}
228
229pub struct Queries<'genv, 'tcx> {
230 pub(crate) providers: Providers,
231 mir: Cache<LocalDefId, QueryResult<Rc<mir::Body<'tcx>>>>,
232 collect_specs: OnceCell<crate::Specs>,
233 resolve_crate: OnceCell<crate::ResolverOutput>,
234 desugar: Cache<LocalDefId, QueryResult<fhir::Node<'genv>>>,
235 fhir_crate: OnceCell<fhir::FluxItems<'genv>>,
236 lower_generics_of: Cache<DefId, ty::Generics<'tcx>>,
237 lower_predicates_of: Cache<DefId, QueryResult<ty::GenericPredicates>>,
238 lower_type_of: Cache<DefId, QueryResult<ty::EarlyBinder<ty::Ty>>>,
239 lower_fn_sig: Cache<DefId, QueryResult<ty::EarlyBinder<ty::PolyFnSig>>>,
240 normalized_defns: Cache<CrateNum, Rc<rty::NormalizedDefns>>,
241 func_sort: Cache<FluxDefId, rty::PolyFuncSort>,
242 qualifiers: OnceCell<QueryResult<Vec<rty::Qualifier>>>,
243 prim_rel: OnceCell<QueryResult<UnordMap<rty::BinOp, rty::PrimRel>>>,
244 adt_sort_def_of: Cache<DefId, QueryResult<rty::AdtSortDef>>,
245 check_wf: Cache<LocalDefId, QueryResult<Rc<rty::WfckResults>>>,
246 adt_def: Cache<DefId, QueryResult<rty::AdtDef>>,
247 constant_info: Cache<DefId, QueryResult<rty::ConstantInfo>>,
248 generics_of: Cache<DefId, QueryResult<rty::Generics>>,
249 refinement_generics_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>>,
250 predicates_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::GenericPredicates>>>,
251 assoc_refinements_of: Cache<DefId, QueryResult<rty::AssocRefinements>>,
252 assoc_refinement_body: Cache<FluxDefId, QueryResult<rty::EarlyBinder<rty::Lambda>>>,
253 default_assoc_refinement_body:
254 Cache<FluxDefId, QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>>,
255 sort_of_assoc_reft: Cache<FluxDefId, QueryResult<rty::EarlyBinder<rty::FuncSort>>>,
256 item_bounds: Cache<DefId, QueryResult<rty::EarlyBinder<List<rty::Clause>>>>,
257 type_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::TyOrCtor>>>,
258 variants_of: Cache<DefId, QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>>,
259 fn_sig: Cache<DefId, QueryResult<rty::EarlyBinder<rty::PolyFnSig>>>,
260 lower_late_bound_vars: Cache<LocalDefId, QueryResult<List<ty::BoundVariableKind>>>,
261}
262
263impl<'genv, 'tcx> Queries<'genv, 'tcx> {
264 pub(crate) fn new(providers: Providers) -> Self {
265 Self {
266 providers,
267 mir: Default::default(),
268 collect_specs: Default::default(),
269 resolve_crate: Default::default(),
270 desugar: Default::default(),
271 fhir_crate: Default::default(),
272 lower_generics_of: Default::default(),
273 lower_predicates_of: Default::default(),
274 lower_type_of: Default::default(),
275 lower_fn_sig: Default::default(),
276 normalized_defns: Default::default(),
277 func_sort: Default::default(),
278 qualifiers: Default::default(),
279 prim_rel: Default::default(),
280 adt_sort_def_of: Default::default(),
281 check_wf: Default::default(),
282 adt_def: Default::default(),
283 constant_info: Default::default(),
284 generics_of: Default::default(),
285 refinement_generics_of: Default::default(),
286 predicates_of: Default::default(),
287 assoc_refinements_of: Default::default(),
288 assoc_refinement_body: Default::default(),
289 default_assoc_refinement_body: Default::default(),
290 sort_of_assoc_reft: Default::default(),
291 item_bounds: Default::default(),
292 type_of: Default::default(),
293 variants_of: Default::default(),
294 fn_sig: Default::default(),
295 lower_late_bound_vars: Default::default(),
296 }
297 }
298
299 pub(crate) fn mir(
300 &self,
301 genv: GlobalEnv<'genv, 'tcx>,
302 def_id: LocalDefId,
303 ) -> QueryResult<Rc<mir::Body<'tcx>>> {
304 run_with_cache(&self.mir, def_id, || {
305 let mir = unsafe { flux_common::mir_storage::retrieve_mir_body(genv.tcx(), def_id) };
306 let mir =
307 lowering::MirLoweringCtxt::lower_mir_body(genv.tcx(), genv.sess(), def_id, mir)?;
308 Ok(Rc::new(mir))
309 })
310 }
311
312 pub(crate) fn collect_specs(&'genv self, genv: GlobalEnv<'genv, 'tcx>) -> &'genv crate::Specs {
313 self.collect_specs
314 .get_or_init(|| (self.providers.collect_specs)(genv))
315 }
316
317 pub(crate) fn resolve_crate(
318 &'genv self,
319 genv: GlobalEnv<'genv, 'tcx>,
320 ) -> &'genv crate::ResolverOutput {
321 self.resolve_crate
322 .get_or_init(|| (self.providers.resolve_crate)(genv))
323 }
324
325 pub(crate) fn desugar(
326 &'genv self,
327 genv: GlobalEnv<'genv, 'tcx>,
328 def_id: LocalDefId,
329 ) -> QueryResult<fhir::Node<'genv>> {
330 if let Some(v) = self.desugar.borrow().get(&def_id) {
331 return v.clone();
332 }
333 match (self.providers.desugar)(genv, def_id) {
334 Ok(nodes) => {
335 let mut cache = self.desugar.borrow_mut();
336 cache.extend_unord(nodes.into_items().map(|(def_id, node)| (def_id, Ok(node))));
337 let Some(res) = cache.get(&def_id) else {
338 tracked_span_bug!("cannot desugar {def_id:?}")
339 };
340 res.clone()
341 }
342 Err(err) => {
343 self.desugar.borrow_mut().insert(def_id, Err(err.clone()));
344 Err(err)
345 }
346 }
347 }
348
349 pub(crate) fn fhir_crate(
350 &'genv self,
351 genv: GlobalEnv<'genv, 'tcx>,
352 ) -> &'genv fhir::FluxItems<'genv> {
353 self.fhir_crate
354 .get_or_init(|| (self.providers.fhir_crate)(genv))
355 }
356
357 pub(crate) fn lower_generics_of(
358 &self,
359 genv: GlobalEnv<'genv, 'tcx>,
360 def_id: DefId,
361 ) -> ty::Generics<'tcx> {
362 run_with_cache(&self.lower_generics_of, def_id, || {
363 genv.tcx().generics_of(def_id).lower(genv.tcx())
364 })
365 }
366
367 pub(crate) fn lower_predicates_of(
368 &self,
369 genv: GlobalEnv,
370 def_id: DefId,
371 ) -> QueryResult<ty::GenericPredicates> {
372 run_with_cache(&self.lower_predicates_of, def_id, || {
373 genv.tcx()
374 .predicates_of(def_id)
375 .lower(genv.tcx())
376 .map_err(|err| QueryErr::unsupported(def_id, err))
377 })
378 }
379
380 pub(crate) fn lower_type_of(
381 &self,
382 genv: GlobalEnv,
383 def_id: DefId,
384 ) -> QueryResult<ty::EarlyBinder<ty::Ty>> {
385 run_with_cache(&self.lower_type_of, def_id, || {
386 let ty = genv.tcx().type_of(def_id).instantiate_identity();
387 Ok(ty::EarlyBinder(
388 ty.lower(genv.tcx())
389 .map_err(|err| QueryErr::unsupported(def_id, err.into_err()))?,
390 ))
391 })
392 }
393
394 pub(crate) fn lower_fn_sig(
395 &self,
396 genv: GlobalEnv,
397 def_id: DefId,
398 ) -> QueryResult<ty::EarlyBinder<ty::PolyFnSig>> {
399 run_with_cache(&self.lower_fn_sig, def_id, || {
400 let fn_sig = genv.tcx().fn_sig(def_id).instantiate_identity();
401 Ok(ty::EarlyBinder(
402 fn_sig
403 .lower(genv.tcx())
404 .map_err(|err| QueryErr::unsupported(def_id, err.into_err()))?,
405 ))
406 })
407 }
408
409 pub(crate) fn lower_late_bound_vars(
410 &self,
411 genv: GlobalEnv,
412 def_id: LocalDefId,
413 ) -> QueryResult<List<ty::BoundVariableKind>> {
414 run_with_cache(&self.lower_late_bound_vars, def_id, || {
415 let hir_id = genv.tcx().local_def_id_to_hir_id(def_id);
416 genv.tcx()
417 .late_bound_vars(hir_id)
418 .lower(genv.tcx())
419 .map_err(|err| QueryErr::unsupported(def_id.to_def_id(), err.into_err()))
420 })
421 }
422
423 pub(crate) fn normalized_defns(
424 &self,
425 genv: GlobalEnv,
426 krate: CrateNum,
427 ) -> Rc<rty::NormalizedDefns> {
428 run_with_cache(&self.normalized_defns, krate, || {
429 if krate == LOCAL_CRATE {
430 Rc::new((self.providers.normalized_defns)(genv))
431 } else {
432 genv.cstore().normalized_defns(krate)
433 }
434 })
435 }
436
437 pub(crate) fn func_sort(&self, genv: GlobalEnv, def_id: FluxDefId) -> rty::PolyFuncSort {
438 run_with_cache(&self.func_sort, def_id, || {
439 dispatch_query_flux_id(
440 genv,
441 def_id,
442 |def_id| {
443 (self.providers.func_sort)(genv, def_id.local_id())
445 },
446 |def_id| genv.cstore().func_sort(def_id),
447 |_| {
448 bug!(
449 "cannot generate default function sort, the refinement must be defined somewhere"
450 )
451 },
452 )
453 })
454 }
455
456 pub(crate) fn qualifiers(&self, genv: GlobalEnv) -> QueryResult<&[rty::Qualifier]> {
457 self.qualifiers
458 .get_or_init(|| (self.providers.qualifiers)(genv))
459 .as_deref()
460 .map_err(Clone::clone)
461 }
462
463 pub(crate) fn prim_rel(
464 &self,
465 genv: GlobalEnv,
466 ) -> QueryResult<&UnordMap<rty::BinOp, rty::PrimRel>> {
467 self.prim_rel
468 .get_or_init(|| (self.providers.prim_rel)(genv))
469 .as_ref()
470 .map_err(|err| err.clone())
471 }
472
473 pub(crate) fn adt_sort_def_of(
474 &self,
475 genv: GlobalEnv,
476 def_id: DefId,
477 ) -> QueryResult<rty::AdtSortDef> {
478 run_with_cache(&self.adt_sort_def_of, def_id, || {
479 dispatch_query(
480 genv,
481 def_id,
482 |def_id| (self.providers.adt_sort_def_of)(genv, def_id.local_id()),
483 |def_id| genv.cstore().adt_sort_def(def_id),
484 |def_id| {
485 let variants = IndexVec::from([rty::AdtSortVariant::new(vec![])]);
486 Ok(rty::AdtSortDef::new(def_id, vec![], variants, false, true))
487 },
488 )
489 })
490 }
491
492 pub(crate) fn check_wf(
493 &self,
494 genv: GlobalEnv<'genv, '_>,
495 def_id: LocalDefId,
496 ) -> QueryResult<Rc<rty::WfckResults>> {
497 run_with_cache(&self.check_wf, def_id, || (self.providers.check_wf)(genv, def_id))
498 }
499
500 pub(crate) fn constant_info(
501 &self,
502 genv: GlobalEnv,
503 def_id: DefId,
504 ) -> QueryResult<rty::ConstantInfo> {
505 run_with_cache(&self.constant_info, def_id, || {
506 dispatch_query(
507 genv,
508 def_id,
509 |def_id| (self.providers.constant_info)(genv, def_id.local_id()),
510 |def_id| genv.cstore().constant_info(def_id),
511 |def_id| {
512 let ty = genv.tcx().type_of(def_id).no_bound_vars().unwrap();
514 if ty.is_integral() {
515 let val = genv.tcx().const_eval_poly(def_id).ok().and_then(|val| {
516 let val = val.try_to_scalar_int()?;
517 rty::Constant::from_scalar_int(genv.tcx(), val, &ty)
518 });
519 if let Some(constant_) = val {
520 return Ok(rty::ConstantInfo::Interpreted(
521 rty::Expr::constant(constant_),
522 rty::Sort::Int,
523 ));
524 }
525 }
526 Ok(rty::ConstantInfo::Uninterpreted)
527 },
528 )
529 })
530 }
531
532 pub(crate) fn adt_def(&self, genv: GlobalEnv, def_id: DefId) -> QueryResult<rty::AdtDef> {
533 run_with_cache(&self.adt_def, def_id, || {
534 dispatch_query(
535 genv,
536 def_id,
537 |def_id| (self.providers.adt_def)(genv, def_id.local_id()),
538 |def_id| genv.cstore().adt_def(def_id),
539 |def_id| {
540 let adt_def = genv.tcx().adt_def(def_id).lower(genv.tcx());
541 Ok(rty::AdtDef::new(adt_def, genv.adt_sort_def_of(def_id)?, vec![], false))
542 },
543 )
544 })
545 }
546
547 pub(crate) fn generics_of(&self, genv: GlobalEnv, def_id: DefId) -> QueryResult<rty::Generics> {
548 run_with_cache(&self.generics_of, def_id, || {
549 dispatch_query(
550 genv,
551 def_id,
552 |def_id| (self.providers.generics_of)(genv, def_id.local_id()),
553 |def_id| genv.cstore().generics_of(def_id),
554 |def_id| {
555 Ok(refining::refine_generics(genv, def_id, &genv.lower_generics_of(def_id)))
556 },
557 )
558 })
559 }
560
561 pub(crate) fn refinement_generics_of(
562 &self,
563 genv: GlobalEnv,
564 def_id: DefId,
565 ) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>> {
566 run_with_cache(&self.refinement_generics_of, def_id, || {
567 dispatch_query(
568 genv,
569 def_id,
570 |def_id| (self.providers.refinement_generics_of)(genv, def_id.local_id()),
571 |def_id| genv.cstore().refinement_generics_of(def_id),
572 |def_id| {
573 let parent = genv.tcx().generics_of(def_id).parent;
574 Ok(rty::EarlyBinder(rty::RefinementGenerics {
575 parent,
576 parent_count: 0,
577 own_params: List::empty(),
578 }))
579 },
580 )
581 })
582 }
583
584 pub(crate) fn item_bounds(
585 &self,
586 genv: GlobalEnv<'genv, 'tcx>,
587 def_id: DefId,
588 ) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>> {
589 run_with_cache(&self.item_bounds, def_id, || {
590 dispatch_query(
591 genv,
592 def_id,
593 |def_id| (self.providers.item_bounds)(genv, def_id.local_id()),
594 |def_id| genv.cstore().item_bounds(def_id),
595 |def_id| {
596 let clauses = genv
597 .tcx()
598 .item_bounds(def_id)
599 .skip_binder()
600 .lower(genv.tcx())
601 .map_err(|err| QueryErr::unsupported(def_id, err))?
602 .refine(&Refiner::default_for_item(genv, def_id)?)?;
603
604 Ok(rty::EarlyBinder(clauses))
605 },
606 )
607 })
608 }
609
610 pub(crate) fn predicates_of(
611 &self,
612 genv: GlobalEnv,
613 def_id: DefId,
614 ) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>> {
615 run_with_cache(&self.predicates_of, def_id, || {
616 dispatch_query(
617 genv,
618 def_id,
619 |def_id| (self.providers.predicates_of)(genv, def_id.local_id()),
620 |def_id| genv.cstore().predicates_of(def_id),
621 |def_id| {
622 let predicates = genv
623 .lower_predicates_of(def_id)?
624 .refine(&Refiner::default_for_item(genv, def_id)?)?;
625 Ok(rty::EarlyBinder(predicates))
626 },
627 )
628 })
629 }
630
631 pub(crate) fn assoc_refinements_of(
632 &self,
633 genv: GlobalEnv,
634 def_id: DefId,
635 ) -> QueryResult<rty::AssocRefinements> {
636 run_with_cache(&self.assoc_refinements_of, def_id, || {
637 dispatch_query(
638 genv,
639 def_id,
640 |def_id| (self.providers.assoc_refinements_of)(genv, def_id.local_id()),
641 |def_id| genv.cstore().assoc_refinements_of(def_id),
642 |_| Ok(rty::AssocRefinements::default()),
643 )
644 })
645 }
646
647 pub(crate) fn assoc_refinement_body(
648 &self,
649 genv: GlobalEnv,
650 impl_assoc_id: FluxDefId,
651 ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
652 run_with_cache(&self.assoc_refinement_body, impl_assoc_id, || {
653 dispatch_query_flux_id(
654 genv,
655 impl_assoc_id,
656 |impl_assoc_id| (self.providers.assoc_refinement_body)(genv, impl_assoc_id),
657 |impl_assoc_id| genv.cstore().assoc_refinements_def(impl_assoc_id),
658 |impl_assoc_id| {
659 Err(query_bug!(
660 impl_assoc_id.parent(),
661 "cannot generate default associate refinement for extern impl"
662 ))
663 },
664 )
665 })
666 }
667
668 pub(crate) fn default_assoc_refinement_body(
669 &self,
670 genv: GlobalEnv,
671 trait_assoc_id: FluxDefId,
672 ) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>> {
673 run_with_cache(&self.default_assoc_refinement_body, trait_assoc_id, || {
674 dispatch_query_flux_id(
675 genv,
676 trait_assoc_id,
677 |trait_assoc_id| {
678 (self.providers.default_assoc_refinement_body)(genv, trait_assoc_id)
679 },
680 |trait_assoc_id| genv.cstore().default_assoc_refinements_def(trait_assoc_id),
681 |trait_assoc_id| {
682 Err(query_bug!(
683 trait_assoc_id.parent(),
684 "cannot generate default assoc refinement for extern trait"
685 ))
686 },
687 )
688 })
689 }
690
691 pub(crate) fn sort_of_assoc_reft(
692 &self,
693 genv: GlobalEnv,
694 assoc_id: FluxDefId,
695 ) -> QueryResult<rty::EarlyBinder<rty::FuncSort>> {
696 run_with_cache(&self.sort_of_assoc_reft, assoc_id, || {
697 dispatch_query_flux_id(
698 genv,
699 assoc_id,
700 |assoc_id| (self.providers.sort_of_assoc_reft)(genv, assoc_id),
701 |assoc_id| genv.cstore().sort_of_assoc_reft(assoc_id),
702 |assoc_id| {
703 Err(query_bug!(
704 assoc_id.parent(),
705 "cannot generate default sort for assoc refinement in extern crate"
706 ))
707 },
708 )
709 })
710 }
711
712 pub(crate) fn type_of(
713 &self,
714 genv: GlobalEnv,
715 def_id: DefId,
716 ) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>> {
717 run_with_cache(&self.type_of, def_id, || {
718 dispatch_query(
719 genv,
720 def_id,
721 |def_id| (self.providers.type_of)(genv, def_id.local_id()),
722 |def_id| genv.cstore().type_of(def_id),
723 |def_id| {
724 let generics_def_id = match genv.def_kind(def_id) {
726 DefKind::TyParam => genv.tcx().parent(def_id),
727 _ => def_id,
728 };
729 let ty = genv.lower_type_of(def_id)?.skip_binder();
730 Ok(rty::EarlyBinder(
731 Refiner::default_for_item(genv, generics_def_id)?
732 .refine_ty_or_base(&ty)?
733 .into(),
734 ))
735 },
736 )
737 })
738 }
739
740 pub(crate) fn variants_of(
741 &self,
742 genv: GlobalEnv,
743 def_id: DefId,
744 ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
745 run_with_cache(&self.variants_of, def_id, || {
746 dispatch_query(
747 genv,
748 def_id,
749 |def_id| (self.providers.variants_of)(genv, def_id.local_id()),
750 |def_id| genv.cstore().variants(def_id),
751 |def_id| {
752 let variants = genv
753 .tcx()
754 .adt_def(def_id)
755 .variants()
756 .indices()
757 .map(|variant_idx| {
758 Refiner::default_for_item(genv, def_id)?
759 .refine_variant_def(def_id, variant_idx)
760 })
761 .try_collect()?;
762 Ok(rty::Opaqueness::Transparent(rty::EarlyBinder(variants)))
763 },
764 )
765 })
766 }
767
768 pub(crate) fn fn_sig(
769 &self,
770 genv: GlobalEnv,
771 def_id: DefId,
772 ) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>> {
773 run_with_cache(&self.fn_sig, def_id, || {
774 dispatch_query(
775 genv,
776 def_id,
777 |def_id| (self.providers.fn_sig)(genv, def_id.local_id()),
778 |def_id| genv.cstore().fn_sig(def_id),
779 |def_id| {
780 let fn_sig = genv
781 .lower_fn_sig(def_id)?
782 .skip_binder()
783 .refine(&Refiner::default_for_item(genv, def_id)?)?
784 .hoist_input_binders();
785 Ok(rty::EarlyBinder(fn_sig))
786 },
787 )
788 })
789 }
790}
791
792fn dispatch_query<R>(
796 genv: GlobalEnv,
797 def_id: DefId,
798 local: impl FnOnce(MaybeExternId) -> R,
799 external: impl FnOnce(DefId) -> Option<R>,
800 default: impl FnOnce(DefId) -> R,
801) -> R {
802 match genv.resolve_id(def_id) {
803 ResolvedDefId::Local(local_id) => {
804 local(MaybeExternId::Local(local_id))
806 }
807 ResolvedDefId::ExternSpec(local_id, def_id) => {
808 local(MaybeExternId::Extern(local_id, def_id))
811 }
812 ResolvedDefId::Extern(def_id) if let Some(v) = external(def_id) => {
813 v
816 }
817 ResolvedDefId::Extern(def_id) => {
818 default(def_id)
820 }
821 }
822}
823
824fn dispatch_query_flux_id<R>(
825 genv: GlobalEnv,
826 def_id: FluxId<DefId>,
827 local: impl FnOnce(FluxId<MaybeExternId>) -> R,
828 external: impl FnOnce(FluxId<DefId>) -> Option<R>,
829 default: impl FnOnce(FluxId<DefId>) -> R,
830) -> R {
831 #[allow(
832 clippy::disallowed_methods,
833 reason = "we are mapping the parent id to a different representation which still guarantees the existence of the item"
834 )]
835 dispatch_query(
836 genv,
837 def_id.parent(),
838 |container_id| local(FluxId::new(container_id, def_id.name())),
839 |container_id| external(FluxId::new(container_id, def_id.name())),
840 |container_id| default(FluxId::new(container_id, def_id.name())),
841 )
842}
843
844fn run_with_cache<K, V>(cache: &Cache<K, V>, key: K, f: impl FnOnce() -> V) -> V
845where
846 K: std::hash::Hash + Eq,
847 V: Clone,
848{
849 if let Some(v) = cache.borrow().get(&key) {
850 return v.clone();
851 }
852 let v = f();
853 cache.borrow_mut().insert(key, v.clone());
854 v
855}
856
857impl<'a> Diagnostic<'a> for QueryErr {
858 #[track_caller]
859 fn into_diag(
860 self,
861 dcx: rustc_errors::DiagCtxtHandle<'a>,
862 _level: rustc_errors::Level,
863 ) -> rustc_errors::Diag<'a, ErrorGuaranteed> {
864 use crate::fluent_generated as fluent;
865
866 rustc_middle::ty::tls::with_opt(
867 #[track_caller]
868 |tcx| {
869 let tcx = tcx.expect("no TyCtxt stored in tls");
870 match self {
871 QueryErr::Unsupported { def_id, err } => {
872 let span = err.span.unwrap_or_else(|| tcx.def_span(def_id));
873 let mut diag = dcx.struct_span_err(span, fluent::middle_query_unsupported);
874 diag.code(E0999);
875 diag.note(err.descr);
876 diag
877 }
878 QueryErr::Ignored { def_id } => {
879 let def_span = tcx.def_span(def_id);
880 let mut diag =
881 dcx.struct_span_err(def_span, fluent::middle_query_ignored_item);
882 diag.code(E0999);
883 diag
884 }
885 QueryErr::InvalidGenericArg { def_id } => {
886 let def_span = tcx.def_span(def_id);
887 let mut diag =
888 dcx.struct_span_err(def_span, fluent::middle_query_invalid_generic_arg);
889 diag.code(E0999);
890 diag
891 }
892 QueryErr::MissingAssocReft { impl_id, name, .. } => {
893 let def_span = tcx.def_span(impl_id);
894 let mut diag =
895 dcx.struct_span_err(def_span, fluent::middle_query_missing_assoc_reft);
896 diag.arg("name", name);
897 diag.code(E0999);
898 diag
899 }
900 QueryErr::Bug { def_id, location, msg } => {
901 let mut diag = dcx.struct_err(fluent::middle_query_bug);
902 if let Some(def_id) = def_id {
903 diag.span(tcx.def_span(def_id));
904 }
905 diag.arg("location", location);
906 diag.note(msg);
907 diag
908 }
909 QueryErr::Emitted(_) => {
910 let mut diag = dcx.struct_err("QueryErr::Emitted should be emitted");
911 diag.downgrade_to_delayed_bug();
912 diag
913 }
914 QueryErr::OpaqueStruct { struct_id } => {
915 let struct_span = tcx.def_span(struct_id);
916 let mut diag =
917 dcx.struct_span_err(struct_span, fluent::middle_query_opaque_struct);
918 diag.arg("struct", tcx.def_path_str(struct_id));
919 diag
920 }
921 }
922 },
923 )
924 }
925}
926
927impl<'a> Diagnostic<'a> for QueryErrAt {
928 #[track_caller]
929 fn into_diag(
930 self,
931 dcx: rustc_errors::DiagCtxtHandle<'a>,
932 level: rustc_errors::Level,
933 ) -> rustc_errors::Diag<'a, ErrorGuaranteed> {
934 use crate::fluent_generated as fluent;
935
936 rustc_middle::ty::tls::with_opt(
937 #[track_caller]
938 |tcx| {
939 let tcx = tcx.expect("no TyCtxt stored in tls");
940 let cx_span = self.cx.span();
941 let mut diag = match self.err {
942 QueryErr::Unsupported { def_id, err, .. } => {
943 let mut diag =
944 dcx.struct_span_err(cx_span, fluent::middle_query_unsupported_at);
945 diag.arg("kind", tcx.def_kind(def_id).descr(def_id));
946 if let Some(def_ident_span) = tcx.def_ident_span(def_id) {
947 diag.span_note(def_ident_span, fluent::_subdiag::note);
948 }
949 diag.note(err.descr);
950 diag
951 }
952 QueryErr::Ignored { def_id } => {
953 let mut diag =
954 dcx.struct_span_err(cx_span, fluent::middle_query_ignored_at);
955 diag.arg("kind", tcx.def_kind(def_id).descr(def_id));
956 diag.arg("name", def_id_to_string(def_id));
957 diag.span_label(cx_span, fluent::_subdiag::label);
958 diag
959 }
960 QueryErr::MissingAssocReft { name, .. } => {
961 let mut diag = dcx
962 .struct_span_err(cx_span, fluent::middle_query_missing_assoc_reft_at);
963 diag.arg("name", name);
964 diag.code(E0999);
965 diag
966 }
967 QueryErr::OpaqueStruct { struct_id } => {
968 let mut diag =
969 dcx.struct_span_err(cx_span, fluent::middle_query_opaque_struct);
970 diag.arg("struct", tcx.def_path_str(struct_id));
971 diag.span_label(cx_span, fluent::_subdiag::label);
972 if let ErrCtxt::FnCheck(_, fn_def_id) = self.cx {
973 let fn_span = tcx.def_span(fn_def_id);
974 diag.arg("def_kind", tcx.def_descr(fn_def_id.to_def_id()));
975 diag.span_label(fn_span, fluent::middle_query_opaque_struct_help);
976 diag.note(fluent::middle_query_opaque_struct_note);
977 }
978 diag
979 }
980 QueryErr::InvalidGenericArg { .. }
981 | QueryErr::Emitted(_)
982 | QueryErr::Bug { .. } => {
983 let mut diag = self.err.into_diag(dcx, level);
984 diag.span(cx_span);
985 diag
986 }
987 };
988 diag.code(E0999);
989 diag
990 },
991 )
992 }
993}
994
995impl From<ErrorGuaranteed> for QueryErr {
996 fn from(err: ErrorGuaranteed) -> Self {
997 Self::Emitted(err)
998 }
999}
1000
1001pub fn try_query<T>(f: impl FnOnce() -> QueryResult<T>) -> QueryResult<T> {
1002 f()
1003}