]>
Commit | Line | Data |
---|---|---|
064997fb | 1 | use super::potentially_plural_count; |
1b1a35ee | 2 | use crate::errors::LifetimesOrBoundsMismatchOnTrait; |
2b03887a | 3 | use hir::def_id::{DefId, LocalDefId}; |
487cf647 | 4 | use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; |
9c376795 FG |
5 | use rustc_errors::{ |
6 | pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan, | |
7 | }; | |
dfeec247 XL |
8 | use rustc_hir as hir; |
9 | use rustc_hir::def::{DefKind, Res}; | |
10 | use rustc_hir::intravisit; | |
9ffffee4 | 11 | use rustc_hir::{GenericParamKind, ImplItemKind}; |
064997fb | 12 | use rustc_infer::infer::outlives::env::OutlivesEnvironment; |
f2b60f7d | 13 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; |
487cf647 | 14 | use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; |
29967ef6 | 15 | use rustc_infer::traits::util; |
ba9703b0 | 16 | use rustc_middle::ty::error::{ExpectedFound, TypeError}; |
ba9703b0 | 17 | use rustc_middle::ty::util::ExplicitSelf; |
f2b60f7d | 18 | use rustc_middle::ty::{ |
353b0b11 | 19 | self, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, |
f2b60f7d | 20 | }; |
3dfed10e | 21 | use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt}; |
dfeec247 | 22 | use rustc_span::Span; |
2b03887a | 23 | use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; |
f2b60f7d | 24 | use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; |
064997fb FG |
25 | use rustc_trait_selection::traits::{ |
26 | self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, | |
27 | }; | |
cdc7bbd5 | 28 | use std::iter; |
85aaf69f SL |
29 | |
30 | /// Checks that a method from an impl conforms to the signature of | |
31 | /// the same method as declared in the trait. | |
32 | /// | |
33 | /// # Parameters | |
34 | /// | |
9fa01778 | 35 | /// - `impl_m`: type of the method we are checking |
9fa01778 XL |
36 | /// - `trait_m`: the method in the trait |
37 | /// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation | |
9c376795 | 38 | pub(super) fn compare_impl_method<'tcx>( |
dc9dc135 | 39 | tcx: TyCtxt<'tcx>, |
9ffffee4 FG |
40 | impl_m: ty::AssocItem, |
41 | trait_m: ty::AssocItem, | |
dc9dc135 | 42 | impl_trait_ref: ty::TraitRef<'tcx>, |
dc9dc135 | 43 | ) { |
dfeec247 | 44 | debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); |
85aaf69f | 45 | |
9c376795 | 46 | let _: Result<_, ErrorGuaranteed> = try { |
9ffffee4 FG |
47 | compare_self_type(tcx, impl_m, trait_m, impl_trait_ref)?; |
48 | compare_number_of_generics(tcx, impl_m, trait_m, false)?; | |
9c376795 | 49 | compare_generic_param_kinds(tcx, impl_m, trait_m, false)?; |
9ffffee4 | 50 | compare_number_of_method_arguments(tcx, impl_m, trait_m)?; |
9c376795 | 51 | compare_synthetic_generics(tcx, impl_m, trait_m)?; |
9ffffee4 | 52 | compare_asyncness(tcx, impl_m, trait_m)?; |
9c376795 FG |
53 | compare_method_predicate_entailment( |
54 | tcx, | |
55 | impl_m, | |
9c376795 FG |
56 | trait_m, |
57 | impl_trait_ref, | |
58 | CheckImpliedWfMode::Check, | |
59 | )?; | |
60 | }; | |
c30ab7b3 SL |
61 | } |
62 | ||
49aad941 | 63 | /// This function is best explained by example. Consider a trait with it's implementation: |
f2b60f7d | 64 | /// |
49aad941 FG |
65 | /// ```rust |
66 | /// trait Trait<'t, T> { | |
67 | /// // `trait_m` | |
68 | /// fn method<'a, M>(t: &'t T, m: &'a M) -> Self; | |
69 | /// } | |
f2b60f7d | 70 | /// |
49aad941 | 71 | /// struct Foo; |
f2b60f7d | 72 | /// |
49aad941 FG |
73 | /// impl<'i, 'j, U> Trait<'j, &'i U> for Foo { |
74 | /// // `impl_m` | |
75 | /// fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo { Foo } | |
76 | /// } | |
77 | /// ``` | |
f2b60f7d FG |
78 | /// |
79 | /// We wish to decide if those two method types are compatible. | |
80 | /// For this we have to show that, assuming the bounds of the impl hold, the | |
81 | /// bounds of `trait_m` imply the bounds of `impl_m`. | |
82 | /// | |
83 | /// We start out with `trait_to_impl_substs`, that maps the trait | |
84 | /// type parameters to impl type parameters. This is taken from the | |
85 | /// impl trait reference: | |
86 | /// | |
49aad941 FG |
87 | /// ```rust,ignore (pseudo-Rust) |
88 | /// trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo} | |
89 | /// ``` | |
f2b60f7d FG |
90 | /// |
91 | /// We create a mapping `dummy_substs` that maps from the impl type | |
92 | /// parameters to fresh types and regions. For type parameters, | |
93 | /// this is the identity transform, but we could as well use any | |
94 | /// placeholder types. For regions, we convert from bound to free | |
95 | /// regions (Note: but only early-bound regions, i.e., those | |
96 | /// declared on the impl or used in type parameter bounds). | |
97 | /// | |
49aad941 FG |
98 | /// ```rust,ignore (pseudo-Rust) |
99 | /// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 } | |
100 | /// ``` | |
f2b60f7d FG |
101 | /// |
102 | /// Now we can apply `placeholder_substs` to the type of the impl method | |
103 | /// to yield a new function type in terms of our fresh, placeholder | |
104 | /// types: | |
105 | /// | |
49aad941 FG |
106 | /// ```rust,ignore (pseudo-Rust) |
107 | /// <'b> fn(t: &'i0 U0, m: &'b) -> Foo | |
108 | /// ``` | |
f2b60f7d FG |
109 | /// |
110 | /// We now want to extract and substitute the type of the *trait* | |
111 | /// method and compare it. To do so, we must create a compound | |
112 | /// substitution by combining `trait_to_impl_substs` and | |
113 | /// `impl_to_placeholder_substs`, and also adding a mapping for the method | |
114 | /// type parameters. We extend the mapping to also include | |
115 | /// the method parameters. | |
116 | /// | |
49aad941 FG |
117 | /// ```rust,ignore (pseudo-Rust) |
118 | /// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 } | |
119 | /// ``` | |
f2b60f7d FG |
120 | /// |
121 | /// Applying this to the trait method type yields: | |
122 | /// | |
49aad941 FG |
123 | /// ```rust,ignore (pseudo-Rust) |
124 | /// <'a> fn(t: &'i0 U0, m: &'a) -> Foo | |
125 | /// ``` | |
f2b60f7d FG |
126 | /// |
127 | /// This type is also the same but the name of the bound region (`'a` | |
9c376795 | 128 | /// vs `'b`). However, the normal subtyping rules on fn types handle |
f2b60f7d FG |
129 | /// this kind of equivalency just fine. |
130 | /// | |
131 | /// We now use these substitutions to ensure that all declared bounds are | |
132 | /// satisfied by the implementation's method. | |
133 | /// | |
134 | /// We do this by creating a parameter environment which contains a | |
135 | /// substitution corresponding to `impl_to_placeholder_substs`. We then build | |
136 | /// `trait_to_placeholder_substs` and use it to convert the predicates contained | |
137 | /// in the `trait_m` generics to the placeholder form. | |
138 | /// | |
139 | /// Finally we register each of these predicates as an obligation and check that | |
140 | /// they hold. | |
9ffffee4 | 141 | #[instrument(level = "debug", skip(tcx, impl_trait_ref))] |
9c376795 | 142 | fn compare_method_predicate_entailment<'tcx>( |
dc9dc135 | 143 | tcx: TyCtxt<'tcx>, |
9ffffee4 FG |
144 | impl_m: ty::AssocItem, |
145 | trait_m: ty::AssocItem, | |
dc9dc135 | 146 | impl_trait_ref: ty::TraitRef<'tcx>, |
487cf647 | 147 | check_implied_wf: CheckImpliedWfMode, |
5e7ed085 | 148 | ) -> Result<(), ErrorGuaranteed> { |
476ff2be SL |
149 | let trait_to_impl_substs = impl_trait_ref.substs; |
150 | ||
7cac9316 | 151 | // This node-id should be used for the `body_id` field on each |
064997fb FG |
152 | // `ObligationCause` (and the `FnCtxt`). |
153 | // | |
154 | // FIXME(@lcnr): remove that after removing `cause.body_id` from | |
155 | // obligations. | |
9ffffee4 FG |
156 | let impl_m_def_id = impl_m.def_id.expect_local(); |
157 | let impl_m_span = tcx.def_span(impl_m_def_id); | |
487cf647 | 158 | let cause = ObligationCause::new( |
f035d41b | 159 | impl_m_span, |
9ffffee4 | 160 | impl_m_def_id, |
064997fb | 161 | ObligationCauseCode::CompareImplItemObligation { |
9ffffee4 | 162 | impl_item_def_id: impl_m_def_id, |
476ff2be | 163 | trait_item_def_id: trait_m.def_id, |
064997fb | 164 | kind: impl_m.kind, |
476ff2be | 165 | }, |
f035d41b | 166 | ); |
85aaf69f | 167 | |
0bf4aa26 | 168 | // Create mapping from impl to placeholder. |
f035d41b | 169 | let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id); |
85aaf69f | 170 | |
0bf4aa26 | 171 | // Create mapping from trait to placeholder. |
f035d41b | 172 | let trait_to_placeholder_substs = |
064997fb | 173 | impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs); |
f035d41b | 174 | debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs); |
85aaf69f | 175 | |
7cac9316 XL |
176 | let impl_m_predicates = tcx.predicates_of(impl_m.def_id); |
177 | let trait_m_predicates = tcx.predicates_of(trait_m.def_id); | |
476ff2be | 178 | |
c30ab7b3 | 179 | // Check region bounds. |
487cf647 | 180 | check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?; |
c30ab7b3 SL |
181 | |
182 | // Create obligations for each predicate declared by the impl | |
183 | // definition in the context of the trait's parameter | |
184 | // environment. We can't just use `impl_env.caller_bounds`, | |
185 | // however, because we want to replace all late-bound regions with | |
186 | // region variables. | |
7cac9316 XL |
187 | let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap()); |
188 | let mut hybrid_preds = impl_predicates.instantiate_identity(tcx); | |
c30ab7b3 SL |
189 | |
190 | debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); | |
191 | ||
192 | // This is the only tricky bit of the new way we check implementation methods | |
193 | // We need to build a set of predicates where only the method-level bounds | |
194 | // are from the trait and we assume all other bounds from the implementation | |
195 | // to be previously satisfied. | |
196 | // | |
197 | // We then register the obligations from the impl_m and check to see | |
198 | // if all constraints hold. | |
9c376795 FG |
199 | hybrid_preds.predicates.extend( |
200 | trait_m_predicates | |
201 | .instantiate_own(tcx, trait_to_placeholder_substs) | |
202 | .map(|(predicate, _)| predicate), | |
203 | ); | |
c30ab7b3 | 204 | |
0bf4aa26 | 205 | // Construct trait parameter environment and then shift it into the placeholder viewpoint. |
c30ab7b3 SL |
206 | // The key step here is to update the caller_bounds's predicates to be |
207 | // the new hybrid bounds we computed. | |
9ffffee4 | 208 | let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id); |
a2a8927a | 209 | let param_env = ty::ParamEnv::new( |
9ffffee4 | 210 | tcx.mk_predicates(&hybrid_preds.predicates), |
a2a8927a XL |
211 | Reveal::UserFacing, |
212 | hir::Constness::NotConst, | |
213 | ); | |
064997fb | 214 | let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); |
7cac9316 | 215 | |
2b03887a FG |
216 | let infcx = &tcx.infer_ctxt().build(); |
217 | let ocx = ObligationCtxt::new(infcx); | |
a7813a04 | 218 | |
2b03887a | 219 | debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds()); |
a7813a04 | 220 | |
2b03887a | 221 | let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs); |
9c376795 | 222 | for (predicate, span) in impl_m_own_bounds { |
9ffffee4 | 223 | let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id); |
487cf647 | 224 | let predicate = ocx.normalize(&normalize_cause, param_env, predicate); |
a7813a04 | 225 | |
2b03887a FG |
226 | let cause = ObligationCause::new( |
227 | span, | |
9ffffee4 | 228 | impl_m_def_id, |
2b03887a | 229 | ObligationCauseCode::CompareImplItemObligation { |
9ffffee4 | 230 | impl_item_def_id: impl_m_def_id, |
2b03887a FG |
231 | trait_item_def_id: trait_m.def_id, |
232 | kind: impl_m.kind, | |
233 | }, | |
a1dfa0c6 | 234 | ); |
487cf647 | 235 | ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate)); |
2b03887a | 236 | } |
064997fb | 237 | |
2b03887a FG |
238 | // We now need to check that the signature of the impl method is |
239 | // compatible with that of the trait method. We do this by | |
240 | // checking that `impl_fty <: trait_fty`. | |
241 | // | |
242 | // FIXME. Unfortunately, this doesn't quite work right now because | |
243 | // associated type normalization is not integrated into subtype | |
244 | // checks. For the comparison to be valid, we need to | |
245 | // normalize the associated types in the impl/trait methods | |
246 | // first. However, because function types bind regions, just | |
247 | // calling `normalize_associated_types_in` would have no effect on | |
248 | // any associated types appearing in the fn arguments or return | |
249 | // type. | |
250 | ||
251 | // Compute placeholder form of impl and trait method tys. | |
252 | let tcx = infcx.tcx; | |
f2b60f7d | 253 | |
487cf647 | 254 | let mut wf_tys = FxIndexSet::default(); |
dfeec247 | 255 | |
9ffffee4 | 256 | let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars( |
2b03887a FG |
257 | impl_m_span, |
258 | infer::HigherRankedType, | |
9ffffee4 | 259 | tcx.fn_sig(impl_m.def_id).subst_identity(), |
2b03887a | 260 | ); |
487cf647 | 261 | let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig)); |
dfeec247 | 262 | |
9ffffee4 | 263 | let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id); |
9c376795 FG |
264 | let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig); |
265 | debug!("compare_impl_method: impl_fty={:?}", impl_sig); | |
2b03887a | 266 | |
9ffffee4 | 267 | let trait_sig = tcx.fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs); |
2b03887a FG |
268 | let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig); |
269 | ||
270 | // Next, add all inputs and output as well-formed tys. Importantly, | |
271 | // we have to do this before normalization, since the normalized ty may | |
272 | // not contain the input parameters. See issue #87748. | |
273 | wf_tys.extend(trait_sig.inputs_and_output.iter()); | |
487cf647 | 274 | let trait_sig = ocx.normalize(&norm_cause, param_env, trait_sig); |
2b03887a FG |
275 | // We also have to add the normalized trait signature |
276 | // as we don't normalize during implied bounds computation. | |
277 | wf_tys.extend(trait_sig.inputs_and_output.iter()); | |
278 | let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)); | |
279 | ||
280 | debug!("compare_impl_method: trait_fty={:?}", trait_fty); | |
281 | ||
282 | // FIXME: We'd want to keep more accurate spans than "the method signature" when | |
283 | // processing the comparison between the trait and impl fn, but we sadly lose them | |
284 | // and point at the whole signature when a trait bound or specific input or output | |
285 | // type would be more appropriate. In other places we have a `Vec<Span>` | |
286 | // corresponding to their `Vec<Predicate>`, but we don't have that here. | |
287 | // Fixing this would improve the output of test `issue-83765.rs`. | |
9c376795 | 288 | let result = ocx.sup(&cause, param_env, trait_sig, impl_sig); |
dfeec247 | 289 | |
2b03887a | 290 | if let Err(terr) = result { |
9c376795 | 291 | debug!(?impl_sig, ?trait_sig, ?terr, "sub_types failed"); |
c30ab7b3 | 292 | |
487cf647 FG |
293 | let emitted = report_trait_method_mismatch( |
294 | &infcx, | |
295 | cause, | |
2b03887a | 296 | terr, |
9c376795 FG |
297 | (trait_m, trait_sig), |
298 | (impl_m, impl_sig), | |
487cf647 | 299 | impl_trait_ref, |
2b03887a | 300 | ); |
487cf647 FG |
301 | return Err(emitted); |
302 | } | |
5e7ed085 | 303 | |
487cf647 FG |
304 | if check_implied_wf == CheckImpliedWfMode::Check { |
305 | // We need to check that the impl's args are well-formed given | |
306 | // the hybrid param-env (impl + trait method where-clauses). | |
307 | ocx.register_obligation(traits::Obligation::new( | |
308 | infcx.tcx, | |
309 | ObligationCause::dummy(), | |
310 | param_env, | |
311 | ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())), | |
312 | )); | |
2b03887a | 313 | } |
85aaf69f | 314 | |
2b03887a FG |
315 | // Check that all obligations are satisfied by the implementation's |
316 | // version. | |
317 | let errors = ocx.select_all_or_error(); | |
318 | if !errors.is_empty() { | |
487cf647 FG |
319 | match check_implied_wf { |
320 | CheckImpliedWfMode::Check => { | |
9ffffee4 | 321 | let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id); |
9c376795 | 322 | return compare_method_predicate_entailment( |
487cf647 FG |
323 | tcx, |
324 | impl_m, | |
487cf647 FG |
325 | trait_m, |
326 | impl_trait_ref, | |
327 | CheckImpliedWfMode::Skip, | |
328 | ) | |
329 | .map(|()| { | |
330 | // If the skip-mode was successful, emit a lint. | |
9c376795 | 331 | emit_implied_wf_lint(infcx.tcx, impl_m, impl_m_hir_id, vec![]); |
487cf647 FG |
332 | }); |
333 | } | |
334 | CheckImpliedWfMode::Skip => { | |
353b0b11 | 335 | let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); |
487cf647 FG |
336 | return Err(reported); |
337 | } | |
338 | } | |
2b03887a | 339 | } |
85aaf69f | 340 | |
2b03887a FG |
341 | // Finally, resolve all regions. This catches wily misuses of |
342 | // lifetime parameters. | |
487cf647 | 343 | let outlives_env = OutlivesEnvironment::with_bounds( |
2b03887a | 344 | param_env, |
9ffffee4 | 345 | infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys.clone()), |
2b03887a | 346 | ); |
487cf647 FG |
347 | let errors = infcx.resolve_regions(&outlives_env); |
348 | if !errors.is_empty() { | |
349 | // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT | |
350 | // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors` | |
9ffffee4 | 351 | let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id); |
487cf647 FG |
352 | match check_implied_wf { |
353 | CheckImpliedWfMode::Check => { | |
9c376795 | 354 | return compare_method_predicate_entailment( |
487cf647 FG |
355 | tcx, |
356 | impl_m, | |
487cf647 FG |
357 | trait_m, |
358 | impl_trait_ref, | |
359 | CheckImpliedWfMode::Skip, | |
360 | ) | |
361 | .map(|()| { | |
9c376795 FG |
362 | let bad_args = extract_bad_args_for_implies_lint( |
363 | tcx, | |
364 | &errors, | |
365 | (trait_m, trait_sig), | |
366 | // Unnormalized impl sig corresponds to the HIR types written | |
367 | (impl_m, unnormalized_impl_sig), | |
368 | impl_m_hir_id, | |
369 | ); | |
487cf647 | 370 | // If the skip-mode was successful, emit a lint. |
9c376795 | 371 | emit_implied_wf_lint(tcx, impl_m, impl_m_hir_id, bad_args); |
487cf647 FG |
372 | }); |
373 | } | |
374 | CheckImpliedWfMode::Skip => { | |
375 | if infcx.tainted_by_errors().is_none() { | |
9ffffee4 | 376 | infcx.err_ctxt().report_region_errors(impl_m_def_id, &errors); |
487cf647 FG |
377 | } |
378 | return Err(tcx | |
379 | .sess | |
380 | .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted")); | |
381 | } | |
382 | } | |
383 | } | |
85aaf69f | 384 | |
2b03887a | 385 | Ok(()) |
c30ab7b3 SL |
386 | } |
387 | ||
9c376795 FG |
388 | fn extract_bad_args_for_implies_lint<'tcx>( |
389 | tcx: TyCtxt<'tcx>, | |
390 | errors: &[infer::RegionResolutionError<'tcx>], | |
9ffffee4 FG |
391 | (trait_m, trait_sig): (ty::AssocItem, ty::FnSig<'tcx>), |
392 | (impl_m, impl_sig): (ty::AssocItem, ty::FnSig<'tcx>), | |
9c376795 FG |
393 | hir_id: hir::HirId, |
394 | ) -> Vec<(Span, Option<String>)> { | |
395 | let mut blame_generics = vec![]; | |
396 | for error in errors { | |
397 | // Look for the subregion origin that contains an input/output type | |
398 | let origin = match error { | |
399 | infer::RegionResolutionError::ConcreteFailure(o, ..) => o, | |
400 | infer::RegionResolutionError::GenericBoundFailure(o, ..) => o, | |
401 | infer::RegionResolutionError::SubSupConflict(_, _, o, ..) => o, | |
402 | infer::RegionResolutionError::UpperBoundUniverseConflict(.., o, _) => o, | |
403 | }; | |
404 | // Extract (possible) input/output types from origin | |
405 | match origin { | |
406 | infer::SubregionOrigin::Subtype(trace) => { | |
407 | if let Some((a, b)) = trace.values.ty() { | |
408 | blame_generics.extend([a, b]); | |
409 | } | |
410 | } | |
411 | infer::SubregionOrigin::RelateParamBound(_, ty, _) => blame_generics.push(*ty), | |
412 | infer::SubregionOrigin::ReferenceOutlivesReferent(ty, _) => blame_generics.push(*ty), | |
413 | _ => {} | |
414 | } | |
415 | } | |
416 | ||
417 | let fn_decl = tcx.hir().fn_decl_by_hir_id(hir_id).unwrap(); | |
418 | let opt_ret_ty = match fn_decl.output { | |
419 | hir::FnRetTy::DefaultReturn(_) => None, | |
420 | hir::FnRetTy::Return(ty) => Some(ty), | |
421 | }; | |
422 | ||
423 | // Map late-bound regions from trait to impl, so the names are right. | |
424 | let mapping = std::iter::zip( | |
9ffffee4 FG |
425 | tcx.fn_sig(trait_m.def_id).skip_binder().bound_vars(), |
426 | tcx.fn_sig(impl_m.def_id).skip_binder().bound_vars(), | |
9c376795 FG |
427 | ) |
428 | .filter_map(|(impl_bv, trait_bv)| { | |
429 | if let ty::BoundVariableKind::Region(impl_bv) = impl_bv | |
430 | && let ty::BoundVariableKind::Region(trait_bv) = trait_bv | |
431 | { | |
432 | Some((impl_bv, trait_bv)) | |
433 | } else { | |
434 | None | |
435 | } | |
436 | }) | |
437 | .collect(); | |
438 | ||
439 | // For each arg, see if it was in the "blame" of any of the region errors. | |
440 | // If so, then try to produce a suggestion to replace the argument type with | |
441 | // one from the trait. | |
442 | let mut bad_args = vec![]; | |
443 | for (idx, (ty, hir_ty)) in | |
444 | std::iter::zip(impl_sig.inputs_and_output, fn_decl.inputs.iter().chain(opt_ret_ty)) | |
445 | .enumerate() | |
446 | { | |
447 | let expected_ty = trait_sig.inputs_and_output[idx] | |
448 | .fold_with(&mut RemapLateBound { tcx, mapping: &mapping }); | |
449 | if blame_generics.iter().any(|blame| ty.contains(*blame)) { | |
450 | let expected_ty_sugg = expected_ty.to_string(); | |
451 | bad_args.push(( | |
452 | hir_ty.span, | |
453 | // Only suggest something if it actually changed. | |
454 | (expected_ty_sugg != ty.to_string()).then_some(expected_ty_sugg), | |
455 | )); | |
456 | } | |
457 | } | |
458 | ||
459 | bad_args | |
460 | } | |
461 | ||
462 | struct RemapLateBound<'a, 'tcx> { | |
463 | tcx: TyCtxt<'tcx>, | |
464 | mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>, | |
465 | } | |
466 | ||
9ffffee4 FG |
467 | impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> { |
468 | fn interner(&self) -> TyCtxt<'tcx> { | |
9c376795 FG |
469 | self.tcx |
470 | } | |
471 | ||
472 | fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { | |
473 | if let ty::ReFree(fr) = *r { | |
9ffffee4 FG |
474 | self.tcx.mk_re_free( |
475 | fr.scope, | |
476 | self.mapping.get(&fr.bound_region).copied().unwrap_or(fr.bound_region), | |
477 | ) | |
9c376795 FG |
478 | } else { |
479 | r | |
480 | } | |
481 | } | |
482 | } | |
483 | ||
484 | fn emit_implied_wf_lint<'tcx>( | |
485 | tcx: TyCtxt<'tcx>, | |
9ffffee4 | 486 | impl_m: ty::AssocItem, |
9c376795 FG |
487 | hir_id: hir::HirId, |
488 | bad_args: Vec<(Span, Option<String>)>, | |
489 | ) { | |
490 | let span: MultiSpan = if bad_args.is_empty() { | |
491 | tcx.def_span(impl_m.def_id).into() | |
492 | } else { | |
493 | bad_args.iter().map(|(span, _)| *span).collect::<Vec<_>>().into() | |
494 | }; | |
495 | tcx.struct_span_lint_hir( | |
496 | rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT, | |
497 | hir_id, | |
498 | span, | |
499 | "impl method assumes more implied bounds than the corresponding trait method", | |
500 | |lint| { | |
501 | let bad_args: Vec<_> = | |
502 | bad_args.into_iter().filter_map(|(span, sugg)| Some((span, sugg?))).collect(); | |
503 | if !bad_args.is_empty() { | |
504 | lint.multipart_suggestion( | |
505 | format!( | |
506 | "replace {} type{} to make the impl signature compatible", | |
507 | pluralize!("this", bad_args.len()), | |
508 | pluralize!(bad_args.len()) | |
509 | ), | |
510 | bad_args, | |
511 | Applicability::MaybeIncorrect, | |
512 | ); | |
513 | } | |
514 | lint | |
515 | }, | |
516 | ); | |
517 | } | |
518 | ||
487cf647 FG |
519 | #[derive(Debug, PartialEq, Eq)] |
520 | enum CheckImpliedWfMode { | |
521 | /// Checks implied well-formedness of the impl method. If it fails, we will | |
522 | /// re-check with `Skip`, and emit a lint if it succeeds. | |
523 | Check, | |
524 | /// Skips checking implied well-formedness of the impl method, but will emit | |
9c376795 | 525 | /// a lint if the `compare_method_predicate_entailment` succeeded. This means that |
487cf647 FG |
526 | /// the reason that we had failed earlier during `Check` was due to the impl |
527 | /// having stronger requirements than the trait. | |
528 | Skip, | |
529 | } | |
530 | ||
9c376795 FG |
531 | fn compare_asyncness<'tcx>( |
532 | tcx: TyCtxt<'tcx>, | |
9ffffee4 FG |
533 | impl_m: ty::AssocItem, |
534 | trait_m: ty::AssocItem, | |
9c376795 FG |
535 | ) -> Result<(), ErrorGuaranteed> { |
536 | if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async { | |
9ffffee4 | 537 | match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() { |
9c376795 FG |
538 | ty::Alias(ty::Opaque, ..) => { |
539 | // allow both `async fn foo()` and `fn foo() -> impl Future` | |
540 | } | |
541 | ty::Error(_) => { | |
542 | // We don't know if it's ok, but at least it's already an error. | |
543 | } | |
544 | _ => { | |
545 | return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync { | |
9ffffee4 | 546 | span: tcx.def_span(impl_m.def_id), |
9c376795 | 547 | method_name: trait_m.name, |
9ffffee4 | 548 | trait_item_span: tcx.hir().span_if_local(trait_m.def_id), |
9c376795 FG |
549 | })); |
550 | } | |
551 | }; | |
552 | } | |
553 | ||
554 | Ok(()) | |
555 | } | |
556 | ||
557 | /// Given a method def-id in an impl, compare the method signature of the impl | |
558 | /// against the trait that it's implementing. In doing so, infer the hidden types | |
559 | /// that this method's signature provides to satisfy each return-position `impl Trait` | |
560 | /// in the trait signature. | |
561 | /// | |
562 | /// The method is also responsible for making sure that the hidden types for each | |
563 | /// RPITIT actually satisfy the bounds of the `impl Trait`, i.e. that if we infer | |
564 | /// `impl Trait = Foo`, that `Foo: Trait` holds. | |
565 | /// | |
566 | /// For example, given the sample code: | |
567 | /// | |
568 | /// ``` | |
569 | /// #![feature(return_position_impl_trait_in_trait)] | |
570 | /// | |
571 | /// use std::ops::Deref; | |
572 | /// | |
573 | /// trait Foo { | |
574 | /// fn bar() -> impl Deref<Target = impl Sized>; | |
575 | /// // ^- RPITIT #1 ^- RPITIT #2 | |
576 | /// } | |
577 | /// | |
578 | /// impl Foo for () { | |
579 | /// fn bar() -> Box<String> { Box::new(String::new()) } | |
580 | /// } | |
581 | /// ``` | |
582 | /// | |
583 | /// The hidden types for the RPITITs in `bar` would be inferred to: | |
584 | /// * `impl Deref` (RPITIT #1) = `Box<String>` | |
585 | /// * `impl Sized` (RPITIT #2) = `String` | |
586 | /// | |
587 | /// The relationship between these two types is straightforward in this case, but | |
588 | /// may be more tenuously connected via other `impl`s and normalization rules for | |
589 | /// cases of more complicated nested RPITITs. | |
487cf647 | 590 | #[instrument(skip(tcx), level = "debug", ret)] |
9c376795 | 591 | pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( |
f2b60f7d | 592 | tcx: TyCtxt<'tcx>, |
353b0b11 | 593 | impl_m_def_id: LocalDefId, |
49aad941 | 594 | ) -> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> { |
353b0b11 | 595 | let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap(); |
f2b60f7d | 596 | let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); |
9c376795 FG |
597 | let impl_trait_ref = |
598 | tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().subst_identity(); | |
353b0b11 | 599 | let param_env = tcx.param_env(impl_m_def_id); |
f2b60f7d | 600 | |
9c376795 FG |
601 | // First, check a few of the same things as `compare_impl_method`, |
602 | // just so we don't ICE during substitution later. | |
9ffffee4 | 603 | compare_number_of_generics(tcx, impl_m, trait_m, true)?; |
487cf647 FG |
604 | compare_generic_param_kinds(tcx, impl_m, trait_m, true)?; |
605 | check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?; | |
606 | ||
f2b60f7d FG |
607 | let trait_to_impl_substs = impl_trait_ref.substs; |
608 | ||
9ffffee4 | 609 | let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id); |
f2b60f7d FG |
610 | let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span(); |
611 | let cause = ObligationCause::new( | |
612 | return_span, | |
9ffffee4 | 613 | impl_m_def_id, |
f2b60f7d | 614 | ObligationCauseCode::CompareImplItemObligation { |
9ffffee4 | 615 | impl_item_def_id: impl_m_def_id, |
f2b60f7d FG |
616 | trait_item_def_id: trait_m.def_id, |
617 | kind: impl_m.kind, | |
618 | }, | |
619 | ); | |
620 | ||
621 | // Create mapping from impl to placeholder. | |
622 | let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id); | |
623 | ||
624 | // Create mapping from trait to placeholder. | |
625 | let trait_to_placeholder_substs = | |
626 | impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs); | |
627 | ||
2b03887a FG |
628 | let infcx = &tcx.infer_ctxt().build(); |
629 | let ocx = ObligationCtxt::new(infcx); | |
f2b60f7d | 630 | |
487cf647 | 631 | // Normalize the impl signature with fresh variables for lifetime inference. |
9ffffee4 | 632 | let norm_cause = ObligationCause::misc(return_span, impl_m_def_id); |
2b03887a | 633 | let impl_sig = ocx.normalize( |
487cf647 | 634 | &norm_cause, |
2b03887a | 635 | param_env, |
9ffffee4 | 636 | infcx.instantiate_binder_with_fresh_vars( |
2b03887a FG |
637 | return_span, |
638 | infer::HigherRankedType, | |
9ffffee4 | 639 | tcx.fn_sig(impl_m.def_id).subst_identity(), |
2b03887a FG |
640 | ), |
641 | ); | |
9c376795 | 642 | impl_sig.error_reported()?; |
2b03887a | 643 | let impl_return_ty = impl_sig.output(); |
f2b60f7d | 644 | |
487cf647 FG |
645 | // Normalize the trait signature with liberated bound vars, passing it through |
646 | // the ImplTraitInTraitCollector, which gathers all of the RPITITs and replaces | |
647 | // them with inference variables. | |
648 | // We will use these inference variables to collect the hidden types of RPITITs. | |
9ffffee4 | 649 | let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_def_id); |
2b03887a FG |
650 | let unnormalized_trait_sig = tcx |
651 | .liberate_late_bound_regions( | |
652 | impl_m.def_id, | |
9ffffee4 | 653 | tcx.fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs), |
2b03887a FG |
654 | ) |
655 | .fold_with(&mut collector); | |
9ffffee4 FG |
656 | |
657 | debug_assert_ne!( | |
658 | collector.types.len(), | |
659 | 0, | |
660 | "expect >1 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`" | |
661 | ); | |
662 | ||
487cf647 | 663 | let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig); |
9c376795 | 664 | trait_sig.error_reported()?; |
2b03887a | 665 | let trait_return_ty = trait_sig.output(); |
f2b60f7d | 666 | |
487cf647 | 667 | let wf_tys = FxIndexSet::from_iter( |
2b03887a FG |
668 | unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()), |
669 | ); | |
f2b60f7d | 670 | |
487cf647 FG |
671 | match ocx.eq(&cause, param_env, trait_return_ty, impl_return_ty) { |
672 | Ok(()) => {} | |
2b03887a FG |
673 | Err(terr) => { |
674 | let mut diag = struct_span_err!( | |
675 | tcx.sess, | |
676 | cause.span(), | |
677 | E0053, | |
678 | "method `{}` has an incompatible return type for trait", | |
679 | trait_m.name | |
680 | ); | |
681 | let hir = tcx.hir(); | |
682 | infcx.err_ctxt().note_type_err( | |
683 | &mut diag, | |
684 | &cause, | |
685 | hir.get_if_local(impl_m.def_id) | |
686 | .and_then(|node| node.fn_decl()) | |
687 | .map(|decl| (decl.output.span(), "return type in trait".to_owned())), | |
688 | Some(infer::ValuePairs::Terms(ExpectedFound { | |
689 | expected: trait_return_ty.into(), | |
690 | found: impl_return_ty.into(), | |
691 | })), | |
692 | terr, | |
693 | false, | |
694 | false, | |
695 | ); | |
696 | return Err(diag.emit()); | |
697 | } | |
698 | } | |
f2b60f7d | 699 | |
487cf647 FG |
700 | debug!(?trait_sig, ?impl_sig, "equating function signatures"); |
701 | ||
2b03887a FG |
702 | // Unify the whole function signature. We need to do this to fully infer |
703 | // the lifetimes of the return type, but do this after unifying just the | |
704 | // return types, since we want to avoid duplicating errors from | |
9c376795 FG |
705 | // `compare_method_predicate_entailment`. |
706 | match ocx.eq(&cause, param_env, trait_sig, impl_sig) { | |
487cf647 | 707 | Ok(()) => {} |
2b03887a | 708 | Err(terr) => { |
9c376795 | 709 | // This function gets called during `compare_method_predicate_entailment` when normalizing a |
487cf647 | 710 | // signature that contains RPITIT. When the method signatures don't match, we have to |
9c376795 | 711 | // emit an error now because `compare_method_predicate_entailment` will not report the error |
487cf647 FG |
712 | // when normalization fails. |
713 | let emitted = report_trait_method_mismatch( | |
714 | infcx, | |
715 | cause, | |
716 | terr, | |
9c376795 FG |
717 | (trait_m, trait_sig), |
718 | (impl_m, impl_sig), | |
487cf647 | 719 | impl_trait_ref, |
2b03887a | 720 | ); |
487cf647 | 721 | return Err(emitted); |
2b03887a FG |
722 | } |
723 | } | |
f2b60f7d | 724 | |
2b03887a FG |
725 | // Check that all obligations are satisfied by the implementation's |
726 | // RPITs. | |
727 | let errors = ocx.select_all_or_error(); | |
728 | if !errors.is_empty() { | |
353b0b11 | 729 | let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); |
2b03887a FG |
730 | return Err(reported); |
731 | } | |
f2b60f7d | 732 | |
353b0b11 FG |
733 | let collected_types = collector.types; |
734 | ||
2b03887a FG |
735 | // Finally, resolve all regions. This catches wily misuses of |
736 | // lifetime parameters. | |
353b0b11 | 737 | let outlives_env = OutlivesEnvironment::with_bounds( |
2b03887a | 738 | param_env, |
9ffffee4 | 739 | infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys), |
2b03887a | 740 | ); |
353b0b11 | 741 | ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?; |
2b03887a FG |
742 | |
743 | let mut collected_tys = FxHashMap::default(); | |
353b0b11 | 744 | for (def_id, (ty, substs)) in collected_types { |
2b03887a FG |
745 | match infcx.fully_resolve(ty) { |
746 | Ok(ty) => { | |
747 | // `ty` contains free regions that we created earlier while liberating the | |
9c376795 | 748 | // trait fn signature. However, projection normalization expects `ty` to |
2b03887a FG |
749 | // contains `def_id`'s early-bound regions. |
750 | let id_substs = InternalSubsts::identity_for_item(tcx, def_id); | |
751 | debug!(?id_substs, ?substs); | |
752 | let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> = | |
753 | std::iter::zip(substs, id_substs).collect(); | |
754 | debug!(?map); | |
755 | ||
756 | // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound | |
757 | // region substs that are synthesized during AST lowering. These are substs | |
758 | // that are appended to the parent substs (trait and trait method). However, | |
759 | // we're trying to infer the unsubstituted type value of the RPITIT inside | |
760 | // the *impl*, so we can later use the impl's method substs to normalize | |
761 | // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`). | |
762 | // | |
763 | // Due to the design of RPITITs, during AST lowering, we have no idea that | |
764 | // an impl method corresponds to a trait method with RPITITs in it. Therefore, | |
765 | // we don't have a list of early-bound region substs for the RPITIT in the impl. | |
766 | // Since early region parameters are index-based, we can't just rebase these | |
767 | // (trait method) early-bound region substs onto the impl, and there's no | |
768 | // guarantee that the indices from the trait substs and impl substs line up. | |
769 | // So to fix this, we subtract the number of trait substs and add the number of | |
770 | // impl substs to *renumber* these early-bound regions to their corresponding | |
771 | // indices in the impl's substitutions list. | |
772 | // | |
773 | // Also, we only need to account for a difference in trait and impl substs, | |
774 | // since we previously enforce that the trait method and impl method have the | |
775 | // same generics. | |
776 | let num_trait_substs = trait_to_impl_substs.len(); | |
777 | let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len(); | |
778 | let ty = tcx.fold_regions(ty, |region, _| { | |
487cf647 FG |
779 | match region.kind() { |
780 | // Remap all free regions, which correspond to late-bound regions in the function. | |
781 | ty::ReFree(_) => {} | |
782 | // Remap early-bound regions as long as they don't come from the `impl` itself. | |
783 | ty::ReEarlyBound(ebr) if tcx.parent(ebr.def_id) != impl_m.container_id(tcx) => {} | |
784 | _ => return region, | |
785 | } | |
2b03887a FG |
786 | let Some(ty::ReEarlyBound(e)) = map.get(®ion.into()).map(|r| r.expect_region().kind()) |
787 | else { | |
9ffffee4 | 788 | return tcx.mk_re_error_with_message(return_span, "expected ReFree to map to ReEarlyBound") |
2b03887a | 789 | }; |
9ffffee4 | 790 | tcx.mk_re_early_bound(ty::EarlyBoundRegion { |
2b03887a FG |
791 | def_id: e.def_id, |
792 | name: e.name, | |
793 | index: (e.index as usize - num_trait_substs + num_impl_substs) as u32, | |
9ffffee4 | 794 | }) |
2b03887a FG |
795 | }); |
796 | debug!(%ty); | |
49aad941 | 797 | collected_tys.insert(def_id, ty::EarlyBinder(ty)); |
2b03887a FG |
798 | } |
799 | Err(err) => { | |
487cf647 | 800 | let reported = tcx.sess.delay_span_bug( |
2b03887a FG |
801 | return_span, |
802 | format!("could not fully resolve: {ty} => {err:?}"), | |
803 | ); | |
49aad941 | 804 | collected_tys.insert(def_id, ty::EarlyBinder(tcx.ty_error(reported))); |
f2b60f7d FG |
805 | } |
806 | } | |
2b03887a | 807 | } |
f2b60f7d | 808 | |
2b03887a | 809 | Ok(&*tcx.arena.alloc(collected_tys)) |
f2b60f7d FG |
810 | } |
811 | ||
812 | struct ImplTraitInTraitCollector<'a, 'tcx> { | |
813 | ocx: &'a ObligationCtxt<'a, 'tcx>, | |
814 | types: FxHashMap<DefId, (Ty<'tcx>, ty::SubstsRef<'tcx>)>, | |
815 | span: Span, | |
816 | param_env: ty::ParamEnv<'tcx>, | |
9ffffee4 | 817 | body_id: LocalDefId, |
f2b60f7d FG |
818 | } |
819 | ||
820 | impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> { | |
821 | fn new( | |
822 | ocx: &'a ObligationCtxt<'a, 'tcx>, | |
823 | span: Span, | |
824 | param_env: ty::ParamEnv<'tcx>, | |
9ffffee4 | 825 | body_id: LocalDefId, |
f2b60f7d FG |
826 | ) -> Self { |
827 | ImplTraitInTraitCollector { ocx, types: FxHashMap::default(), span, param_env, body_id } | |
828 | } | |
829 | } | |
830 | ||
9ffffee4 FG |
831 | impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> { |
832 | fn interner(&self) -> TyCtxt<'tcx> { | |
f2b60f7d FG |
833 | self.ocx.infcx.tcx |
834 | } | |
835 | ||
836 | fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { | |
9c376795 | 837 | if let ty::Alias(ty::Projection, proj) = ty.kind() |
353b0b11 | 838 | && self.interner().is_impl_trait_in_trait(proj.def_id) |
f2b60f7d | 839 | { |
9c376795 | 840 | if let Some((ty, _)) = self.types.get(&proj.def_id) { |
f2b60f7d FG |
841 | return *ty; |
842 | } | |
843 | //FIXME(RPITIT): Deny nested RPITIT in substs too | |
844 | if proj.substs.has_escaping_bound_vars() { | |
845 | bug!("FIXME(RPITIT): error here"); | |
846 | } | |
847 | // Replace with infer var | |
848 | let infer_ty = self.ocx.infcx.next_ty_var(TypeVariableOrigin { | |
849 | span: self.span, | |
850 | kind: TypeVariableOriginKind::MiscVariable, | |
851 | }); | |
9c376795 | 852 | self.types.insert(proj.def_id, (infer_ty, proj.substs)); |
f2b60f7d | 853 | // Recurse into bounds |
49aad941 | 854 | for (pred, pred_span) in self.interner().explicit_item_bounds(proj.def_id).subst_iter_copied(self.interner(), proj.substs) { |
f2b60f7d FG |
855 | let pred = pred.fold_with(self); |
856 | let pred = self.ocx.normalize( | |
487cf647 | 857 | &ObligationCause::misc(self.span, self.body_id), |
f2b60f7d FG |
858 | self.param_env, |
859 | pred, | |
860 | ); | |
861 | ||
862 | self.ocx.register_obligation(traits::Obligation::new( | |
9ffffee4 | 863 | self.interner(), |
f2b60f7d FG |
864 | ObligationCause::new( |
865 | self.span, | |
866 | self.body_id, | |
9c376795 | 867 | ObligationCauseCode::BindingObligation(proj.def_id, pred_span), |
f2b60f7d FG |
868 | ), |
869 | self.param_env, | |
870 | pred, | |
871 | )); | |
872 | } | |
873 | infer_ty | |
874 | } else { | |
875 | ty.super_fold_with(self) | |
876 | } | |
877 | } | |
878 | } | |
879 | ||
487cf647 FG |
880 | fn report_trait_method_mismatch<'tcx>( |
881 | infcx: &InferCtxt<'tcx>, | |
882 | mut cause: ObligationCause<'tcx>, | |
883 | terr: TypeError<'tcx>, | |
9ffffee4 FG |
884 | (trait_m, trait_sig): (ty::AssocItem, ty::FnSig<'tcx>), |
885 | (impl_m, impl_sig): (ty::AssocItem, ty::FnSig<'tcx>), | |
487cf647 FG |
886 | impl_trait_ref: ty::TraitRef<'tcx>, |
887 | ) -> ErrorGuaranteed { | |
888 | let tcx = infcx.tcx; | |
889 | let (impl_err_span, trait_err_span) = | |
890 | extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m); | |
891 | ||
892 | let mut diag = struct_span_err!( | |
893 | tcx.sess, | |
894 | impl_err_span, | |
895 | E0053, | |
896 | "method `{}` has an incompatible type for trait", | |
897 | trait_m.name | |
898 | ); | |
899 | match &terr { | |
900 | TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0) | |
901 | if trait_m.fn_has_self_parameter => | |
902 | { | |
903 | let ty = trait_sig.inputs()[0]; | |
904 | let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) { | |
905 | ExplicitSelf::ByValue => "self".to_owned(), | |
906 | ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(), | |
907 | ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(), | |
908 | _ => format!("self: {ty}"), | |
909 | }; | |
910 | ||
911 | // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the | |
912 | // span points only at the type `Box<Self`>, but we want to cover the whole | |
913 | // argument pattern and type. | |
9ffffee4 | 914 | let (sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); |
9c376795 FG |
915 | let span = tcx |
916 | .hir() | |
917 | .body_param_names(body) | |
918 | .zip(sig.decl.inputs.iter()) | |
919 | .map(|(param, ty)| param.span.to(ty.span)) | |
920 | .next() | |
921 | .unwrap_or(impl_err_span); | |
487cf647 FG |
922 | |
923 | diag.span_suggestion( | |
924 | span, | |
925 | "change the self-receiver type to match the trait", | |
926 | sugg, | |
927 | Applicability::MachineApplicable, | |
928 | ); | |
929 | } | |
930 | TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => { | |
931 | if trait_sig.inputs().len() == *i { | |
932 | // Suggestion to change output type. We do not suggest in `async` functions | |
933 | // to avoid complex logic or incorrect output. | |
9c376795 FG |
934 | if let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind |
935 | && !sig.header.asyncness.is_async() | |
936 | { | |
937 | let msg = "change the output type to match the trait"; | |
938 | let ap = Applicability::MachineApplicable; | |
939 | match sig.decl.output { | |
940 | hir::FnRetTy::DefaultReturn(sp) => { | |
941 | let sugg = format!("-> {} ", trait_sig.output()); | |
942 | diag.span_suggestion_verbose(sp, msg, sugg, ap); | |
943 | } | |
944 | hir::FnRetTy::Return(hir_ty) => { | |
945 | let sugg = trait_sig.output(); | |
946 | diag.span_suggestion(hir_ty.span, msg, sugg, ap); | |
947 | } | |
948 | }; | |
487cf647 FG |
949 | }; |
950 | } else if let Some(trait_ty) = trait_sig.inputs().get(*i) { | |
951 | diag.span_suggestion( | |
952 | impl_err_span, | |
953 | "change the parameter type to match the trait", | |
954 | trait_ty, | |
955 | Applicability::MachineApplicable, | |
956 | ); | |
957 | } | |
958 | } | |
959 | _ => {} | |
960 | } | |
961 | ||
962 | cause.span = impl_err_span; | |
963 | infcx.err_ctxt().note_type_err( | |
964 | &mut diag, | |
965 | &cause, | |
966 | trait_err_span.map(|sp| (sp, "type in trait".to_owned())), | |
9c376795 | 967 | Some(infer::ValuePairs::Sigs(ExpectedFound { expected: trait_sig, found: impl_sig })), |
487cf647 FG |
968 | terr, |
969 | false, | |
970 | false, | |
971 | ); | |
972 | ||
973 | return diag.emit(); | |
974 | } | |
975 | ||
dfeec247 | 976 | fn check_region_bounds_on_impl_item<'tcx>( |
dc9dc135 | 977 | tcx: TyCtxt<'tcx>, |
9ffffee4 FG |
978 | impl_m: ty::AssocItem, |
979 | trait_m: ty::AssocItem, | |
487cf647 | 980 | delay: bool, |
5e7ed085 | 981 | ) -> Result<(), ErrorGuaranteed> { |
487cf647 | 982 | let impl_generics = tcx.generics_of(impl_m.def_id); |
94b46f34 | 983 | let impl_params = impl_generics.own_counts().lifetimes; |
c30ab7b3 | 984 | |
487cf647 FG |
985 | let trait_generics = tcx.generics_of(trait_m.def_id); |
986 | let trait_params = trait_generics.own_counts().lifetimes; | |
987 | ||
dfeec247 XL |
988 | debug!( |
989 | "check_region_bounds_on_impl_item: \ | |
c30ab7b3 | 990 | trait_generics={:?} \ |
dfeec247 XL |
991 | impl_generics={:?}", |
992 | trait_generics, impl_generics | |
993 | ); | |
c30ab7b3 SL |
994 | |
995 | // Must have same number of early-bound lifetime parameters. | |
996 | // Unfortunately, if the user screws up the bounds, then this | |
9c376795 | 997 | // will change classification between early and late. E.g., |
c30ab7b3 SL |
998 | // if in trait we have `<'a,'b:'a>`, and in impl we just have |
999 | // `<'a,'b>`, then we have 2 early-bound lifetime parameters | |
1000 | // in trait but 0 in the impl. But if we report "expected 2 | |
1001 | // but found 0" it's confusing, because it looks like there | |
1002 | // are zero. Since I don't quite know how to phrase things at | |
1003 | // the moment, give a kind of vague error message. | |
94b46f34 | 1004 | if trait_params != impl_params { |
064997fb FG |
1005 | let span = tcx |
1006 | .hir() | |
1007 | .get_generics(impl_m.def_id.expect_local()) | |
1008 | .expect("expected impl item to have generics or else we can't compare them") | |
1009 | .span; | |
5869c6ff | 1010 | |
487cf647 FG |
1011 | let mut generics_span = None; |
1012 | let mut bounds_span = vec![]; | |
1013 | let mut where_span = None; | |
1014 | if let Some(trait_node) = tcx.hir().get_if_local(trait_m.def_id) | |
1015 | && let Some(trait_generics) = trait_node.generics() | |
1016 | { | |
1017 | generics_span = Some(trait_generics.span); | |
1018 | // FIXME: we could potentially look at the impl's bounds to not point at bounds that | |
1019 | // *are* present in the impl. | |
1020 | for p in trait_generics.predicates { | |
1021 | if let hir::WherePredicate::BoundPredicate(pred) = p { | |
1022 | for b in pred.bounds { | |
1023 | if let hir::GenericBound::Outlives(lt) = b { | |
1024 | bounds_span.push(lt.ident.span); | |
1025 | } | |
1026 | } | |
1027 | } | |
1028 | } | |
1029 | if let Some(impl_node) = tcx.hir().get_if_local(impl_m.def_id) | |
1030 | && let Some(impl_generics) = impl_node.generics() | |
1031 | { | |
1032 | let mut impl_bounds = 0; | |
1033 | for p in impl_generics.predicates { | |
1034 | if let hir::WherePredicate::BoundPredicate(pred) = p { | |
1035 | for b in pred.bounds { | |
1036 | if let hir::GenericBound::Outlives(_) = b { | |
1037 | impl_bounds += 1; | |
1038 | } | |
1039 | } | |
1040 | } | |
1041 | } | |
1042 | if impl_bounds == bounds_span.len() { | |
1043 | bounds_span = vec![]; | |
1044 | } else if impl_generics.has_where_clause_predicates { | |
1045 | where_span = Some(impl_generics.where_clause_span); | |
1046 | } | |
1047 | } | |
1048 | } | |
1049 | let reported = tcx | |
1050 | .sess | |
1051 | .create_err(LifetimesOrBoundsMismatchOnTrait { | |
1052 | span, | |
9ffffee4 | 1053 | item_kind: assoc_item_kind_str(&impl_m), |
487cf647 FG |
1054 | ident: impl_m.ident(tcx), |
1055 | generics_span, | |
1056 | bounds_span, | |
1057 | where_span, | |
1058 | }) | |
1059 | .emit_unless(delay); | |
5e7ed085 | 1060 | return Err(reported); |
85aaf69f | 1061 | } |
9e0c209e | 1062 | |
0bf4aa26 | 1063 | Ok(()) |
c30ab7b3 | 1064 | } |
9e0c209e | 1065 | |
3c0e092e | 1066 | #[instrument(level = "debug", skip(infcx))] |
2b03887a FG |
1067 | fn extract_spans_for_error_reporting<'tcx>( |
1068 | infcx: &infer::InferCtxt<'tcx>, | |
f2b60f7d | 1069 | terr: TypeError<'_>, |
dc9dc135 | 1070 | cause: &ObligationCause<'tcx>, |
9ffffee4 FG |
1071 | impl_m: ty::AssocItem, |
1072 | trait_m: ty::AssocItem, | |
dc9dc135 | 1073 | ) -> (Span, Option<Span>) { |
c30ab7b3 | 1074 | let tcx = infcx.tcx; |
9c376795 | 1075 | let mut impl_args = { |
9ffffee4 | 1076 | let (sig, _) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); |
9c376795 | 1077 | sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) |
c30ab7b3 | 1078 | }; |
9c376795 FG |
1079 | |
1080 | let trait_args = trait_m.def_id.as_local().map(|def_id| { | |
9ffffee4 | 1081 | let (sig, _) = tcx.hir().expect_trait_item(def_id).expect_fn(); |
9c376795 FG |
1082 | sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) |
1083 | }); | |
9e0c209e | 1084 | |
f2b60f7d | 1085 | match terr { |
9c376795 | 1086 | TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => { |
cdc7bbd5 | 1087 | (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i))) |
c30ab7b3 | 1088 | } |
064997fb | 1089 | _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)), |
c30ab7b3 SL |
1090 | } |
1091 | } | |
1092 | ||
dc9dc135 XL |
1093 | fn compare_self_type<'tcx>( |
1094 | tcx: TyCtxt<'tcx>, | |
9ffffee4 FG |
1095 | impl_m: ty::AssocItem, |
1096 | trait_m: ty::AssocItem, | |
dc9dc135 | 1097 | impl_trait_ref: ty::TraitRef<'tcx>, |
5e7ed085 | 1098 | ) -> Result<(), ErrorGuaranteed> { |
c30ab7b3 | 1099 | // Try to give more informative error messages about self typing |
9c376795 | 1100 | // mismatches. Note that any mismatch will also be detected |
c30ab7b3 | 1101 | // below, where we construct a canonical function type that |
9c376795 | 1102 | // includes the self parameter as a normal parameter. It's just |
c30ab7b3 SL |
1103 | // that the error messages you get out of this code are a bit more |
1104 | // inscrutable, particularly for cases where one method has no | |
1105 | // self. | |
476ff2be | 1106 | |
9ffffee4 | 1107 | let self_string = |method: ty::AssocItem| { |
476ff2be | 1108 | let untransformed_self_ty = match method.container { |
064997fb FG |
1109 | ty::ImplContainer => impl_trait_ref.self_ty(), |
1110 | ty::TraitContainer => tcx.types.self_param, | |
476ff2be | 1111 | }; |
9ffffee4 | 1112 | let self_arg_ty = tcx.fn_sig(method.def_id).subst_identity().input(0); |
0531ce1d | 1113 | let param_env = ty::ParamEnv::reveal_all(); |
abe05a73 | 1114 | |
2b03887a FG |
1115 | let infcx = tcx.infer_ctxt().build(); |
1116 | let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty); | |
9ffffee4 | 1117 | let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty); |
2b03887a FG |
1118 | match ExplicitSelf::determine(self_arg_ty, can_eq_self) { |
1119 | ExplicitSelf::ByValue => "self".to_owned(), | |
1120 | ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(), | |
1121 | ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(), | |
1122 | _ => format!("self: {self_arg_ty}"), | |
1123 | } | |
476ff2be SL |
1124 | }; |
1125 | ||
ba9703b0 | 1126 | match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) { |
476ff2be SL |
1127 | (false, false) | (true, true) => {} |
1128 | ||
1129 | (false, true) => { | |
1130 | let self_descr = self_string(impl_m); | |
9ffffee4 | 1131 | let impl_m_span = tcx.def_span(impl_m.def_id); |
dfeec247 XL |
1132 | let mut err = struct_span_err!( |
1133 | tcx.sess, | |
1134 | impl_m_span, | |
1135 | E0185, | |
cdc7bbd5 | 1136 | "method `{}` has a `{}` declaration in the impl, but not in the trait", |
5099ac24 | 1137 | trait_m.name, |
dfeec247 XL |
1138 | self_descr |
1139 | ); | |
04454e1e | 1140 | err.span_label(impl_m_span, format!("`{self_descr}` used in impl")); |
0731742a | 1141 | if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) { |
04454e1e | 1142 | err.span_label(span, format!("trait method declared without `{self_descr}`")); |
2c00a5a8 | 1143 | } else { |
064997fb | 1144 | err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); |
c30ab7b3 | 1145 | } |
9c376795 | 1146 | return Err(err.emit()); |
c30ab7b3 | 1147 | } |
476ff2be SL |
1148 | |
1149 | (true, false) => { | |
1150 | let self_descr = self_string(trait_m); | |
9ffffee4 | 1151 | let impl_m_span = tcx.def_span(impl_m.def_id); |
dfeec247 XL |
1152 | let mut err = struct_span_err!( |
1153 | tcx.sess, | |
1154 | impl_m_span, | |
1155 | E0186, | |
cdc7bbd5 | 1156 | "method `{}` has a `{}` declaration in the trait, but not in the impl", |
5099ac24 | 1157 | trait_m.name, |
dfeec247 XL |
1158 | self_descr |
1159 | ); | |
04454e1e | 1160 | err.span_label(impl_m_span, format!("expected `{self_descr}` in impl")); |
0731742a | 1161 | if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) { |
04454e1e | 1162 | err.span_label(span, format!("`{self_descr}` used in trait")); |
7cac9316 | 1163 | } else { |
064997fb | 1164 | err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); |
c30ab7b3 | 1165 | } |
9c376795 FG |
1166 | |
1167 | return Err(err.emit()); | |
c30ab7b3 | 1168 | } |
c30ab7b3 SL |
1169 | } |
1170 | ||
1171 | Ok(()) | |
1172 | } | |
1173 | ||
04454e1e FG |
1174 | /// Checks that the number of generics on a given assoc item in a trait impl is the same |
1175 | /// as the number of generics on the respective assoc item in the trait definition. | |
1176 | /// | |
1177 | /// For example this code emits the errors in the following code: | |
49aad941 | 1178 | /// ```rust,compile_fail |
04454e1e FG |
1179 | /// trait Trait { |
1180 | /// fn foo(); | |
1181 | /// type Assoc<T>; | |
1182 | /// } | |
1183 | /// | |
1184 | /// impl Trait for () { | |
1185 | /// fn foo<T>() {} | |
1186 | /// //~^ error | |
1187 | /// type Assoc = u32; | |
1188 | /// //~^ error | |
1189 | /// } | |
1190 | /// ``` | |
1191 | /// | |
1192 | /// Notably this does not error on `foo<T>` implemented as `foo<const N: u8>` or | |
1193 | /// `foo<const N: u8>` implemented as `foo<const N: u32>`. This is handled in | |
1194 | /// [`compare_generic_param_kinds`]. This function also does not handle lifetime parameters | |
dc9dc135 XL |
1195 | fn compare_number_of_generics<'tcx>( |
1196 | tcx: TyCtxt<'tcx>, | |
9ffffee4 FG |
1197 | impl_: ty::AssocItem, |
1198 | trait_: ty::AssocItem, | |
487cf647 | 1199 | delay: bool, |
5e7ed085 | 1200 | ) -> Result<(), ErrorGuaranteed> { |
532ac7d7 XL |
1201 | let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts(); |
1202 | let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts(); | |
1203 | ||
04454e1e FG |
1204 | // This avoids us erroring on `foo<T>` implemented as `foo<const N: u8>` as this is implemented |
1205 | // in `compare_generic_param_kinds` which will give a nicer error message than something like: | |
1206 | // "expected 1 type parameter, found 0 type parameters" | |
1207 | if (trait_own_counts.types + trait_own_counts.consts) | |
1208 | == (impl_own_counts.types + impl_own_counts.consts) | |
1209 | { | |
1210 | return Ok(()); | |
1211 | } | |
1212 | ||
353b0b11 FG |
1213 | // We never need to emit a separate error for RPITITs, since if an RPITIT |
1214 | // has mismatched type or const generic arguments, then the method that it's | |
1215 | // inheriting the generics from will also have mismatched arguments, and | |
1216 | // we'll report an error for that instead. Delay a bug for safety, though. | |
1217 | if tcx.opt_rpitit_info(trait_.def_id).is_some() { | |
1218 | return Err(tcx.sess.delay_span_bug( | |
1219 | rustc_span::DUMMY_SP, | |
1220 | "errors comparing numbers of generics of trait/impl functions were not emitted", | |
1221 | )); | |
1222 | } | |
1223 | ||
532ac7d7 XL |
1224 | let matchings = [ |
1225 | ("type", trait_own_counts.types, impl_own_counts.types), | |
1226 | ("const", trait_own_counts.consts, impl_own_counts.consts), | |
1227 | ]; | |
1228 | ||
9ffffee4 | 1229 | let item_kind = assoc_item_kind_str(&impl_); |
dfeec247 | 1230 | |
5e7ed085 | 1231 | let mut err_occurred = None; |
136023e0 | 1232 | for (kind, trait_count, impl_count) in matchings { |
532ac7d7 | 1233 | if impl_count != trait_count { |
923072b8 FG |
1234 | let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| { |
1235 | let mut spans = generics | |
1236 | .params | |
1237 | .iter() | |
1238 | .filter(|p| match p.kind { | |
1239 | hir::GenericParamKind::Lifetime { | |
1240 | kind: hir::LifetimeParamKind::Elided, | |
1241 | } => { | |
1242 | // A fn can have an arbitrary number of extra elided lifetimes for the | |
1243 | // same signature. | |
1244 | !matches!(kind, ty::AssocKind::Fn) | |
1245 | } | |
1246 | _ => true, | |
1247 | }) | |
1248 | .map(|p| p.span) | |
1249 | .collect::<Vec<Span>>(); | |
1250 | if spans.is_empty() { | |
1251 | spans = vec![generics.span] | |
1252 | } | |
1253 | spans | |
1254 | }; | |
f9f354fc | 1255 | let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() { |
a2a8927a | 1256 | let trait_item = tcx.hir().expect_trait_item(def_id); |
923072b8 FG |
1257 | let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics); |
1258 | let impl_trait_spans: Vec<Span> = trait_item | |
1259 | .generics | |
1260 | .params | |
1261 | .iter() | |
1262 | .filter_map(|p| match p.kind { | |
1263 | GenericParamKind::Type { synthetic: true, .. } => Some(p.span), | |
1264 | _ => None, | |
1265 | }) | |
1266 | .collect(); | |
1267 | (Some(arg_spans), impl_trait_spans) | |
f9f354fc | 1268 | } else { |
9ffffee4 | 1269 | let trait_span = tcx.hir().span_if_local(trait_.def_id); |
f9f354fc XL |
1270 | (trait_span.map(|s| vec![s]), vec![]) |
1271 | }; | |
9e0c209e | 1272 | |
a2a8927a | 1273 | let impl_item = tcx.hir().expect_impl_item(impl_.def_id.expect_local()); |
dfeec247 XL |
1274 | let impl_item_impl_trait_spans: Vec<Span> = impl_item |
1275 | .generics | |
1276 | .params | |
1277 | .iter() | |
dc9dc135 | 1278 | .filter_map(|p| match p.kind { |
3c0e092e | 1279 | GenericParamKind::Type { synthetic: true, .. } => Some(p.span), |
dc9dc135 | 1280 | _ => None, |
dfeec247 XL |
1281 | }) |
1282 | .collect(); | |
923072b8 FG |
1283 | let spans = arg_spans(impl_.kind, impl_item.generics); |
1284 | let span = spans.first().copied(); | |
dc9dc135 | 1285 | |
532ac7d7 | 1286 | let mut err = tcx.sess.struct_span_err_with_code( |
dc9dc135 | 1287 | spans, |
49aad941 | 1288 | format!( |
dfeec247 | 1289 | "{} `{}` has {} {kind} parameter{} but its trait \ |
532ac7d7 | 1290 | declaration has {} {kind} parameter{}", |
dfeec247 | 1291 | item_kind, |
5099ac24 | 1292 | trait_.name, |
532ac7d7 | 1293 | impl_count, |
60c5eb7d | 1294 | pluralize!(impl_count), |
532ac7d7 | 1295 | trait_count, |
60c5eb7d | 1296 | pluralize!(trait_count), |
532ac7d7 XL |
1297 | kind = kind, |
1298 | ), | |
1299 | DiagnosticId::Error("E0049".into()), | |
1300 | ); | |
c30ab7b3 | 1301 | |
532ac7d7 | 1302 | let mut suffix = None; |
c30ab7b3 | 1303 | |
dc9dc135 XL |
1304 | if let Some(spans) = trait_spans { |
1305 | let mut spans = spans.iter(); | |
1306 | if let Some(span) = spans.next() { | |
dfeec247 XL |
1307 | err.span_label( |
1308 | *span, | |
1309 | format!( | |
1310 | "expected {} {} parameter{}", | |
1311 | trait_count, | |
1312 | kind, | |
1313 | pluralize!(trait_count), | |
1314 | ), | |
1315 | ); | |
dc9dc135 XL |
1316 | } |
1317 | for span in spans { | |
1318 | err.span_label(*span, ""); | |
1319 | } | |
532ac7d7 | 1320 | } else { |
04454e1e | 1321 | suffix = Some(format!(", expected {trait_count}")); |
532ac7d7 | 1322 | } |
c30ab7b3 | 1323 | |
dc9dc135 | 1324 | if let Some(span) = span { |
dfeec247 XL |
1325 | err.span_label( |
1326 | span, | |
1327 | format!( | |
1328 | "found {} {} parameter{}{}", | |
1329 | impl_count, | |
1330 | kind, | |
1331 | pluralize!(impl_count), | |
49aad941 | 1332 | suffix.unwrap_or_default(), |
dfeec247 XL |
1333 | ), |
1334 | ); | |
dc9dc135 XL |
1335 | } |
1336 | ||
1337 | for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) { | |
1338 | err.span_label(*span, "`impl Trait` introduces an implicit type parameter"); | |
1339 | } | |
c30ab7b3 | 1340 | |
487cf647 | 1341 | let reported = err.emit_unless(delay); |
5e7ed085 | 1342 | err_occurred = Some(reported); |
532ac7d7 | 1343 | } |
c30ab7b3 SL |
1344 | } |
1345 | ||
5e7ed085 | 1346 | if let Some(reported) = err_occurred { Err(reported) } else { Ok(()) } |
c30ab7b3 SL |
1347 | } |
1348 | ||
dc9dc135 XL |
1349 | fn compare_number_of_method_arguments<'tcx>( |
1350 | tcx: TyCtxt<'tcx>, | |
9ffffee4 FG |
1351 | impl_m: ty::AssocItem, |
1352 | trait_m: ty::AssocItem, | |
5e7ed085 | 1353 | ) -> Result<(), ErrorGuaranteed> { |
041b39d2 XL |
1354 | let impl_m_fty = tcx.fn_sig(impl_m.def_id); |
1355 | let trait_m_fty = tcx.fn_sig(trait_m.def_id); | |
9ffffee4 FG |
1356 | let trait_number_args = trait_m_fty.skip_binder().inputs().skip_binder().len(); |
1357 | let impl_number_args = impl_m_fty.skip_binder().inputs().skip_binder().len(); | |
9c376795 | 1358 | |
476ff2be | 1359 | if trait_number_args != impl_number_args { |
9c376795 FG |
1360 | let trait_span = trait_m |
1361 | .def_id | |
1362 | .as_local() | |
1363 | .and_then(|def_id| { | |
9ffffee4 | 1364 | let (trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).expect_fn(); |
9c376795 FG |
1365 | let pos = trait_number_args.saturating_sub(1); |
1366 | trait_m_sig.decl.inputs.get(pos).map(|arg| { | |
0731742a XL |
1367 | if pos == 0 { |
1368 | arg.span | |
1369 | } else { | |
9c376795 | 1370 | arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo()) |
0731742a | 1371 | } |
9c376795 FG |
1372 | }) |
1373 | }) | |
9ffffee4 | 1374 | .or_else(|| tcx.hir().span_if_local(trait_m.def_id)); |
9c376795 | 1375 | |
9ffffee4 | 1376 | let (impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); |
9c376795 FG |
1377 | let pos = impl_number_args.saturating_sub(1); |
1378 | let impl_span = impl_m_sig | |
1379 | .decl | |
1380 | .inputs | |
1381 | .get(pos) | |
1382 | .map(|arg| { | |
1383 | if pos == 0 { | |
1384 | arg.span | |
9e0c209e | 1385 | } else { |
9c376795 | 1386 | arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo()) |
9e0c209e | 1387 | } |
9c376795 | 1388 | }) |
9ffffee4 | 1389 | .unwrap_or_else(|| tcx.def_span(impl_m.def_id)); |
9c376795 | 1390 | |
dfeec247 XL |
1391 | let mut err = struct_span_err!( |
1392 | tcx.sess, | |
1393 | impl_span, | |
1394 | E0050, | |
a2a8927a | 1395 | "method `{}` has {} but the declaration in trait `{}` has {}", |
5099ac24 | 1396 | trait_m.name, |
dfeec247 XL |
1397 | potentially_plural_count(impl_number_args, "parameter"), |
1398 | tcx.def_path_str(trait_m.def_id), | |
1399 | trait_number_args | |
1400 | ); | |
9c376795 | 1401 | |
c30ab7b3 | 1402 | if let Some(trait_span) = trait_span { |
dfeec247 XL |
1403 | err.span_label( |
1404 | trait_span, | |
1405 | format!( | |
1406 | "trait requires {}", | |
1407 | potentially_plural_count(trait_number_args, "parameter") | |
1408 | ), | |
1409 | ); | |
7cac9316 | 1410 | } else { |
064997fb | 1411 | err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); |
9e0c209e | 1412 | } |
9c376795 | 1413 | |
dfeec247 XL |
1414 | err.span_label( |
1415 | impl_span, | |
1416 | format!( | |
1417 | "expected {}, found {}", | |
1418 | potentially_plural_count(trait_number_args, "parameter"), | |
1419 | impl_number_args | |
1420 | ), | |
1421 | ); | |
9c376795 FG |
1422 | |
1423 | return Err(err.emit()); | |
9e0c209e | 1424 | } |
c30ab7b3 SL |
1425 | |
1426 | Ok(()) | |
85aaf69f | 1427 | } |
d9579d0f | 1428 | |
dc9dc135 XL |
1429 | fn compare_synthetic_generics<'tcx>( |
1430 | tcx: TyCtxt<'tcx>, | |
9ffffee4 FG |
1431 | impl_m: ty::AssocItem, |
1432 | trait_m: ty::AssocItem, | |
5e7ed085 | 1433 | ) -> Result<(), ErrorGuaranteed> { |
abe05a73 | 1434 | // FIXME(chrisvittal) Clean up this function, list of FIXME items: |
94b46f34 | 1435 | // 1. Better messages for the span labels |
abe05a73 | 1436 | // 2. Explanation as to what is going on |
abe05a73 XL |
1437 | // If we get here, we already have the same number of generics, so the zip will |
1438 | // be okay. | |
5e7ed085 | 1439 | let mut error_found = None; |
abe05a73 XL |
1440 | let impl_m_generics = tcx.generics_of(impl_m.def_id); |
1441 | let trait_m_generics = tcx.generics_of(trait_m.def_id); | |
8faf50e0 XL |
1442 | let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind { |
1443 | GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), | |
cdc7bbd5 | 1444 | GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None, |
94b46f34 | 1445 | }); |
dfeec247 XL |
1446 | let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| match param.kind { |
1447 | GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), | |
cdc7bbd5 | 1448 | GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None, |
94b46f34 | 1449 | }); |
dfeec247 | 1450 | for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) in |
cdc7bbd5 | 1451 | iter::zip(impl_m_type_params, trait_m_type_params) |
0bf4aa26 | 1452 | { |
94b46f34 | 1453 | if impl_synthetic != trait_synthetic { |
04454e1e | 1454 | let impl_def_id = impl_def_id.expect_local(); |
f2b60f7d | 1455 | let impl_span = tcx.def_span(impl_def_id); |
94b46f34 | 1456 | let trait_span = tcx.def_span(trait_def_id); |
dfeec247 XL |
1457 | let mut err = struct_span_err!( |
1458 | tcx.sess, | |
1459 | impl_span, | |
1460 | E0643, | |
1461 | "method `{}` has incompatible signature for trait", | |
5099ac24 | 1462 | trait_m.name |
dfeec247 | 1463 | ); |
94b46f34 XL |
1464 | err.span_label(trait_span, "declaration in trait here"); |
1465 | match (impl_synthetic, trait_synthetic) { | |
1466 | // The case where the impl method uses `impl Trait` but the trait method uses | |
1467 | // explicit generics | |
3c0e092e | 1468 | (true, false) => { |
94b46f34 | 1469 | err.span_label(impl_span, "expected generic parameter, found `impl Trait`"); |
9c376795 | 1470 | let _: Option<_> = try { |
94b46f34 XL |
1471 | // try taking the name from the trait impl |
1472 | // FIXME: this is obviously suboptimal since the name can already be used | |
1473 | // as another generic argument | |
f2b60f7d | 1474 | let new_name = tcx.opt_item_name(trait_def_id)?; |
6a06907d | 1475 | let trait_m = trait_m.def_id.as_local()?; |
f2b60f7d | 1476 | let trait_m = tcx.hir().expect_trait_item(trait_m); |
94b46f34 | 1477 | |
6a06907d | 1478 | let impl_m = impl_m.def_id.as_local()?; |
f2b60f7d | 1479 | let impl_m = tcx.hir().expect_impl_item(impl_m); |
94b46f34 XL |
1480 | |
1481 | // in case there are no generics, take the spot between the function name | |
1482 | // and the opening paren of the argument list | |
f2b60f7d | 1483 | let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi(); |
94b46f34 | 1484 | // in case there are generics, just replace them |
dfeec247 XL |
1485 | let generics_span = |
1486 | impl_m.generics.span.substitute_dummy(new_generics_span); | |
94b46f34 | 1487 | // replace with the generics from the trait |
dfeec247 XL |
1488 | let new_generics = |
1489 | tcx.sess.source_map().span_to_snippet(trait_m.generics.span).ok()?; | |
94b46f34 | 1490 | |
9fa01778 | 1491 | err.multipart_suggestion( |
94b46f34 XL |
1492 | "try changing the `impl Trait` argument to a generic parameter", |
1493 | vec![ | |
1494 | // replace `impl Trait` with `T` | |
f2b60f7d | 1495 | (impl_span, new_name.to_string()), |
94b46f34 XL |
1496 | // replace impl method generics with trait method generics |
1497 | // This isn't quite right, as users might have changed the names | |
1498 | // of the generics, but it works for the common case | |
1499 | (generics_span, new_generics), | |
1500 | ], | |
0bf4aa26 | 1501 | Applicability::MaybeIncorrect, |
94b46f34 | 1502 | ); |
9c376795 | 1503 | }; |
dfeec247 | 1504 | } |
94b46f34 XL |
1505 | // The case where the trait method uses `impl Trait`, but the impl method uses |
1506 | // explicit generics. | |
3c0e092e | 1507 | (false, true) => { |
94b46f34 | 1508 | err.span_label(impl_span, "expected `impl Trait`, found generic parameter"); |
9c376795 | 1509 | let _: Option<_> = try { |
6a06907d | 1510 | let impl_m = impl_m.def_id.as_local()?; |
f2b60f7d | 1511 | let impl_m = tcx.hir().expect_impl_item(impl_m); |
9ffffee4 | 1512 | let (sig, _) = impl_m.expect_fn(); |
9c376795 FG |
1513 | let input_tys = sig.decl.inputs; |
1514 | ||
04454e1e | 1515 | struct Visitor(Option<Span>, hir::def_id::LocalDefId); |
dfeec247 XL |
1516 | impl<'v> intravisit::Visitor<'v> for Visitor { |
1517 | fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { | |
1518 | intravisit::walk_ty(self, ty); | |
9c376795 | 1519 | if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind |
04454e1e FG |
1520 | && let Res::Def(DefKind::TyParam, def_id) = path.res |
1521 | && def_id == self.1.to_def_id() | |
0bf4aa26 | 1522 | { |
04454e1e | 1523 | self.0 = Some(ty.span); |
94b46f34 XL |
1524 | } |
1525 | } | |
94b46f34 | 1526 | } |
9c376795 | 1527 | |
94b46f34 XL |
1528 | let mut visitor = Visitor(None, impl_def_id); |
1529 | for ty in input_tys { | |
dfeec247 | 1530 | intravisit::Visitor::visit_ty(&mut visitor, ty); |
94b46f34 XL |
1531 | } |
1532 | let span = visitor.0?; | |
1533 | ||
04454e1e | 1534 | let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds; |
8faf50e0 | 1535 | let bounds = bounds.first()?.span().to(bounds.last()?.span()); |
dfeec247 | 1536 | let bounds = tcx.sess.source_map().span_to_snippet(bounds).ok()?; |
94b46f34 | 1537 | |
9fa01778 | 1538 | err.multipart_suggestion( |
94b46f34 XL |
1539 | "try removing the generic parameter and using `impl Trait` instead", |
1540 | vec![ | |
1541 | // delete generic parameters | |
1542 | (impl_m.generics.span, String::new()), | |
1543 | // replace param usage with `impl Trait` | |
04454e1e | 1544 | (span, format!("impl {bounds}")), |
94b46f34 | 1545 | ], |
0bf4aa26 | 1546 | Applicability::MaybeIncorrect, |
94b46f34 | 1547 | ); |
9c376795 | 1548 | }; |
dfeec247 | 1549 | } |
94b46f34 XL |
1550 | _ => unreachable!(), |
1551 | } | |
9c376795 | 1552 | error_found = Some(err.emit()); |
abe05a73 XL |
1553 | } |
1554 | } | |
5e7ed085 | 1555 | if let Some(reported) = error_found { Err(reported) } else { Ok(()) } |
abe05a73 XL |
1556 | } |
1557 | ||
04454e1e FG |
1558 | /// Checks that all parameters in the generics of a given assoc item in a trait impl have |
1559 | /// the same kind as the respective generic parameter in the trait def. | |
1560 | /// | |
1561 | /// For example all 4 errors in the following code are emitted here: | |
49aad941 | 1562 | /// ```rust,ignore (pseudo-Rust) |
04454e1e FG |
1563 | /// trait Foo { |
1564 | /// fn foo<const N: u8>(); | |
1565 | /// type bar<const N: u8>; | |
1566 | /// fn baz<const N: u32>(); | |
1567 | /// type blah<T>; | |
1568 | /// } | |
1569 | /// | |
1570 | /// impl Foo for () { | |
1571 | /// fn foo<const N: u64>() {} | |
1572 | /// //~^ error | |
1573 | /// type bar<const N: u64> {} | |
1574 | /// //~^ error | |
1575 | /// fn baz<T>() {} | |
1576 | /// //~^ error | |
1577 | /// type blah<const N: i64> = u32; | |
1578 | /// //~^ error | |
1579 | /// } | |
1580 | /// ``` | |
1581 | /// | |
1582 | /// This function does not handle lifetime parameters | |
1583 | fn compare_generic_param_kinds<'tcx>( | |
136023e0 | 1584 | tcx: TyCtxt<'tcx>, |
9ffffee4 FG |
1585 | impl_item: ty::AssocItem, |
1586 | trait_item: ty::AssocItem, | |
487cf647 | 1587 | delay: bool, |
5e7ed085 | 1588 | ) -> Result<(), ErrorGuaranteed> { |
04454e1e FG |
1589 | assert_eq!(impl_item.kind, trait_item.kind); |
1590 | ||
1591 | let ty_const_params_of = |def_id| { | |
1592 | tcx.generics_of(def_id).params.iter().filter(|param| { | |
1593 | matches!( | |
1594 | param.kind, | |
1595 | GenericParamDefKind::Const { .. } | GenericParamDefKind::Type { .. } | |
1596 | ) | |
136023e0 XL |
1597 | }) |
1598 | }; | |
04454e1e FG |
1599 | |
1600 | for (param_impl, param_trait) in | |
1601 | iter::zip(ty_const_params_of(impl_item.def_id), ty_const_params_of(trait_item.def_id)) | |
1602 | { | |
1603 | use GenericParamDefKind::*; | |
1604 | if match (¶m_impl.kind, ¶m_trait.kind) { | |
1605 | (Const { .. }, Const { .. }) | |
1606 | if tcx.type_of(param_impl.def_id) != tcx.type_of(param_trait.def_id) => | |
1607 | { | |
1608 | true | |
1609 | } | |
1610 | (Const { .. }, Type { .. }) | (Type { .. }, Const { .. }) => true, | |
1611 | // this is exhaustive so that anyone adding new generic param kinds knows | |
1612 | // to make sure this error is reported for them. | |
1613 | (Const { .. }, Const { .. }) | (Type { .. }, Type { .. }) => false, | |
1614 | (Lifetime { .. }, _) | (_, Lifetime { .. }) => unreachable!(), | |
1615 | } { | |
1616 | let param_impl_span = tcx.def_span(param_impl.def_id); | |
1617 | let param_trait_span = tcx.def_span(param_trait.def_id); | |
1618 | ||
136023e0 XL |
1619 | let mut err = struct_span_err!( |
1620 | tcx.sess, | |
04454e1e | 1621 | param_impl_span, |
136023e0 | 1622 | E0053, |
04454e1e FG |
1623 | "{} `{}` has an incompatible generic parameter for trait `{}`", |
1624 | assoc_item_kind_str(&impl_item), | |
1625 | trait_item.name, | |
1626 | &tcx.def_path_str(tcx.parent(trait_item.def_id)) | |
136023e0 | 1627 | ); |
04454e1e FG |
1628 | |
1629 | let make_param_message = |prefix: &str, param: &ty::GenericParamDef| match param.kind { | |
1630 | Const { .. } => { | |
9ffffee4 FG |
1631 | format!( |
1632 | "{} const parameter of type `{}`", | |
1633 | prefix, | |
1634 | tcx.type_of(param.def_id).subst_identity() | |
1635 | ) | |
04454e1e FG |
1636 | } |
1637 | Type { .. } => format!("{} type parameter", prefix), | |
1638 | Lifetime { .. } => unreachable!(), | |
1639 | }; | |
1640 | ||
1641 | let trait_header_span = tcx.def_ident_span(tcx.parent(trait_item.def_id)).unwrap(); | |
1642 | err.span_label(trait_header_span, ""); | |
1643 | err.span_label(param_trait_span, make_param_message("expected", param_trait)); | |
1644 | ||
064997fb | 1645 | let impl_header_span = tcx.def_span(tcx.parent(impl_item.def_id)); |
04454e1e FG |
1646 | err.span_label(impl_header_span, ""); |
1647 | err.span_label(param_impl_span, make_param_message("found", param_impl)); | |
1648 | ||
487cf647 | 1649 | let reported = err.emit_unless(delay); |
5e7ed085 | 1650 | return Err(reported); |
136023e0 XL |
1651 | } |
1652 | } | |
1653 | ||
1654 | Ok(()) | |
1655 | } | |
1656 | ||
9c376795 FG |
1657 | /// Use `tcx.compare_impl_const` instead |
1658 | pub(super) fn compare_impl_const_raw( | |
1659 | tcx: TyCtxt<'_>, | |
2b03887a FG |
1660 | (impl_const_item_def, trait_const_item_def): (LocalDefId, DefId), |
1661 | ) -> Result<(), ErrorGuaranteed> { | |
1662 | let impl_const_item = tcx.associated_item(impl_const_item_def); | |
1663 | let trait_const_item = tcx.associated_item(trait_const_item_def); | |
9c376795 FG |
1664 | let impl_trait_ref = |
1665 | tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().subst_identity(); | |
c30ab7b3 | 1666 | debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); |
d9579d0f | 1667 | |
2b03887a | 1668 | let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id()); |
a7813a04 | 1669 | |
2b03887a FG |
1670 | let infcx = tcx.infer_ctxt().build(); |
1671 | let param_env = tcx.param_env(impl_const_item_def.to_def_id()); | |
1672 | let ocx = ObligationCtxt::new(&infcx); | |
c30ab7b3 | 1673 | |
2b03887a FG |
1674 | // The below is for the most part highly similar to the procedure |
1675 | // for methods above. It is simpler in many respects, especially | |
1676 | // because we shouldn't really have to deal with lifetimes or | |
1677 | // predicates. In fact some of this should probably be put into | |
1678 | // shared functions because of DRY violations... | |
1679 | let trait_to_impl_substs = impl_trait_ref.substs; | |
c30ab7b3 | 1680 | |
2b03887a FG |
1681 | // Create a parameter environment that represents the implementation's |
1682 | // method. | |
2b03887a | 1683 | // Compute placeholder form of impl and trait const tys. |
9ffffee4 FG |
1684 | let impl_ty = tcx.type_of(impl_const_item_def.to_def_id()).subst_identity(); |
1685 | let trait_ty = tcx.type_of(trait_const_item_def).subst(tcx, trait_to_impl_substs); | |
2b03887a FG |
1686 | let mut cause = ObligationCause::new( |
1687 | impl_c_span, | |
9ffffee4 | 1688 | impl_const_item_def, |
2b03887a FG |
1689 | ObligationCauseCode::CompareImplItemObligation { |
1690 | impl_item_def_id: impl_const_item_def, | |
1691 | trait_item_def_id: trait_const_item_def, | |
1692 | kind: impl_const_item.kind, | |
1693 | }, | |
1694 | ); | |
a7813a04 | 1695 | |
2b03887a | 1696 | // There is no "body" here, so just pass dummy id. |
487cf647 | 1697 | let impl_ty = ocx.normalize(&cause, param_env, impl_ty); |
d9579d0f | 1698 | |
2b03887a | 1699 | debug!("compare_const_impl: impl_ty={:?}", impl_ty); |
5bcae85e | 1700 | |
487cf647 | 1701 | let trait_ty = ocx.normalize(&cause, param_env, trait_ty); |
5bcae85e | 1702 | |
2b03887a | 1703 | debug!("compare_const_impl: trait_ty={:?}", trait_ty); |
5bcae85e | 1704 | |
487cf647 | 1705 | let err = ocx.sup(&cause, param_env, trait_ty, impl_ty); |
5bcae85e | 1706 | |
2b03887a FG |
1707 | if let Err(terr) = err { |
1708 | debug!( | |
1709 | "checking associated const for compatibility: impl ty {:?}, trait ty {:?}", | |
1710 | impl_ty, trait_ty | |
1711 | ); | |
cc61c64b | 1712 | |
2b03887a | 1713 | // Locate the Span containing just the type of the offending impl |
9ffffee4 | 1714 | let (ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).expect_const(); |
9c376795 | 1715 | cause.span = ty.span; |
7cac9316 | 1716 | |
2b03887a FG |
1717 | let mut diag = struct_span_err!( |
1718 | tcx.sess, | |
1719 | cause.span, | |
1720 | E0326, | |
1721 | "implemented const `{}` has an incompatible type for trait", | |
1722 | trait_const_item.name | |
064997fb | 1723 | ); |
2b03887a FG |
1724 | |
1725 | let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| { | |
1726 | // Add a label to the Span containing just the type of the const | |
9ffffee4 | 1727 | let (ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).expect_const(); |
9c376795 | 1728 | ty.span |
2b03887a FG |
1729 | }); |
1730 | ||
1731 | infcx.err_ctxt().note_type_err( | |
1732 | &mut diag, | |
1733 | &cause, | |
1734 | trait_c_span.map(|span| (span, "type in trait".to_owned())), | |
1735 | Some(infer::ValuePairs::Terms(ExpectedFound { | |
1736 | expected: trait_ty.into(), | |
1737 | found: impl_ty.into(), | |
1738 | })), | |
1739 | terr, | |
1740 | false, | |
1741 | false, | |
1742 | ); | |
1743 | return Err(diag.emit()); | |
1744 | }; | |
1745 | ||
1746 | // Check that all obligations are satisfied by the implementation's | |
1747 | // version. | |
1748 | let errors = ocx.select_all_or_error(); | |
1749 | if !errors.is_empty() { | |
353b0b11 | 1750 | return Err(infcx.err_ctxt().report_fulfillment_errors(&errors)); |
2b03887a FG |
1751 | } |
1752 | ||
353b0b11 FG |
1753 | let outlives_env = OutlivesEnvironment::new(param_env); |
1754 | ocx.resolve_regions_and_report_errors(impl_const_item_def, &outlives_env) | |
d9579d0f | 1755 | } |
dfeec247 | 1756 | |
9c376795 | 1757 | pub(super) fn compare_impl_ty<'tcx>( |
dfeec247 | 1758 | tcx: TyCtxt<'tcx>, |
9ffffee4 FG |
1759 | impl_ty: ty::AssocItem, |
1760 | trait_ty: ty::AssocItem, | |
dfeec247 | 1761 | impl_trait_ref: ty::TraitRef<'tcx>, |
dfeec247 XL |
1762 | ) { |
1763 | debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref); | |
1764 | ||
9c376795 | 1765 | let _: Result<(), ErrorGuaranteed> = try { |
9ffffee4 | 1766 | compare_number_of_generics(tcx, impl_ty, trait_ty, false)?; |
487cf647 | 1767 | compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?; |
9ffffee4 FG |
1768 | compare_type_predicate_entailment(tcx, impl_ty, trait_ty, impl_trait_ref)?; |
1769 | check_type_bounds(tcx, trait_ty, impl_ty, impl_trait_ref)?; | |
9c376795 | 1770 | }; |
dfeec247 XL |
1771 | } |
1772 | ||
9c376795 | 1773 | /// The equivalent of [compare_method_predicate_entailment], but for associated types |
dfeec247 | 1774 | /// instead of associated functions. |
f035d41b | 1775 | fn compare_type_predicate_entailment<'tcx>( |
dfeec247 | 1776 | tcx: TyCtxt<'tcx>, |
9ffffee4 FG |
1777 | impl_ty: ty::AssocItem, |
1778 | trait_ty: ty::AssocItem, | |
dfeec247 | 1779 | impl_trait_ref: ty::TraitRef<'tcx>, |
5e7ed085 | 1780 | ) -> Result<(), ErrorGuaranteed> { |
dfeec247 XL |
1781 | let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id); |
1782 | let trait_to_impl_substs = | |
064997fb | 1783 | impl_substs.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.substs); |
dfeec247 | 1784 | |
dfeec247 XL |
1785 | let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id); |
1786 | let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id); | |
1787 | ||
487cf647 | 1788 | check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?; |
dfeec247 XL |
1789 | |
1790 | let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs); | |
9c376795 | 1791 | if impl_ty_own_bounds.len() == 0 { |
dfeec247 XL |
1792 | // Nothing to check. |
1793 | return Ok(()); | |
1794 | } | |
1795 | ||
1796 | // This `HirId` should be used for the `body_id` field on each | |
1797 | // `ObligationCause` (and the `FnCtxt`). This is what | |
1798 | // `regionck_item` expects. | |
9ffffee4 | 1799 | let impl_ty_def_id = impl_ty.def_id.expect_local(); |
dfeec247 XL |
1800 | debug!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs); |
1801 | ||
1802 | // The predicates declared by the impl definition, the trait and the | |
1803 | // associated type in the trait are assumed. | |
1804 | let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap()); | |
1805 | let mut hybrid_preds = impl_predicates.instantiate_identity(tcx); | |
9c376795 FG |
1806 | hybrid_preds.predicates.extend( |
1807 | trait_ty_predicates | |
1808 | .instantiate_own(tcx, trait_to_impl_substs) | |
1809 | .map(|(predicate, _)| predicate), | |
1810 | ); | |
dfeec247 XL |
1811 | |
1812 | debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds); | |
1813 | ||
9ffffee4 FG |
1814 | let impl_ty_span = tcx.def_span(impl_ty_def_id); |
1815 | let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_def_id); | |
a2a8927a | 1816 | let param_env = ty::ParamEnv::new( |
9ffffee4 | 1817 | tcx.mk_predicates(&hybrid_preds.predicates), |
a2a8927a XL |
1818 | Reveal::UserFacing, |
1819 | hir::Constness::NotConst, | |
1820 | ); | |
064997fb | 1821 | let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); |
2b03887a FG |
1822 | let infcx = tcx.infer_ctxt().build(); |
1823 | let ocx = ObligationCtxt::new(&infcx); | |
dfeec247 | 1824 | |
2b03887a | 1825 | debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); |
dfeec247 | 1826 | |
9c376795 | 1827 | for (predicate, span) in impl_ty_own_bounds { |
9ffffee4 | 1828 | let cause = ObligationCause::misc(span, impl_ty_def_id); |
487cf647 | 1829 | let predicate = ocx.normalize(&cause, param_env, predicate); |
dfeec247 | 1830 | |
2b03887a FG |
1831 | let cause = ObligationCause::new( |
1832 | span, | |
9ffffee4 | 1833 | impl_ty_def_id, |
2b03887a FG |
1834 | ObligationCauseCode::CompareImplItemObligation { |
1835 | impl_item_def_id: impl_ty.def_id.expect_local(), | |
1836 | trait_item_def_id: trait_ty.def_id, | |
1837 | kind: impl_ty.kind, | |
1838 | }, | |
064997fb | 1839 | ); |
487cf647 | 1840 | ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate)); |
2b03887a FG |
1841 | } |
1842 | ||
1843 | // Check that all obligations are satisfied by the implementation's | |
1844 | // version. | |
1845 | let errors = ocx.select_all_or_error(); | |
1846 | if !errors.is_empty() { | |
353b0b11 | 1847 | let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); |
2b03887a FG |
1848 | return Err(reported); |
1849 | } | |
1850 | ||
1851 | // Finally, resolve all regions. This catches wily misuses of | |
1852 | // lifetime parameters. | |
353b0b11 FG |
1853 | let outlives_env = OutlivesEnvironment::new(param_env); |
1854 | ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env) | |
dfeec247 XL |
1855 | } |
1856 | ||
f035d41b XL |
1857 | /// Validate that `ProjectionCandidate`s created for this associated type will |
1858 | /// be valid. | |
1859 | /// | |
1860 | /// Usually given | |
1861 | /// | |
1862 | /// trait X { type Y: Copy } impl X for T { type Y = S; } | |
1863 | /// | |
1864 | /// We are able to normalize `<T as X>::U` to `S`, and so when we check the | |
1865 | /// impl is well-formed we have to prove `S: Copy`. | |
1866 | /// | |
1867 | /// For default associated types the normalization is not possible (the value | |
1868 | /// from the impl could be overridden). We also can't normalize generic | |
1869 | /// associated types (yet) because they contain bound parameters. | |
f2b60f7d | 1870 | #[instrument(level = "debug", skip(tcx))] |
9c376795 | 1871 | pub(super) fn check_type_bounds<'tcx>( |
f035d41b | 1872 | tcx: TyCtxt<'tcx>, |
9ffffee4 FG |
1873 | trait_ty: ty::AssocItem, |
1874 | impl_ty: ty::AssocItem, | |
f035d41b | 1875 | impl_trait_ref: ty::TraitRef<'tcx>, |
5e7ed085 | 1876 | ) -> Result<(), ErrorGuaranteed> { |
353b0b11 FG |
1877 | let param_env = tcx.param_env(impl_ty.def_id); |
1878 | let container_id = impl_ty.container_id(tcx); | |
f035d41b XL |
1879 | // Given |
1880 | // | |
1881 | // impl<A, B> Foo<u32> for (A, B) { | |
353b0b11 | 1882 | // type Bar<C> = Wrapper<A, B, C> |
f035d41b XL |
1883 | // } |
1884 | // | |
9ffffee4 | 1885 | // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>` |
353b0b11 FG |
1886 | // - `normalize_impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0) |
1887 | // - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>` | |
94222f64 XL |
1888 | // - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from |
1889 | // the *trait* with the generic associated type parameters (as bound vars). | |
1890 | // | |
1891 | // A note regarding the use of bound vars here: | |
1892 | // Imagine as an example | |
1893 | // ``` | |
1894 | // trait Family { | |
1895 | // type Member<C: Eq>; | |
1896 | // } | |
1897 | // | |
1898 | // impl Family for VecFamily { | |
1899 | // type Member<C: Eq> = i32; | |
1900 | // } | |
1901 | // ``` | |
1902 | // Here, we would generate | |
1903 | // ```notrust | |
1904 | // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) } | |
1905 | // ``` | |
1906 | // when we really would like to generate | |
1907 | // ```notrust | |
1908 | // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) } | |
1909 | // ``` | |
1910 | // But, this is probably fine, because although the first clause can be used with types C that | |
1911 | // do not implement Eq, for it to cause some kind of problem, there would have to be a | |
1912 | // VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type | |
1913 | // Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing | |
1914 | // elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in | |
1915 | // the trait (notably, that X: Eq and T: Family). | |
94222f64 | 1916 | let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = |
353b0b11 FG |
1917 | smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); |
1918 | // Extend the impl's identity substs with late-bound GAT vars | |
1919 | let normalize_impl_ty_substs = ty::InternalSubsts::identity_for_item(tcx, container_id) | |
1920 | .extend_to(tcx, impl_ty.def_id, |param, _| match param.kind { | |
1921 | GenericParamDefKind::Type { .. } => { | |
1922 | let kind = ty::BoundTyKind::Param(param.def_id, param.name); | |
1923 | let bound_var = ty::BoundVariableKind::Ty(kind); | |
1924 | bound_vars.push(bound_var); | |
1925 | tcx.mk_bound( | |
1926 | ty::INNERMOST, | |
1927 | ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, | |
1928 | ) | |
1929 | .into() | |
1930 | } | |
1931 | GenericParamDefKind::Lifetime => { | |
1932 | let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); | |
1933 | let bound_var = ty::BoundVariableKind::Region(kind); | |
1934 | bound_vars.push(bound_var); | |
1935 | tcx.mk_re_late_bound( | |
1936 | ty::INNERMOST, | |
1937 | ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, | |
1938 | ) | |
1939 | .into() | |
1940 | } | |
1941 | GenericParamDefKind::Const { .. } => { | |
1942 | let bound_var = ty::BoundVariableKind::Const; | |
1943 | bound_vars.push(bound_var); | |
1944 | tcx.mk_const( | |
1945 | ty::ConstKind::Bound( | |
1946 | ty::INNERMOST, | |
1947 | ty::BoundVar::from_usize(bound_vars.len() - 1), | |
1948 | ), | |
1949 | tcx.type_of(param.def_id) | |
1950 | .no_bound_vars() | |
1951 | .expect("const parameter types cannot be generic"), | |
1952 | ) | |
1953 | .into() | |
1954 | } | |
1955 | }); | |
3dfed10e | 1956 | // When checking something like |
f035d41b | 1957 | // |
3dfed10e XL |
1958 | // trait X { type Y: PartialEq<<Self as X>::Y> } |
1959 | // impl X for T { default type Y = S; } | |
f035d41b | 1960 | // |
3dfed10e XL |
1961 | // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case |
1962 | // we want <T as X>::Y to normalize to S. This is valid because we are | |
1963 | // checking the default value specifically here. Add this equality to the | |
1964 | // ParamEnv for normalization specifically. | |
353b0b11 FG |
1965 | let normalize_impl_ty = tcx.type_of(impl_ty.def_id).subst(tcx, normalize_impl_ty_substs); |
1966 | let rebased_substs = | |
1967 | normalize_impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs); | |
1968 | let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars); | |
3dfed10e XL |
1969 | let normalize_param_env = { |
1970 | let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>(); | |
353b0b11 | 1971 | match normalize_impl_ty.kind() { |
9c376795 FG |
1972 | ty::Alias(ty::Projection, proj) |
1973 | if proj.def_id == trait_ty.def_id && proj.substs == rebased_substs => | |
29967ef6 XL |
1974 | { |
1975 | // Don't include this predicate if the projected type is | |
1976 | // exactly the same as the projection. This can occur in | |
1977 | // (somewhat dubious) code like this: | |
1978 | // | |
1979 | // impl<T> X for T where T: X { type Y = <T as X>::Y; } | |
1980 | } | |
1981 | _ => predicates.push( | |
94222f64 XL |
1982 | ty::Binder::bind_with_vars( |
1983 | ty::ProjectionPredicate { | |
9c376795 | 1984 | projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs), |
353b0b11 | 1985 | term: normalize_impl_ty.into(), |
29967ef6 | 1986 | }, |
94222f64 XL |
1987 | bound_vars, |
1988 | ) | |
29967ef6 XL |
1989 | .to_predicate(tcx), |
1990 | ), | |
1991 | }; | |
9ffffee4 | 1992 | ty::ParamEnv::new(tcx.mk_predicates(&predicates), Reveal::UserFacing, param_env.constness()) |
f035d41b | 1993 | }; |
94222f64 XL |
1994 | debug!(?normalize_param_env); |
1995 | ||
9ffffee4 | 1996 | let impl_ty_def_id = impl_ty.def_id.expect_local(); |
94222f64 | 1997 | let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id); |
064997fb | 1998 | let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs); |
f035d41b | 1999 | |
2b03887a FG |
2000 | let infcx = tcx.infer_ctxt().build(); |
2001 | let ocx = ObligationCtxt::new(&infcx); | |
f035d41b | 2002 | |
353b0b11 FG |
2003 | // A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the |
2004 | // span for an impl's associated type. Instead, for these, use the def_span for the synthesized | |
2005 | // associated type. | |
2006 | let impl_ty_span = if tcx.opt_rpitit_info(impl_ty.def_id).is_some() { | |
2007 | tcx.def_span(impl_ty_def_id) | |
2008 | } else { | |
2009 | match tcx.hir().get_by_def_id(impl_ty_def_id) { | |
2010 | hir::Node::TraitItem(hir::TraitItem { | |
2011 | kind: hir::TraitItemKind::Type(_, Some(ty)), | |
2012 | .. | |
2013 | }) => ty.span, | |
2014 | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Type(ty), .. }) => ty.span, | |
2015 | _ => bug!(), | |
2016 | } | |
9ffffee4 FG |
2017 | }; |
2018 | let assumed_wf_types = ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty_def_id); | |
f2b60f7d | 2019 | |
2b03887a FG |
2020 | let normalize_cause = ObligationCause::new( |
2021 | impl_ty_span, | |
9ffffee4 | 2022 | impl_ty_def_id, |
2b03887a FG |
2023 | ObligationCauseCode::CheckAssociatedTypeBounds { |
2024 | impl_item_def_id: impl_ty.def_id.expect_local(), | |
2025 | trait_item_def_id: trait_ty.def_id, | |
2026 | }, | |
2027 | ); | |
2028 | let mk_cause = |span: Span| { | |
2029 | let code = if span.is_dummy() { | |
2030 | traits::ItemObligation(trait_ty.def_id) | |
2031 | } else { | |
2032 | traits::BindingObligation(trait_ty.def_id, span) | |
29967ef6 | 2033 | }; |
9ffffee4 | 2034 | ObligationCause::new(impl_ty_span, impl_ty_def_id, code) |
2b03887a | 2035 | }; |
f035d41b | 2036 | |
353b0b11 | 2037 | let obligations: Vec<_> = tcx |
49aad941 | 2038 | .explicit_item_bounds(trait_ty.def_id) |
2b03887a FG |
2039 | .subst_iter_copied(tcx, rebased_substs) |
2040 | .map(|(concrete_ty_bound, span)| { | |
2041 | debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound); | |
487cf647 | 2042 | traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound) |
2b03887a FG |
2043 | }) |
2044 | .collect(); | |
2045 | debug!("check_type_bounds: item_bounds={:?}", obligations); | |
2046 | ||
353b0b11 | 2047 | for mut obligation in util::elaborate(tcx, obligations) { |
487cf647 FG |
2048 | let normalized_predicate = |
2049 | ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate); | |
2b03887a FG |
2050 | debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); |
2051 | obligation.predicate = normalized_predicate; | |
f035d41b | 2052 | |
2b03887a FG |
2053 | ocx.register_obligation(obligation); |
2054 | } | |
2055 | // Check that all obligations are satisfied by the implementation's | |
2056 | // version. | |
2057 | let errors = ocx.select_all_or_error(); | |
2058 | if !errors.is_empty() { | |
353b0b11 | 2059 | let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); |
2b03887a FG |
2060 | return Err(reported); |
2061 | } | |
f035d41b | 2062 | |
2b03887a FG |
2063 | // Finally, resolve all regions. This catches wily misuses of |
2064 | // lifetime parameters. | |
9ffffee4 | 2065 | let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types); |
353b0b11 FG |
2066 | let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); |
2067 | ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env) | |
f035d41b XL |
2068 | } |
2069 | ||
dfeec247 XL |
2070 | fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str { |
2071 | match impl_item.kind { | |
2072 | ty::AssocKind::Const => "const", | |
ba9703b0 | 2073 | ty::AssocKind::Fn => "method", |
f035d41b | 2074 | ty::AssocKind::Type => "type", |
dfeec247 XL |
2075 | } |
2076 | } |