1#![allow(warnings, unused)]
2
3use super::graph::TyWrapper;
4use super::utils::{self, fn_sig_with_generic_args};
5use crate::compat;
6use crate::helpers::def_path::path_str_def_id;
7use crate::{rap_debug, rap_trace};
8use rand::Rng;
9use rand::seq::SliceRandom;
10#[cfg(not(rapx_has_skip_norm_wip))]
11use crate::compat::SkipNormWip;
12
13#[cfg(not(rapx_ge_100))]
14use rustc_hir::LangItem;
15#[cfg(rapx_ge_100)]
16use rustc_hir::attrs::lang_items::LangItem;
17use rustc_hir::def_id::DefId;
18use rustc_infer::infer::DefineOpaqueTypes;
19use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
20use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
21use rustc_middle::ty::{
22 self, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingEnv,
23};
24use rustc_span::DUMMY_SP;
25use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
26use std::collections::HashSet;
27
28static MAX_STEP_SET_SIZE: usize = 1000;
29
30#[derive(Clone, Debug, Hash, PartialEq, Eq)]
31pub struct Mono<'tcx> {
32 pub value: Vec<ty::GenericArg<'tcx>>,
33}
34
35impl<'tcx> FromIterator<ty::GenericArg<'tcx>> for Mono<'tcx> {
36 fn from_iter<T>(iter: T) -> Self
37 where
38 T: IntoIterator<Item = ty::GenericArg<'tcx>>,
39 {
40 Mono {
41 value: iter.into_iter().collect(),
42 }
43 }
44}
45
46impl<'tcx> Mono<'tcx> {
47 pub fn new(identity: &[ty::GenericArg<'tcx>]) -> Self {
48 Mono {
49 value: Vec::from(identity),
50 }
51 }
52
53 fn has_infer_types(&self) -> bool {
54 self.value.iter().any(|arg| match arg.kind() {
55 ty::GenericArgKind::Type(ty) => ty.has_infer_types(),
56 _ => false,
57 })
58 }
59
60 fn mut_arg_at(&mut self, idx: usize) -> &mut ty::GenericArg<'tcx> {
61 &mut self.value[idx]
62 }
63
64 fn merge(&self, other: &Mono<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Mono<'tcx>> {
65 assert!(self.value.len() == other.value.len());
66 let mut res = Vec::new();
67 for i in 0..self.value.len() {
68 let arg = self.value[i];
69 let other_arg = other.value[i];
70 let new_arg = if let GenericArgKind::Type(ty) = arg.kind() {
71 let other_ty = other_arg.expect_ty();
72 if ty.is_ty_var() && other_ty.is_ty_var() {
73 arg
74 } else if ty.is_ty_var() {
75 other_arg
76 } else if other_ty.is_ty_var() {
77 arg
78 } else if utils::is_ty_eq(ty, other_ty, tcx) {
79 arg
80 } else {
81 return None;
82 }
83 } else {
84 arg
85 };
86 res.push(new_arg);
87 }
88 Some(Mono { value: res })
89 }
90
91 fn fill_unbound_var(&self, tcx: TyCtxt<'tcx>) -> Vec<Mono<'tcx>> {
92 let candidates = get_unbound_generic_candidates(tcx);
93 let mut res = vec![self.clone()];
94 rap_trace!("fill unbound: {:?}", self);
95
96 for (i, arg) in self.value.iter().enumerate() {
97 if let GenericArgKind::Type(ty) = arg.kind() {
98 if ty.is_ty_var() {
99 let mut last = Vec::new();
100 std::mem::swap(&mut res, &mut last);
101 last.into_iter().for_each(|mono| {
102 for candidate in &candidates {
103 let mut new_mono = mono.clone();
104 *new_mono.mut_arg_at(i) = (*candidate).into();
105 res.push(new_mono);
106 }
107 });
108 }
109 }
110 }
111 res
112 }
113}
114
115#[derive(Clone, Debug, Default)]
116pub struct MonoSet<'tcx> {
117 pub monos: Vec<Mono<'tcx>>,
118}
119
120impl<'tcx> MonoSet<'tcx> {
121 pub fn all(identity: &[ty::GenericArg<'tcx>]) -> MonoSet<'tcx> {
122 MonoSet {
123 monos: vec![Mono::new(identity)],
124 }
125 }
126
127 pub fn empty() -> MonoSet<'tcx> {
128 MonoSet { monos: Vec::new() }
129 }
130
131 pub fn count(&self) -> usize {
132 self.monos.len()
133 }
134
135 pub fn at(&self, no: usize) -> &Mono<'tcx> {
136 &self.monos[no]
137 }
138
139 pub fn is_empty(&self) -> bool {
140 self.monos.is_empty()
141 }
142
143 pub fn new() -> MonoSet<'tcx> {
144 MonoSet { monos: Vec::new() }
145 }
146
147 pub fn insert(&mut self, mono: Mono<'tcx>) {
148 self.monos.push(mono);
149 }
150
151 pub fn merge(&mut self, other: &MonoSet<'tcx>, tcx: TyCtxt<'tcx>) -> MonoSet<'tcx> {
152 let mut res = MonoSet::new();
153
154 for args in self.monos.iter() {
155 for other_args in other.monos.iter() {
156 let merged = args.merge(other_args, tcx);
157 if let Some(mono) = merged {
158 res.insert(mono);
159 }
160 }
161 }
162 res
163 }
164
165
166
167 fn instantiate_unbound(&self, tcx: TyCtxt<'tcx>) -> Self {
171 let mut res = MonoSet::new();
172 for mono in &self.monos {
173 let filled = mono.fill_unbound_var(tcx);
174 res.monos.extend(filled);
175 }
176 res
177 }
178
179 fn erase_region_var(&mut self, tcx: TyCtxt<'tcx>) {
180 for mono in &mut self.monos {
181 mono.value
182 .iter_mut()
183 .for_each(|arg| *arg = tcx.erase_and_anonymize_regions(*arg))
184 }
185 }
186
187 pub fn filter(mut self, f: impl Fn(&Mono<'tcx>) -> bool) -> Self {
188 self.monos.retain(|args| f(args));
189 self
190 }
191
192 pub fn random_sample<R: Rng>(&mut self, rng: &mut R) {
193 if self.monos.len() <= MAX_STEP_SET_SIZE {
194 return;
195 }
196 self.monos.shuffle(rng);
197 self.monos.truncate(MAX_STEP_SET_SIZE);
198 }
199}
200
201fn unify_ty<'tcx>(
206 lhs: Ty<'tcx>,
207 rhs: Ty<'tcx>,
208 identity: &[ty::GenericArg<'tcx>],
209 infcx: &InferCtxt<'tcx>,
210 cause: &ObligationCause<'tcx>,
211 param_env: ty::ParamEnv<'tcx>,
212) -> Option<Mono<'tcx>> {
213 infcx.probe(|_| {
215 match infcx
216 .at(cause, param_env)
217 .eq(DefineOpaqueTypes::Yes, lhs, rhs)
218 {
219 Ok(_infer_ok) => {
220 let mono = identity
222 .iter()
223 .map(|arg| match arg.kind() {
224 ty::GenericArgKind::Lifetime(region) => {
225 infcx.resolve_vars_if_possible(region).into()
226 }
227 ty::GenericArgKind::Type(ty) => infcx.resolve_vars_if_possible(ty).into(),
228 ty::GenericArgKind::Const(ct) => infcx.resolve_vars_if_possible(ct).into(),
229 })
230 .collect();
231 Some(mono)
232 }
233 Err(_e) => {
234 None
236 }
237 }
238 })
239}
240
241fn is_args_fit_trait_bound<'tcx>(
242 fn_did: DefId,
243 args: &[ty::GenericArg<'tcx>],
244 tcx: TyCtxt<'tcx>,
245) -> bool {
246 let args = tcx.mk_args(args);
247 rap_trace!(
248 "fn: {:?} args: {:?} identity: {:?}",
249 fn_did,
250 args,
251 ty::GenericArgs::identity_for_item(tcx, fn_did)
252 );
253 let infcx = tcx.infer_ctxt().build(ty::TypingMode::PostAnalysis);
254 let param_env = tcx.param_env(fn_did);
255 let pred = crate::compat::predicates_of(tcx, fn_did);
256 let inst_pred = pred.instantiate(tcx, args);
257 rap_trace!(
258 "[trait bound] check {}",
259 tcx.def_path_str_with_args(fn_did, args)
260 );
261
262 #[cfg(not(rapx_ge_100))]
263 let iter = inst_pred.predicates.iter();
264 #[cfg(rapx_ge_100)]
265 let iter = inst_pred.clauses.iter();
266 for pred in iter {
267 #[cfg(rapx_ge_99)]
268 let pred = pred.skip_norm_wip();
269 let obligation = Obligation::new(
270 tcx,
271 ObligationCause::dummy(),
272 param_env,
273 pred.as_predicate(),
274 );
275 rap_trace!("[trait bound] check pred: {:?}", pred);
276
277 let res = infcx.evaluate_obligation(&obligation);
278 match res {
279 Ok(eva) => {
280 if !eva.may_apply() {
281 rap_trace!("[trait bound] check fail for {pred:?}");
282 return false;
283 }
284 }
285 Err(_) => {
286 rap_trace!("[trait bound] check fail for {pred:?}");
287 return false;
288 }
289 }
290 }
291 rap_trace!("[trait bound] check succ");
292 true
293}
294
295fn is_fn_solvable<'tcx>(fn_did: DefId, tcx: TyCtxt<'tcx>) -> bool {
296 let predicates = crate::compat::predicates_of(tcx, fn_did);
297 #[cfg(not(rapx_ge_100))]
298 let iter = predicates
299 .instantiate_identity(tcx)
300 .predicates;
301 #[cfg(rapx_ge_100)]
302 let iter = predicates
303 .instantiate_identity(tcx)
304 .clauses;
305 for pred in iter
306 {
307 #[cfg(rapx_ge_99)]
308 let pred = pred.skip_norm_wip();
309 if let Some(pred) = pred.as_trait_clause() {
310 let trait_did = pred.skip_binder().trait_ref.def_id;
311 if tcx.is_lang_item(trait_did, LangItem::Fn)
312 || tcx.is_lang_item(trait_did, LangItem::FnMut)
313 || tcx.is_lang_item(trait_did, LangItem::FnOnce)
314 {
315 return false;
316 }
317 }
318 }
319 true
320}
321
322fn get_mono_set<'tcx>(
323 fn_did: DefId,
324 available_ty: &HashSet<TyWrapper<'tcx>>,
325 tcx: TyCtxt<'tcx>,
326) -> MonoSet<'tcx> {
327 let mut rng = rand::rng();
328
329 rap_debug!("[get_mono_set] solve {}", tcx.def_path_str(fn_did));
331 let identity = ty::GenericArgs::identity_for_item(tcx, fn_did);
332 let infcx = tcx
333 .infer_ctxt()
334 .ignoring_regions()
335 .build(ty::TypingMode::PostAnalysis);
336 let param_env = tcx.param_env(fn_did);
337 let dummy_cause = ObligationCause::dummy();
338 let fresh_args = infcx.fresh_args_for_item(DUMMY_SP, fn_did);
339 let fn_sig = fn_sig_with_generic_args(fn_did, fresh_args, tcx);
341 let identity_fnsig = fn_sig_with_generic_args(fn_did, identity, tcx);
342 let generics = tcx.generics_of(fn_did);
343
344 for i in 0..fresh_args.len() {
346 rap_trace!(
347 "[get_mono_set] arg#{}: {:?} -> {:?}",
348 i,
349 generics.param_at(i, tcx).name,
350 fresh_args[i]
351 );
352 }
353
354 let mut s = MonoSet::all(&fresh_args);
355
356 rap_trace!("[get_mono_set] initialize s: {:?}", s);
357
358 for (no, input_ty) in fn_sig.inputs().iter().enumerate() {
359 if !input_ty.has_infer_types() {
360 continue;
361 }
362 rap_debug!(
363 "[get_mono_set] input_ty#{}: {}",
364 no,
365 identity_fnsig.inputs()[no]
366 );
367
368 let reachable_set = available_ty
369 .iter()
370 .fold(MonoSet::new(), |mut reachable_set, ty| {
371 if let Some(mono) = unify_ty(
372 *input_ty,
373 (*ty).into(),
374 &fresh_args,
375 &infcx,
376 &dummy_cause,
377 param_env,
378 ) {
379 reachable_set.insert(mono);
380 }
381 reachable_set
382 });
383 rap_debug!(
385 "[get_mono_set] size of s: {}, size of input: {}",
386 s.count(),
387 reachable_set.count()
388 );
389 rap_trace!("[get_mono_set] input = {:?}", reachable_set);
390 s = s.merge(&reachable_set, tcx);
391 s.random_sample(&mut rng);
392 rap_trace!("[get_mono_set] after merge s = {:?}", reachable_set);
393 }
394
395 rap_debug!(
396 "[get_mono_set] after input filter, size of s: {}",
397 s.count()
398 );
399
400 let mut res = MonoSet::new();
401
402 for mono in s.monos {
403 solve_unbound_type_generics(
404 fn_did,
405 mono,
406 &mut res,
407 &infcx,
409 &dummy_cause,
410 param_env,
411 tcx,
412 );
413 }
414
415 res.erase_region_var(tcx);
417
418 res.instantiate_unbound(tcx)
420}
421
422fn solve_unbound_type_generics<'tcx>(
423 did: DefId,
424 mono: Mono<'tcx>,
425 res: &mut MonoSet<'tcx>,
426 infcx: &InferCtxt<'tcx>,
427 cause: &ObligationCause<'tcx>,
428 param_env: ty::ParamEnv<'tcx>,
429 tcx: TyCtxt<'tcx>,
430) {
431 if !mono.has_infer_types() {
432 res.insert(mono);
433 return;
434 }
435 let args = tcx.mk_args(&mono.value);
436 let preds = crate::compat::predicates_of(tcx, did);
437 let preds = preds.instantiate(tcx, args);
438 let mut mset = MonoSet::all(args);
439 rap_debug!("[solve_unbound] did = {did:?}, mset={mset:?}");
440 #[cfg(not(rapx_ge_100))]
441 let pred_iter = preds.predicates.iter();
442 #[cfg(rapx_ge_100)]
443 let pred_iter = preds.clauses.iter();
444 for pred in pred_iter {
445 rap_debug!("[solve_unbound] pred = {:?}", pred);
446 #[cfg(rapx_ge_99)]
447 let pred = pred.skip_norm_wip();
448 if let Some(trait_pred) = pred.as_trait_clause() {
449 let trait_pred = trait_pred.skip_binder();
450
451 rap_trace!("[solve_unbound] pred: {:?}", trait_pred);
452
453 let trait_def_id = trait_pred.trait_ref.def_id;
454 if tcx.is_lang_item(trait_def_id, LangItem::Sized)
456 || tcx.is_lang_item(trait_def_id, LangItem::Copy)
457 {
458 continue;
459 }
460
461 let mut p = MonoSet::new();
462
463 for impl_did in tcx.all_impls(trait_def_id)
464 {
466 let impl_trait_ref = tcx.impl_trait_ref(impl_did).skip_binder();
468
469 if !impl_did.is_local() && !impl_trait_ref.self_ty().is_primitive() {
473 continue;
474 }
475
476 if let Some(mono) = unify_trait(
477 trait_pred.trait_ref,
478 impl_trait_ref,
479 args,
480 &infcx,
481 &cause,
482 param_env,
483 tcx,
484 ) {
485 p.insert(mono);
486 }
487 }
488 mset = mset.merge(&p, tcx);
489 rap_trace!("[solve_unbound] mset: {:?}", mset);
490 }
491 }
492
493 rap_trace!("[solve_unbound] (final) mset: {:?}", mset);
494 for mono in mset.monos {
495 res.insert(mono);
496 }
497}
498
499fn unify_trait<'tcx>(
502 lhs: ty::TraitRef<'tcx>,
503 rhs: ty::TraitRef<'tcx>,
504 identity: &[ty::GenericArg<'tcx>],
505 infcx: &InferCtxt<'tcx>,
506 cause: &ObligationCause<'tcx>,
507 param_env: ty::ParamEnv<'tcx>,
508 tcx: TyCtxt<'tcx>,
509) -> Option<Mono<'tcx>> {
510 rap_trace!("[unify_trait] lhs: {:?}, rhs: {:?}", lhs, rhs);
511 if lhs.def_id != rhs.def_id {
512 return None;
513 }
514
515 assert!(lhs.args.len() == rhs.args.len());
516 let mut s = Mono::new(identity);
517 for (lhs_arg, rhs_arg) in lhs.args.iter().zip(rhs.args.iter()) {
518 if let (GenericArgKind::Type(lhs_ty), GenericArgKind::Type(rhs_ty)) =
519 (lhs_arg.kind(), rhs_arg.kind())
520 {
521 if rhs_ty.has_infer_types() || rhs_ty.has_param() {
522 return None;
524 }
525 let mono = unify_ty(lhs_ty, rhs_ty, identity, infcx, cause, param_env)?;
526 rap_trace!("[unify_trait] unified mono: {:?}", mono);
527 s = s.merge(&mono, tcx)?;
528 }
529 }
530 Some(s)
531}
532
533pub fn resolve_mono_apis<'tcx>(
534 fn_did: DefId,
535 available_ty: &HashSet<TyWrapper<'tcx>>,
536 tcx: TyCtxt<'tcx>,
537) -> MonoSet<'tcx> {
538 if !is_fn_solvable(fn_did, tcx) {
540 return MonoSet::empty();
541 }
542
543 let ret = get_mono_set(fn_did, &available_ty, tcx);
545
546 let ret = ret.filter(|mono| {
548 is_args_fit_trait_bound(fn_did, &mono.value, tcx)
549 && mono.value.iter().all(|arg| {
550 if let GenericArgKind::Type(ty) = arg.kind() {
551 !utils::is_ty_unstable(ty, tcx)
552 } else {
553 true
554 }
555 })
556 });
557
558 rap_debug!(
559 "[resolve_mono_apis] fn_did: {:?}, size of mono: {:?}",
560 fn_did,
561 ret.count()
562 );
563
564 ret
565}
566
567
568
569
570
571pub fn get_unbound_generic_candidates<'tcx>(tcx: TyCtxt<'tcx>) -> Vec<ty::Ty<'tcx>> {
574 vec![
575 tcx.types.bool,
576 tcx.types.char,
577 tcx.types.u8,
578 tcx.types.i8,
579 tcx.types.i32,
580 tcx.types.u32,
581 tcx.types.f32,
584 Ty::new_imm_ref(
586 tcx,
587 tcx.lifetimes.re_erased,
588 Ty::new_slice(tcx, tcx.types.u8),
589 ),
590 Ty::new_mut_ref(
591 tcx,
592 tcx.lifetimes.re_erased,
593 Ty::new_slice(tcx, tcx.types.u8),
594 ),
595 ]
596}
597
598pub fn get_mono_complexity<'tcx>(args: &GenericArgsRef<'tcx>) -> usize {
601 args.iter().fold(0, |acc, arg| {
602 if let GenericArgKind::Type(ty) = arg.kind() {
603 acc + utils::ty_complexity(ty)
604 } else {
605 acc
606 }
607 })
608}
609
610pub fn get_impls<'tcx>(
611 tcx: TyCtxt<'tcx>,
612 fn_did: DefId,
613 args: GenericArgsRef<'tcx>,
614) -> HashSet<DefId> {
615 rap_debug!(
616 "get impls for fn: {:?} args: {:?}",
617 tcx.def_path_str_with_args(fn_did, args),
618 args
619 );
620 let mut impls = HashSet::new();
621 let preds = crate::compat::predicates_of(tcx, fn_did);
622 let preds = preds.instantiate(tcx, args);
623 for (pred, _) in preds {
624 #[cfg(rapx_ge_99)]
625 let pred = pred.skip_norm_wip();
626 if let Some(trait_pred) = pred.as_trait_clause() {
627 let trait_ref: rustc_type_ir::TraitRef<TyCtxt<'tcx>> = tcx
628 .liberate_late_bound_regions(fn_did, trait_pred)
629 .trait_ref;
630
631 let res = tcx.codegen_select_candidate(
632 TypingEnv::fully_monomorphized().as_query_input(trait_ref),
633 );
634 if let Ok(source) = res {
635 match source {
636 ImplSource::UserDefined(data) => {
637 if data.impl_def_id.is_local() {
638 impls.insert(data.impl_def_id);
639 }
640 }
641 _ => {}
642 }
643 }
644 }
646 }
647 rap_trace!("fn: {:?} args: {:?} impls: {:?}", fn_did, args, impls);
648 impls
649}