@@ -85,6 +85,7 @@ use rustc_trait_selection::traits::query::normalize::AtExt;
85
85
use smallvec:: SmallVec ;
86
86
87
87
use crate :: consts:: { constant, Constant } ;
88
+ use std:: collections:: HashMap ;
88
89
89
90
pub fn parse_msrv ( msrv : & str , sess : Option < & Session > , span : Option < Span > ) -> Option < RustcVersion > {
90
91
if let Ok ( version) = RustcVersion :: parse ( msrv) {
@@ -1488,10 +1489,45 @@ pub fn match_function_call<'tcx>(
1488
1489
/// Checks if `Ty` is normalizable. This function is useful
1489
1490
/// to avoid crashes on `layout_of`.
1490
1491
pub fn is_normalizable < ' tcx > ( cx : & LateContext < ' tcx > , param_env : ty:: ParamEnv < ' tcx > , ty : Ty < ' tcx > ) -> bool {
1491
- cx. tcx . infer_ctxt ( ) . enter ( |infcx| {
1492
+ is_normalizable_helper ( cx, param_env, ty, & mut HashMap :: new ( ) )
1493
+ }
1494
+
1495
+ fn is_normalizable_helper < ' tcx > (
1496
+ cx : & LateContext < ' tcx > ,
1497
+ param_env : ty:: ParamEnv < ' tcx > ,
1498
+ ty : Ty < ' tcx > ,
1499
+ cache : & mut HashMap < Ty < ' tcx > , bool > ,
1500
+ ) -> bool {
1501
+ if let Some ( & cached_result) = cache. get ( ty) {
1502
+ return cached_result;
1503
+ }
1504
+ cache. insert ( ty, false ) ; // prevent recursive loops
1505
+ let result = cx. tcx . infer_ctxt ( ) . enter ( |infcx| {
1492
1506
let cause = rustc_middle:: traits:: ObligationCause :: dummy ( ) ;
1493
- infcx. at ( & cause, param_env) . normalize ( ty) . is_ok ( )
1494
- } )
1507
+ if infcx. at ( & cause, param_env) . normalize ( ty) . is_err ( ) {
1508
+ false
1509
+ } else {
1510
+ match ty. kind ( ) {
1511
+ ty:: Adt ( def, substs) => !def. variants . iter ( ) . any ( |variant| {
1512
+ variant
1513
+ . fields
1514
+ . iter ( )
1515
+ . any ( |field| !is_normalizable_helper ( cx, param_env, field. ty ( cx. tcx , substs) , cache) )
1516
+ } ) ,
1517
+ ty:: Ref ( _, pointee, _) | ty:: RawPtr ( ty:: TypeAndMut { ty : pointee, .. } ) => {
1518
+ is_normalizable_helper ( cx, param_env, pointee, cache)
1519
+ } ,
1520
+ ty:: Array ( inner_ty, _) | ty:: Slice ( inner_ty) => is_normalizable_helper ( cx, param_env, inner_ty, cache) ,
1521
+ ty:: Tuple ( tys) => !tys. iter ( ) . any ( |inner| match inner. unpack ( ) {
1522
+ GenericArgKind :: Type ( inner_ty) => !is_normalizable_helper ( cx, param_env, inner_ty, cache) ,
1523
+ _ => false ,
1524
+ } ) ,
1525
+ _ => true ,
1526
+ }
1527
+ }
1528
+ } ) ;
1529
+ cache. insert ( ty, result) ;
1530
+ result
1495
1531
}
1496
1532
1497
1533
pub fn match_def_path < ' tcx > ( cx : & LateContext < ' tcx > , did : DefId , syms : & [ & str ] ) -> bool {
0 commit comments