@@ -57,22 +57,24 @@ pub(crate) fn check_impl_wf(
5757 tcx : TyCtxt < ' _ > ,
5858 impl_def_id : LocalDefId ,
5959) -> Result < ( ) , ErrorGuaranteed > {
60- let min_specialization = tcx. features ( ) . min_specialization ( ) ;
61- let mut res = Ok ( ( ) ) ;
6260 debug_assert_matches ! ( tcx. def_kind( impl_def_id) , DefKind :: Impl { .. } ) ;
63- res = res. and ( enforce_impl_params_are_constrained ( tcx, impl_def_id) ) ;
64- if min_specialization {
61+
62+ // Check that the args are constrained. We queryfied the check for ty/const params
63+ // since unconstrained type/const params cause ICEs in projection, so we want to
64+ // detect those specifically and project those to `TyKind::Error`.
65+ let mut res = tcx. ensure ( ) . enforce_impl_non_lifetime_params_are_constrained ( impl_def_id) ;
66+ res = res. and ( enforce_impl_lifetime_params_are_constrained ( tcx, impl_def_id) ) ;
67+
68+ if tcx. features ( ) . min_specialization ( ) {
6569 res = res. and ( check_min_specialization ( tcx, impl_def_id) ) ;
6670 }
67-
6871 res
6972}
7073
71- fn enforce_impl_params_are_constrained (
74+ pub ( crate ) fn enforce_impl_lifetime_params_are_constrained (
7275 tcx : TyCtxt < ' _ > ,
7376 impl_def_id : LocalDefId ,
7477) -> Result < ( ) , ErrorGuaranteed > {
75- // Every lifetime used in an associated type must be constrained.
7678 let impl_self_ty = tcx. type_of ( impl_def_id) . instantiate_identity ( ) ;
7779 if impl_self_ty. references_error ( ) {
7880 // Don't complain about unconstrained type params when self ty isn't known due to errors.
@@ -88,6 +90,7 @@ fn enforce_impl_params_are_constrained(
8890 // Compilation must continue in order for other important diagnostics to keep showing up.
8991 return Ok ( ( ) ) ;
9092 }
93+
9194 let impl_generics = tcx. generics_of ( impl_def_id) ;
9295 let impl_predicates = tcx. predicates_of ( impl_def_id) ;
9396 let impl_trait_ref = tcx. impl_trait_ref ( impl_def_id) . map ( ty:: EarlyBinder :: instantiate_identity) ;
@@ -121,6 +124,84 @@ fn enforce_impl_params_are_constrained(
121124 } )
122125 . collect ( ) ;
123126
127+ let mut res = Ok ( ( ) ) ;
128+ for param in & impl_generics. own_params {
129+ match param. kind {
130+ ty:: GenericParamDefKind :: Lifetime => {
131+ let param_lt = cgp:: Parameter :: from ( param. to_early_bound_region_data ( ) ) ;
132+ if lifetimes_in_associated_types. contains ( & param_lt) // (*)
133+ && !input_parameters. contains ( & param_lt)
134+ {
135+ let mut diag = tcx. dcx ( ) . create_err ( UnconstrainedGenericParameter {
136+ span : tcx. def_span ( param. def_id ) ,
137+ param_name : param. name ,
138+ param_def_kind : tcx. def_descr ( param. def_id ) ,
139+ const_param_note : false ,
140+ const_param_note2 : false ,
141+ } ) ;
142+ diag. code ( E0207 ) ;
143+ res = Err ( diag. emit ( ) ) ;
144+ }
145+ // (*) This is a horrible concession to reality. I think it'd be
146+ // better to just ban unconstrained lifetimes outright, but in
147+ // practice people do non-hygienic macros like:
148+ //
149+ // ```
150+ // macro_rules! __impl_slice_eq1 {
151+ // ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
152+ // impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
153+ // ....
154+ // }
155+ // }
156+ // }
157+ // ```
158+ //
159+ // In a concession to backwards compatibility, we continue to
160+ // permit those, so long as the lifetimes aren't used in
161+ // associated types. I believe this is sound, because lifetimes
162+ // used elsewhere are not projected back out.
163+ }
164+ ty:: GenericParamDefKind :: Type { .. } | ty:: GenericParamDefKind :: Const { .. } => {
165+ // Enforced in `enforce_impl_non_lifetime_params_are_constrained`.
166+ }
167+ }
168+ }
169+ res
170+ }
171+
172+ pub ( crate ) fn enforce_impl_non_lifetime_params_are_constrained (
173+ tcx : TyCtxt < ' _ > ,
174+ impl_def_id : LocalDefId ,
175+ ) -> Result < ( ) , ErrorGuaranteed > {
176+ let impl_self_ty = tcx. type_of ( impl_def_id) . instantiate_identity ( ) ;
177+ if impl_self_ty. references_error ( ) {
178+ // Don't complain about unconstrained type params when self ty isn't known due to errors.
179+ // (#36836)
180+ tcx. dcx ( ) . span_delayed_bug (
181+ tcx. def_span ( impl_def_id) ,
182+ format ! (
183+ "potentially unconstrained type parameters weren't evaluated: {impl_self_ty:?}" ,
184+ ) ,
185+ ) ;
186+ // This is super fishy, but our current `rustc_hir_analysis::check_crate` pipeline depends on
187+ // `type_of` having been called much earlier, and thus this value being read from cache.
188+ // Compilation must continue in order for other important diagnostics to keep showing up.
189+ return Ok ( ( ) ) ;
190+ }
191+ let impl_generics = tcx. generics_of ( impl_def_id) ;
192+ let impl_predicates = tcx. predicates_of ( impl_def_id) ;
193+ let impl_trait_ref = tcx. impl_trait_ref ( impl_def_id) . map ( ty:: EarlyBinder :: instantiate_identity) ;
194+
195+ impl_trait_ref. error_reported ( ) ?;
196+
197+ let mut input_parameters = cgp:: parameters_for_impl ( tcx, impl_self_ty, impl_trait_ref) ;
198+ cgp:: identify_constrained_generic_params (
199+ tcx,
200+ impl_predicates,
201+ impl_trait_ref,
202+ & mut input_parameters,
203+ ) ;
204+
124205 let mut res = Ok ( ( ) ) ;
125206 for param in & impl_generics. own_params {
126207 let err = match param. kind {
@@ -129,15 +210,14 @@ fn enforce_impl_params_are_constrained(
129210 let param_ty = ty:: ParamTy :: for_def ( param) ;
130211 !input_parameters. contains ( & cgp:: Parameter :: from ( param_ty) )
131212 }
132- ty:: GenericParamDefKind :: Lifetime => {
133- let param_lt = cgp:: Parameter :: from ( param. to_early_bound_region_data ( ) ) ;
134- lifetimes_in_associated_types. contains ( & param_lt) && // (*)
135- !input_parameters. contains ( & param_lt)
136- }
137213 ty:: GenericParamDefKind :: Const { .. } => {
138214 let param_ct = ty:: ParamConst :: for_def ( param) ;
139215 !input_parameters. contains ( & cgp:: Parameter :: from ( param_ct) )
140216 }
217+ ty:: GenericParamDefKind :: Lifetime => {
218+ // Enforced in `enforce_impl_type_params_are_constrained`.
219+ false
220+ }
141221 } ;
142222 if err {
143223 let const_param_note = matches ! ( param. kind, ty:: GenericParamDefKind :: Const { .. } ) ;
@@ -153,23 +233,4 @@ fn enforce_impl_params_are_constrained(
153233 }
154234 }
155235 res
156-
157- // (*) This is a horrible concession to reality. I think it'd be
158- // better to just ban unconstrained lifetimes outright, but in
159- // practice people do non-hygienic macros like:
160- //
161- // ```
162- // macro_rules! __impl_slice_eq1 {
163- // ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
164- // impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
165- // ....
166- // }
167- // }
168- // }
169- // ```
170- //
171- // In a concession to backwards compatibility, we continue to
172- // permit those, so long as the lifetimes aren't used in
173- // associated types. I believe this is sound, because lifetimes
174- // used elsewhere are not projected back out.
175236}
0 commit comments