@@ -2162,128 +2162,10 @@ 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 = 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) ;
22862167
2168+ let container_id = impl_ty. container_id ( tcx) ;
22872169 let impl_ty_def_id = impl_ty. def_id . expect_local ( ) ;
22882170 let impl_ty_args = GenericArgs :: identity_for_item ( tcx, impl_ty. def_id ) ;
22892171 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>(
23362218 debug ! ( "check_type_bounds: item_bounds={:?}" , obligations) ;
23372219
23382220 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 ) ;
23412222 debug ! ( "compare_projection_bounds: normalized predicate = {:?}" , normalized_predicate) ;
23422223 obligation. predicate = normalized_predicate;
23432224
@@ -2358,6 +2239,171 @@ pub(super) fn check_type_bounds<'tcx>(
23582239 ocx. resolve_regions_and_report_errors ( impl_ty_def_id, & outlives_env)
23592240}
23602241
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+
23612407fn assoc_item_kind_str ( impl_item : & ty:: AssocItem ) -> & ' static str {
23622408 match impl_item. kind {
23632409 ty:: AssocKind :: Const => "const" ,
0 commit comments