compare_method.rs 52.8 KB
Newer Older
1
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
2
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported};
3 4
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
5
use rustc_hir::intravisit;
6
use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
C
Camille GILLOT 已提交
7
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
8
use rustc_infer::traits::util;
9
use rustc_middle::ty;
10
use rustc_middle::ty::error::{ExpectedFound, TypeError};
11
use rustc_middle::ty::subst::{InternalSubsts, Subst};
12
use rustc_middle::ty::util::ExplicitSelf;
13
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
14
use rustc_span::Span;
C
Camille GILLOT 已提交
15 16
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
J
Josh Stone 已提交
17
use std::iter;
18

M
Mark Rousskov 已提交
19
use super::{potentially_plural_count, FnCtxt, Inherited};
20 21 22 23 24 25

/// Checks that a method from an impl conforms to the signature of
/// the same method as declared in the trait.
///
/// # Parameters
///
A
Alexander Regueiro 已提交
26 27 28 29
/// - `impl_m`: type of the method we are checking
/// - `impl_m_span`: span to use for reporting errors
/// - `trait_m`: the method in the trait
/// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
30

31
crate fn compare_impl_method<'tcx>(
32
    tcx: TyCtxt<'tcx>,
33 34 35 36 37 38
    impl_m: &ty::AssocItem,
    impl_m_span: Span,
    trait_m: &ty::AssocItem,
    impl_trait_ref: ty::TraitRef<'tcx>,
    trait_item_span: Option<Span>,
) {
M
Mark Rousskov 已提交
39
    debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
40

41
    let impl_m_span = tcx.sess.source_map().guess_head_span(impl_m_span);
42

M
Mark Rousskov 已提交
43 44
    if let Err(ErrorReported) = compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
    {
N
Niko Matsakis 已提交
45
        return;
46 47
    }

M
Mark Rousskov 已提交
48 49 50
    if let Err(ErrorReported) =
        compare_number_of_generics(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
    {
N
Niko Matsakis 已提交
51 52
        return;
    }
T
Tim Neumann 已提交
53

M
Mark Rousskov 已提交
54 55 56
    if let Err(ErrorReported) =
        compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
    {
57 58 59
        return;
    }

M
Mark Rousskov 已提交
60
    if let Err(ErrorReported) = compare_synthetic_generics(tcx, impl_m, trait_m) {
61 62 63
        return;
    }

M
Mark Rousskov 已提交
64 65 66
    if let Err(ErrorReported) =
        compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
    {
67 68
        return;
    }
N
Niko Matsakis 已提交
69 70
}

71
fn compare_predicate_entailment<'tcx>(
72
    tcx: TyCtxt<'tcx>,
73 74 75 76 77
    impl_m: &ty::AssocItem,
    impl_m_span: Span,
    trait_m: &ty::AssocItem,
    impl_trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), ErrorReported> {
78
    let trait_to_impl_substs = impl_trait_ref.substs;
79

T
Taylor Cramer 已提交
80 81 82
    // This node-id should be used for the `body_id` field on each
    // `ObligationCause` (and the `FnCtxt`). This is what
    // `regionck_item` expects.
83
    let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
T
Taylor Cramer 已提交
84

85 86 87 88 89
    // We sometimes modify the span further down.
    let mut cause = ObligationCause::new(
        impl_m_span,
        impl_m_hir_id,
        ObligationCauseCode::CompareImplMethodObligation {
90
            item_name: impl_m.ident.name,
91 92 93
            impl_item_def_id: impl_m.def_id,
            trait_item_def_id: trait_m.def_id,
        },
94
    );
95

96 97
    // This code is best explained by example. Consider a trait:
    //
B
Bastian Kauschke 已提交
98 99
    //     trait Trait<'t, T> {
    //         fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
100 101 102 103 104
    //     }
    //
    // And an impl:
    //
    //     impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
B
Bastian Kauschke 已提交
105
    //          fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
106 107 108 109 110 111 112 113 114 115 116 117 118
    //     }
    //
    // We wish to decide if those two method types are compatible.
    //
    // We start out with trait_to_impl_substs, that maps the trait
    // type parameters to impl type parameters. This is taken from the
    // impl trait reference:
    //
    //     trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
    //
    // We create a mapping `dummy_substs` that maps from the impl type
    // parameters to fresh types and regions. For type parameters,
    // this is the identity transform, but we could as well use any
N
Niko Matsakis 已提交
119
    // placeholder types. For regions, we convert from bound to free
120 121 122
    // regions (Note: but only early-bound regions, i.e., those
    // declared on the impl or used in type parameter bounds).
    //
B
Bastian Kauschke 已提交
123
    //     impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
124
    //
B
Bastian Kauschke 已提交
125
    // Now we can apply placeholder_substs to the type of the impl method
N
Niko Matsakis 已提交
126
    // to yield a new function type in terms of our fresh, placeholder
127 128 129 130 131 132 133
    // types:
    //
    //     <'b> fn(t: &'i0 U0, m: &'b) -> Foo
    //
    // We now want to extract and substitute the type of the *trait*
    // method and compare it. To do so, we must create a compound
    // substitution by combining trait_to_impl_substs and
B
Bastian Kauschke 已提交
134
    // impl_to_placeholder_substs, and also adding a mapping for the method
135 136 137
    // type parameters. We extend the mapping to also include
    // the method parameters.
    //
B
Bastian Kauschke 已提交
138
    //     trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
139 140 141 142 143 144 145 146 147
    //
    // Applying this to the trait method type yields:
    //
    //     <'a> fn(t: &'i0 U0, m: &'a) -> Foo
    //
    // This type is also the same but the name of the bound region ('a
    // vs 'b).  However, the normal subtyping rules on fn types handle
    // this kind of equivalency just fine.
    //
J
Joseph Crail 已提交
148
    // We now use these substitutions to ensure that all declared bounds are
149 150 151
    // satisfied by the implementation's method.
    //
    // We do this by creating a parameter environment which contains a
B
Bastian Kauschke 已提交
152 153
    // substitution corresponding to impl_to_placeholder_substs. We then build
    // trait_to_placeholder_substs and use it to convert the predicates contained
N
Niko Matsakis 已提交
154
    // in the trait_m.generics to the placeholder form.
155 156 157 158
    //
    // Finally we register each of these predicates as an obligation in
    // a fresh FulfillmentCtxt, and invoke select_all_or_error.

N
Niko Matsakis 已提交
159
    // Create mapping from impl to placeholder.
B
Bastian Kauschke 已提交
160
    let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
161

N
Niko Matsakis 已提交
162
    // Create mapping from trait to placeholder.
B
Bastian Kauschke 已提交
163 164 165
    let trait_to_placeholder_substs =
        impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container.id(), trait_to_impl_substs);
    debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
166

167 168 169 170
    let impl_m_generics = tcx.generics_of(impl_m.def_id);
    let trait_m_generics = tcx.generics_of(trait_m.def_id);
    let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
    let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
171

N
Niko Matsakis 已提交
172
    // Check region bounds.
173 174 175 176 177 178 179 180
    check_region_bounds_on_impl_item(
        tcx,
        impl_m_span,
        impl_m,
        trait_m,
        &trait_m_generics,
        &impl_m_generics,
    )?;
N
Niko Matsakis 已提交
181 182 183 184 185 186

    // Create obligations for each predicate declared by the impl
    // definition in the context of the trait's parameter
    // environment. We can't just use `impl_env.caller_bounds`,
    // however, because we want to replace all late-bound regions with
    // region variables.
187
    let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
188
    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
N
Niko Matsakis 已提交
189 190 191 192 193 194 195 196 197 198

    debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);

    // This is the only tricky bit of the new way we check implementation methods
    // We need to build a set of predicates where only the method-level bounds
    // are from the trait and we assume all other bounds from the implementation
    // to be previously satisfied.
    //
    // We then register the obligations from the impl_m and check to see
    // if all constraints hold.
M
Mark Rousskov 已提交
199 200
    hybrid_preds
        .predicates
B
Bastian Kauschke 已提交
201
        .extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates);
N
Niko Matsakis 已提交
202

N
Niko Matsakis 已提交
203
    // Construct trait parameter environment and then shift it into the placeholder viewpoint.
N
Niko Matsakis 已提交
204 205
    // The key step here is to update the caller_bounds's predicates to be
    // the new hybrid bounds we computed.
L
ljedrz 已提交
206
    let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
207 208
    let param_env =
        ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
M
Mark Rousskov 已提交
209 210 211 212 213
    let param_env = traits::normalize_param_env_or_error(
        tcx,
        impl_m.def_id,
        param_env,
        normalize_cause.clone(),
S
scalexm 已提交
214
    );
215

216
    tcx.infer_ctxt().enter(|infcx| {
217
        let inh = Inherited::new(infcx, impl_m.def_id.expect_local());
218
        let infcx = &inh.infcx;
219

M
Mark Rousskov 已提交
220
        debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
221 222 223

        let mut selcx = traits::SelectionContext::new(&infcx);

B
Bastian Kauschke 已提交
224
        let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
S
scalexm 已提交
225
        let (impl_m_own_bounds, _) = infcx.replace_bound_vars_with_fresh_vars(
226 227
            impl_m_span,
            infer::HigherRankedType,
J
Jack Huey 已提交
228
            ty::Binder::bind(impl_m_own_bounds.predicates, tcx),
229
        );
230
        for predicate in impl_m_own_bounds {
231
            let traits::Normalized { value: predicate, obligations } =
B
Bastian Kauschke 已提交
232
                traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate);
233

234
            inh.register_predicates(obligations);
N
Niko Matsakis 已提交
235
            inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate));
236
        }
237

238 239 240 241 242 243 244 245 246 247 248 249 250
        // We now need to check that the signature of the impl method is
        // compatible with that of the trait method. We do this by
        // checking that `impl_fty <: trait_fty`.
        //
        // FIXME. Unfortunately, this doesn't quite work right now because
        // associated type normalization is not integrated into subtype
        // checks. For the comparison to be valid, we need to
        // normalize the associated types in the impl/trait methods
        // first. However, because function types bind regions, just
        // calling `normalize_associated_types_in` would have no effect on
        // any associated types appearing in the fn arguments or return
        // type.

N
Niko Matsakis 已提交
251
        // Compute placeholder form of impl and trait method tys.
252 253
        let tcx = infcx.tcx;

S
scalexm 已提交
254 255 256
        let (impl_sig, _) = infcx.replace_bound_vars_with_fresh_vars(
            impl_m_span,
            infer::HigherRankedType,
B
Bastian Kauschke 已提交
257
            tcx.fn_sig(impl_m.def_id),
S
scalexm 已提交
258
        );
259
        let impl_sig =
B
Bastian Kauschke 已提交
260
            inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, impl_sig);
J
Jack Huey 已提交
261
        let impl_fty = tcx.mk_fn_ptr(ty::Binder::bind(impl_sig, tcx));
262 263
        debug!("compare_impl_method: impl_fty={:?}", impl_fty);

B
Bastian Kauschke 已提交
264
        let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id));
B
Bastian Kauschke 已提交
265
        let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
266
        let trait_sig =
B
Bastian Kauschke 已提交
267
            inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig);
J
Jack Huey 已提交
268
        let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig, tcx));
269 270 271

        debug!("compare_impl_method: trait_fty={:?}", trait_fty);

M
Mark Rousskov 已提交
272 273 274 275 276
        let sub_result = infcx.at(&cause, param_env).sup(trait_fty, impl_fty).map(
            |InferOk { obligations, .. }| {
                inh.register_predicates(obligations);
            },
        );
277 278

        if let Err(terr) = sub_result {
M
Mark Rousskov 已提交
279 280
            debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);

281 282
            let (impl_err_span, trait_err_span) =
                extract_spans_for_error_reporting(&infcx, &terr, &cause, impl_m, trait_m);
M
Mark Rousskov 已提交
283

284
            cause.make_mut().span = impl_err_span;
M
Mark Rousskov 已提交
285 286 287 288 289 290 291 292

            let mut diag = struct_span_err!(
                tcx.sess,
                cause.span(tcx),
                E0053,
                "method `{}` has an incompatible type for trait",
                trait_m.ident
            );
293 294 295 296 297 298
            match &terr {
                TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
                    if trait_m.fn_has_self_parameter =>
                {
                    let ty = trait_sig.inputs()[0];
                    let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty())
M
Mark Rousskov 已提交
299
                    {
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
                        ExplicitSelf::ByValue => "self".to_owned(),
                        ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
                        ExplicitSelf::ByReference(_, hir::Mutability::Mut) => {
                            "&mut self".to_owned()
                        }
                        _ => format!("self: {}", ty),
                    };

                    // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
                    // span points only at the type `Box<Self`>, but we want to cover the whole
                    // argument pattern and type.
                    let impl_m_hir_id =
                        tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
                    let span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
                        ImplItemKind::Fn(ref sig, body) => tcx
                            .hir()
                            .body_param_names(body)
                            .zip(sig.decl.inputs.iter())
                            .map(|(param, ty)| param.span.to(ty.span))
                            .next()
                            .unwrap_or(impl_err_span),
                        _ => bug!("{:?} is not a method", impl_m),
                    };

                    diag.span_suggestion(
                        span,
                        "change the self-receiver type to match the trait",
                        sugg,
                        Applicability::MachineApplicable,
                    );
                }
                TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
E
Esteban Küber 已提交
332 333 334 335 336 337 338 339 340
                    if trait_sig.inputs().len() == *i {
                        // Suggestion to change output type. We do not suggest in `async` functions
                        // to avoid complex logic or incorrect output.
                        let impl_m_hir_id =
                            tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
                        match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
                            ImplItemKind::Fn(ref sig, _)
                                if sig.header.asyncness == hir::IsAsync::NotAsync =>
                            {
341 342 343
                                let msg = "change the output type to match the trait";
                                let ap = Applicability::MachineApplicable;
                                match sig.decl.output {
E
Esteban Küber 已提交
344
                                    hir::FnRetTy::DefaultReturn(sp) => {
345 346
                                        let sugg = format!("-> {} ", trait_sig.output());
                                        diag.span_suggestion_verbose(sp, msg, sugg, ap);
E
Esteban Küber 已提交
347 348
                                    }
                                    hir::FnRetTy::Return(hir_ty) => {
349 350
                                        let sugg = trait_sig.output().to_string();
                                        diag.span_suggestion(hir_ty.span, msg, sugg, ap);
E
Esteban Küber 已提交
351 352 353 354 355 356
                                    }
                                };
                            }
                            _ => {}
                        };
                    } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
357
                        diag.span_suggestion(
358
                            impl_err_span,
359 360
                            "change the parameter type to match the trait",
                            trait_ty.to_string(),
361
                            Applicability::MachineApplicable,
362 363 364
                        );
                    }
                }
365
                _ => {}
366
            }
367

M
Mark Rousskov 已提交
368 369 370 371 372 373 374 375 376 377
            infcx.note_type_err(
                &mut diag,
                &cause,
                trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
                Some(infer::ValuePairs::Types(ExpectedFound {
                    expected: trait_fty,
                    found: impl_fty,
                })),
                &terr,
            );
378
            diag.emit();
N
Niko Matsakis 已提交
379
            return Err(ErrorReported);
380 381
        }

382 383
        // Check that all obligations are satisfied by the implementation's
        // version.
384
        if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
385
            infcx.report_fulfillment_errors(errors, None, false);
N
Niko Matsakis 已提交
386
            return Err(ErrorReported);
387
        }
388

389
        // Finally, resolve all regions. This catches wily misuses of
390
        // lifetime parameters.
L
ljedrz 已提交
391
        let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id);
392
        fcx.regionck_item(impl_m_hir_id, impl_m_span, trait_sig.inputs_and_output);
N
Niko Matsakis 已提交
393 394 395 396 397

        Ok(())
    })
}

398
fn check_region_bounds_on_impl_item<'tcx>(
399
    tcx: TyCtxt<'tcx>,
400 401 402 403 404 405
    span: Span,
    impl_m: &ty::AssocItem,
    trait_m: &ty::AssocItem,
    trait_generics: &ty::Generics,
    impl_generics: &ty::Generics,
) -> Result<(), ErrorReported> {
V
varkor 已提交
406 407
    let trait_params = trait_generics.own_counts().lifetimes;
    let impl_params = impl_generics.own_counts().lifetimes;
N
Niko Matsakis 已提交
408

M
Mark Rousskov 已提交
409 410
    debug!(
        "check_region_bounds_on_impl_item: \
N
Niko Matsakis 已提交
411
            trait_generics={:?} \
412
            impl_generics={:?}",
M
Mark Rousskov 已提交
413 414
        trait_generics, impl_generics
    );
N
Niko Matsakis 已提交
415 416 417 418 419 420 421 422 423 424

    // Must have same number of early-bound lifetime parameters.
    // Unfortunately, if the user screws up the bounds, then this
    // will change classification between early and late.  E.g.,
    // if in trait we have `<'a,'b:'a>`, and in impl we just have
    // `<'a,'b>`, then we have 2 early-bound lifetime parameters
    // in trait but 0 in the impl. But if we report "expected 2
    // but found 0" it's confusing, because it looks like there
    // are zero. Since I don't quite know how to phrase things at
    // the moment, give a kind of vague error message.
425
    if trait_params != impl_params {
426
        let item_kind = assoc_item_kind_str(impl_m);
427
        let def_span = tcx.sess.source_map().guess_head_span(span);
428
        let span = tcx.hir().get_generics(impl_m.def_id).map_or(def_span, |g| g.span);
429
        let generics_span = tcx.hir().span_if_local(trait_m.def_id).map(|sp| {
430
            let def_sp = tcx.sess.source_map().guess_head_span(sp);
431 432
            tcx.hir().get_generics(trait_m.def_id).map_or(def_sp, |g| g.span)
        });
433

434
        tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait {
435
            span,
436
            item_kind,
437 438 439
            ident: impl_m.ident,
            generics_span,
        });
N
Niko Matsakis 已提交
440 441 442
        return Err(ErrorReported);
    }

443
    Ok(())
N
Niko Matsakis 已提交
444 445
}

446 447 448 449 450 451 452
fn extract_spans_for_error_reporting<'a, 'tcx>(
    infcx: &infer::InferCtxt<'a, 'tcx>,
    terr: &TypeError<'_>,
    cause: &ObligationCause<'tcx>,
    impl_m: &ty::AssocItem,
    trait_m: &ty::AssocItem,
) -> (Span, Option<Span>) {
N
Niko Matsakis 已提交
453
    let tcx = infcx.tcx;
454
    let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
455 456 457
    let mut impl_args = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
        ImplItemKind::Fn(ref sig, _) => {
            sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
N
Niko Matsakis 已提交
458 459 460
        }
        _ => bug!("{:?} is not a method", impl_m),
    };
461 462 463 464 465 466 467 468 469
    let trait_args = trait_m.def_id.as_local().map(|def_id| {
        let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
        match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
            TraitItemKind::Fn(ref sig, _) => {
                sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
            }
            _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
        }
    });
N
Niko Matsakis 已提交
470 471

    match *terr {
472 473
        TypeError::ArgumentMutability(i) => {
            (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
474
        }
475 476
        TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
            (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
N
Niko Matsakis 已提交
477
        }
F
flip1995 已提交
478
        _ => (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)),
479
    }
N
Niko Matsakis 已提交
480
}
481

482
fn compare_self_type<'tcx>(
483
    tcx: TyCtxt<'tcx>,
484 485 486 487 488
    impl_m: &ty::AssocItem,
    impl_m_span: Span,
    trait_m: &ty::AssocItem,
    impl_trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), ErrorReported> {
N
Niko Matsakis 已提交
489 490 491 492 493 494 495
    // Try to give more informative error messages about self typing
    // mismatches.  Note that any mismatch will also be detected
    // below, where we construct a canonical function type that
    // includes the self parameter as a normal parameter.  It's just
    // that the error messages you get out of this code are a bit more
    // inscrutable, particularly for cases where one method has no
    // self.
496

A
Andrew Xu 已提交
497
    let self_string = |method: &ty::AssocItem| {
498 499
        let untransformed_self_ty = match method.container {
            ty::ImplContainer(_) => impl_trait_ref.self_ty(),
M
Mark Rousskov 已提交
500
            ty::TraitContainer(_) => tcx.types.self_param,
501
        };
J
Jack Huey 已提交
502
        let self_arg_ty = tcx.fn_sig(method.def_id).input(0);
503
        let param_env = ty::ParamEnv::reveal_all();
504

505
        tcx.infer_ctxt().enter(|infcx| {
J
Jack Huey 已提交
506
            let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
507 508
            let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
            match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
509
                ExplicitSelf::ByValue => "self".to_owned(),
510 511
                ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
                ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
M
Mark Rousskov 已提交
512
                _ => format!("self: {}", self_arg_ty),
513 514
            }
        })
515 516
    };

517
    match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
518 519 520 521
        (false, false) | (true, true) => {}

        (false, true) => {
            let self_descr = self_string(impl_m);
M
Mark Rousskov 已提交
522 523 524 525
            let mut err = struct_span_err!(
                tcx.sess,
                impl_m_span,
                E0185,
526
                "method `{}` has a `{}` declaration in the impl, but not in the trait",
M
Mark Rousskov 已提交
527 528 529
                trait_m.ident,
                self_descr
            );
530
            err.span_label(impl_m_span, format!("`{}` used in impl", self_descr));
531
            if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
E
Esteban Küber 已提交
532 533
                err.span_label(span, format!("trait method declared without `{}`", self_descr));
            } else {
M
Mark Rousskov 已提交
534
                err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx));
N
Niko Matsakis 已提交
535 536 537 538
            }
            err.emit();
            return Err(ErrorReported);
        }
539 540 541

        (true, false) => {
            let self_descr = self_string(trait_m);
M
Mark Rousskov 已提交
542 543 544 545
            let mut err = struct_span_err!(
                tcx.sess,
                impl_m_span,
                E0186,
546
                "method `{}` has a `{}` declaration in the trait, but not in the impl",
M
Mark Rousskov 已提交
547 548 549
                trait_m.ident,
                self_descr
            );
E
Esteban Küber 已提交
550
            err.span_label(impl_m_span, format!("expected `{}` in impl", self_descr));
551
            if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
552
                err.span_label(span, format!("`{}` used in trait", self_descr));
553
            } else {
M
Mark Rousskov 已提交
554
                err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx));
N
Niko Matsakis 已提交
555 556 557 558 559 560 561 562 563
            }
            err.emit();
            return Err(ErrorReported);
        }
    }

    Ok(())
}

564
fn compare_number_of_generics<'tcx>(
565
    tcx: TyCtxt<'tcx>,
A
Andrew Xu 已提交
566
    impl_: &ty::AssocItem,
567
    _impl_span: Span,
A
Andrew Xu 已提交
568
    trait_: &ty::AssocItem,
V
varkor 已提交
569 570 571 572 573 574 575 576 577 578
    trait_span: Option<Span>,
) -> Result<(), ErrorReported> {
    let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
    let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();

    let matchings = [
        ("type", trait_own_counts.types, impl_own_counts.types),
        ("const", trait_own_counts.consts, impl_own_counts.consts),
    ];

579 580
    let item_kind = assoc_item_kind_str(impl_);

V
varkor 已提交
581 582 583 584 585
    let mut err_occurred = false;
    for &(kind, trait_count, impl_count) in &matchings {
        if impl_count != trait_count {
            err_occurred = true;

M
marmeladema 已提交
586
            let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
587
                let trait_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
588 589 590
                let trait_item = tcx.hir().expect_trait_item(trait_hir_id);
                if trait_item.generics.params.is_empty() {
                    (Some(vec![trait_item.generics.span]), vec![])
591
                } else {
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
                    let arg_spans: Vec<Span> =
                        trait_item.generics.params.iter().map(|p| p.span).collect();
                    let impl_trait_spans: Vec<Span> = trait_item
                        .generics
                        .params
                        .iter()
                        .filter_map(|p| match p.kind {
                            GenericParamKind::Type {
                                synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
                                ..
                            } => Some(p.span),
                            _ => None,
                        })
                        .collect();
                    (Some(arg_spans), impl_trait_spans)
                }
            } else {
                (trait_span.map(|s| vec![s]), vec![])
            };
611

612
            let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_.def_id.expect_local());
613
            let impl_item = tcx.hir().expect_impl_item(impl_hir_id);
M
Mark Rousskov 已提交
614 615 616 617
            let impl_item_impl_trait_spans: Vec<Span> = impl_item
                .generics
                .params
                .iter()
618 619
                .filter_map(|p| match p.kind {
                    GenericParamKind::Type {
M
Mark Rousskov 已提交
620 621
                        synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
                        ..
622 623
                    } => Some(p.span),
                    _ => None,
M
Mark Rousskov 已提交
624 625
                })
                .collect();
626 627 628
            let spans = impl_item.generics.spans();
            let span = spans.primary_span();

V
varkor 已提交
629
            let mut err = tcx.sess.struct_span_err_with_code(
630
                spans,
V
varkor 已提交
631
                &format!(
632
                    "{} `{}` has {} {kind} parameter{} but its trait \
V
varkor 已提交
633
                     declaration has {} {kind} parameter{}",
634
                    item_kind,
V
varkor 已提交
635 636
                    trait_.ident,
                    impl_count,
637
                    pluralize!(impl_count),
V
varkor 已提交
638
                    trait_count,
639
                    pluralize!(trait_count),
V
varkor 已提交
640 641 642 643
                    kind = kind,
                ),
                DiagnosticId::Error("E0049".into()),
            );
644

V
varkor 已提交
645
            let mut suffix = None;
N
Niko Matsakis 已提交
646

647 648 649
            if let Some(spans) = trait_spans {
                let mut spans = spans.iter();
                if let Some(span) = spans.next() {
M
Mark Rousskov 已提交
650 651 652 653 654 655 656 657 658
                    err.span_label(
                        *span,
                        format!(
                            "expected {} {} parameter{}",
                            trait_count,
                            kind,
                            pluralize!(trait_count),
                        ),
                    );
659 660 661 662
                }
                for span in spans {
                    err.span_label(*span, "");
                }
V
varkor 已提交
663 664 665
            } else {
                suffix = Some(format!(", expected {}", trait_count));
            }
N
Niko Matsakis 已提交
666

667
            if let Some(span) = span {
M
Mark Rousskov 已提交
668 669 670 671 672 673 674
                err.span_label(
                    span,
                    format!(
                        "found {} {} parameter{}{}",
                        impl_count,
                        kind,
                        pluralize!(impl_count),
675
                        suffix.unwrap_or_else(String::new),
M
Mark Rousskov 已提交
676 677
                    ),
                );
678
            }
N
Niko Matsakis 已提交
679

680 681 682 683
            for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) {
                err.span_label(*span, "`impl Trait` introduces an implicit type parameter");
            }

V
varkor 已提交
684 685
            err.emit();
        }
N
Niko Matsakis 已提交
686 687
    }

M
Mark Rousskov 已提交
688
    if err_occurred { Err(ErrorReported) } else { Ok(()) }
N
Niko Matsakis 已提交
689 690
}

691
fn compare_number_of_method_arguments<'tcx>(
692
    tcx: TyCtxt<'tcx>,
693 694 695 696 697
    impl_m: &ty::AssocItem,
    impl_m_span: Span,
    trait_m: &ty::AssocItem,
    trait_item_span: Option<Span>,
) -> Result<(), ErrorReported> {
698 699
    let impl_m_fty = tcx.fn_sig(impl_m.def_id);
    let trait_m_fty = tcx.fn_sig(trait_m.def_id);
700 701
    let trait_number_args = trait_m_fty.inputs().skip_binder().len();
    let impl_number_args = impl_m_fty.inputs().skip_binder().len();
702
    if trait_number_args != impl_number_args {
703
        let trait_span = if let Some(def_id) = trait_m.def_id.as_local() {
704
            let trait_id = tcx.hir().local_def_id_to_hir_id(def_id);
705
            match tcx.hir().expect_trait_item(trait_id).kind {
M
Mark Mansi 已提交
706
                TraitItemKind::Fn(ref trait_m_sig, _) => {
M
Mark Rousskov 已提交
707
                    let pos = if trait_number_args > 0 { trait_number_args - 1 } else { 0 };
708 709 710 711
                    if let Some(arg) = trait_m_sig.decl.inputs.get(pos) {
                        Some(if pos == 0 {
                            arg.span
                        } else {
M
Mark Rousskov 已提交
712 713 714 715 716
                            Span::new(
                                trait_m_sig.decl.inputs[0].span.lo(),
                                arg.span.hi(),
                                arg.span.ctxt(),
                            )
717
                        })
N
Niko Matsakis 已提交
718 719 720
                    } else {
                        trait_item_span
                    }
721
                }
N
Niko Matsakis 已提交
722
                _ => bug!("{:?} is not a method", impl_m),
723
            }
N
Niko Matsakis 已提交
724 725 726
        } else {
            trait_item_span
        };
727
        let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
728
        let impl_span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
M
Mark Mansi 已提交
729
            ImplItemKind::Fn(ref impl_m_sig, _) => {
M
Mark Rousskov 已提交
730
                let pos = if impl_number_args > 0 { impl_number_args - 1 } else { 0 };
731 732 733 734
                if let Some(arg) = impl_m_sig.decl.inputs.get(pos) {
                    if pos == 0 {
                        arg.span
                    } else {
M
Mark Rousskov 已提交
735 736 737 738 739
                        Span::new(
                            impl_m_sig.decl.inputs[0].span.lo(),
                            arg.span.hi(),
                            arg.span.ctxt(),
                        )
740
                    }
N
Niko Matsakis 已提交
741 742
                } else {
                    impl_m_span
743 744
                }
            }
N
Niko Matsakis 已提交
745 746
            _ => bug!("{:?} is not a method", impl_m),
        };
M
Mark Rousskov 已提交
747 748 749 750 751
        let mut err = struct_span_err!(
            tcx.sess,
            impl_span,
            E0050,
            "method `{}` has {} but the declaration in \
N
Niko Matsakis 已提交
752
                                        trait `{}` has {}",
M
Mark Rousskov 已提交
753 754 755 756 757
            trait_m.ident,
            potentially_plural_count(impl_number_args, "parameter"),
            tcx.def_path_str(trait_m.def_id),
            trait_number_args
        );
N
Niko Matsakis 已提交
758
        if let Some(trait_span) = trait_span {
M
Mark Rousskov 已提交
759 760 761 762 763 764 765
            err.span_label(
                trait_span,
                format!(
                    "trait requires {}",
                    potentially_plural_count(trait_number_args, "parameter")
                ),
            );
766
        } else {
M
Mark Rousskov 已提交
767
            err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx));
768
        }
M
Mark Rousskov 已提交
769 770 771 772 773 774 775 776
        err.span_label(
            impl_span,
            format!(
                "expected {}, found {}",
                potentially_plural_count(trait_number_args, "parameter"),
                impl_number_args
            ),
        );
N
Niko Matsakis 已提交
777 778
        err.emit();
        return Err(ErrorReported);
779
    }
N
Niko Matsakis 已提交
780 781

    Ok(())
782
}
783

784
fn compare_synthetic_generics<'tcx>(
785
    tcx: TyCtxt<'tcx>,
786 787 788
    impl_m: &ty::AssocItem,
    trait_m: &ty::AssocItem,
) -> Result<(), ErrorReported> {
789
    // FIXME(chrisvittal) Clean up this function, list of FIXME items:
790
    //     1. Better messages for the span labels
791 792 793 794 795 796
    //     2. Explanation as to what is going on
    // If we get here, we already have the same number of generics, so the zip will
    // be okay.
    let mut error_found = false;
    let impl_m_generics = tcx.generics_of(impl_m.def_id);
    let trait_m_generics = tcx.generics_of(trait_m.def_id);
797 798
    let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind {
        GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
799
        GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
V
varkor 已提交
800
    });
M
Mark Rousskov 已提交
801 802
    let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| match param.kind {
        GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
803
        GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
V
varkor 已提交
804
    });
M
Mark Rousskov 已提交
805
    for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) in
J
Josh Stone 已提交
806
        iter::zip(impl_m_type_params, trait_m_type_params)
807
    {
V
varkor 已提交
808
        if impl_synthetic != trait_synthetic {
809
            let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id.expect_local());
810
            let impl_span = tcx.hir().span(impl_hir_id);
V
varkor 已提交
811
            let trait_span = tcx.def_span(trait_def_id);
M
Mark Rousskov 已提交
812 813 814 815 816 817 818
            let mut err = struct_span_err!(
                tcx.sess,
                impl_span,
                E0643,
                "method `{}` has incompatible signature for trait",
                trait_m.ident
            );
819 820 821 822 823 824 825 826 827 828
            err.span_label(trait_span, "declaration in trait here");
            match (impl_synthetic, trait_synthetic) {
                // The case where the impl method uses `impl Trait` but the trait method uses
                // explicit generics
                (Some(hir::SyntheticTyParamKind::ImplTrait), None) => {
                    err.span_label(impl_span, "expected generic parameter, found `impl Trait`");
                    (|| {
                        // try taking the name from the trait impl
                        // FIXME: this is obviously suboptimal since the name can already be used
                        // as another generic argument
M
Mark Rousskov 已提交
829
                        let new_name = tcx.sess.source_map().span_to_snippet(trait_span).ok()?;
830 831
                        let trait_m = trait_m.def_id.as_local()?;
                        let trait_m = tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m });
832

833 834
                        let impl_m = impl_m.def_id.as_local()?;
                        let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m });
835 836 837

                        // in case there are no generics, take the spot between the function name
                        // and the opening paren of the argument list
M
Mark Rousskov 已提交
838 839
                        let new_generics_span =
                            tcx.sess.source_map().generate_fn_name_span(impl_span)?.shrink_to_hi();
840
                        // in case there are generics, just replace them
M
Mark Rousskov 已提交
841 842
                        let generics_span =
                            impl_m.generics.span.substitute_dummy(new_generics_span);
843
                        // replace with the generics from the trait
M
Mark Rousskov 已提交
844 845
                        let new_generics =
                            tcx.sess.source_map().span_to_snippet(trait_m.generics.span).ok()?;
846

847
                        err.multipart_suggestion(
848 849 850 851 852 853 854 855 856
                            "try changing the `impl Trait` argument to a generic parameter",
                            vec![
                                // replace `impl Trait` with `T`
                                (impl_span, new_name),
                                // replace impl method generics with trait method generics
                                // This isn't quite right, as users might have changed the names
                                // of the generics, but it works for the common case
                                (generics_span, new_generics),
                            ],
857
                            Applicability::MaybeIncorrect,
858 859 860
                        );
                        Some(())
                    })();
M
Mark Rousskov 已提交
861
                }
862 863 864 865 866
                // The case where the trait method uses `impl Trait`, but the impl method uses
                // explicit generics.
                (None, Some(hir::SyntheticTyParamKind::ImplTrait)) => {
                    err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
                    (|| {
867 868
                        let impl_m = impl_m.def_id.as_local()?;
                        let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m });
869
                        let input_tys = match impl_m.kind {
M
Mark Mansi 已提交
870
                            hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
871 872 873
                            _ => unreachable!(),
                        };
                        struct Visitor(Option<Span>, hir::def_id::DefId);
874
                        impl<'v> intravisit::Visitor<'v> for Visitor {
C
Camille GILLOT 已提交
875
                            fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
876
                                intravisit::walk_ty(self, ty);
M
Mark Rousskov 已提交
877 878
                                if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) =
                                    ty.kind
879
                                {
880
                                    if let Res::Def(DefKind::TyParam, def_id) = path.res {
881 882
                                        if def_id == self.1 {
                                            self.0 = Some(ty.span);
883
                                        }
884
                                    }
885 886
                                }
                            }
887
                            type Map = intravisit::ErasedMap<'v>;
888 889
                            fn nested_visit_map(
                                &mut self,
890
                            ) -> intravisit::NestedVisitorMap<Self::Map>
M
Mark Rousskov 已提交
891
                            {
892
                                intravisit::NestedVisitorMap::None
893 894 895 896
                            }
                        }
                        let mut visitor = Visitor(None, impl_def_id);
                        for ty in input_tys {
897
                            intravisit::Visitor::visit_ty(&mut visitor, ty);
898 899 900
                        }
                        let span = visitor.0?;

M
Mark Rousskov 已提交
901 902
                        let bounds =
                            impl_m.generics.params.iter().find_map(|param| match param.kind {
V
varkor 已提交
903
                                GenericParamKind::Lifetime { .. } => None,
M
Mark Rousskov 已提交
904
                                GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
V
varkor 已提交
905
                                    if param.hir_id == impl_hir_id {
V
varkor 已提交
906
                                        Some(&param.bounds)
907 908 909
                                    } else {
                                        None
                                    }
V
varkor 已提交
910
                                }
M
Mark Rousskov 已提交
911
                            })?;
V
varkor 已提交
912
                        let bounds = bounds.first()?.span().to(bounds.last()?.span());
M
Mark Rousskov 已提交
913
                        let bounds = tcx.sess.source_map().span_to_snippet(bounds).ok()?;
914

915
                        err.multipart_suggestion(
916 917 918 919 920 921 922
                            "try removing the generic parameter and using `impl Trait` instead",
                            vec![
                                // delete generic parameters
                                (impl_m.generics.span, String::new()),
                                // replace param usage with `impl Trait`
                                (span, format!("impl {}", bounds)),
                            ],
923
                            Applicability::MaybeIncorrect,
924 925 926
                        );
                        Some(())
                    })();
M
Mark Rousskov 已提交
927
                }
928 929
                _ => unreachable!(),
            }
930 931 932 933
            err.emit();
            error_found = true;
        }
    }
M
Mark Rousskov 已提交
934
    if error_found { Err(ErrorReported) } else { Ok(()) }
935 936
}

937
crate fn compare_const_impl<'tcx>(
938
    tcx: TyCtxt<'tcx>,
939 940 941 942 943
    impl_c: &ty::AssocItem,
    impl_c_span: Span,
    trait_c: &ty::AssocItem,
    impl_trait_ref: ty::TraitRef<'tcx>,
) {
944
    debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
945

946
    tcx.infer_ctxt().enter(|infcx| {
K
kyren 已提交
947
        let param_env = tcx.param_env(impl_c.def_id);
948
        let inh = Inherited::new(infcx, impl_c.def_id.expect_local());
949
        let infcx = &inh.infcx;
950 951 952 953 954 955

        // The below is for the most part highly similar to the procedure
        // for methods above. It is simpler in many respects, especially
        // because we shouldn't really have to deal with lifetimes or
        // predicates. In fact some of this should probably be put into
        // shared functions because of DRY violations...
956
        let trait_to_impl_substs = impl_trait_ref.substs;
957 958 959

        // Create a parameter environment that represents the implementation's
        // method.
960
        let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_c.def_id.expect_local());
961

N
Niko Matsakis 已提交
962
        // Compute placeholder form of impl and trait const tys.
963 964
        let impl_ty = tcx.type_of(impl_c.def_id);
        let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
965 966 967 968 969
        let mut cause = ObligationCause::new(
            impl_c_span,
            impl_c_hir_id,
            ObligationCauseCode::CompareImplConstObligation,
        );
970

971
        // There is no "body" here, so just pass dummy id.
M
Mark Rousskov 已提交
972
        let impl_ty =
B
Bastian Kauschke 已提交
973
            inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, impl_ty);
974

975
        debug!("compare_const_impl: impl_ty={:?}", impl_ty);
976

M
Mark Rousskov 已提交
977
        let trait_ty =
B
Bastian Kauschke 已提交
978
            inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, trait_ty);
979

980
        debug!("compare_const_impl: trait_ty={:?}", trait_ty);
981

M
Mark Rousskov 已提交
982 983 984 985
        let err = infcx
            .at(&cause, param_env)
            .sup(trait_ty, impl_ty)
            .map(|ok| inh.register_infer_ok_obligations(ok));
986

987
        if let Err(terr) = err {
M
Mark Rousskov 已提交
988 989 990 991
            debug!(
                "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
                impl_ty, trait_ty
            );
T
trixnz 已提交
992 993

            // Locate the Span containing just the type of the offending impl
994
            match tcx.hir().expect_impl_item(impl_c_hir_id).kind {
995
                ImplItemKind::Const(ref ty, _) => cause.make_mut().span = ty.span,
996
                _ => bug!("{:?} is not a impl const", impl_c),
T
trixnz 已提交
997 998
            }

M
Mark Rousskov 已提交
999 1000 1001 1002
            let mut diag = struct_span_err!(
                tcx.sess,
                cause.span,
                E0326,
1003
                "implemented const `{}` has an incompatible type for trait",
M
Mark Rousskov 已提交
1004 1005
                trait_c.ident
            );
T
trixnz 已提交
1006

1007
            let trait_c_hir_id =
1008
                trait_c.def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
1009
            let trait_c_span = trait_c_hir_id.map(|trait_c_hir_id| {
1010
                // Add a label to the Span containing just the type of the const
1011
                match tcx.hir().expect_trait_item(trait_c_hir_id).kind {
1012 1013 1014 1015
                    TraitItemKind::Const(ref ty, _) => ty.span,
                    _ => bug!("{:?} is not a trait const", trait_c),
                }
            });
T
trixnz 已提交
1016

M
Mark Rousskov 已提交
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
            infcx.note_type_err(
                &mut diag,
                &cause,
                trait_c_span.map(|span| (span, "type in trait".to_owned())),
                Some(infer::ValuePairs::Types(ExpectedFound {
                    expected: trait_ty,
                    found: impl_ty,
                })),
                &terr,
            );
1027
            diag.emit();
1028
        }
1029

1030 1031 1032
        // Check that all obligations are satisfied by the implementation's
        // version.
        if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
1033
            infcx.report_fulfillment_errors(errors, None, false);
1034 1035 1036
            return;
        }

L
ljedrz 已提交
1037 1038
        let fcx = FnCtxt::new(&inh, param_env, impl_c_hir_id);
        fcx.regionck_item(impl_c_hir_id, impl_c_span, &[]);
1039
    });
1040
}
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054

crate fn compare_ty_impl<'tcx>(
    tcx: TyCtxt<'tcx>,
    impl_ty: &ty::AssocItem,
    impl_ty_span: Span,
    trait_ty: &ty::AssocItem,
    impl_trait_ref: ty::TraitRef<'tcx>,
    trait_item_span: Option<Span>,
) {
    debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);

    let _: Result<(), ErrorReported> = (|| {
        compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;

1055 1056
        compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)?;

1057
        check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
1058 1059 1060 1061 1062
    })();
}

/// The equivalent of [compare_predicate_entailment], but for associated types
/// instead of associated functions.
1063
fn compare_type_predicate_entailment<'tcx>(
1064 1065 1066 1067 1068 1069 1070
    tcx: TyCtxt<'tcx>,
    impl_ty: &ty::AssocItem,
    impl_ty_span: Span,
    trait_ty: &ty::AssocItem,
    impl_trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), ErrorReported> {
    let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
M
Mark Rousskov 已提交
1071 1072
    let trait_to_impl_substs =
        impl_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097

    let impl_ty_generics = tcx.generics_of(impl_ty.def_id);
    let trait_ty_generics = tcx.generics_of(trait_ty.def_id);
    let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id);
    let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);

    check_region_bounds_on_impl_item(
        tcx,
        impl_ty_span,
        impl_ty,
        trait_ty,
        &trait_ty_generics,
        &impl_ty_generics,
    )?;

    let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);

    if impl_ty_own_bounds.is_empty() {
        // Nothing to check.
        return Ok(());
    }

    // This `HirId` should be used for the `body_id` field on each
    // `ObligationCause` (and the `FnCtxt`). This is what
    // `regionck_item` expects.
1098
    let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
1099 1100 1101 1102
    let cause = ObligationCause::new(
        impl_ty_span,
        impl_ty_hir_id,
        ObligationCauseCode::CompareImplTypeObligation {
1103 1104 1105 1106
            item_name: impl_ty.ident.name,
            impl_item_def_id: impl_ty.def_id,
            trait_item_def_id: trait_ty.def_id,
        },
1107
    );
1108 1109 1110 1111 1112 1113 1114

    debug!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs);

    // The predicates declared by the impl definition, the trait and the
    // associated type in the trait are assumed.
    let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
M
Mark Rousskov 已提交
1115 1116 1117
    hybrid_preds
        .predicates
        .extend(trait_ty_predicates.instantiate_own(tcx, trait_to_impl_substs).predicates);
1118 1119 1120 1121

    debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);

    let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
1122 1123
    let param_env =
        ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
M
Mark Rousskov 已提交
1124 1125 1126 1127 1128
    let param_env = traits::normalize_param_env_or_error(
        tcx,
        impl_ty.def_id,
        param_env,
        normalize_cause.clone(),
1129 1130
    );
    tcx.infer_ctxt().enter(|infcx| {
1131
        let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
1132 1133
        let infcx = &inh.infcx;

M
Mark Rousskov 已提交
1134
        debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
1135 1136 1137 1138 1139

        let mut selcx = traits::SelectionContext::new(&infcx);

        for predicate in impl_ty_own_bounds.predicates {
            let traits::Normalized { value: predicate, obligations } =
B
Bastian Kauschke 已提交
1140
                traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate);
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161

            inh.register_predicates(obligations);
            inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate));
        }

        // Check that all obligations are satisfied by the implementation's
        // version.
        if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
            infcx.report_fulfillment_errors(errors, None, false);
            return Err(ErrorReported);
        }

        // Finally, resolve all regions. This catches wily misuses of
        // lifetime parameters.
        let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id);
        fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &[]);

        Ok(())
    })
}

1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174
/// Validate that `ProjectionCandidate`s created for this associated type will
/// be valid.
///
/// Usually given
///
/// trait X { type Y: Copy } impl X for T { type Y = S; }
///
/// We are able to normalize `<T as X>::U` to `S`, and so when we check the
/// impl is well-formed we have to prove `S: Copy`.
///
/// For default associated types the normalization is not possible (the value
/// from the impl could be overridden). We also can't normalize generic
/// associated types (yet) because they contain bound parameters.
1175
pub fn check_type_bounds<'tcx>(
1176 1177 1178 1179 1180 1181
    tcx: TyCtxt<'tcx>,
    trait_ty: &ty::AssocItem,
    impl_ty: &ty::AssocItem,
    impl_ty_span: Span,
    impl_trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), ErrorReported> {
1182 1183 1184 1185 1186 1187 1188 1189 1190
    // Given
    //
    // impl<A, B> Foo<u32> for (A, B) {
    //     type Bar<C> =...
    // }
    //
    // - `impl_substs` would be `[A, B, C]`
    // - `rebased_substs` would be `[(A, B), u32, C]`, combining the substs from
    //    the *trait* with the generic associated type parameters.
1191 1192 1193
    let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
    let rebased_substs =
        impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
1194 1195
    let impl_ty_value = tcx.type_of(impl_ty.def_id);

1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
    let param_env = tcx.param_env(impl_ty.def_id);

    // When checking something like
    //
    // trait X { type Y: PartialEq<<Self as X>::Y> }
    // impl X for T { default type Y = S; }
    //
    // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
    // we want <T as X>::Y to normalize to S. This is valid because we are
    // checking the default value specifically here. Add this equality to the
    // ParamEnv for normalization specifically.
1207
    let normalize_param_env = {
1208
        let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
        match impl_ty_value.kind() {
            ty::Projection(proj)
                if proj.item_def_id == trait_ty.def_id && proj.substs == rebased_substs =>
            {
                // Don't include this predicate if the projected type is
                // exactly the same as the projection. This can occur in
                // (somewhat dubious) code like this:
                //
                // impl<T> X for T where T: X { type Y = <T as X>::Y; }
            }
            _ => predicates.push(
                ty::Binder::dummy(ty::ProjectionPredicate {
                    projection_ty: ty::ProjectionTy {
                        item_def_id: trait_ty.def_id,
                        substs: rebased_substs,
                    },
                    ty: impl_ty_value,
                })
                .to_predicate(tcx),
            ),
        };
1230
        ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing)
1231 1232
    };

1233 1234 1235 1236 1237
    tcx.infer_ctxt().enter(move |infcx| {
        let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
        let infcx = &inh.infcx;
        let mut selcx = traits::SelectionContext::new(&infcx);

1238
        let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
1239
        let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
M
Matthew Jasper 已提交
1240 1241 1242 1243 1244 1245 1246
        let mk_cause = |span| {
            ObligationCause::new(
                impl_ty_span,
                impl_ty_hir_id,
                ObligationCauseCode::BindingObligation(trait_ty.def_id, span),
            )
        };
1247

1248 1249 1250 1251
        let obligations = tcx
            .explicit_item_bounds(trait_ty.def_id)
            .iter()
            .map(|&(bound, span)| {
M
Matthew Jasper 已提交
1252
                let concrete_ty_bound = bound.subst(tcx, rebased_substs);
1253
                debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
1254

1255 1256 1257 1258 1259
                traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound)
            })
            .collect();
        debug!("check_type_bounds: item_bounds={:?}", obligations);

M
Matthew Jasper 已提交
1260
        for mut obligation in util::elaborate_obligations(tcx, obligations) {
1261 1262
            let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
                &mut selcx,
1263
                normalize_param_env,
1264
                normalize_cause.clone(),
B
Bastian Kauschke 已提交
1265
                obligation.predicate,
1266 1267
            );
            debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
M
Matthew Jasper 已提交
1268
            obligation.predicate = normalized_predicate;
1269

M
Matthew Jasper 已提交
1270
            inh.register_predicates(obligations);
1271
            inh.register_predicate(obligation);
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283
        }

        // Check that all obligations are satisfied by the implementation's
        // version.
        if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
            infcx.report_fulfillment_errors(errors, None, false);
            return Err(ErrorReported);
        }

        // Finally, resolve all regions. This catches wily misuses of
        // lifetime parameters.
        let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id);
1284 1285 1286 1287 1288
        let implied_bounds = match impl_ty.container {
            ty::TraitContainer(_) => vec![],
            ty::ImplContainer(def_id) => fcx.impl_implied_bounds(def_id, impl_ty_span),
        };
        fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &implied_bounds);
1289 1290 1291 1292 1293

        Ok(())
    })
}

1294 1295 1296
fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
    match impl_item.kind {
        ty::AssocKind::Const => "const",
1297
        ty::AssocKind::Fn => "method",
M
Matthew Jasper 已提交
1298
        ty::AssocKind::Type => "type",
1299 1300
    }
}