@@ -85,6 +85,7 @@ use rustc_trait_selection::traits::query::normalize::AtExt;
8585use smallvec:: SmallVec ;
8686
8787use crate :: consts:: { constant, Constant } ;
88+ use std:: collections:: HashMap ;
8889
8990pub fn parse_msrv ( msrv : & str , sess : Option < & Session > , span : Option < Span > ) -> Option < RustcVersion > {
9091 if let Ok ( version) = RustcVersion :: parse ( msrv) {
@@ -1488,10 +1489,45 @@ pub fn match_function_call<'tcx>(
14881489/// Checks if `Ty` is normalizable. This function is useful
14891490/// to avoid crashes on `layout_of`.
14901491pub 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| {
14921506 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
14951531}
14961532
14971533pub fn match_def_path < ' tcx > ( cx : & LateContext < ' tcx > , did : DefId , syms : & [ & str ] ) -> bool {
0 commit comments