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