@@ -2162,7 +2162,7 @@ pub(super) fn check_type_bounds<'tcx>(
21622162 impl_ty : ty:: AssocItem ,
21632163 impl_trait_ref : ty:: TraitRef < ' tcx > ,
21642164) -> 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) ;
21662166 debug ! ( ?param_env) ;
21672167
21682168 let container_id = impl_ty. container_id ( tcx) ;
@@ -2239,7 +2239,13 @@ pub(super) fn check_type_bounds<'tcx>(
22392239 ocx. resolve_regions_and_report_errors ( impl_ty_def_id, & outlives_env)
22402240}
22412241
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
22432249///
22442250/// impl<A, B> Foo<u32> for (A, B) {
22452251/// type Bar<C> = Wrapper<A, B, C>
@@ -2266,10 +2272,12 @@ pub(super) fn check_type_bounds<'tcx>(
22662272/// ```notrust
22672273/// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
22682274/// ```
2275+ ///
22692276/// when we really would like to generate
22702277/// ```notrust
22712278/// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
22722279/// ```
2280+ ///
22732281/// But, this is probably fine, because although the first clause can be used with types C that
22742282/// do not implement Eq, for it to cause some kind of problem, there would have to be a
22752283/// 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>(
22782286/// the trait (notably, that X: Eq and T: Family).
22792287fn param_env_with_gat_bounds < ' tcx > (
22802288 tcx : TyCtxt < ' tcx > ,
2281- trait_ty : ty:: AssocItem ,
22822289 impl_ty : ty:: AssocItem ,
22832290 impl_trait_ref : ty:: TraitRef < ' tcx > ,
22842291) -> ty:: ParamEnv < ' tcx > {
22852292 let param_env = tcx. param_env ( impl_ty. def_id ) ;
22862293 let container_id = impl_ty. container_id ( tcx) ;
22872294 let mut predicates = param_env. caller_bounds ( ) . to_vec ( ) ;
22882295
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 ( ) )
23062317 }
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; }
23172388 }
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,
23282396 )
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+ }
23672401
23682402 ty:: ParamEnv :: new ( tcx. mk_clauses ( & predicates) , Reveal :: UserFacing )
23692403}
0 commit comments