|
| 1 | +use std::ops::ControlFlow; |
| 2 | + |
1 | 3 | use rustc_ast as ast; |
2 | | -use rustc_data_structures::fx::FxHashMap; |
| 4 | +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
3 | 5 | use rustc_hir::def_id::DefId; |
4 | 6 | use rustc_macros::{HashStable, TyDecodable, TyEncodable}; |
5 | 7 | use rustc_span::{Span, Symbol, kw}; |
| 8 | +use rustc_type_ir::{TypeSuperVisitable as _, TypeVisitable, TypeVisitor}; |
6 | 9 | use tracing::instrument; |
7 | 10 |
|
8 | 11 | use super::{Clause, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt}; |
9 | | -use crate::ty; |
10 | | -use crate::ty::{EarlyBinder, GenericArgsRef}; |
| 12 | +use crate::ty::{self, EarlyBinder, GenericArgsRef, Region, RegionKind, TyKind}; |
11 | 13 |
|
12 | 14 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] |
13 | 15 | pub enum GenericParamDefKind { |
@@ -417,6 +419,54 @@ impl<'tcx> GenericPredicates<'tcx> { |
417 | 419 | instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p)); |
418 | 420 | instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s)); |
419 | 421 | } |
| 422 | + |
| 423 | + pub fn is_fully_generic_for_reflection(self, params: FxHashSet<u32>) -> bool { |
| 424 | + #[derive(Default)] |
| 425 | + struct ParamChecker { |
| 426 | + params: FxHashSet<u32>, |
| 427 | + } |
| 428 | + impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParamChecker { |
| 429 | + type Result = ControlFlow<()>; |
| 430 | + fn visit_region(&mut self, r: Region<'tcx>) -> Self::Result { |
| 431 | + match r.kind() { |
| 432 | + RegionKind::ReEarlyParam(param) => { |
| 433 | + if self.params.contains(¶m.index) { |
| 434 | + ControlFlow::Break(()) |
| 435 | + } else { |
| 436 | + ControlFlow::Continue(()) |
| 437 | + } |
| 438 | + } |
| 439 | + RegionKind::ReBound(..) |
| 440 | + | RegionKind::ReLateParam(_) |
| 441 | + | RegionKind::ReStatic |
| 442 | + | RegionKind::ReVar(_) |
| 443 | + | RegionKind::RePlaceholder(_) |
| 444 | + | RegionKind::ReErased |
| 445 | + | RegionKind::ReError(_) => ControlFlow::Continue(()), |
| 446 | + } |
| 447 | + } |
| 448 | + |
| 449 | + fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { |
| 450 | + match t.kind() { |
| 451 | + TyKind::Param(p) => { |
| 452 | + // Reject using parameters used in the type in where bounds |
| 453 | + if self.params.contains(&p.index) { |
| 454 | + return ControlFlow::Break(()); |
| 455 | + } |
| 456 | + } |
| 457 | + TyKind::Alias(..) => return ControlFlow::Break(()), |
| 458 | + _ => (), |
| 459 | + } |
| 460 | + t.super_visit_with(self) |
| 461 | + } |
| 462 | + } |
| 463 | + |
| 464 | + let mut checker = ParamChecker { params }; |
| 465 | + |
| 466 | + // Pessimistic: if any of the lifetimes used in the type show up in where bounds |
| 467 | + // don't allow this impl to be used. |
| 468 | + self.predicates.iter().all(|(clause, _)| clause.visit_with(&mut checker).is_continue()) |
| 469 | + } |
420 | 470 | } |
421 | 471 |
|
422 | 472 | /// `[const]` bounds for a given item. This is represented using a struct much like |
|
0 commit comments