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