@@ -2162,7 +2162,7 @@ pub(super) fn check_type_bounds<'tcx>(
2162
2162
impl_ty : ty:: AssocItem ,
2163
2163
impl_trait_ref : ty:: TraitRef < ' tcx > ,
2164
2164
) -> Result < ( ) , ErrorGuaranteed > {
2165
- let param_env = param_env_with_gat_bounds ( tcx, trait_ty , impl_ty, impl_trait_ref) ;
2165
+ let param_env = param_env_with_gat_bounds ( tcx, impl_ty, impl_trait_ref) ;
2166
2166
debug ! ( ?param_env) ;
2167
2167
2168
2168
let container_id = impl_ty. container_id ( tcx) ;
@@ -2239,7 +2239,13 @@ pub(super) fn check_type_bounds<'tcx>(
2239
2239
ocx. resolve_regions_and_report_errors ( impl_ty_def_id, & outlives_env)
2240
2240
}
2241
2241
2242
- /// Given
2242
+ /// Install projection predicates that allow GATs to project to their own
2243
+ /// definition types. This is not allowed in general in cases of default
2244
+ /// associated types in trait definitions, or when specialization is involved,
2245
+ /// but is needed when checking these definition types actually satisfy the
2246
+ /// trait bounds of the GAT.
2247
+ ///
2248
+ /// # How it works
2243
2249
///
2244
2250
/// impl<A, B> Foo<u32> for (A, B) {
2245
2251
/// type Bar<C> = Wrapper<A, B, C>
@@ -2266,10 +2272,12 @@ pub(super) fn check_type_bounds<'tcx>(
2266
2272
/// ```notrust
2267
2273
/// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
2268
2274
/// ```
2275
+ ///
2269
2276
/// when we really would like to generate
2270
2277
/// ```notrust
2271
2278
/// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
2272
2279
/// ```
2280
+ ///
2273
2281
/// But, this is probably fine, because although the first clause can be used with types C that
2274
2282
/// do not implement Eq, for it to cause some kind of problem, there would have to be a
2275
2283
/// VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type
@@ -2278,92 +2286,118 @@ pub(super) fn check_type_bounds<'tcx>(
2278
2286
/// the trait (notably, that X: Eq and T: Family).
2279
2287
fn param_env_with_gat_bounds < ' tcx > (
2280
2288
tcx : TyCtxt < ' tcx > ,
2281
- trait_ty : ty:: AssocItem ,
2282
2289
impl_ty : ty:: AssocItem ,
2283
2290
impl_trait_ref : ty:: TraitRef < ' tcx > ,
2284
2291
) -> ty:: ParamEnv < ' tcx > {
2285
2292
let param_env = tcx. param_env ( impl_ty. def_id ) ;
2286
2293
let container_id = impl_ty. container_id ( tcx) ;
2287
2294
let mut predicates = param_env. caller_bounds ( ) . to_vec ( ) ;
2288
2295
2289
- let mut bound_vars: smallvec:: SmallVec < [ ty:: BoundVariableKind ; 8 ] > =
2290
- smallvec:: SmallVec :: with_capacity ( tcx. generics_of ( impl_ty. def_id ) . params . len ( ) ) ;
2291
- // Extend the impl's identity args with late-bound GAT vars
2292
- let normalize_impl_ty_args = ty:: GenericArgs :: identity_for_item ( tcx, container_id) . extend_to (
2293
- tcx,
2294
- impl_ty. def_id ,
2295
- |param, _| match param. kind {
2296
- GenericParamDefKind :: Type { .. } => {
2297
- let kind = ty:: BoundTyKind :: Param ( param. def_id , param. name ) ;
2298
- let bound_var = ty:: BoundVariableKind :: Ty ( kind) ;
2299
- bound_vars. push ( bound_var) ;
2300
- Ty :: new_bound (
2301
- tcx,
2302
- ty:: INNERMOST ,
2303
- ty:: BoundTy { var : ty:: BoundVar :: from_usize ( bound_vars. len ( ) - 1 ) , kind } ,
2304
- )
2305
- . into ( )
2296
+ // for RPITITs, we should install predicates that allow us to project all
2297
+ // of the RPITITs associated with the same body. This is because checking
2298
+ // the item bounds of RPITITs often involves nested RPITITs having to prove
2299
+ // bounds about themselves.
2300
+ let impl_tys_to_install = match impl_ty. opt_rpitit_info {
2301
+ None => vec ! [ impl_ty] ,
2302
+ Some (
2303
+ ty:: ImplTraitInTraitData :: Impl { fn_def_id }
2304
+ | ty:: ImplTraitInTraitData :: Trait { fn_def_id, .. } ,
2305
+ ) => tcx
2306
+ . associated_types_for_impl_traits_in_associated_fn ( fn_def_id)
2307
+ . iter ( )
2308
+ . map ( |def_id| tcx. associated_item ( * def_id) )
2309
+ . collect ( ) ,
2310
+ } ;
2311
+
2312
+ for impl_ty in impl_tys_to_install {
2313
+ let trait_ty = match impl_ty. container {
2314
+ ty:: AssocItemContainer :: TraitContainer => impl_ty,
2315
+ ty:: AssocItemContainer :: ImplContainer => {
2316
+ tcx. associated_item ( impl_ty. trait_item_def_id . unwrap ( ) )
2306
2317
}
2307
- GenericParamDefKind :: Lifetime => {
2308
- let kind = ty:: BoundRegionKind :: BrNamed ( param. def_id , param. name ) ;
2309
- let bound_var = ty:: BoundVariableKind :: Region ( kind) ;
2310
- bound_vars. push ( bound_var) ;
2311
- ty:: Region :: new_late_bound (
2312
- tcx,
2313
- ty:: INNERMOST ,
2314
- ty:: BoundRegion { var : ty:: BoundVar :: from_usize ( bound_vars. len ( ) - 1 ) , kind } ,
2315
- )
2316
- . into ( )
2318
+ } ;
2319
+
2320
+ let mut bound_vars: smallvec:: SmallVec < [ ty:: BoundVariableKind ; 8 ] > =
2321
+ smallvec:: SmallVec :: with_capacity ( tcx. generics_of ( impl_ty. def_id ) . params . len ( ) ) ;
2322
+ // Extend the impl's identity args with late-bound GAT vars
2323
+ let normalize_impl_ty_args = ty:: GenericArgs :: identity_for_item ( tcx, container_id)
2324
+ . extend_to ( tcx, impl_ty. def_id , |param, _| match param. kind {
2325
+ GenericParamDefKind :: Type { .. } => {
2326
+ let kind = ty:: BoundTyKind :: Param ( param. def_id , param. name ) ;
2327
+ let bound_var = ty:: BoundVariableKind :: Ty ( kind) ;
2328
+ bound_vars. push ( bound_var) ;
2329
+ Ty :: new_bound (
2330
+ tcx,
2331
+ ty:: INNERMOST ,
2332
+ ty:: BoundTy { var : ty:: BoundVar :: from_usize ( bound_vars. len ( ) - 1 ) , kind } ,
2333
+ )
2334
+ . into ( )
2335
+ }
2336
+ GenericParamDefKind :: Lifetime => {
2337
+ let kind = ty:: BoundRegionKind :: BrNamed ( param. def_id , param. name ) ;
2338
+ let bound_var = ty:: BoundVariableKind :: Region ( kind) ;
2339
+ bound_vars. push ( bound_var) ;
2340
+ ty:: Region :: new_late_bound (
2341
+ tcx,
2342
+ ty:: INNERMOST ,
2343
+ ty:: BoundRegion {
2344
+ var : ty:: BoundVar :: from_usize ( bound_vars. len ( ) - 1 ) ,
2345
+ kind,
2346
+ } ,
2347
+ )
2348
+ . into ( )
2349
+ }
2350
+ GenericParamDefKind :: Const { .. } => {
2351
+ let bound_var = ty:: BoundVariableKind :: Const ;
2352
+ bound_vars. push ( bound_var) ;
2353
+ ty:: Const :: new_bound (
2354
+ tcx,
2355
+ ty:: INNERMOST ,
2356
+ ty:: BoundVar :: from_usize ( bound_vars. len ( ) - 1 ) ,
2357
+ tcx. type_of ( param. def_id )
2358
+ . no_bound_vars ( )
2359
+ . expect ( "const parameter types cannot be generic" ) ,
2360
+ )
2361
+ . into ( )
2362
+ }
2363
+ } ) ;
2364
+ // When checking something like
2365
+ //
2366
+ // trait X { type Y: PartialEq<<Self as X>::Y> }
2367
+ // impl X for T { default type Y = S; }
2368
+ //
2369
+ // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
2370
+ // we want <T as X>::Y to normalize to S. This is valid because we are
2371
+ // checking the default value specifically here. Add this equality to the
2372
+ // ParamEnv for normalization specifically.
2373
+ let normalize_impl_ty =
2374
+ tcx. type_of ( impl_ty. def_id ) . instantiate ( tcx, normalize_impl_ty_args) ;
2375
+ let rebased_args =
2376
+ normalize_impl_ty_args. rebase_onto ( tcx, container_id, impl_trait_ref. args ) ;
2377
+ let bound_vars = tcx. mk_bound_variable_kinds ( & bound_vars) ;
2378
+
2379
+ match normalize_impl_ty. kind ( ) {
2380
+ ty:: Alias ( ty:: Projection , proj)
2381
+ if proj. def_id == trait_ty. def_id && proj. args == rebased_args =>
2382
+ {
2383
+ // Don't include this predicate if the projected type is
2384
+ // exactly the same as the projection. This can occur in
2385
+ // (somewhat dubious) code like this:
2386
+ //
2387
+ // impl<T> X for T where T: X { type Y = <T as X>::Y; }
2317
2388
}
2318
- GenericParamDefKind :: Const { .. } => {
2319
- let bound_var = ty:: BoundVariableKind :: Const ;
2320
- bound_vars. push ( bound_var) ;
2321
- ty:: Const :: new_bound (
2322
- tcx,
2323
- ty:: INNERMOST ,
2324
- ty:: BoundVar :: from_usize ( bound_vars. len ( ) - 1 ) ,
2325
- tcx. type_of ( param. def_id )
2326
- . no_bound_vars ( )
2327
- . expect ( "const parameter types cannot be generic" ) ,
2389
+ _ => predicates. push (
2390
+ ty:: Binder :: bind_with_vars (
2391
+ ty:: ProjectionPredicate {
2392
+ projection_ty : ty:: AliasTy :: new ( tcx, trait_ty. def_id , rebased_args) ,
2393
+ term : normalize_impl_ty. into ( ) ,
2394
+ } ,
2395
+ bound_vars,
2328
2396
)
2329
- . into ( )
2330
- }
2331
- } ,
2332
- ) ;
2333
- // When checking something like
2334
- //
2335
- // trait X { type Y: PartialEq<<Self as X>::Y> }
2336
- // impl X for T { default type Y = S; }
2337
- //
2338
- // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
2339
- // we want <T as X>::Y to normalize to S. This is valid because we are
2340
- // checking the default value specifically here. Add this equality to the
2341
- // ParamEnv for normalization specifically.
2342
- let normalize_impl_ty = tcx. type_of ( impl_ty. def_id ) . instantiate ( tcx, normalize_impl_ty_args) ;
2343
- let rebased_args = normalize_impl_ty_args. rebase_onto ( tcx, container_id, impl_trait_ref. args ) ;
2344
- let bound_vars = tcx. mk_bound_variable_kinds ( & bound_vars) ;
2345
-
2346
- match normalize_impl_ty. kind ( ) {
2347
- ty:: Alias ( ty:: Projection , proj)
2348
- if proj. def_id == trait_ty. def_id && proj. args == rebased_args =>
2349
- {
2350
- // Don't include this predicate if the projected type is
2351
- // exactly the same as the projection. This can occur in
2352
- // (somewhat dubious) code like this:
2353
- //
2354
- // impl<T> X for T where T: X { type Y = <T as X>::Y; }
2355
- }
2356
- _ => predicates. push (
2357
- ty:: Binder :: bind_with_vars (
2358
- ty:: ProjectionPredicate {
2359
- projection_ty : ty:: AliasTy :: new ( tcx, trait_ty. def_id , rebased_args) ,
2360
- term : normalize_impl_ty. into ( ) ,
2361
- } ,
2362
- bound_vars,
2363
- )
2364
- . to_predicate ( tcx) ,
2365
- ) ,
2366
- } ;
2397
+ . to_predicate ( tcx) ,
2398
+ ) ,
2399
+ } ;
2400
+ }
2367
2401
2368
2402
ty:: ParamEnv :: new ( tcx. mk_clauses ( & predicates) , Reveal :: UserFacing )
2369
2403
}
0 commit comments