@@ -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, trait_ty, 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,135 @@ pub(super) fn check_type_bounds<'tcx>(
23582239 ocx. resolve_regions_and_report_errors ( impl_ty_def_id, & outlives_env)
23592240}
23602241
2242+ /// Given
2243+ ///
2244+ /// impl<A, B> Foo<u32> for (A, B) {
2245+ /// type Bar<C> = Wrapper<A, B, C>
2246+ /// }
2247+ ///
2248+ /// - `impl_trait_ref` would be `<(A, B) as Foo<u32>>`
2249+ /// - `normalize_impl_ty_args` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
2250+ /// - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>`
2251+ /// - `rebased_args` would be `[(A, B), u32, ^0.0]`, combining the args from
2252+ /// the *trait* with the generic associated type parameters (as bound vars).
2253+ ///
2254+ /// A note regarding the use of bound vars here:
2255+ /// Imagine as an example
2256+ /// ```
2257+ /// trait Family {
2258+ /// type Member<C: Eq>;
2259+ /// }
2260+ ///
2261+ /// impl Family for VecFamily {
2262+ /// type Member<C: Eq> = i32;
2263+ /// }
2264+ /// ```
2265+ /// Here, we would generate
2266+ /// ```notrust
2267+ /// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
2268+ /// ```
2269+ /// when we really would like to generate
2270+ /// ```notrust
2271+ /// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
2272+ /// ```
2273+ /// But, this is probably fine, because although the first clause can be used with types C that
2274+ /// do not implement Eq, for it to cause some kind of problem, there would have to be a
2275+ /// VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type
2276+ /// Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
2277+ /// elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
2278+ /// the trait (notably, that X: Eq and T: Family).
2279+ fn param_env_with_gat_bounds < ' tcx > (
2280+ tcx : TyCtxt < ' tcx > ,
2281+ trait_ty : ty:: AssocItem ,
2282+ impl_ty : ty:: AssocItem ,
2283+ impl_trait_ref : ty:: TraitRef < ' tcx > ,
2284+ ) -> ty:: ParamEnv < ' tcx > {
2285+ let param_env = tcx. param_env ( impl_ty. def_id ) ;
2286+ let container_id = impl_ty. container_id ( tcx) ;
2287+ let mut predicates = param_env. caller_bounds ( ) . to_vec ( ) ;
2288+
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 ( )
2306+ }
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 ( )
2317+ }
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" ) ,
2328+ )
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+ } ;
2367+
2368+ ty:: ParamEnv :: new ( tcx. mk_clauses ( & predicates) , Reveal :: UserFacing )
2369+ }
2370+
23612371fn assoc_item_kind_str ( impl_item : & ty:: AssocItem ) -> & ' static str {
23622372 match impl_item. kind {
23632373 ty:: AssocKind :: Const => "const" ,
0 commit comments