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;
@@ -16,16 +17,17 @@ use rustc_infer::infer::{
1617use rustc_lint:: LateContext ;
1718use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
1819use rustc_middle:: ty:: {
19- self , AdtDef , AliasTy , AssocKind , Binder , BoundRegion , DefIdTree , FnSig , IntTy , List , ParamEnv , Predicate ,
20- PredicateKind , Region , RegionKind , SubstsRef , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor , UintTy ,
21- VariantDef , VariantDiscr ,
20+ self , AdtDef , AliasTy , AssocKind , Binder , BoundRegion , DefIdTree , FnSig , GenericParamDefKind , IntTy , List ,
21+ ParamEnv , Predicate , PredicateKind , Region , RegionKind , SubstsRef , ToPredicate , Ty , TyCtxt , TypeSuperVisitable ,
22+ TypeVisitable , TypeVisitor , UintTy , VariantDef , VariantDiscr ,
2223} ;
2324use rustc_middle:: ty:: { GenericArg , GenericArgKind } ;
2425use rustc_span:: symbol:: Ident ;
2526use rustc_span:: { sym, Span , Symbol , DUMMY_SP } ;
2627use rustc_target:: abi:: { Size , VariantIdx } ;
27- use rustc_trait_selection:: infer :: InferCtxtExt ;
28+ use rustc_trait_selection:: traits :: query :: evaluate_obligation :: InferCtxtExt as _ ;
2829use rustc_trait_selection:: traits:: query:: normalize:: QueryNormalizeExt ;
30+ use rustc_trait_selection:: traits:: { Obligation , ObligationCause } ;
2931use std:: iter;
3032
3133use crate :: { match_def_path, path_res, paths} ;
@@ -206,15 +208,9 @@ pub fn implements_trait<'tcx>(
206208 cx : & LateContext < ' tcx > ,
207209 ty : Ty < ' tcx > ,
208210 trait_id : DefId ,
209- ty_params : & [ GenericArg < ' tcx > ] ,
211+ substs : & [ GenericArg < ' tcx > ] ,
210212) -> 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- )
213+ implements_trait_with_env_from_iter ( cx. tcx , cx. param_env , ty, trait_id, substs. iter ( ) . map ( |& x| Some ( x) ) )
218214}
219215
220216/// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
@@ -223,7 +219,18 @@ pub fn implements_trait_with_env<'tcx>(
223219 param_env : ParamEnv < ' tcx > ,
224220 ty : Ty < ' tcx > ,
225221 trait_id : DefId ,
226- ty_params : impl IntoIterator < Item = Option < GenericArg < ' tcx > > > ,
222+ substs : & [ GenericArg < ' tcx > ] ,
223+ ) -> bool {
224+ implements_trait_with_env_from_iter ( tcx, param_env, ty, trait_id, substs. iter ( ) . map ( |& x| Some ( x) ) )
225+ }
226+
227+ /// Same as `implements_trait_from_env` but takes the substitutions as an iterator.
228+ pub fn implements_trait_with_env_from_iter < ' tcx > (
229+ tcx : TyCtxt < ' tcx > ,
230+ param_env : ParamEnv < ' tcx > ,
231+ ty : Ty < ' tcx > ,
232+ trait_id : DefId ,
233+ substs : impl IntoIterator < Item = impl Into < Option < GenericArg < ' tcx > > > > ,
227234) -> bool {
228235 // Clippy shouldn't have infer types
229236 assert ! ( !ty. needs_infer( ) ) ;
@@ -232,19 +239,36 @@ pub fn implements_trait_with_env<'tcx>(
232239 if ty. has_escaping_bound_vars ( ) {
233240 return false ;
234241 }
242+
235243 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 (
241- ty_params
244+ let trait_ref = tcx. mk_trait_ref (
245+ trait_id,
246+ Some ( GenericArg :: from ( ty) )
242247 . into_iter ( )
243- . map ( |arg| arg. unwrap_or_else ( || infcx. next_ty_var ( orig) . into ( ) ) ) ,
248+ . chain ( substs. into_iter ( ) . map ( |subst| {
249+ subst. into ( ) . unwrap_or_else ( || {
250+ let orig = TypeVariableOrigin {
251+ kind : TypeVariableOriginKind :: MiscVariable ,
252+ span : DUMMY_SP ,
253+ } ;
254+ infcx. next_ty_var ( orig) . into ( )
255+ } )
256+ } ) ) ,
244257 ) ;
258+
259+ debug_assert_eq ! ( tcx. def_kind( trait_id) , DefKind :: Trait ) ;
260+ #[ cfg( debug_assertions) ]
261+ assert_substs_match ( tcx, trait_id, trait_ref. substs ) ;
262+
263+ let obligation = Obligation {
264+ cause : ObligationCause :: dummy ( ) ,
265+ param_env,
266+ recursion_depth : 0 ,
267+ predicate : ty:: Binder :: dummy ( trait_ref) . without_const ( ) . to_predicate ( tcx) ,
268+ } ;
245269 infcx
246- . type_implements_trait ( trait_id , [ ty . into ( ) ] . into_iter ( ) . chain ( ty_params ) , param_env )
247- . must_apply_modulo_regions ( )
270+ . evaluate_obligation ( & obligation )
271+ . is_ok_and ( |x| x . must_apply_modulo_regions ( ) )
248272}
249273
250274/// Checks whether this type implements `Drop`.
@@ -392,6 +416,11 @@ pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangI
392416 }
393417}
394418
419+ /// Gets the diagnostic name of the type, if it has one
420+ pub fn type_diagnostic_name ( cx : & LateContext < ' _ > , ty : Ty < ' _ > ) -> Option < Symbol > {
421+ ty. ty_adt_def ( ) . and_then ( |adt| cx. tcx . get_diagnostic_name ( adt. did ( ) ) )
422+ }
423+
395424/// Return `true` if the passed `typ` is `isize` or `usize`.
396425pub fn is_isize_or_usize ( typ : Ty < ' _ > ) -> bool {
397426 matches ! ( typ. kind( ) , ty:: Int ( IntTy :: Isize ) | ty:: Uint ( UintTy :: Usize ) )
@@ -1001,6 +1030,53 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
10011030 }
10021031}
10031032
1033+ /// Asserts that the given substitutions matches the generic parameters of the given item.
1034+ fn assert_substs_match < ' tcx > ( tcx : TyCtxt < ' tcx > , did : DefId , substs : & [ GenericArg < ' tcx > ] ) {
1035+ let g = tcx. generics_of ( did) ;
1036+ let parent = g. parent . map ( |did| tcx. generics_of ( did) ) ;
1037+ let count = g. parent_count + g. params . len ( ) ;
1038+ let params = parent
1039+ . map_or ( [ ] . as_slice ( ) , |p| p. params . as_slice ( ) )
1040+ . iter ( )
1041+ . chain ( & g. params )
1042+ . map ( |x| & x. kind ) ;
1043+
1044+ assert ! (
1045+ count == substs. len( ) ,
1046+ "wrong number substs for `{did:?}`: expected `{count}`, found {}\n \
1047+ note: the expected parameters are: `[{}]`\n \
1048+ the given substs are: `{substs:#?}`",
1049+ substs. len( ) ,
1050+ params. clone( ) . map( ty:: GenericParamDefKind :: descr) . format( ", " ) ,
1051+ ) ;
1052+
1053+ if let Some ( ( idx, ( param, arg) ) ) =
1054+ params
1055+ . clone ( )
1056+ . zip ( substs. iter ( ) . map ( |& x| x. unpack ( ) ) )
1057+ . enumerate ( )
1058+ . find ( |( _, ( param, arg) ) | match ( param, arg) {
1059+ ( GenericParamDefKind :: Lifetime , GenericArgKind :: Lifetime ( _) )
1060+ | ( GenericParamDefKind :: Type { .. } , GenericArgKind :: Type ( _) )
1061+ | ( GenericParamDefKind :: Const { .. } , GenericArgKind :: Const ( _) ) => false ,
1062+ (
1063+ GenericParamDefKind :: Lifetime
1064+ | GenericParamDefKind :: Type { .. }
1065+ | GenericParamDefKind :: Const { .. } ,
1066+ _,
1067+ ) => true ,
1068+ } )
1069+ {
1070+ panic ! (
1071+ "incorrect subst for `{did:?}` at index `{idx}`: expected a {}, found `{arg:?}`\n \
1072+ note: the expected parameters are `[{}]`\n \
1073+ the given arguments are `{substs:#?}`",
1074+ param. descr( ) ,
1075+ params. clone( ) . map( ty:: GenericParamDefKind :: descr) . format( ", " ) ,
1076+ ) ;
1077+ }
1078+ }
1079+
10041080/// Makes the projection type for the named associated type in the given impl or trait impl.
10051081///
10061082/// This function is for associated types which are "known" to exist, and as such, will only return
@@ -1028,49 +1104,7 @@ pub fn make_projection<'tcx>(
10281104 return None ;
10291105 } ;
10301106 #[ cfg( debug_assertions) ]
1031- {
1032- let generics = tcx. generics_of ( assoc_item. def_id ) ;
1033- let generic_count = generics. parent_count + generics. params . len ( ) ;
1034- let params = generics
1035- . parent
1036- . map_or ( [ ] . as_slice ( ) , |id| & * tcx. generics_of ( id) . params )
1037- . iter ( )
1038- . chain ( & generics. params )
1039- . map ( |x| & x. kind ) ;
1040-
1041- debug_assert ! (
1042- generic_count == substs. len( ) ,
1043- "wrong number of substs for `{:?}`: found `{}` expected `{generic_count}`.\n \
1044- note: the expected parameters are: {:#?}\n \
1045- the given arguments are: `{substs:#?}`",
1046- assoc_item. def_id,
1047- substs. len( ) ,
1048- params. map( ty:: GenericParamDefKind :: descr) . collect:: <Vec <_>>( ) ,
1049- ) ;
1050-
1051- if let Some ( ( idx, ( param, arg) ) ) = params
1052- . clone ( )
1053- . zip ( substs. iter ( ) . map ( GenericArg :: unpack) )
1054- . enumerate ( )
1055- . find ( |( _, ( param, arg) ) | {
1056- !matches ! (
1057- ( param, arg) ,
1058- ( ty:: GenericParamDefKind :: Lifetime , GenericArgKind :: Lifetime ( _) )
1059- | ( ty:: GenericParamDefKind :: Type { .. } , GenericArgKind :: Type ( _) )
1060- | ( ty:: GenericParamDefKind :: Const { .. } , GenericArgKind :: Const ( _) )
1061- )
1062- } )
1063- {
1064- debug_assert ! (
1065- false ,
1066- "mismatched subst type at index {idx}: expected a {}, found `{arg:?}`\n \
1067- note: the expected parameters are {:#?}\n \
1068- the given arguments are {substs:#?}",
1069- param. descr( ) ,
1070- params. map( ty:: GenericParamDefKind :: descr) . collect:: <Vec <_>>( )
1071- ) ;
1072- }
1073- }
1107+ assert_substs_match ( tcx, assoc_item. def_id , substs) ;
10741108
10751109 Some ( tcx. mk_alias_ty ( assoc_item. def_id , substs) )
10761110 }
0 commit comments