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;
@@ -13,17 +14,19 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
13
14
use rustc_infer:: infer:: TyCtxtInferExt ;
14
15
use rustc_lint:: LateContext ;
15
16
use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
17
+ use rustc_middle:: traits:: EvaluationResult ;
16
18
use rustc_middle:: ty:: layout:: ValidityRequirement ;
17
19
use 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 ,
21
23
} ;
22
24
use rustc_span:: symbol:: Ident ;
23
25
use rustc_span:: { sym, Span , Symbol , DUMMY_SP } ;
24
26
use rustc_target:: abi:: { Size , VariantIdx } ;
25
- use rustc_trait_selection:: infer :: InferCtxtExt ;
27
+ use rustc_trait_selection:: traits :: query :: evaluate_obligation :: InferCtxtExt as _ ;
26
28
use rustc_trait_selection:: traits:: query:: normalize:: QueryNormalizeExt ;
29
+ use rustc_trait_selection:: traits:: { Obligation , ObligationCause } ;
27
30
use std:: iter;
28
31
29
32
use crate :: { match_def_path, path_res, paths} ;
@@ -207,15 +210,9 @@ pub fn implements_trait<'tcx>(
207
210
cx : & LateContext < ' tcx > ,
208
211
ty : Ty < ' tcx > ,
209
212
trait_id : DefId ,
210
- ty_params : & [ GenericArg < ' tcx > ] ,
213
+ args : & [ GenericArg < ' tcx > ] ,
211
214
) -> 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) ) )
219
216
}
220
217
221
218
/// 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>(
224
221
param_env : ParamEnv < ' tcx > ,
225
222
ty : Ty < ' tcx > ,
226
223
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 > > > > ,
228
236
) -> bool {
229
237
// Clippy shouldn't have infer types
230
238
assert ! ( !ty. has_infer( ) ) ;
@@ -233,19 +241,37 @@ pub fn implements_trait_with_env<'tcx>(
233
241
if ty. has_escaping_bound_vars ( ) {
234
242
return false ;
235
243
}
244
+
236
245
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) )
243
250
. 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
+ } ) ) ,
245
260
) ;
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
+ } ;
246
272
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 )
249
275
}
250
276
251
277
/// Checks whether this type implements `Drop`.
@@ -1014,12 +1040,60 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
1014
1040
}
1015
1041
}
1016
1042
1043
+ /// Asserts that the given arguments match the generic parameters of the given item.
1044
+ #[ allow( dead_code) ]
1045
+ fn assert_generic_args_match < ' tcx > ( tcx : TyCtxt < ' tcx > , did : DefId , args : & [ GenericArg < ' tcx > ] ) {
1046
+ let g = tcx. generics_of ( did) ;
1047
+ let parent = g. parent . map ( |did| tcx. generics_of ( did) ) ;
1048
+ let count = g. parent_count + g. params . len ( ) ;
1049
+ let params = parent
1050
+ . map_or ( [ ] . as_slice ( ) , |p| p. params . as_slice ( ) )
1051
+ . iter ( )
1052
+ . chain ( & g. params )
1053
+ . map ( |x| & x. kind ) ;
1054
+
1055
+ assert ! (
1056
+ count == args. len( ) ,
1057
+ "wrong number of arguments for `{did:?}`: expected `{count}`, found {}\n \
1058
+ note: the expected arguments are: `[{}]`\n \
1059
+ the given arguments are: `{args:#?}`",
1060
+ args. len( ) ,
1061
+ params. clone( ) . map( GenericParamDefKind :: descr) . format( ", " ) ,
1062
+ ) ;
1063
+
1064
+ if let Some ( ( idx, ( param, arg) ) ) =
1065
+ params
1066
+ . clone ( )
1067
+ . zip ( args. iter ( ) . map ( |& x| x. unpack ( ) ) )
1068
+ . enumerate ( )
1069
+ . find ( |( _, ( param, arg) ) | match ( param, arg) {
1070
+ ( GenericParamDefKind :: Lifetime , GenericArgKind :: Lifetime ( _) )
1071
+ | ( GenericParamDefKind :: Type { .. } , GenericArgKind :: Type ( _) )
1072
+ | ( GenericParamDefKind :: Const { .. } , GenericArgKind :: Const ( _) ) => false ,
1073
+ (
1074
+ GenericParamDefKind :: Lifetime
1075
+ | GenericParamDefKind :: Type { .. }
1076
+ | GenericParamDefKind :: Const { .. } ,
1077
+ _,
1078
+ ) => true ,
1079
+ } )
1080
+ {
1081
+ panic ! (
1082
+ "incorrect argument for `{did:?}` at index `{idx}`: expected a {}, found `{arg:?}`\n \
1083
+ note: the expected arguments are `[{}]`\n \
1084
+ the given arguments are `{args:#?}`",
1085
+ param. descr( ) ,
1086
+ params. clone( ) . map( GenericParamDefKind :: descr) . format( ", " ) ,
1087
+ ) ;
1088
+ }
1089
+ }
1090
+
1017
1091
/// Makes the projection type for the named associated type in the given impl or trait impl.
1018
1092
///
1019
1093
/// This function is for associated types which are "known" to exist, and as such, will only return
1020
1094
/// `None` when debug assertions are disabled in order to prevent ICE's. With debug assertions
1021
1095
/// 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,
1096
+ /// arguments are given, and that the correct kinds of arguments are given (lifetime,
1023
1097
/// constant or type). This will not check if type normalization would succeed.
1024
1098
pub fn make_projection < ' tcx > (
1025
1099
tcx : TyCtxt < ' tcx > ,
@@ -1043,49 +1117,7 @@ pub fn make_projection<'tcx>(
1043
1117
return None ;
1044
1118
} ;
1045
1119
#[ 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
- }
1120
+ assert_generic_args_match ( tcx, assoc_item. def_id , args) ;
1089
1121
1090
1122
Some ( tcx. mk_alias_ty ( assoc_item. def_id , args) )
1091
1123
}
@@ -1100,7 +1132,7 @@ pub fn make_projection<'tcx>(
1100
1132
/// Normalizes the named associated type in the given impl or trait impl.
1101
1133
///
1102
1134
/// 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
1135
+ /// arguments , and as such, will only return `None` when debug assertions are disabled in order
1104
1136
/// to prevent ICE's. With debug assertions enabled this will check that type normalization
1105
1137
/// succeeds as well as everything checked by `make_projection`.
1106
1138
pub fn make_normalized_projection < ' tcx > (
@@ -1112,17 +1144,12 @@ pub fn make_normalized_projection<'tcx>(
1112
1144
) -> Option < Ty < ' tcx > > {
1113
1145
fn helper < ' tcx > ( tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > , ty : AliasTy < ' tcx > ) -> Option < Ty < ' tcx > > {
1114
1146
#[ 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
- {
1147
+ if let Some ( ( i, arg) ) = ty. args . iter ( ) . enumerate ( ) . find ( |( _, arg) | arg. has_late_bound_regions ( ) ) {
1121
1148
debug_assert ! (
1122
1149
false ,
1123
1150
"args contain late-bound region at index `{i}` which can't be normalized.\n \
1124
1151
use `TyCtxt::erase_late_bound_regions`\n \
1125
- note: subst is `{subst :#?}`",
1152
+ note: arg is `{arg :#?}`",
1126
1153
) ;
1127
1154
return None ;
1128
1155
}
@@ -1190,17 +1217,12 @@ pub fn make_normalized_projection_with_regions<'tcx>(
1190
1217
) -> Option < Ty < ' tcx > > {
1191
1218
fn helper < ' tcx > ( tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > , ty : AliasTy < ' tcx > ) -> Option < Ty < ' tcx > > {
1192
1219
#[ 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
- {
1220
+ if let Some ( ( i, arg) ) = ty. args . iter ( ) . enumerate ( ) . find ( |( _, arg) | arg. has_late_bound_regions ( ) ) {
1199
1221
debug_assert ! (
1200
1222
false ,
1201
1223
"args contain late-bound region at index `{i}` which can't be normalized.\n \
1202
1224
use `TyCtxt::erase_late_bound_regions`\n \
1203
- note: subst is `{subst :#?}`",
1225
+ note: arg is `{arg :#?}`",
1204
1226
) ;
1205
1227
return None ;
1206
1228
}
0 commit comments