]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_typeck/src/check/compare_method.rs
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / compiler / rustc_typeck / src / check / compare_method.rs
CommitLineData
1b1a35ee 1use crate::errors::LifetimesOrBoundsMismatchOnTrait;
ba9703b0 2use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported};
dfeec247
XL
3use rustc_hir as hir;
4use rustc_hir::def::{DefKind, Res};
5use rustc_hir::intravisit;
6use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
74b04a01 7use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
29967ef6 8use rustc_infer::traits::util;
f035d41b 9use rustc_middle::ty;
ba9703b0 10use rustc_middle::ty::error::{ExpectedFound, TypeError};
3dfed10e 11use rustc_middle::ty::subst::{InternalSubsts, Subst};
ba9703b0 12use rustc_middle::ty::util::ExplicitSelf;
3dfed10e 13use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
dfeec247 14use rustc_span::Span;
ba9703b0
XL
15use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
16use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
85aaf69f 17
dfeec247 18use super::{potentially_plural_count, FnCtxt, Inherited};
60c5eb7d 19
85aaf69f
SL
20/// Checks that a method from an impl conforms to the signature of
21/// the same method as declared in the trait.
22///
23/// # Parameters
24///
9fa01778
XL
25/// - `impl_m`: type of the method we are checking
26/// - `impl_m_span`: span to use for reporting errors
27/// - `trait_m`: the method in the trait
28/// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
85aaf69f 29
dfeec247 30crate fn compare_impl_method<'tcx>(
dc9dc135
XL
31 tcx: TyCtxt<'tcx>,
32 impl_m: &ty::AssocItem,
33 impl_m_span: Span,
34 trait_m: &ty::AssocItem,
35 impl_trait_ref: ty::TraitRef<'tcx>,
36 trait_item_span: Option<Span>,
37) {
dfeec247 38 debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
85aaf69f 39
ba9703b0 40 let impl_m_span = tcx.sess.source_map().guess_head_span(impl_m_span);
2c00a5a8 41
dfeec247
XL
42 if let Err(ErrorReported) = compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
43 {
c30ab7b3 44 return;
85aaf69f
SL
45 }
46
dfeec247
XL
47 if let Err(ErrorReported) =
48 compare_number_of_generics(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
49 {
c30ab7b3
SL
50 return;
51 }
9e0c209e 52
dfeec247
XL
53 if let Err(ErrorReported) =
54 compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
55 {
85aaf69f
SL
56 return;
57 }
58
dfeec247 59 if let Err(ErrorReported) = compare_synthetic_generics(tcx, impl_m, trait_m) {
abe05a73
XL
60 return;
61 }
62
dfeec247
XL
63 if let Err(ErrorReported) =
64 compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
65 {
85aaf69f
SL
66 return;
67 }
c30ab7b3
SL
68}
69
dc9dc135
XL
70fn compare_predicate_entailment<'tcx>(
71 tcx: TyCtxt<'tcx>,
72 impl_m: &ty::AssocItem,
73 impl_m_span: Span,
74 trait_m: &ty::AssocItem,
75 impl_trait_ref: ty::TraitRef<'tcx>,
76) -> Result<(), ErrorReported> {
476ff2be
SL
77 let trait_to_impl_substs = impl_trait_ref.substs;
78
7cac9316
XL
79 // This node-id should be used for the `body_id` field on each
80 // `ObligationCause` (and the `FnCtxt`). This is what
81 // `regionck_item` expects.
3dfed10e 82 let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
7cac9316 83
f035d41b
XL
84 // We sometimes modify the span further down.
85 let mut cause = ObligationCause::new(
86 impl_m_span,
87 impl_m_hir_id,
88 ObligationCauseCode::CompareImplMethodObligation {
8faf50e0 89 item_name: impl_m.ident.name,
476ff2be
SL
90 impl_item_def_id: impl_m.def_id,
91 trait_item_def_id: trait_m.def_id,
476ff2be 92 },
f035d41b 93 );
85aaf69f
SL
94
95 // This code is best explained by example. Consider a trait:
96 //
f035d41b
XL
97 // trait Trait<'t, T> {
98 // fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
85aaf69f
SL
99 // }
100 //
101 // And an impl:
102 //
103 // impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
f035d41b 104 // fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
85aaf69f
SL
105 // }
106 //
107 // We wish to decide if those two method types are compatible.
108 //
109 // We start out with trait_to_impl_substs, that maps the trait
110 // type parameters to impl type parameters. This is taken from the
111 // impl trait reference:
112 //
113 // trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
114 //
115 // We create a mapping `dummy_substs` that maps from the impl type
116 // parameters to fresh types and regions. For type parameters,
117 // this is the identity transform, but we could as well use any
0bf4aa26 118 // placeholder types. For regions, we convert from bound to free
85aaf69f
SL
119 // regions (Note: but only early-bound regions, i.e., those
120 // declared on the impl or used in type parameter bounds).
121 //
f035d41b 122 // impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
85aaf69f 123 //
f035d41b 124 // Now we can apply placeholder_substs to the type of the impl method
0bf4aa26 125 // to yield a new function type in terms of our fresh, placeholder
85aaf69f
SL
126 // types:
127 //
128 // <'b> fn(t: &'i0 U0, m: &'b) -> Foo
129 //
130 // We now want to extract and substitute the type of the *trait*
131 // method and compare it. To do so, we must create a compound
132 // substitution by combining trait_to_impl_substs and
f035d41b 133 // impl_to_placeholder_substs, and also adding a mapping for the method
85aaf69f
SL
134 // type parameters. We extend the mapping to also include
135 // the method parameters.
136 //
f035d41b 137 // trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
85aaf69f
SL
138 //
139 // Applying this to the trait method type yields:
140 //
141 // <'a> fn(t: &'i0 U0, m: &'a) -> Foo
142 //
143 // This type is also the same but the name of the bound region ('a
144 // vs 'b). However, the normal subtyping rules on fn types handle
145 // this kind of equivalency just fine.
146 //
147 // We now use these substitutions to ensure that all declared bounds are
148 // satisfied by the implementation's method.
149 //
150 // We do this by creating a parameter environment which contains a
f035d41b
XL
151 // substitution corresponding to impl_to_placeholder_substs. We then build
152 // trait_to_placeholder_substs and use it to convert the predicates contained
0bf4aa26 153 // in the trait_m.generics to the placeholder form.
85aaf69f
SL
154 //
155 // Finally we register each of these predicates as an obligation in
156 // a fresh FulfillmentCtxt, and invoke select_all_or_error.
157
0bf4aa26 158 // Create mapping from impl to placeholder.
f035d41b 159 let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
85aaf69f 160
0bf4aa26 161 // Create mapping from trait to placeholder.
f035d41b
XL
162 let trait_to_placeholder_substs =
163 impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container.id(), trait_to_impl_substs);
164 debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
85aaf69f 165
7cac9316
XL
166 let impl_m_generics = tcx.generics_of(impl_m.def_id);
167 let trait_m_generics = tcx.generics_of(trait_m.def_id);
168 let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
169 let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
476ff2be 170
c30ab7b3 171 // Check region bounds.
dfeec247
XL
172 check_region_bounds_on_impl_item(
173 tcx,
174 impl_m_span,
175 impl_m,
176 trait_m,
177 &trait_m_generics,
178 &impl_m_generics,
179 )?;
c30ab7b3
SL
180
181 // Create obligations for each predicate declared by the impl
182 // definition in the context of the trait's parameter
183 // environment. We can't just use `impl_env.caller_bounds`,
184 // however, because we want to replace all late-bound regions with
185 // region variables.
7cac9316
XL
186 let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
187 let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
c30ab7b3
SL
188
189 debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
190
191 // This is the only tricky bit of the new way we check implementation methods
192 // We need to build a set of predicates where only the method-level bounds
193 // are from the trait and we assume all other bounds from the implementation
194 // to be previously satisfied.
195 //
196 // We then register the obligations from the impl_m and check to see
197 // if all constraints hold.
dfeec247
XL
198 hybrid_preds
199 .predicates
f035d41b 200 .extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates);
c30ab7b3 201
0bf4aa26 202 // Construct trait parameter environment and then shift it into the placeholder viewpoint.
c30ab7b3
SL
203 // The key step here is to update the caller_bounds's predicates to be
204 // the new hybrid bounds we computed.
9fa01778 205 let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
1b1a35ee
XL
206 let param_env =
207 ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
dfeec247
XL
208 let param_env = traits::normalize_param_env_or_error(
209 tcx,
210 impl_m.def_id,
211 param_env,
212 normalize_cause.clone(),
0731742a 213 );
7cac9316 214
041b39d2 215 tcx.infer_ctxt().enter(|infcx| {
ba9703b0 216 let inh = Inherited::new(infcx, impl_m.def_id.expect_local());
c30ab7b3 217 let infcx = &inh.infcx;
a7813a04 218
f035d41b 219 debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
a7813a04
XL
220
221 let mut selcx = traits::SelectionContext::new(&infcx);
222
f035d41b 223 let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
a1dfa0c6 224 let (impl_m_own_bounds, _) = infcx.replace_bound_vars_with_fresh_vars(
83c7162d
XL
225 impl_m_span,
226 infer::HigherRankedType,
fc512014 227 ty::Binder::bind(impl_m_own_bounds.predicates),
83c7162d 228 );
9e0c209e 229 for predicate in impl_m_own_bounds {
cc61c64b 230 let traits::Normalized { value: predicate, obligations } =
fc512014 231 traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate);
a7813a04 232
cc61c64b 233 inh.register_predicates(obligations);
7cac9316 234 inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate));
a7813a04 235 }
85aaf69f 236
a7813a04
XL
237 // We now need to check that the signature of the impl method is
238 // compatible with that of the trait method. We do this by
239 // checking that `impl_fty <: trait_fty`.
240 //
241 // FIXME. Unfortunately, this doesn't quite work right now because
242 // associated type normalization is not integrated into subtype
243 // checks. For the comparison to be valid, we need to
244 // normalize the associated types in the impl/trait methods
245 // first. However, because function types bind regions, just
246 // calling `normalize_associated_types_in` would have no effect on
247 // any associated types appearing in the fn arguments or return
248 // type.
249
0bf4aa26 250 // Compute placeholder form of impl and trait method tys.
3157f602 251 let tcx = infcx.tcx;
476ff2be 252
a1dfa0c6
XL
253 let (impl_sig, _) = infcx.replace_bound_vars_with_fresh_vars(
254 impl_m_span,
255 infer::HigherRankedType,
fc512014 256 tcx.fn_sig(impl_m.def_id),
a1dfa0c6 257 );
3157f602 258 let impl_sig =
fc512014 259 inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, impl_sig);
83c7162d 260 let impl_fty = tcx.mk_fn_ptr(ty::Binder::bind(impl_sig));
3157f602
XL
261 debug!("compare_impl_method: impl_fty={:?}", impl_fty);
262
fc512014 263 let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id));
f035d41b 264 let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
3157f602 265 let trait_sig =
fc512014 266 inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig);
83c7162d 267 let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig));
3157f602
XL
268
269 debug!("compare_impl_method: trait_fty={:?}", trait_fty);
270
dfeec247
XL
271 let sub_result = infcx.at(&cause, param_env).sup(trait_fty, impl_fty).map(
272 |InferOk { obligations, .. }| {
273 inh.register_predicates(obligations);
274 },
275 );
c30ab7b3
SL
276
277 if let Err(terr) = sub_result {
dfeec247
XL
278 debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
279
280 let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(
281 &infcx, param_env, &terr, &cause, impl_m, impl_sig, trait_m, trait_sig,
282 );
283
f035d41b 284 cause.make_mut().span = impl_err_span;
dfeec247
XL
285
286 let mut diag = struct_span_err!(
287 tcx.sess,
288 cause.span(tcx),
289 E0053,
290 "method `{}` has an incompatible type for trait",
291 trait_m.ident
292 );
8faf50e0
XL
293 if let TypeError::Mutability = terr {
294 if let Some(trait_err_span) = trait_err_span {
dfeec247
XL
295 if let Ok(trait_err_str) = tcx.sess.source_map().span_to_snippet(trait_err_span)
296 {
9fa01778 297 diag.span_suggestion(
8faf50e0 298 impl_err_span,
5869c6ff 299 "consider changing the mutability to match the trait",
0bf4aa26
XL
300 trait_err_str,
301 Applicability::MachineApplicable,
8faf50e0
XL
302 );
303 }
304 }
305 }
c30ab7b3 306
dfeec247
XL
307 infcx.note_type_err(
308 &mut diag,
309 &cause,
310 trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
311 Some(infer::ValuePairs::Types(ExpectedFound {
312 expected: trait_fty,
313 found: impl_fty,
314 })),
315 &terr,
316 );
5bcae85e 317 diag.emit();
c30ab7b3 318 return Err(ErrorReported);
a7813a04 319 }
85aaf69f 320
a7813a04
XL
321 // Check that all obligations are satisfied by the implementation's
322 // version.
cc61c64b 323 if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
0531ce1d 324 infcx.report_fulfillment_errors(errors, None, false);
c30ab7b3 325 return Err(ErrorReported);
85aaf69f 326 }
85aaf69f 327
a7813a04 328 // Finally, resolve all regions. This catches wily misuses of
c30ab7b3 329 // lifetime parameters.
9fa01778 330 let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id);
29967ef6 331 fcx.regionck_item(impl_m_hir_id, impl_m_span, trait_sig.inputs_and_output);
85aaf69f 332
c30ab7b3
SL
333 Ok(())
334 })
335}
336
dfeec247 337fn check_region_bounds_on_impl_item<'tcx>(
dc9dc135
XL
338 tcx: TyCtxt<'tcx>,
339 span: Span,
340 impl_m: &ty::AssocItem,
341 trait_m: &ty::AssocItem,
342 trait_generics: &ty::Generics,
343 impl_generics: &ty::Generics,
dc9dc135 344) -> Result<(), ErrorReported> {
94b46f34
XL
345 let trait_params = trait_generics.own_counts().lifetimes;
346 let impl_params = impl_generics.own_counts().lifetimes;
c30ab7b3 347
dfeec247
XL
348 debug!(
349 "check_region_bounds_on_impl_item: \
c30ab7b3 350 trait_generics={:?} \
dfeec247
XL
351 impl_generics={:?}",
352 trait_generics, impl_generics
353 );
c30ab7b3
SL
354
355 // Must have same number of early-bound lifetime parameters.
356 // Unfortunately, if the user screws up the bounds, then this
357 // will change classification between early and late. E.g.,
358 // if in trait we have `<'a,'b:'a>`, and in impl we just have
359 // `<'a,'b>`, then we have 2 early-bound lifetime parameters
360 // in trait but 0 in the impl. But if we report "expected 2
361 // but found 0" it's confusing, because it looks like there
362 // are zero. Since I don't quite know how to phrase things at
363 // the moment, give a kind of vague error message.
94b46f34 364 if trait_params != impl_params {
dfeec247 365 let item_kind = assoc_item_kind_str(impl_m);
ba9703b0 366 let def_span = tcx.sess.source_map().guess_head_span(span);
5869c6ff
XL
367 let span = tcx.hir().get_generics(impl_m.def_id).map_or(def_span, |g| g.span);
368 let generics_span = tcx.hir().span_if_local(trait_m.def_id).map(|sp| {
1b1a35ee 369 let def_sp = tcx.sess.source_map().guess_head_span(sp);
5869c6ff
XL
370 tcx.hir().get_generics(trait_m.def_id).map_or(def_sp, |g| g.span)
371 });
372
1b1a35ee 373 tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait {
8faf50e0 374 span,
dfeec247 375 item_kind,
1b1a35ee
XL
376 ident: impl_m.ident,
377 generics_span,
378 });
c30ab7b3 379 return Err(ErrorReported);
85aaf69f 380 }
9e0c209e 381
0bf4aa26 382 Ok(())
c30ab7b3 383}
9e0c209e 384
dc9dc135
XL
385fn extract_spans_for_error_reporting<'a, 'tcx>(
386 infcx: &infer::InferCtxt<'a, 'tcx>,
387 param_env: ty::ParamEnv<'tcx>,
388 terr: &TypeError<'_>,
389 cause: &ObligationCause<'tcx>,
390 impl_m: &ty::AssocItem,
391 impl_sig: ty::FnSig<'tcx>,
392 trait_m: &ty::AssocItem,
393 trait_sig: ty::FnSig<'tcx>,
394) -> (Span, Option<Span>) {
c30ab7b3 395 let tcx = infcx.tcx;
3dfed10e 396 let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
dfeec247 397 let (impl_m_output, impl_m_iter) = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
ba9703b0 398 ImplItemKind::Fn(ref impl_m_sig, _) => {
c30ab7b3
SL
399 (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter())
400 }
401 _ => bug!("{:?} is not a method", impl_m),
402 };
403
404 match *terr {
405 TypeError::Mutability => {
f9f354fc 406 if let Some(def_id) = trait_m.def_id.as_local() {
3dfed10e 407 let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
dfeec247 408 let trait_m_iter = match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
ba9703b0
XL
409 TraitItemKind::Fn(ref trait_m_sig, _) => trait_m_sig.decl.inputs.iter(),
410 _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
c30ab7b3
SL
411 };
412
dfeec247
XL
413 impl_m_iter
414 .zip(trait_m_iter)
415 .find(|&(ref impl_arg, ref trait_arg)| {
416 match (&impl_arg.kind, &trait_arg.kind) {
417 (
418 &hir::TyKind::Rptr(_, ref impl_mt),
419 &hir::TyKind::Rptr(_, ref trait_mt),
420 )
421 | (&hir::TyKind::Ptr(ref impl_mt), &hir::TyKind::Ptr(ref trait_mt)) => {
422 impl_mt.mutbl != trait_mt.mutbl
423 }
424 _ => false,
32a655c1 425 }
dfeec247
XL
426 })
427 .map(|(ref impl_arg, ref trait_arg)| (impl_arg.span, Some(trait_arg.span)))
428 .unwrap_or_else(|| (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)))
c30ab7b3 429 } else {
48663c56 430 (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
c30ab7b3
SL
431 }
432 }
433 TypeError::Sorts(ExpectedFound { .. }) => {
f9f354fc 434 if let Some(def_id) = trait_m.def_id.as_local() {
3dfed10e 435 let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
c30ab7b3 436 let (trait_m_output, trait_m_iter) =
e74abb32 437 match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
ba9703b0 438 TraitItemKind::Fn(ref trait_m_sig, _) => {
c30ab7b3
SL
439 (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
440 }
ba9703b0 441 _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
9e0c209e
SL
442 };
443
476ff2be
SL
444 let impl_iter = impl_sig.inputs().iter();
445 let trait_iter = trait_sig.inputs().iter();
dfeec247
XL
446 impl_iter
447 .zip(trait_iter)
448 .zip(impl_m_iter)
449 .zip(trait_m_iter)
f9f354fc
XL
450 .find_map(|(((&impl_arg_ty, &trait_arg_ty), impl_arg), trait_arg)| match infcx
451 .at(&cause, param_env)
452 .sub(trait_arg_ty, impl_arg_ty)
453 {
454 Ok(_) => None,
455 Err(_) => Some((impl_arg.span, Some(trait_arg.span))),
456 })
dfeec247
XL
457 .unwrap_or_else(|| {
458 if infcx
459 .at(&cause, param_env)
460 .sup(trait_sig.output(), impl_sig.output())
461 .is_err()
462 {
463 (impl_m_output.span(), Some(trait_m_output.span()))
464 } else {
465 (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
466 }
467 })
c30ab7b3 468 } else {
48663c56 469 (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
c30ab7b3
SL
470 }
471 }
48663c56 472 _ => (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)),
c30ab7b3
SL
473 }
474}
475
dc9dc135
XL
476fn compare_self_type<'tcx>(
477 tcx: TyCtxt<'tcx>,
478 impl_m: &ty::AssocItem,
479 impl_m_span: Span,
480 trait_m: &ty::AssocItem,
481 impl_trait_ref: ty::TraitRef<'tcx>,
482) -> Result<(), ErrorReported> {
c30ab7b3
SL
483 // Try to give more informative error messages about self typing
484 // mismatches. Note that any mismatch will also be detected
485 // below, where we construct a canonical function type that
486 // includes the self parameter as a normal parameter. It's just
487 // that the error messages you get out of this code are a bit more
488 // inscrutable, particularly for cases where one method has no
489 // self.
476ff2be 490
dc9dc135 491 let self_string = |method: &ty::AssocItem| {
476ff2be
SL
492 let untransformed_self_ty = match method.container {
493 ty::ImplContainer(_) => impl_trait_ref.self_ty(),
dfeec247 494 ty::TraitContainer(_) => tcx.types.self_param,
476ff2be 495 };
fc512014 496 let self_arg_ty = tcx.fn_sig(method.def_id).input(0);
0531ce1d 497 let param_env = ty::ParamEnv::reveal_all();
abe05a73
XL
498
499 tcx.infer_ctxt().enter(|infcx| {
fc512014 500 let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
abe05a73
XL
501 let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
502 match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
0bf4aa26 503 ExplicitSelf::ByValue => "self".to_owned(),
dfeec247
XL
504 ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
505 ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
506 _ => format!("self: {}", self_arg_ty),
abe05a73
XL
507 }
508 })
476ff2be
SL
509 };
510
ba9703b0 511 match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
476ff2be
SL
512 (false, false) | (true, true) => {}
513
514 (false, true) => {
515 let self_descr = self_string(impl_m);
dfeec247
XL
516 let mut err = struct_span_err!(
517 tcx.sess,
518 impl_m_span,
519 E0185,
520 "method `{}` has a `{}` declaration in the impl, but \
c30ab7b3 521 not in the trait",
dfeec247
XL
522 trait_m.ident,
523 self_descr
524 );
7cac9316 525 err.span_label(impl_m_span, format!("`{}` used in impl", self_descr));
0731742a 526 if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
2c00a5a8
XL
527 err.span_label(span, format!("trait method declared without `{}`", self_descr));
528 } else {
dfeec247 529 err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx));
c30ab7b3
SL
530 }
531 err.emit();
532 return Err(ErrorReported);
533 }
476ff2be
SL
534
535 (true, false) => {
536 let self_descr = self_string(trait_m);
dfeec247
XL
537 let mut err = struct_span_err!(
538 tcx.sess,
539 impl_m_span,
540 E0186,
541 "method `{}` has a `{}` declaration in the trait, but \
c30ab7b3 542 not in the impl",
dfeec247
XL
543 trait_m.ident,
544 self_descr
545 );
2c00a5a8 546 err.span_label(impl_m_span, format!("expected `{}` in impl", self_descr));
0731742a 547 if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
7cac9316
XL
548 err.span_label(span, format!("`{}` used in trait", self_descr));
549 } else {
dfeec247 550 err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx));
c30ab7b3
SL
551 }
552 err.emit();
553 return Err(ErrorReported);
554 }
c30ab7b3
SL
555 }
556
557 Ok(())
558}
559
dc9dc135
XL
560fn compare_number_of_generics<'tcx>(
561 tcx: TyCtxt<'tcx>,
562 impl_: &ty::AssocItem,
563 _impl_span: Span,
564 trait_: &ty::AssocItem,
532ac7d7
XL
565 trait_span: Option<Span>,
566) -> Result<(), ErrorReported> {
567 let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
568 let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();
569
570 let matchings = [
571 ("type", trait_own_counts.types, impl_own_counts.types),
572 ("const", trait_own_counts.consts, impl_own_counts.consts),
573 ];
574
dfeec247
XL
575 let item_kind = assoc_item_kind_str(impl_);
576
532ac7d7
XL
577 let mut err_occurred = false;
578 for &(kind, trait_count, impl_count) in &matchings {
579 if impl_count != trait_count {
580 err_occurred = true;
581
f9f354fc 582 let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
3dfed10e 583 let trait_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
f9f354fc
XL
584 let trait_item = tcx.hir().expect_trait_item(trait_hir_id);
585 if trait_item.generics.params.is_empty() {
586 (Some(vec![trait_item.generics.span]), vec![])
dc9dc135 587 } else {
f9f354fc
XL
588 let arg_spans: Vec<Span> =
589 trait_item.generics.params.iter().map(|p| p.span).collect();
590 let impl_trait_spans: Vec<Span> = trait_item
591 .generics
592 .params
593 .iter()
594 .filter_map(|p| match p.kind {
595 GenericParamKind::Type {
596 synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
597 ..
598 } => Some(p.span),
599 _ => None,
600 })
601 .collect();
602 (Some(arg_spans), impl_trait_spans)
603 }
604 } else {
605 (trait_span.map(|s| vec![s]), vec![])
606 };
9e0c209e 607
3dfed10e 608 let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_.def_id.expect_local());
dc9dc135 609 let impl_item = tcx.hir().expect_impl_item(impl_hir_id);
dfeec247
XL
610 let impl_item_impl_trait_spans: Vec<Span> = impl_item
611 .generics
612 .params
613 .iter()
dc9dc135
XL
614 .filter_map(|p| match p.kind {
615 GenericParamKind::Type {
dfeec247
XL
616 synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
617 ..
dc9dc135
XL
618 } => Some(p.span),
619 _ => None,
dfeec247
XL
620 })
621 .collect();
dc9dc135
XL
622 let spans = impl_item.generics.spans();
623 let span = spans.primary_span();
624
532ac7d7 625 let mut err = tcx.sess.struct_span_err_with_code(
dc9dc135 626 spans,
532ac7d7 627 &format!(
dfeec247 628 "{} `{}` has {} {kind} parameter{} but its trait \
532ac7d7 629 declaration has {} {kind} parameter{}",
dfeec247 630 item_kind,
532ac7d7
XL
631 trait_.ident,
632 impl_count,
60c5eb7d 633 pluralize!(impl_count),
532ac7d7 634 trait_count,
60c5eb7d 635 pluralize!(trait_count),
532ac7d7
XL
636 kind = kind,
637 ),
638 DiagnosticId::Error("E0049".into()),
639 );
c30ab7b3 640
532ac7d7 641 let mut suffix = None;
c30ab7b3 642
dc9dc135
XL
643 if let Some(spans) = trait_spans {
644 let mut spans = spans.iter();
645 if let Some(span) = spans.next() {
dfeec247
XL
646 err.span_label(
647 *span,
648 format!(
649 "expected {} {} parameter{}",
650 trait_count,
651 kind,
652 pluralize!(trait_count),
653 ),
654 );
dc9dc135
XL
655 }
656 for span in spans {
657 err.span_label(*span, "");
658 }
532ac7d7
XL
659 } else {
660 suffix = Some(format!(", expected {}", trait_count));
661 }
c30ab7b3 662
dc9dc135 663 if let Some(span) = span {
dfeec247
XL
664 err.span_label(
665 span,
666 format!(
667 "found {} {} parameter{}{}",
668 impl_count,
669 kind,
670 pluralize!(impl_count),
ba9703b0 671 suffix.unwrap_or_else(String::new),
dfeec247
XL
672 ),
673 );
dc9dc135
XL
674 }
675
676 for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) {
677 err.span_label(*span, "`impl Trait` introduces an implicit type parameter");
678 }
c30ab7b3 679
532ac7d7
XL
680 err.emit();
681 }
c30ab7b3
SL
682 }
683
dfeec247 684 if err_occurred { Err(ErrorReported) } else { Ok(()) }
c30ab7b3
SL
685}
686
dc9dc135
XL
687fn compare_number_of_method_arguments<'tcx>(
688 tcx: TyCtxt<'tcx>,
689 impl_m: &ty::AssocItem,
690 impl_m_span: Span,
691 trait_m: &ty::AssocItem,
692 trait_item_span: Option<Span>,
693) -> Result<(), ErrorReported> {
041b39d2
XL
694 let impl_m_fty = tcx.fn_sig(impl_m.def_id);
695 let trait_m_fty = tcx.fn_sig(trait_m.def_id);
8bb4bdeb
XL
696 let trait_number_args = trait_m_fty.inputs().skip_binder().len();
697 let impl_number_args = impl_m_fty.inputs().skip_binder().len();
476ff2be 698 if trait_number_args != impl_number_args {
f9f354fc 699 let trait_span = if let Some(def_id) = trait_m.def_id.as_local() {
3dfed10e 700 let trait_id = tcx.hir().local_def_id_to_hir_id(def_id);
e74abb32 701 match tcx.hir().expect_trait_item(trait_id).kind {
ba9703b0 702 TraitItemKind::Fn(ref trait_m_sig, _) => {
dfeec247 703 let pos = if trait_number_args > 0 { trait_number_args - 1 } else { 0 };
0731742a
XL
704 if let Some(arg) = trait_m_sig.decl.inputs.get(pos) {
705 Some(if pos == 0 {
706 arg.span
707 } else {
dfeec247
XL
708 Span::new(
709 trait_m_sig.decl.inputs[0].span.lo(),
710 arg.span.hi(),
711 arg.span.ctxt(),
712 )
0731742a 713 })
c30ab7b3
SL
714 } else {
715 trait_item_span
716 }
717 }
718 _ => bug!("{:?} is not a method", impl_m),
719 }
720 } else {
721 trait_item_span
722 };
3dfed10e 723 let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
e74abb32 724 let impl_span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
ba9703b0 725 ImplItemKind::Fn(ref impl_m_sig, _) => {
dfeec247 726 let pos = if impl_number_args > 0 { impl_number_args - 1 } else { 0 };
0731742a
XL
727 if let Some(arg) = impl_m_sig.decl.inputs.get(pos) {
728 if pos == 0 {
729 arg.span
730 } else {
dfeec247
XL
731 Span::new(
732 impl_m_sig.decl.inputs[0].span.lo(),
733 arg.span.hi(),
734 arg.span.ctxt(),
735 )
0731742a 736 }
9e0c209e 737 } else {
c30ab7b3 738 impl_m_span
9e0c209e
SL
739 }
740 }
c30ab7b3
SL
741 _ => bug!("{:?} is not a method", impl_m),
742 };
dfeec247
XL
743 let mut err = struct_span_err!(
744 tcx.sess,
745 impl_span,
746 E0050,
747 "method `{}` has {} but the declaration in \
c30ab7b3 748 trait `{}` has {}",
dfeec247
XL
749 trait_m.ident,
750 potentially_plural_count(impl_number_args, "parameter"),
751 tcx.def_path_str(trait_m.def_id),
752 trait_number_args
753 );
c30ab7b3 754 if let Some(trait_span) = trait_span {
dfeec247
XL
755 err.span_label(
756 trait_span,
757 format!(
758 "trait requires {}",
759 potentially_plural_count(trait_number_args, "parameter")
760 ),
761 );
7cac9316 762 } else {
dfeec247 763 err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx));
9e0c209e 764 }
dfeec247
XL
765 err.span_label(
766 impl_span,
767 format!(
768 "expected {}, found {}",
769 potentially_plural_count(trait_number_args, "parameter"),
770 impl_number_args
771 ),
772 );
c30ab7b3
SL
773 err.emit();
774 return Err(ErrorReported);
9e0c209e 775 }
c30ab7b3
SL
776
777 Ok(())
85aaf69f 778}
d9579d0f 779
dc9dc135
XL
780fn compare_synthetic_generics<'tcx>(
781 tcx: TyCtxt<'tcx>,
782 impl_m: &ty::AssocItem,
783 trait_m: &ty::AssocItem,
784) -> Result<(), ErrorReported> {
abe05a73 785 // FIXME(chrisvittal) Clean up this function, list of FIXME items:
94b46f34 786 // 1. Better messages for the span labels
abe05a73 787 // 2. Explanation as to what is going on
abe05a73
XL
788 // If we get here, we already have the same number of generics, so the zip will
789 // be okay.
790 let mut error_found = false;
791 let impl_m_generics = tcx.generics_of(impl_m.def_id);
792 let trait_m_generics = tcx.generics_of(trait_m.def_id);
8faf50e0
XL
793 let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind {
794 GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
532ac7d7 795 GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None,
94b46f34 796 });
dfeec247
XL
797 let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| match param.kind {
798 GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
799 GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None,
94b46f34 800 });
dfeec247
XL
801 for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) in
802 impl_m_type_params.zip(trait_m_type_params)
0bf4aa26 803 {
94b46f34 804 if impl_synthetic != trait_synthetic {
3dfed10e 805 let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id.expect_local());
dc9dc135 806 let impl_span = tcx.hir().span(impl_hir_id);
94b46f34 807 let trait_span = tcx.def_span(trait_def_id);
dfeec247
XL
808 let mut err = struct_span_err!(
809 tcx.sess,
810 impl_span,
811 E0643,
812 "method `{}` has incompatible signature for trait",
813 trait_m.ident
814 );
94b46f34
XL
815 err.span_label(trait_span, "declaration in trait here");
816 match (impl_synthetic, trait_synthetic) {
817 // The case where the impl method uses `impl Trait` but the trait method uses
818 // explicit generics
819 (Some(hir::SyntheticTyParamKind::ImplTrait), None) => {
820 err.span_label(impl_span, "expected generic parameter, found `impl Trait`");
821 (|| {
822 // try taking the name from the trait impl
823 // FIXME: this is obviously suboptimal since the name can already be used
824 // as another generic argument
dfeec247 825 let new_name = tcx.sess.source_map().span_to_snippet(trait_span).ok()?;
6a06907d
XL
826 let trait_m = trait_m.def_id.as_local()?;
827 let trait_m = tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m });
94b46f34 828
6a06907d
XL
829 let impl_m = impl_m.def_id.as_local()?;
830 let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m });
94b46f34
XL
831
832 // in case there are no generics, take the spot between the function name
833 // and the opening paren of the argument list
dfeec247
XL
834 let new_generics_span =
835 tcx.sess.source_map().generate_fn_name_span(impl_span)?.shrink_to_hi();
94b46f34 836 // in case there are generics, just replace them
dfeec247
XL
837 let generics_span =
838 impl_m.generics.span.substitute_dummy(new_generics_span);
94b46f34 839 // replace with the generics from the trait
dfeec247
XL
840 let new_generics =
841 tcx.sess.source_map().span_to_snippet(trait_m.generics.span).ok()?;
94b46f34 842
9fa01778 843 err.multipart_suggestion(
94b46f34
XL
844 "try changing the `impl Trait` argument to a generic parameter",
845 vec![
846 // replace `impl Trait` with `T`
847 (impl_span, new_name),
848 // replace impl method generics with trait method generics
849 // This isn't quite right, as users might have changed the names
850 // of the generics, but it works for the common case
851 (generics_span, new_generics),
852 ],
0bf4aa26 853 Applicability::MaybeIncorrect,
94b46f34
XL
854 );
855 Some(())
856 })();
dfeec247 857 }
94b46f34
XL
858 // The case where the trait method uses `impl Trait`, but the impl method uses
859 // explicit generics.
860 (None, Some(hir::SyntheticTyParamKind::ImplTrait)) => {
861 err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
862 (|| {
6a06907d
XL
863 let impl_m = impl_m.def_id.as_local()?;
864 let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m });
e74abb32 865 let input_tys = match impl_m.kind {
ba9703b0 866 hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
94b46f34
XL
867 _ => unreachable!(),
868 };
869 struct Visitor(Option<Span>, hir::def_id::DefId);
dfeec247
XL
870 impl<'v> intravisit::Visitor<'v> for Visitor {
871 fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
872 intravisit::walk_ty(self, ty);
873 if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) =
874 ty.kind
0bf4aa26 875 {
48663c56 876 if let Res::Def(DefKind::TyParam, def_id) = path.res {
0bf4aa26
XL
877 if def_id == self.1 {
878 self.0 = Some(ty.span);
94b46f34 879 }
0bf4aa26 880 }
94b46f34
XL
881 }
882 }
ba9703b0 883 type Map = intravisit::ErasedMap<'v>;
dfeec247
XL
884 fn nested_visit_map(
885 &mut self,
ba9703b0 886 ) -> intravisit::NestedVisitorMap<Self::Map>
dfeec247
XL
887 {
888 intravisit::NestedVisitorMap::None
94b46f34
XL
889 }
890 }
891 let mut visitor = Visitor(None, impl_def_id);
892 for ty in input_tys {
dfeec247 893 intravisit::Visitor::visit_ty(&mut visitor, ty);
94b46f34
XL
894 }
895 let span = visitor.0?;
896
dfeec247
XL
897 let bounds =
898 impl_m.generics.params.iter().find_map(|param| match param.kind {
8faf50e0 899 GenericParamKind::Lifetime { .. } => None,
dfeec247 900 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
9fa01778 901 if param.hir_id == impl_hir_id {
8faf50e0 902 Some(&param.bounds)
94b46f34
XL
903 } else {
904 None
905 }
8faf50e0 906 }
dfeec247 907 })?;
8faf50e0 908 let bounds = bounds.first()?.span().to(bounds.last()?.span());
dfeec247 909 let bounds = tcx.sess.source_map().span_to_snippet(bounds).ok()?;
94b46f34 910
9fa01778 911 err.multipart_suggestion(
94b46f34
XL
912 "try removing the generic parameter and using `impl Trait` instead",
913 vec![
914 // delete generic parameters
915 (impl_m.generics.span, String::new()),
916 // replace param usage with `impl Trait`
917 (span, format!("impl {}", bounds)),
918 ],
0bf4aa26 919 Applicability::MaybeIncorrect,
94b46f34
XL
920 );
921 Some(())
922 })();
dfeec247 923 }
94b46f34
XL
924 _ => unreachable!(),
925 }
abe05a73
XL
926 err.emit();
927 error_found = true;
928 }
929 }
dfeec247 930 if error_found { Err(ErrorReported) } else { Ok(()) }
abe05a73
XL
931}
932
dfeec247 933crate fn compare_const_impl<'tcx>(
dc9dc135
XL
934 tcx: TyCtxt<'tcx>,
935 impl_c: &ty::AssocItem,
936 impl_c_span: Span,
937 trait_c: &ty::AssocItem,
938 impl_trait_ref: ty::TraitRef<'tcx>,
939) {
c30ab7b3 940 debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
d9579d0f 941
041b39d2 942 tcx.infer_ctxt().enter(|infcx| {
532ac7d7 943 let param_env = tcx.param_env(impl_c.def_id);
ba9703b0 944 let inh = Inherited::new(infcx, impl_c.def_id.expect_local());
cc61c64b 945 let infcx = &inh.infcx;
a7813a04
XL
946
947 // The below is for the most part highly similar to the procedure
948 // for methods above. It is simpler in many respects, especially
949 // because we shouldn't really have to deal with lifetimes or
950 // predicates. In fact some of this should probably be put into
951 // shared functions because of DRY violations...
476ff2be 952 let trait_to_impl_substs = impl_trait_ref.substs;
a7813a04
XL
953
954 // Create a parameter environment that represents the implementation's
955 // method.
3dfed10e 956 let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_c.def_id.expect_local());
a7813a04 957
0bf4aa26 958 // Compute placeholder form of impl and trait const tys.
7cac9316
XL
959 let impl_ty = tcx.type_of(impl_c.def_id);
960 let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
f035d41b
XL
961 let mut cause = ObligationCause::new(
962 impl_c_span,
963 impl_c_hir_id,
964 ObligationCauseCode::CompareImplConstObligation,
965 );
a7813a04 966
cc61c64b 967 // There is no "body" here, so just pass dummy id.
dfeec247 968 let impl_ty =
fc512014 969 inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, impl_ty);
c30ab7b3 970
cc61c64b 971 debug!("compare_const_impl: impl_ty={:?}", impl_ty);
c30ab7b3 972
dfeec247 973 let trait_ty =
fc512014 974 inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, trait_ty);
c30ab7b3 975
cc61c64b 976 debug!("compare_const_impl: trait_ty={:?}", trait_ty);
a7813a04 977
dfeec247
XL
978 let err = infcx
979 .at(&cause, param_env)
980 .sup(trait_ty, impl_ty)
981 .map(|ok| inh.register_infer_ok_obligations(ok));
d9579d0f 982
a7813a04 983 if let Err(terr) = err {
dfeec247
XL
984 debug!(
985 "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
986 impl_ty, trait_ty
987 );
5bcae85e
SL
988
989 // Locate the Span containing just the type of the offending impl
e74abb32 990 match tcx.hir().expect_impl_item(impl_c_hir_id).kind {
f035d41b 991 ImplItemKind::Const(ref ty, _) => cause.make_mut().span = ty.span,
c30ab7b3 992 _ => bug!("{:?} is not a impl const", impl_c),
5bcae85e
SL
993 }
994
dfeec247
XL
995 let mut diag = struct_span_err!(
996 tcx.sess,
997 cause.span,
998 E0326,
999 "implemented const `{}` has an incompatible type for \
c30ab7b3 1000 trait",
dfeec247
XL
1001 trait_c.ident
1002 );
5bcae85e 1003
f9f354fc 1004 let trait_c_hir_id =
3dfed10e 1005 trait_c.def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
532ac7d7 1006 let trait_c_span = trait_c_hir_id.map(|trait_c_hir_id| {
7cac9316 1007 // Add a label to the Span containing just the type of the const
e74abb32 1008 match tcx.hir().expect_trait_item(trait_c_hir_id).kind {
7cac9316
XL
1009 TraitItemKind::Const(ref ty, _) => ty.span,
1010 _ => bug!("{:?} is not a trait const", trait_c),
1011 }
1012 });
5bcae85e 1013
dfeec247
XL
1014 infcx.note_type_err(
1015 &mut diag,
1016 &cause,
1017 trait_c_span.map(|span| (span, "type in trait".to_owned())),
1018 Some(infer::ValuePairs::Types(ExpectedFound {
1019 expected: trait_ty,
1020 found: impl_ty,
1021 })),
1022 &terr,
1023 );
5bcae85e 1024 diag.emit();
d9579d0f 1025 }
cc61c64b 1026
7cac9316
XL
1027 // Check that all obligations are satisfied by the implementation's
1028 // version.
1029 if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
0531ce1d 1030 infcx.report_fulfillment_errors(errors, None, false);
7cac9316
XL
1031 return;
1032 }
1033
9fa01778
XL
1034 let fcx = FnCtxt::new(&inh, param_env, impl_c_hir_id);
1035 fcx.regionck_item(impl_c_hir_id, impl_c_span, &[]);
a7813a04 1036 });
d9579d0f 1037}
dfeec247
XL
1038
1039crate fn compare_ty_impl<'tcx>(
1040 tcx: TyCtxt<'tcx>,
1041 impl_ty: &ty::AssocItem,
1042 impl_ty_span: Span,
1043 trait_ty: &ty::AssocItem,
1044 impl_trait_ref: ty::TraitRef<'tcx>,
1045 trait_item_span: Option<Span>,
1046) {
1047 debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);
1048
1049 let _: Result<(), ErrorReported> = (|| {
1050 compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;
1051
f035d41b
XL
1052 compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)?;
1053
29967ef6 1054 check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
dfeec247
XL
1055 })();
1056}
1057
1058/// The equivalent of [compare_predicate_entailment], but for associated types
1059/// instead of associated functions.
f035d41b 1060fn compare_type_predicate_entailment<'tcx>(
dfeec247
XL
1061 tcx: TyCtxt<'tcx>,
1062 impl_ty: &ty::AssocItem,
1063 impl_ty_span: Span,
1064 trait_ty: &ty::AssocItem,
1065 impl_trait_ref: ty::TraitRef<'tcx>,
1066) -> Result<(), ErrorReported> {
1067 let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
1068 let trait_to_impl_substs =
1069 impl_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
1070
1071 let impl_ty_generics = tcx.generics_of(impl_ty.def_id);
1072 let trait_ty_generics = tcx.generics_of(trait_ty.def_id);
1073 let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id);
1074 let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
1075
1076 check_region_bounds_on_impl_item(
1077 tcx,
1078 impl_ty_span,
1079 impl_ty,
1080 trait_ty,
1081 &trait_ty_generics,
1082 &impl_ty_generics,
1083 )?;
1084
1085 let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);
1086
1087 if impl_ty_own_bounds.is_empty() {
1088 // Nothing to check.
1089 return Ok(());
1090 }
1091
1092 // This `HirId` should be used for the `body_id` field on each
1093 // `ObligationCause` (and the `FnCtxt`). This is what
1094 // `regionck_item` expects.
3dfed10e 1095 let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
f035d41b
XL
1096 let cause = ObligationCause::new(
1097 impl_ty_span,
1098 impl_ty_hir_id,
1099 ObligationCauseCode::CompareImplTypeObligation {
dfeec247
XL
1100 item_name: impl_ty.ident.name,
1101 impl_item_def_id: impl_ty.def_id,
1102 trait_item_def_id: trait_ty.def_id,
1103 },
f035d41b 1104 );
dfeec247
XL
1105
1106 debug!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs);
1107
1108 // The predicates declared by the impl definition, the trait and the
1109 // associated type in the trait are assumed.
1110 let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
1111 let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
1112 hybrid_preds
1113 .predicates
1114 .extend(trait_ty_predicates.instantiate_own(tcx, trait_to_impl_substs).predicates);
1115
1116 debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
1117
1118 let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
1b1a35ee
XL
1119 let param_env =
1120 ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
dfeec247
XL
1121 let param_env = traits::normalize_param_env_or_error(
1122 tcx,
1123 impl_ty.def_id,
1124 param_env,
1125 normalize_cause.clone(),
1126 );
1127 tcx.infer_ctxt().enter(|infcx| {
ba9703b0 1128 let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
dfeec247
XL
1129 let infcx = &inh.infcx;
1130
f035d41b 1131 debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
dfeec247
XL
1132
1133 let mut selcx = traits::SelectionContext::new(&infcx);
1134
1135 for predicate in impl_ty_own_bounds.predicates {
1136 let traits::Normalized { value: predicate, obligations } =
fc512014 1137 traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate);
dfeec247
XL
1138
1139 inh.register_predicates(obligations);
1140 inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate));
1141 }
1142
1143 // Check that all obligations are satisfied by the implementation's
1144 // version.
1145 if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
1146 infcx.report_fulfillment_errors(errors, None, false);
1147 return Err(ErrorReported);
1148 }
1149
1150 // Finally, resolve all regions. This catches wily misuses of
1151 // lifetime parameters.
1152 let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id);
1153 fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &[]);
1154
1155 Ok(())
1156 })
1157}
1158
f035d41b
XL
1159/// Validate that `ProjectionCandidate`s created for this associated type will
1160/// be valid.
1161///
1162/// Usually given
1163///
1164/// trait X { type Y: Copy } impl X for T { type Y = S; }
1165///
1166/// We are able to normalize `<T as X>::U` to `S`, and so when we check the
1167/// impl is well-formed we have to prove `S: Copy`.
1168///
1169/// For default associated types the normalization is not possible (the value
1170/// from the impl could be overridden). We also can't normalize generic
1171/// associated types (yet) because they contain bound parameters.
29967ef6 1172pub fn check_type_bounds<'tcx>(
f035d41b
XL
1173 tcx: TyCtxt<'tcx>,
1174 trait_ty: &ty::AssocItem,
1175 impl_ty: &ty::AssocItem,
1176 impl_ty_span: Span,
1177 impl_trait_ref: ty::TraitRef<'tcx>,
1178) -> Result<(), ErrorReported> {
f035d41b
XL
1179 // Given
1180 //
1181 // impl<A, B> Foo<u32> for (A, B) {
1182 // type Bar<C> =...
1183 // }
1184 //
1185 // - `impl_substs` would be `[A, B, C]`
1186 // - `rebased_substs` would be `[(A, B), u32, C]`, combining the substs from
1187 // the *trait* with the generic associated type parameters.
1188 let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
1189 let rebased_substs =
1190 impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
1191 let impl_ty_value = tcx.type_of(impl_ty.def_id);
1192
3dfed10e
XL
1193 let param_env = tcx.param_env(impl_ty.def_id);
1194
1195 // When checking something like
f035d41b 1196 //
3dfed10e
XL
1197 // trait X { type Y: PartialEq<<Self as X>::Y> }
1198 // impl X for T { default type Y = S; }
f035d41b 1199 //
3dfed10e
XL
1200 // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
1201 // we want <T as X>::Y to normalize to S. This is valid because we are
1202 // checking the default value specifically here. Add this equality to the
1203 // ParamEnv for normalization specifically.
1204 let normalize_param_env = {
1205 let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
29967ef6
XL
1206 match impl_ty_value.kind() {
1207 ty::Projection(proj)
1208 if proj.item_def_id == trait_ty.def_id && proj.substs == rebased_substs =>
1209 {
1210 // Don't include this predicate if the projected type is
1211 // exactly the same as the projection. This can occur in
1212 // (somewhat dubious) code like this:
1213 //
1214 // impl<T> X for T where T: X { type Y = <T as X>::Y; }
1215 }
1216 _ => predicates.push(
1217 ty::Binder::dummy(ty::ProjectionPredicate {
1218 projection_ty: ty::ProjectionTy {
1219 item_def_id: trait_ty.def_id,
1220 substs: rebased_substs,
1221 },
1222 ty: impl_ty_value,
1223 })
1224 .to_predicate(tcx),
1225 ),
1226 };
1b1a35ee 1227 ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing)
f035d41b
XL
1228 };
1229
1230 tcx.infer_ctxt().enter(move |infcx| {
1231 let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
1232 let infcx = &inh.infcx;
1233 let mut selcx = traits::SelectionContext::new(&infcx);
1234
3dfed10e 1235 let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
f035d41b 1236 let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
29967ef6
XL
1237 let mk_cause = |span| {
1238 ObligationCause::new(
1239 impl_ty_span,
1240 impl_ty_hir_id,
1241 ObligationCauseCode::BindingObligation(trait_ty.def_id, span),
1242 )
1243 };
f035d41b 1244
29967ef6
XL
1245 let obligations = tcx
1246 .explicit_item_bounds(trait_ty.def_id)
1247 .iter()
1248 .map(|&(bound, span)| {
1249 let concrete_ty_bound = bound.subst(tcx, rebased_substs);
1250 debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
f035d41b 1251
29967ef6
XL
1252 traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound)
1253 })
1254 .collect();
1255 debug!("check_type_bounds: item_bounds={:?}", obligations);
f035d41b 1256
29967ef6 1257 for mut obligation in util::elaborate_obligations(tcx, obligations) {
f035d41b
XL
1258 let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
1259 &mut selcx,
3dfed10e 1260 normalize_param_env,
f035d41b 1261 normalize_cause.clone(),
fc512014 1262 obligation.predicate,
f035d41b 1263 );
f035d41b 1264 debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
29967ef6 1265 obligation.predicate = normalized_predicate;
f035d41b
XL
1266
1267 inh.register_predicates(obligations);
29967ef6 1268 inh.register_predicate(obligation);
f035d41b
XL
1269 }
1270
1271 // Check that all obligations are satisfied by the implementation's
1272 // version.
1273 if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
1274 infcx.report_fulfillment_errors(errors, None, false);
1275 return Err(ErrorReported);
1276 }
1277
1278 // Finally, resolve all regions. This catches wily misuses of
1279 // lifetime parameters.
1280 let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id);
29967ef6
XL
1281 let implied_bounds = match impl_ty.container {
1282 ty::TraitContainer(_) => vec![],
1283 ty::ImplContainer(def_id) => fcx.impl_implied_bounds(def_id, impl_ty_span),
1284 };
1285 fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &implied_bounds);
f035d41b
XL
1286
1287 Ok(())
1288 })
1289}
1290
dfeec247
XL
1291fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
1292 match impl_item.kind {
1293 ty::AssocKind::Const => "const",
ba9703b0 1294 ty::AssocKind::Fn => "method",
f035d41b 1295 ty::AssocKind::Type => "type",
dfeec247
XL
1296 }
1297}