@@ -2162,128 +2162,10 @@ 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 = tcx. param_env ( impl_ty. def_id ) ;
2166
- let container_id = impl_ty. container_id ( tcx) ;
2167
- // Given
2168
- //
2169
- // impl<A, B> Foo<u32> for (A, B) {
2170
- // type Bar<C> = Wrapper<A, B, C>
2171
- // }
2172
- //
2173
- // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>`
2174
- // - `normalize_impl_ty_args` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
2175
- // - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>`
2176
- // - `rebased_args` would be `[(A, B), u32, ^0.0]`, combining the args from
2177
- // the *trait* with the generic associated type parameters (as bound vars).
2178
- //
2179
- // A note regarding the use of bound vars here:
2180
- // Imagine as an example
2181
- // ```
2182
- // trait Family {
2183
- // type Member<C: Eq>;
2184
- // }
2185
- //
2186
- // impl Family for VecFamily {
2187
- // type Member<C: Eq> = i32;
2188
- // }
2189
- // ```
2190
- // Here, we would generate
2191
- // ```notrust
2192
- // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
2193
- // ```
2194
- // when we really would like to generate
2195
- // ```notrust
2196
- // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
2197
- // ```
2198
- // But, this is probably fine, because although the first clause can be used with types C that
2199
- // do not implement Eq, for it to cause some kind of problem, there would have to be a
2200
- // VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type
2201
- // Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
2202
- // elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
2203
- // the trait (notably, that X: Eq and T: Family).
2204
- let mut bound_vars: smallvec:: SmallVec < [ ty:: BoundVariableKind ; 8 ] > =
2205
- smallvec:: SmallVec :: with_capacity ( tcx. generics_of ( impl_ty. def_id ) . params . len ( ) ) ;
2206
- // Extend the impl's identity args with late-bound GAT vars
2207
- let normalize_impl_ty_args = ty:: GenericArgs :: identity_for_item ( tcx, container_id) . extend_to (
2208
- tcx,
2209
- impl_ty. def_id ,
2210
- |param, _| match param. kind {
2211
- GenericParamDefKind :: Type { .. } => {
2212
- let kind = ty:: BoundTyKind :: Param ( param. def_id , param. name ) ;
2213
- let bound_var = ty:: BoundVariableKind :: Ty ( kind) ;
2214
- bound_vars. push ( bound_var) ;
2215
- Ty :: new_bound (
2216
- tcx,
2217
- ty:: INNERMOST ,
2218
- ty:: BoundTy { var : ty:: BoundVar :: from_usize ( bound_vars. len ( ) - 1 ) , kind } ,
2219
- )
2220
- . into ( )
2221
- }
2222
- GenericParamDefKind :: Lifetime => {
2223
- let kind = ty:: BoundRegionKind :: BrNamed ( param. def_id , param. name ) ;
2224
- let bound_var = ty:: BoundVariableKind :: Region ( kind) ;
2225
- bound_vars. push ( bound_var) ;
2226
- ty:: Region :: new_late_bound (
2227
- tcx,
2228
- ty:: INNERMOST ,
2229
- ty:: BoundRegion { var : ty:: BoundVar :: from_usize ( bound_vars. len ( ) - 1 ) , kind } ,
2230
- )
2231
- . into ( )
2232
- }
2233
- GenericParamDefKind :: Const { .. } => {
2234
- let bound_var = ty:: BoundVariableKind :: Const ;
2235
- bound_vars. push ( bound_var) ;
2236
- ty:: Const :: new_bound (
2237
- tcx,
2238
- ty:: INNERMOST ,
2239
- ty:: BoundVar :: from_usize ( bound_vars. len ( ) - 1 ) ,
2240
- tcx. type_of ( param. def_id )
2241
- . no_bound_vars ( )
2242
- . expect ( "const parameter types cannot be generic" ) ,
2243
- )
2244
- . into ( )
2245
- }
2246
- } ,
2247
- ) ;
2248
- // When checking something like
2249
- //
2250
- // trait X { type Y: PartialEq<<Self as X>::Y> }
2251
- // impl X for T { default type Y = S; }
2252
- //
2253
- // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
2254
- // we want <T as X>::Y to normalize to S. This is valid because we are
2255
- // checking the default value specifically here. Add this equality to the
2256
- // ParamEnv for normalization specifically.
2257
- let normalize_impl_ty = tcx. type_of ( impl_ty. def_id ) . instantiate ( tcx, normalize_impl_ty_args) ;
2258
- let rebased_args = normalize_impl_ty_args. rebase_onto ( tcx, container_id, impl_trait_ref. args ) ;
2259
- let bound_vars = tcx. mk_bound_variable_kinds ( & bound_vars) ;
2260
- let normalize_param_env = {
2261
- let mut predicates = param_env. caller_bounds ( ) . iter ( ) . collect :: < Vec < _ > > ( ) ;
2262
- match normalize_impl_ty. kind ( ) {
2263
- ty:: Alias ( ty:: Projection , proj)
2264
- if proj. def_id == trait_ty. def_id && proj. args == rebased_args =>
2265
- {
2266
- // Don't include this predicate if the projected type is
2267
- // exactly the same as the projection. This can occur in
2268
- // (somewhat dubious) code like this:
2269
- //
2270
- // impl<T> X for T where T: X { type Y = <T as X>::Y; }
2271
- }
2272
- _ => predicates. push (
2273
- ty:: Binder :: bind_with_vars (
2274
- ty:: ProjectionPredicate {
2275
- projection_ty : ty:: AliasTy :: new ( tcx, trait_ty. def_id , rebased_args) ,
2276
- term : normalize_impl_ty. into ( ) ,
2277
- } ,
2278
- bound_vars,
2279
- )
2280
- . to_predicate ( tcx) ,
2281
- ) ,
2282
- } ;
2283
- ty:: ParamEnv :: new ( tcx. mk_clauses ( & predicates) , Reveal :: UserFacing )
2284
- } ;
2285
- debug ! ( ?normalize_param_env) ;
2165
+ let param_env = param_env_with_gat_bounds ( tcx, impl_ty, impl_trait_ref) ;
2166
+ debug ! ( ?param_env) ;
2286
2167
2168
+ let container_id = impl_ty. container_id ( tcx) ;
2287
2169
let impl_ty_def_id = impl_ty. def_id . expect_local ( ) ;
2288
2170
let impl_ty_args = GenericArgs :: identity_for_item ( tcx, impl_ty. def_id ) ;
2289
2171
let rebased_args = impl_ty_args. rebase_onto ( tcx, container_id, impl_trait_ref. args ) ;
@@ -2336,8 +2218,7 @@ pub(super) fn check_type_bounds<'tcx>(
2336
2218
debug ! ( "check_type_bounds: item_bounds={:?}" , obligations) ;
2337
2219
2338
2220
for mut obligation in util:: elaborate ( tcx, obligations) {
2339
- let normalized_predicate =
2340
- ocx. normalize ( & normalize_cause, normalize_param_env, obligation. predicate ) ;
2221
+ let normalized_predicate = ocx. normalize ( & normalize_cause, param_env, obligation. predicate ) ;
2341
2222
debug ! ( "compare_projection_bounds: normalized predicate = {:?}" , normalized_predicate) ;
2342
2223
obligation. predicate = normalized_predicate;
2343
2224
@@ -2358,6 +2239,171 @@ pub(super) fn check_type_bounds<'tcx>(
2358
2239
ocx. resolve_regions_and_report_errors ( impl_ty_def_id, & outlives_env)
2359
2240
}
2360
2241
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
2249
+ ///
2250
+ /// ```ignore (example)
2251
+ /// impl<A, B> Foo<u32> for (A, B) {
2252
+ /// type Bar<C> = Wrapper<A, B, C>
2253
+ /// }
2254
+ /// ```
2255
+ ///
2256
+ /// - `impl_trait_ref` would be `<(A, B) as Foo<u32>>`
2257
+ /// - `normalize_impl_ty_args` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
2258
+ /// - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>`
2259
+ /// - `rebased_args` would be `[(A, B), u32, ^0.0]`, combining the args from
2260
+ /// the *trait* with the generic associated type parameters (as bound vars).
2261
+ ///
2262
+ /// A note regarding the use of bound vars here:
2263
+ /// Imagine as an example
2264
+ /// ```
2265
+ /// trait Family {
2266
+ /// type Member<C: Eq>;
2267
+ /// }
2268
+ ///
2269
+ /// impl Family for VecFamily {
2270
+ /// type Member<C: Eq> = i32;
2271
+ /// }
2272
+ /// ```
2273
+ /// Here, we would generate
2274
+ /// ```ignore (pseudo-rust)
2275
+ /// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
2276
+ /// ```
2277
+ ///
2278
+ /// when we really would like to generate
2279
+ /// ```ignore (pseudo-rust)
2280
+ /// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
2281
+ /// ```
2282
+ ///
2283
+ /// But, this is probably fine, because although the first clause can be used with types `C` that
2284
+ /// do not implement `Eq`, for it to cause some kind of problem, there would have to be a
2285
+ /// `VecFamily::Member<X>` for some type `X` where `!(X: Eq)`, that appears in the value of type
2286
+ /// `Member<C: Eq> = ....` That type would fail a well-formedness check that we ought to be doing
2287
+ /// elsewhere, which would check that any `<T as Family>::Member<X>` meets the bounds declared in
2288
+ /// the trait (notably, that `X: Eq` and `T: Family`).
2289
+ fn param_env_with_gat_bounds < ' tcx > (
2290
+ tcx : TyCtxt < ' tcx > ,
2291
+ impl_ty : ty:: AssocItem ,
2292
+ impl_trait_ref : ty:: TraitRef < ' tcx > ,
2293
+ ) -> ty:: ParamEnv < ' tcx > {
2294
+ let param_env = tcx. param_env ( impl_ty. def_id ) ;
2295
+ let container_id = impl_ty. container_id ( tcx) ;
2296
+ let mut predicates = param_env. caller_bounds ( ) . to_vec ( ) ;
2297
+
2298
+ // for RPITITs, we should install predicates that allow us to project all
2299
+ // of the RPITITs associated with the same body. This is because checking
2300
+ // the item bounds of RPITITs often involves nested RPITITs having to prove
2301
+ // bounds about themselves.
2302
+ let impl_tys_to_install = match impl_ty. opt_rpitit_info {
2303
+ None => vec ! [ impl_ty] ,
2304
+ Some (
2305
+ ty:: ImplTraitInTraitData :: Impl { fn_def_id }
2306
+ | ty:: ImplTraitInTraitData :: Trait { fn_def_id, .. } ,
2307
+ ) => tcx
2308
+ . associated_types_for_impl_traits_in_associated_fn ( fn_def_id)
2309
+ . iter ( )
2310
+ . map ( |def_id| tcx. associated_item ( * def_id) )
2311
+ . collect ( ) ,
2312
+ } ;
2313
+
2314
+ for impl_ty in impl_tys_to_install {
2315
+ let trait_ty = match impl_ty. container {
2316
+ ty:: AssocItemContainer :: TraitContainer => impl_ty,
2317
+ ty:: AssocItemContainer :: ImplContainer => {
2318
+ tcx. associated_item ( impl_ty. trait_item_def_id . unwrap ( ) )
2319
+ }
2320
+ } ;
2321
+
2322
+ let mut bound_vars: smallvec:: SmallVec < [ ty:: BoundVariableKind ; 8 ] > =
2323
+ smallvec:: SmallVec :: with_capacity ( tcx. generics_of ( impl_ty. def_id ) . params . len ( ) ) ;
2324
+ // Extend the impl's identity args with late-bound GAT vars
2325
+ let normalize_impl_ty_args = ty:: GenericArgs :: identity_for_item ( tcx, container_id)
2326
+ . extend_to ( tcx, impl_ty. def_id , |param, _| match param. kind {
2327
+ GenericParamDefKind :: Type { .. } => {
2328
+ let kind = ty:: BoundTyKind :: Param ( param. def_id , param. name ) ;
2329
+ let bound_var = ty:: BoundVariableKind :: Ty ( kind) ;
2330
+ bound_vars. push ( bound_var) ;
2331
+ Ty :: new_bound (
2332
+ tcx,
2333
+ ty:: INNERMOST ,
2334
+ ty:: BoundTy { var : ty:: BoundVar :: from_usize ( bound_vars. len ( ) - 1 ) , kind } ,
2335
+ )
2336
+ . into ( )
2337
+ }
2338
+ GenericParamDefKind :: Lifetime => {
2339
+ let kind = ty:: BoundRegionKind :: BrNamed ( param. def_id , param. name ) ;
2340
+ let bound_var = ty:: BoundVariableKind :: Region ( kind) ;
2341
+ bound_vars. push ( bound_var) ;
2342
+ ty:: Region :: new_late_bound (
2343
+ tcx,
2344
+ ty:: INNERMOST ,
2345
+ ty:: BoundRegion {
2346
+ var : ty:: BoundVar :: from_usize ( bound_vars. len ( ) - 1 ) ,
2347
+ kind,
2348
+ } ,
2349
+ )
2350
+ . into ( )
2351
+ }
2352
+ GenericParamDefKind :: Const { .. } => {
2353
+ let bound_var = ty:: BoundVariableKind :: Const ;
2354
+ bound_vars. push ( bound_var) ;
2355
+ ty:: Const :: new_bound (
2356
+ tcx,
2357
+ ty:: INNERMOST ,
2358
+ ty:: BoundVar :: from_usize ( bound_vars. len ( ) - 1 ) ,
2359
+ tcx. type_of ( param. def_id )
2360
+ . no_bound_vars ( )
2361
+ . expect ( "const parameter types cannot be generic" ) ,
2362
+ )
2363
+ . into ( )
2364
+ }
2365
+ } ) ;
2366
+ // When checking something like
2367
+ //
2368
+ // trait X { type Y: PartialEq<<Self as X>::Y> }
2369
+ // impl X for T { default type Y = S; }
2370
+ //
2371
+ // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
2372
+ // we want <T as X>::Y to normalize to S. This is valid because we are
2373
+ // checking the default value specifically here. Add this equality to the
2374
+ // ParamEnv for normalization specifically.
2375
+ let normalize_impl_ty =
2376
+ tcx. type_of ( impl_ty. def_id ) . instantiate ( tcx, normalize_impl_ty_args) ;
2377
+ let rebased_args =
2378
+ normalize_impl_ty_args. rebase_onto ( tcx, container_id, impl_trait_ref. args ) ;
2379
+ let bound_vars = tcx. mk_bound_variable_kinds ( & bound_vars) ;
2380
+
2381
+ match normalize_impl_ty. kind ( ) {
2382
+ ty:: Alias ( ty:: Projection , proj)
2383
+ if proj. def_id == trait_ty. def_id && proj. args == rebased_args =>
2384
+ {
2385
+ // Don't include this predicate if the projected type is
2386
+ // exactly the same as the projection. This can occur in
2387
+ // (somewhat dubious) code like this:
2388
+ //
2389
+ // impl<T> X for T where T: X { type Y = <T as X>::Y; }
2390
+ }
2391
+ _ => predicates. push (
2392
+ ty:: Binder :: bind_with_vars (
2393
+ ty:: ProjectionPredicate {
2394
+ projection_ty : ty:: AliasTy :: new ( tcx, trait_ty. def_id , rebased_args) ,
2395
+ term : normalize_impl_ty. into ( ) ,
2396
+ } ,
2397
+ bound_vars,
2398
+ )
2399
+ . to_predicate ( tcx) ,
2400
+ ) ,
2401
+ } ;
2402
+ }
2403
+
2404
+ ty:: ParamEnv :: new ( tcx. mk_clauses ( & predicates) , Reveal :: UserFacing )
2405
+ }
2406
+
2361
2407
fn assoc_item_kind_str ( impl_item : & ty:: AssocItem ) -> & ' static str {
2362
2408
match impl_item. kind {
2363
2409
ty:: AssocKind :: Const => "const" ,
0 commit comments