33#![ allow( clippy:: module_name_repetitions) ]
44
55use core:: ops:: ControlFlow ;
6+ use itertools:: Itertools ;
67use rustc_ast:: ast:: Mutability ;
78use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
89use rustc_hir as hir;
@@ -15,17 +16,19 @@ use rustc_infer::infer::{
1516} ;
1617use rustc_lint:: LateContext ;
1718use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
19+ use rustc_middle:: traits:: EvaluationResult ;
1820use rustc_middle:: ty:: {
19- self , layout:: ValidityRequirement , AdtDef , AliasTy , AssocKind , Binder , BoundRegion , FnSig , IntTy , List , ParamEnv ,
20- Predicate , PredicateKind , Region , RegionKind , SubstsRef , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable ,
21- TypeVisitableExt , TypeVisitor , UintTy , VariantDef , VariantDiscr ,
21+ self , layout:: ValidityRequirement , AdtDef , AliasTy , AssocKind , Binder , BoundRegion , FnSig , GenericArg ,
22+ GenericArgKind , GenericParamDefKind , IntTy , List , ParamEnv , Predicate , PredicateKind , Region , RegionKind ,
23+ SubstsRef , ToPredicate , TraitRef , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor ,
24+ UintTy , VariantDef , VariantDiscr ,
2225} ;
23- use rustc_middle:: ty:: { GenericArg , GenericArgKind } ;
2426use rustc_span:: symbol:: Ident ;
2527use rustc_span:: { sym, Span , Symbol , DUMMY_SP } ;
2628use rustc_target:: abi:: { Size , VariantIdx } ;
27- use rustc_trait_selection:: infer :: InferCtxtExt ;
29+ use rustc_trait_selection:: traits :: query :: evaluate_obligation :: InferCtxtExt as _ ;
2830use rustc_trait_selection:: traits:: query:: normalize:: QueryNormalizeExt ;
31+ use rustc_trait_selection:: traits:: { Obligation , ObligationCause } ;
2932use std:: iter;
3033
3134use crate :: { match_def_path, path_res, paths} ;
@@ -206,15 +209,9 @@ pub fn implements_trait<'tcx>(
206209 cx : & LateContext < ' tcx > ,
207210 ty : Ty < ' tcx > ,
208211 trait_id : DefId ,
209- ty_params : & [ GenericArg < ' tcx > ] ,
212+ substs : & [ GenericArg < ' tcx > ] ,
210213) -> bool {
211- implements_trait_with_env (
212- cx. tcx ,
213- cx. param_env ,
214- ty,
215- trait_id,
216- ty_params. iter ( ) . map ( |& arg| Some ( arg) ) ,
217- )
214+ implements_trait_with_env_from_iter ( cx. tcx , cx. param_env , ty, trait_id, substs. iter ( ) . map ( |& x| Some ( x) ) )
218215}
219216
220217/// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
@@ -223,7 +220,18 @@ pub fn implements_trait_with_env<'tcx>(
223220 param_env : ParamEnv < ' tcx > ,
224221 ty : Ty < ' tcx > ,
225222 trait_id : DefId ,
226- ty_params : impl IntoIterator < Item = Option < GenericArg < ' tcx > > > ,
223+ substs : & [ GenericArg < ' tcx > ] ,
224+ ) -> bool {
225+ implements_trait_with_env_from_iter ( tcx, param_env, ty, trait_id, substs. iter ( ) . map ( |& x| Some ( x) ) )
226+ }
227+
228+ /// Same as `implements_trait_from_env` but takes the substitutions as an iterator.
229+ pub fn implements_trait_with_env_from_iter < ' tcx > (
230+ tcx : TyCtxt < ' tcx > ,
231+ param_env : ParamEnv < ' tcx > ,
232+ ty : Ty < ' tcx > ,
233+ trait_id : DefId ,
234+ substs : impl IntoIterator < Item = impl Into < Option < GenericArg < ' tcx > > > > ,
227235) -> bool {
228236 // Clippy shouldn't have infer types
229237 assert ! ( !ty. has_infer( ) ) ;
@@ -232,19 +240,37 @@ pub fn implements_trait_with_env<'tcx>(
232240 if ty. has_escaping_bound_vars ( ) {
233241 return false ;
234242 }
243+
235244 let infcx = tcx. infer_ctxt ( ) . build ( ) ;
236- let orig = TypeVariableOrigin {
237- kind : TypeVariableOriginKind :: MiscVariable ,
238- span : DUMMY_SP ,
239- } ;
240- let ty_params = tcx. mk_substs_from_iter (
241- ty_params
245+ let trait_ref = TraitRef :: new (
246+ tcx,
247+ trait_id,
248+ Some ( GenericArg :: from ( ty) )
242249 . into_iter ( )
243- . map ( |arg| arg. unwrap_or_else ( || infcx. next_ty_var ( orig) . into ( ) ) ) ,
250+ . chain ( substs. into_iter ( ) . map ( |subst| {
251+ subst. into ( ) . unwrap_or_else ( || {
252+ let orig = TypeVariableOrigin {
253+ kind : TypeVariableOriginKind :: MiscVariable ,
254+ span : DUMMY_SP ,
255+ } ;
256+ infcx. next_ty_var ( orig) . into ( )
257+ } )
258+ } ) ) ,
244259 ) ;
260+
261+ debug_assert_eq ! ( tcx. def_kind( trait_id) , DefKind :: Trait ) ;
262+ #[ cfg( debug_assertions) ]
263+ assert_substs_match ( tcx, trait_id, trait_ref. substs ) ;
264+
265+ let obligation = Obligation {
266+ cause : ObligationCause :: dummy ( ) ,
267+ param_env,
268+ recursion_depth : 0 ,
269+ predicate : ty:: Binder :: dummy ( trait_ref) . without_const ( ) . to_predicate ( tcx) ,
270+ } ;
245271 infcx
246- . type_implements_trait ( trait_id , [ ty . into ( ) ] . into_iter ( ) . chain ( ty_params ) , param_env )
247- . must_apply_modulo_regions ( )
272+ . evaluate_obligation ( & obligation )
273+ . is_ok_and ( EvaluationResult :: must_apply_modulo_regions )
248274}
249275
250276/// Checks whether this type implements `Drop`.
@@ -392,6 +418,11 @@ pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangI
392418 }
393419}
394420
421+ /// Gets the diagnostic name of the type, if it has one
422+ pub fn type_diagnostic_name ( cx : & LateContext < ' _ > , ty : Ty < ' _ > ) -> Option < Symbol > {
423+ ty. ty_adt_def ( ) . and_then ( |adt| cx. tcx . get_diagnostic_name ( adt. did ( ) ) )
424+ }
425+
395426/// Return `true` if the passed `typ` is `isize` or `usize`.
396427pub fn is_isize_or_usize ( typ : Ty < ' _ > ) -> bool {
397428 matches ! ( typ. kind( ) , ty:: Int ( IntTy :: Isize ) | ty:: Uint ( UintTy :: Usize ) )
@@ -1016,6 +1047,54 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
10161047 }
10171048}
10181049
1050+ /// Asserts that the given substitutions matches the generic parameters of the given item.
1051+ #[ allow( dead_code) ]
1052+ fn assert_substs_match < ' tcx > ( tcx : TyCtxt < ' tcx > , did : DefId , substs : & [ GenericArg < ' tcx > ] ) {
1053+ let g = tcx. generics_of ( did) ;
1054+ let parent = g. parent . map ( |did| tcx. generics_of ( did) ) ;
1055+ let count = g. parent_count + g. params . len ( ) ;
1056+ let params = parent
1057+ . map_or ( [ ] . as_slice ( ) , |p| p. params . as_slice ( ) )
1058+ . iter ( )
1059+ . chain ( & g. params )
1060+ . map ( |x| & x. kind ) ;
1061+
1062+ assert ! (
1063+ count == substs. len( ) ,
1064+ "wrong number substs for `{did:?}`: expected `{count}`, found {}\n \
1065+ note: the expected parameters are: `[{}]`\n \
1066+ the given substs are: `{substs:#?}`",
1067+ substs. len( ) ,
1068+ params. clone( ) . map( GenericParamDefKind :: descr) . format( ", " ) ,
1069+ ) ;
1070+
1071+ if let Some ( ( idx, ( param, arg) ) ) =
1072+ params
1073+ . clone ( )
1074+ . zip ( substs. iter ( ) . map ( |& x| x. unpack ( ) ) )
1075+ . enumerate ( )
1076+ . find ( |( _, ( param, arg) ) | match ( param, arg) {
1077+ ( GenericParamDefKind :: Lifetime , GenericArgKind :: Lifetime ( _) )
1078+ | ( GenericParamDefKind :: Type { .. } , GenericArgKind :: Type ( _) )
1079+ | ( GenericParamDefKind :: Const { .. } , GenericArgKind :: Const ( _) ) => false ,
1080+ (
1081+ GenericParamDefKind :: Lifetime
1082+ | GenericParamDefKind :: Type { .. }
1083+ | GenericParamDefKind :: Const { .. } ,
1084+ _,
1085+ ) => true ,
1086+ } )
1087+ {
1088+ panic ! (
1089+ "incorrect subst for `{did:?}` at index `{idx}`: expected a {}, found `{arg:?}`\n \
1090+ note: the expected parameters are `[{}]`\n \
1091+ the given arguments are `{substs:#?}`",
1092+ param. descr( ) ,
1093+ params. clone( ) . map( GenericParamDefKind :: descr) . format( ", " ) ,
1094+ ) ;
1095+ }
1096+ }
1097+
10191098/// Makes the projection type for the named associated type in the given impl or trait impl.
10201099///
10211100/// This function is for associated types which are "known" to exist, and as such, will only return
@@ -1043,49 +1122,7 @@ pub fn make_projection<'tcx>(
10431122 return None ;
10441123 } ;
10451124 #[ cfg( debug_assertions) ]
1046- {
1047- let generics = tcx. generics_of ( assoc_item. def_id ) ;
1048- let generic_count = generics. parent_count + generics. params . len ( ) ;
1049- let params = generics
1050- . parent
1051- . map_or ( [ ] . as_slice ( ) , |id| & * tcx. generics_of ( id) . params )
1052- . iter ( )
1053- . chain ( & generics. params )
1054- . map ( |x| & x. kind ) ;
1055-
1056- debug_assert ! (
1057- generic_count == substs. len( ) ,
1058- "wrong number of substs for `{:?}`: found `{}` expected `{generic_count}`.\n \
1059- note: the expected parameters are: {:#?}\n \
1060- the given arguments are: `{substs:#?}`",
1061- assoc_item. def_id,
1062- substs. len( ) ,
1063- params. map( ty:: GenericParamDefKind :: descr) . collect:: <Vec <_>>( ) ,
1064- ) ;
1065-
1066- if let Some ( ( idx, ( param, arg) ) ) = params
1067- . clone ( )
1068- . zip ( substs. iter ( ) . map ( GenericArg :: unpack) )
1069- . enumerate ( )
1070- . find ( |( _, ( param, arg) ) | {
1071- !matches ! (
1072- ( param, arg) ,
1073- ( ty:: GenericParamDefKind :: Lifetime , GenericArgKind :: Lifetime ( _) )
1074- | ( ty:: GenericParamDefKind :: Type { .. } , GenericArgKind :: Type ( _) )
1075- | ( ty:: GenericParamDefKind :: Const { .. } , GenericArgKind :: Const ( _) )
1076- )
1077- } )
1078- {
1079- debug_assert ! (
1080- false ,
1081- "mismatched subst type at index {idx}: expected a {}, found `{arg:?}`\n \
1082- note: the expected parameters are {:#?}\n \
1083- the given arguments are {substs:#?}",
1084- param. descr( ) ,
1085- params. map( ty:: GenericParamDefKind :: descr) . collect:: <Vec <_>>( )
1086- ) ;
1087- }
1088- }
1125+ assert_substs_match ( tcx, assoc_item. def_id , substs) ;
10891126
10901127 Some ( tcx. mk_alias_ty ( assoc_item. def_id , substs) )
10911128 }
0 commit comments