3
3
#![ allow( clippy:: module_name_repetitions) ]
4
4
5
5
use core:: ops:: ControlFlow ;
6
+ use itertools:: Itertools ;
6
7
use rustc_ast:: ast:: Mutability ;
7
8
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
8
9
use rustc_hir as hir;
@@ -16,16 +17,17 @@ use rustc_infer::infer::{
16
17
use rustc_lint:: LateContext ;
17
18
use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
18
19
use 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 ,
22
23
} ;
23
24
use rustc_middle:: ty:: { GenericArg , GenericArgKind } ;
24
25
use rustc_span:: symbol:: Ident ;
25
26
use rustc_span:: { sym, Span , Symbol , DUMMY_SP } ;
26
27
use rustc_target:: abi:: { Size , VariantIdx } ;
27
- use rustc_trait_selection:: infer :: InferCtxtExt ;
28
+ use rustc_trait_selection:: traits :: query :: evaluate_obligation :: InferCtxtExt as _ ;
28
29
use rustc_trait_selection:: traits:: query:: normalize:: QueryNormalizeExt ;
30
+ use rustc_trait_selection:: traits:: { Obligation , ObligationCause } ;
29
31
use std:: iter;
30
32
31
33
use crate :: { match_def_path, path_res, paths} ;
@@ -206,15 +208,9 @@ pub fn implements_trait<'tcx>(
206
208
cx : & LateContext < ' tcx > ,
207
209
ty : Ty < ' tcx > ,
208
210
trait_id : DefId ,
209
- ty_params : & [ GenericArg < ' tcx > ] ,
211
+ substs : & [ GenericArg < ' tcx > ] ,
210
212
) -> 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) ) )
218
214
}
219
215
220
216
/// 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>(
223
219
param_env : ParamEnv < ' tcx > ,
224
220
ty : Ty < ' tcx > ,
225
221
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 > > > > ,
227
234
) -> bool {
228
235
// Clippy shouldn't have infer types
229
236
assert ! ( !ty. needs_infer( ) ) ;
@@ -232,19 +239,36 @@ pub fn implements_trait_with_env<'tcx>(
232
239
if ty. has_escaping_bound_vars ( ) {
233
240
return false ;
234
241
}
242
+
235
243
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) )
242
247
. 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
+ } ) ) ,
244
257
) ;
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
+ } ;
245
269
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 ( ) )
248
272
}
249
273
250
274
/// Checks whether this type implements `Drop`.
@@ -392,6 +416,11 @@ pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangI
392
416
}
393
417
}
394
418
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
+
395
424
/// Return `true` if the passed `typ` is `isize` or `usize`.
396
425
pub fn is_isize_or_usize ( typ : Ty < ' _ > ) -> bool {
397
426
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 {
1001
1030
}
1002
1031
}
1003
1032
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
+
1004
1080
/// Makes the projection type for the named associated type in the given impl or trait impl.
1005
1081
///
1006
1082
/// 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>(
1028
1104
return None ;
1029
1105
} ;
1030
1106
#[ 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) ;
1074
1108
1075
1109
Some ( tcx. mk_alias_ty ( assoc_item. def_id , substs) )
1076
1110
}
0 commit comments