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;
@@ -13,17 +14,19 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
1314use rustc_infer:: infer:: TyCtxtInferExt ;
1415use rustc_lint:: LateContext ;
1516use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
17+ use rustc_middle:: traits:: EvaluationResult ;
1618use rustc_middle:: ty:: layout:: ValidityRequirement ;
1719use rustc_middle:: ty:: {
18- self , AdtDef , AliasTy , AssocKind , Binder , BoundRegion , FnSig , GenericArg , GenericArgKind , GenericArgsRef , IntTy ,
19- List , ParamEnv , Region , RegionKind , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor ,
20- UintTy , VariantDef , VariantDiscr ,
20+ self , AdtDef , AliasTy , AssocKind , Binder , BoundRegion , FnSig , GenericArg , GenericArgKind , GenericArgsRef ,
21+ GenericParamDefKind , IntTy , List , ParamEnv , Region , RegionKind , ToPredicate , TraitRef , Ty , TyCtxt ,
22+ TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor , UintTy , VariantDef , VariantDiscr ,
2123} ;
2224use rustc_span:: symbol:: Ident ;
2325use rustc_span:: { sym, Span , Symbol , DUMMY_SP } ;
2426use rustc_target:: abi:: { Size , VariantIdx } ;
25- use rustc_trait_selection:: infer :: InferCtxtExt ;
27+ use rustc_trait_selection:: traits :: query :: evaluate_obligation :: InferCtxtExt as _ ;
2628use rustc_trait_selection:: traits:: query:: normalize:: QueryNormalizeExt ;
29+ use rustc_trait_selection:: traits:: { Obligation , ObligationCause } ;
2730use std:: iter;
2831
2932use crate :: { match_def_path, path_res, paths} ;
@@ -207,15 +210,9 @@ pub fn implements_trait<'tcx>(
207210 cx : & LateContext < ' tcx > ,
208211 ty : Ty < ' tcx > ,
209212 trait_id : DefId ,
210- ty_params : & [ GenericArg < ' tcx > ] ,
213+ args : & [ GenericArg < ' tcx > ] ,
211214) -> bool {
212- implements_trait_with_env (
213- cx. tcx ,
214- cx. param_env ,
215- ty,
216- trait_id,
217- ty_params. iter ( ) . map ( |& arg| Some ( arg) ) ,
218- )
215+ implements_trait_with_env_from_iter ( cx. tcx , cx. param_env , ty, trait_id, args. iter ( ) . map ( |& x| Some ( x) ) )
219216}
220217
221218/// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
@@ -224,7 +221,18 @@ pub fn implements_trait_with_env<'tcx>(
224221 param_env : ParamEnv < ' tcx > ,
225222 ty : Ty < ' tcx > ,
226223 trait_id : DefId ,
227- ty_params : impl IntoIterator < Item = Option < GenericArg < ' tcx > > > ,
224+ args : & [ GenericArg < ' tcx > ] ,
225+ ) -> bool {
226+ implements_trait_with_env_from_iter ( tcx, param_env, ty, trait_id, args. iter ( ) . map ( |& x| Some ( x) ) )
227+ }
228+
229+ /// Same as `implements_trait_from_env` but takes the arguments as an iterator.
230+ pub fn implements_trait_with_env_from_iter < ' tcx > (
231+ tcx : TyCtxt < ' tcx > ,
232+ param_env : ParamEnv < ' tcx > ,
233+ ty : Ty < ' tcx > ,
234+ trait_id : DefId ,
235+ args : impl IntoIterator < Item = impl Into < Option < GenericArg < ' tcx > > > > ,
228236) -> bool {
229237 // Clippy shouldn't have infer types
230238 assert ! ( !ty. has_infer( ) ) ;
@@ -233,19 +241,37 @@ pub fn implements_trait_with_env<'tcx>(
233241 if ty. has_escaping_bound_vars ( ) {
234242 return false ;
235243 }
244+
236245 let infcx = tcx. infer_ctxt ( ) . build ( ) ;
237- let orig = TypeVariableOrigin {
238- kind : TypeVariableOriginKind :: MiscVariable ,
239- span : DUMMY_SP ,
240- } ;
241- let ty_params = tcx. mk_args_from_iter (
242- ty_params
246+ let trait_ref = TraitRef :: new (
247+ tcx,
248+ trait_id,
249+ Some ( GenericArg :: from ( ty) )
243250 . into_iter ( )
244- . map ( |arg| arg. unwrap_or_else ( || infcx. next_ty_var ( orig) . into ( ) ) ) ,
251+ . chain ( args. into_iter ( ) . map ( |arg| {
252+ arg. into ( ) . unwrap_or_else ( || {
253+ let orig = TypeVariableOrigin {
254+ kind : TypeVariableOriginKind :: MiscVariable ,
255+ span : DUMMY_SP ,
256+ } ;
257+ infcx. next_ty_var ( orig) . into ( )
258+ } )
259+ } ) ) ,
245260 ) ;
261+
262+ debug_assert_eq ! ( tcx. def_kind( trait_id) , DefKind :: Trait ) ;
263+ #[ cfg( debug_assertions) ]
264+ assert_generic_args_match ( tcx, trait_id, trait_ref. args ) ;
265+
266+ let obligation = Obligation {
267+ cause : ObligationCause :: dummy ( ) ,
268+ param_env,
269+ recursion_depth : 0 ,
270+ predicate : ty:: Binder :: dummy ( trait_ref) . without_const ( ) . to_predicate ( tcx) ,
271+ } ;
246272 infcx
247- . type_implements_trait ( trait_id , [ ty . into ( ) ] . into_iter ( ) . chain ( ty_params ) , param_env )
248- . must_apply_modulo_regions ( )
273+ . evaluate_obligation ( & obligation )
274+ . is_ok_and ( EvaluationResult :: must_apply_modulo_regions )
249275}
250276
251277/// Checks whether this type implements `Drop`.
@@ -393,6 +419,11 @@ pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangI
393419 }
394420}
395421
422+ /// Gets the diagnostic name of the type, if it has one
423+ pub fn type_diagnostic_name ( cx : & LateContext < ' _ > , ty : Ty < ' _ > ) -> Option < Symbol > {
424+ ty. ty_adt_def ( ) . and_then ( |adt| cx. tcx . get_diagnostic_name ( adt. did ( ) ) )
425+ }
426+
396427/// Return `true` if the passed `typ` is `isize` or `usize`.
397428pub fn is_isize_or_usize ( typ : Ty < ' _ > ) -> bool {
398429 matches ! ( typ. kind( ) , ty:: Int ( IntTy :: Isize ) | ty:: Uint ( UintTy :: Usize ) )
@@ -1014,12 +1045,60 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
10141045 }
10151046}
10161047
1048+ /// Asserts that the given arguments match the generic parameters of the given item.
1049+ #[ allow( dead_code) ]
1050+ fn assert_generic_args_match < ' tcx > ( tcx : TyCtxt < ' tcx > , did : DefId , args : & [ GenericArg < ' tcx > ] ) {
1051+ let g = tcx. generics_of ( did) ;
1052+ let parent = g. parent . map ( |did| tcx. generics_of ( did) ) ;
1053+ let count = g. parent_count + g. params . len ( ) ;
1054+ let params = parent
1055+ . map_or ( [ ] . as_slice ( ) , |p| p. params . as_slice ( ) )
1056+ . iter ( )
1057+ . chain ( & g. params )
1058+ . map ( |x| & x. kind ) ;
1059+
1060+ assert ! (
1061+ count == args. len( ) ,
1062+ "wrong number of arguments for `{did:?}`: expected `{count}`, found {}\n \
1063+ note: the expected arguments are: `[{}]`\n \
1064+ the given arguments are: `{args:#?}`",
1065+ args. len( ) ,
1066+ params. clone( ) . map( GenericParamDefKind :: descr) . format( ", " ) ,
1067+ ) ;
1068+
1069+ if let Some ( ( idx, ( param, arg) ) ) =
1070+ params
1071+ . clone ( )
1072+ . zip ( args. iter ( ) . map ( |& x| x. unpack ( ) ) )
1073+ . enumerate ( )
1074+ . find ( |( _, ( param, arg) ) | match ( param, arg) {
1075+ ( GenericParamDefKind :: Lifetime , GenericArgKind :: Lifetime ( _) )
1076+ | ( GenericParamDefKind :: Type { .. } , GenericArgKind :: Type ( _) )
1077+ | ( GenericParamDefKind :: Const { .. } , GenericArgKind :: Const ( _) ) => false ,
1078+ (
1079+ GenericParamDefKind :: Lifetime
1080+ | GenericParamDefKind :: Type { .. }
1081+ | GenericParamDefKind :: Const { .. } ,
1082+ _,
1083+ ) => true ,
1084+ } )
1085+ {
1086+ panic ! (
1087+ "incorrect argument for `{did:?}` at index `{idx}`: expected a {}, found `{arg:?}`\n \
1088+ note: the expected arguments are `[{}]`\n \
1089+ the given arguments are `{args:#?}`",
1090+ param. descr( ) ,
1091+ params. clone( ) . map( GenericParamDefKind :: descr) . format( ", " ) ,
1092+ ) ;
1093+ }
1094+ }
1095+
10171096/// Makes the projection type for the named associated type in the given impl or trait impl.
10181097///
10191098/// This function is for associated types which are "known" to exist, and as such, will only return
10201099/// `None` when debug assertions are disabled in order to prevent ICE's. With debug assertions
10211100/// enabled this will check that the named associated type exists, the correct number of
1022- /// substitutions are given, and that the correct kinds of substitutions are given (lifetime,
1101+ /// arguments are given, and that the correct kinds of arguments are given (lifetime,
10231102/// constant or type). This will not check if type normalization would succeed.
10241103pub fn make_projection < ' tcx > (
10251104 tcx : TyCtxt < ' tcx > ,
@@ -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 == args. len( ) ,
1058- "wrong number of args for `{:?}`: found `{}` expected `{generic_count}`.\n \
1059- note: the expected parameters are: {:#?}\n \
1060- the given arguments are: `{args:#?}`",
1061- assoc_item. def_id,
1062- args. len( ) ,
1063- params. map( ty:: GenericParamDefKind :: descr) . collect:: <Vec <_>>( ) ,
1064- ) ;
1065-
1066- if let Some ( ( idx, ( param, arg) ) ) = params
1067- . clone ( )
1068- . zip ( args. 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 {args:#?}",
1084- param. descr( ) ,
1085- params. map( ty:: GenericParamDefKind :: descr) . collect:: <Vec <_>>( )
1086- ) ;
1087- }
1088- }
1125+ assert_generic_args_match ( tcx, assoc_item. def_id , args) ;
10891126
10901127 Some ( tcx. mk_alias_ty ( assoc_item. def_id , args) )
10911128 }
@@ -1100,7 +1137,7 @@ pub fn make_projection<'tcx>(
11001137/// Normalizes the named associated type in the given impl or trait impl.
11011138///
11021139/// This function is for associated types which are "known" to be valid with the given
1103- /// substitutions , and as such, will only return `None` when debug assertions are disabled in order
1140+ /// arguments , and as such, will only return `None` when debug assertions are disabled in order
11041141/// to prevent ICE's. With debug assertions enabled this will check that type normalization
11051142/// succeeds as well as everything checked by `make_projection`.
11061143pub fn make_normalized_projection < ' tcx > (
@@ -1112,17 +1149,12 @@ pub fn make_normalized_projection<'tcx>(
11121149) -> Option < Ty < ' tcx > > {
11131150 fn helper < ' tcx > ( tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > , ty : AliasTy < ' tcx > ) -> Option < Ty < ' tcx > > {
11141151 #[ cfg( debug_assertions) ]
1115- if let Some ( ( i, subst) ) = ty
1116- . args
1117- . iter ( )
1118- . enumerate ( )
1119- . find ( |( _, subst) | subst. has_late_bound_regions ( ) )
1120- {
1152+ if let Some ( ( i, arg) ) = ty. args . iter ( ) . enumerate ( ) . find ( |( _, arg) | arg. has_late_bound_regions ( ) ) {
11211153 debug_assert ! (
11221154 false ,
11231155 "args contain late-bound region at index `{i}` which can't be normalized.\n \
11241156 use `TyCtxt::erase_late_bound_regions`\n \
1125- note: subst is `{subst :#?}`",
1157+ note: arg is `{arg :#?}`",
11261158 ) ;
11271159 return None ;
11281160 }
@@ -1190,17 +1222,12 @@ pub fn make_normalized_projection_with_regions<'tcx>(
11901222) -> Option < Ty < ' tcx > > {
11911223 fn helper < ' tcx > ( tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > , ty : AliasTy < ' tcx > ) -> Option < Ty < ' tcx > > {
11921224 #[ cfg( debug_assertions) ]
1193- if let Some ( ( i, subst) ) = ty
1194- . args
1195- . iter ( )
1196- . enumerate ( )
1197- . find ( |( _, subst) | subst. has_late_bound_regions ( ) )
1198- {
1225+ if let Some ( ( i, arg) ) = ty. args . iter ( ) . enumerate ( ) . find ( |( _, arg) | arg. has_late_bound_regions ( ) ) {
11991226 debug_assert ! (
12001227 false ,
12011228 "args contain late-bound region at index `{i}` which can't be normalized.\n \
12021229 use `TyCtxt::erase_late_bound_regions`\n \
1203- note: subst is `{subst :#?}`",
1230+ note: arg is `{arg :#?}`",
12041231 ) ;
12051232 return None ;
12061233 }
0 commit comments