Emit error in collecting_trait_impl_trait_tys
on mismatched signatures
Previously, a `delay_span_bug` was isssued, failing normalization. This create a `TyKind::Error` in the signature, which caused `compare_predicate_entailment` to swallow its signature mismatch error, causing ICEs because no error was emitted.
This commit is contained in:
parent
cc9b259b5e
commit
07a47e0708
3 changed files with 277 additions and 105 deletions
|
@ -9,14 +9,15 @@ use rustc_hir::intravisit;
|
||||||
use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
|
use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
|
||||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_infer::infer::{self, TyCtxtInferExt};
|
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::util;
|
use rustc_infer::traits::util;
|
||||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||||
use rustc_middle::ty::util::ExplicitSelf;
|
use rustc_middle::ty::util::ExplicitSelf;
|
||||||
use rustc_middle::ty::InternalSubsts;
|
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, AssocItem, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
|
self, AssocItem, DefIdTree, TraitRef, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||||
|
TypeVisitable,
|
||||||
};
|
};
|
||||||
|
use rustc_middle::ty::{FnSig, InternalSubsts};
|
||||||
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
|
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||||
|
@ -303,102 +304,19 @@ fn compare_predicate_entailment<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(terr) = result {
|
if let Err(terr) = result {
|
||||||
debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
|
debug!(?terr, "sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
|
||||||
|
|
||||||
let (impl_err_span, trait_err_span) =
|
let emitted = report_trait_method_mismatch(
|
||||||
extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
|
tcx,
|
||||||
|
&mut cause,
|
||||||
cause.span = impl_err_span;
|
&infcx,
|
||||||
|
|
||||||
let mut diag = struct_span_err!(
|
|
||||||
tcx.sess,
|
|
||||||
cause.span(),
|
|
||||||
E0053,
|
|
||||||
"method `{}` has an incompatible type for trait",
|
|
||||||
trait_m.name
|
|
||||||
);
|
|
||||||
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()) {
|
|
||||||
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 span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).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) => {
|
|
||||||
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.
|
|
||||||
match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
|
|
||||||
ImplItemKind::Fn(ref sig, _)
|
|
||||||
if sig.header.asyncness == hir::IsAsync::NotAsync =>
|
|
||||||
{
|
|
||||||
let msg = "change the output type to match the trait";
|
|
||||||
let ap = Applicability::MachineApplicable;
|
|
||||||
match sig.decl.output {
|
|
||||||
hir::FnRetTy::DefaultReturn(sp) => {
|
|
||||||
let sugg = format!("-> {} ", trait_sig.output());
|
|
||||||
diag.span_suggestion_verbose(sp, msg, sugg, ap);
|
|
||||||
}
|
|
||||||
hir::FnRetTy::Return(hir_ty) => {
|
|
||||||
let sugg = trait_sig.output();
|
|
||||||
diag.span_suggestion(hir_ty.span, msg, sugg, ap);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
} else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
|
|
||||||
diag.span_suggestion(
|
|
||||||
impl_err_span,
|
|
||||||
"change the parameter type to match the trait",
|
|
||||||
trait_ty,
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
infcx.err_ctxt().note_type_err(
|
|
||||||
&mut diag,
|
|
||||||
&cause,
|
|
||||||
trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
|
|
||||||
Some(infer::ValuePairs::Terms(ExpectedFound {
|
|
||||||
expected: trait_fty.into(),
|
|
||||||
found: impl_fty.into(),
|
|
||||||
})),
|
|
||||||
terr,
|
terr,
|
||||||
false,
|
(trait_m, trait_fty),
|
||||||
false,
|
(impl_m, impl_fty),
|
||||||
|
&trait_sig,
|
||||||
|
&impl_trait_ref,
|
||||||
);
|
);
|
||||||
|
return Err(emitted);
|
||||||
return Err(diag.emit());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that all obligations are satisfied by the implementation's
|
// Check that all obligations are satisfied by the implementation's
|
||||||
|
@ -424,6 +342,7 @@ fn compare_predicate_entailment<'tcx>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(tcx), level = "debug", ret)]
|
||||||
pub fn collect_trait_impl_trait_tys<'tcx>(
|
pub fn collect_trait_impl_trait_tys<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
|
@ -437,7 +356,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
|
||||||
|
|
||||||
let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
|
let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
|
||||||
let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
|
let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
|
||||||
let cause = ObligationCause::new(
|
let mut cause = ObligationCause::new(
|
||||||
return_span,
|
return_span,
|
||||||
impl_m_hir_id,
|
impl_m_hir_id,
|
||||||
ObligationCauseCode::CompareImplItemObligation {
|
ObligationCauseCode::CompareImplItemObligation {
|
||||||
|
@ -514,23 +433,35 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!(?trait_sig, ?impl_sig, "equating function signatures");
|
||||||
|
|
||||||
|
let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
|
||||||
|
let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
|
||||||
|
|
||||||
// Unify the whole function signature. We need to do this to fully infer
|
// Unify the whole function signature. We need to do this to fully infer
|
||||||
// the lifetimes of the return type, but do this after unifying just the
|
// the lifetimes of the return type, but do this after unifying just the
|
||||||
// return types, since we want to avoid duplicating errors from
|
// return types, since we want to avoid duplicating errors from
|
||||||
// `compare_predicate_entailment`.
|
// `compare_predicate_entailment`.
|
||||||
match infcx
|
match infcx.at(&cause, param_env).eq(trait_fty, impl_fty) {
|
||||||
.at(&cause, param_env)
|
|
||||||
.eq(tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)), tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)))
|
|
||||||
{
|
|
||||||
Ok(infer::InferOk { value: (), obligations }) => {
|
Ok(infer::InferOk { value: (), obligations }) => {
|
||||||
ocx.register_obligations(obligations);
|
ocx.register_obligations(obligations);
|
||||||
}
|
}
|
||||||
Err(terr) => {
|
Err(terr) => {
|
||||||
let guar = tcx.sess.delay_span_bug(
|
// This function gets called during `compare_predicate_entailment` when normalizing a
|
||||||
return_span,
|
// signature that contains RPITIT. When the method signatures don't match, we have to
|
||||||
format!("could not unify `{trait_sig}` and `{impl_sig}`: {terr:?}"),
|
// emit an error now because `compare_predicate_entailment` will not report the error
|
||||||
|
// when normalization fails.
|
||||||
|
let emitted = report_trait_method_mismatch(
|
||||||
|
tcx,
|
||||||
|
&mut cause,
|
||||||
|
infcx,
|
||||||
|
terr,
|
||||||
|
(trait_m, trait_fty),
|
||||||
|
(impl_m, impl_fty),
|
||||||
|
&trait_sig,
|
||||||
|
&impl_trait_ref,
|
||||||
);
|
);
|
||||||
return Err(guar);
|
return Err(emitted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,6 +621,112 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report_trait_method_mismatch<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
cause: &mut ObligationCause<'tcx>,
|
||||||
|
infcx: &InferCtxt<'tcx>,
|
||||||
|
terr: TypeError<'tcx>,
|
||||||
|
(trait_m, trait_fty): (&AssocItem, Ty<'tcx>),
|
||||||
|
(impl_m, impl_fty): (&AssocItem, Ty<'tcx>),
|
||||||
|
trait_sig: &FnSig<'tcx>,
|
||||||
|
impl_trait_ref: &TraitRef<'tcx>,
|
||||||
|
) -> ErrorGuaranteed {
|
||||||
|
let (impl_err_span, trait_err_span) =
|
||||||
|
extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
|
||||||
|
|
||||||
|
cause.span = impl_err_span;
|
||||||
|
|
||||||
|
let mut diag = struct_span_err!(
|
||||||
|
tcx.sess,
|
||||||
|
cause.span(),
|
||||||
|
E0053,
|
||||||
|
"method `{}` has an incompatible type for trait",
|
||||||
|
trait_m.name
|
||||||
|
);
|
||||||
|
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()) {
|
||||||
|
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 span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).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) => {
|
||||||
|
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.
|
||||||
|
match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
|
||||||
|
ImplItemKind::Fn(ref sig, _)
|
||||||
|
if sig.header.asyncness == hir::IsAsync::NotAsync =>
|
||||||
|
{
|
||||||
|
let msg = "change the output type to match the trait";
|
||||||
|
let ap = Applicability::MachineApplicable;
|
||||||
|
match sig.decl.output {
|
||||||
|
hir::FnRetTy::DefaultReturn(sp) => {
|
||||||
|
let sugg = format!("-> {} ", trait_sig.output());
|
||||||
|
diag.span_suggestion_verbose(sp, msg, sugg, ap);
|
||||||
|
}
|
||||||
|
hir::FnRetTy::Return(hir_ty) => {
|
||||||
|
let sugg = trait_sig.output();
|
||||||
|
diag.span_suggestion(hir_ty.span, msg, sugg, ap);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
} else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
|
||||||
|
diag.span_suggestion(
|
||||||
|
impl_err_span,
|
||||||
|
"change the parameter type to match the trait",
|
||||||
|
trait_ty,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
infcx.err_ctxt().note_type_err(
|
||||||
|
&mut diag,
|
||||||
|
&cause,
|
||||||
|
trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
|
||||||
|
Some(infer::ValuePairs::Terms(ExpectedFound {
|
||||||
|
expected: trait_fty.into(),
|
||||||
|
found: impl_fty.into(),
|
||||||
|
})),
|
||||||
|
terr,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
return diag.emit();
|
||||||
|
}
|
||||||
|
|
||||||
fn check_region_bounds_on_impl_item<'tcx>(
|
fn check_region_bounds_on_impl_item<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
impl_m: &ty::AssocItem,
|
impl_m: &ty::AssocItem,
|
||||||
|
|
51
src/test/ui/impl-trait/in-trait/method-signature-matches.rs
Normal file
51
src/test/ui/impl-trait/in-trait/method-signature-matches.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// edition: 2021
|
||||||
|
|
||||||
|
#![feature(return_position_impl_trait_in_trait, async_fn_in_trait)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
trait Uwu {
|
||||||
|
fn owo(x: ()) -> impl Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Uwu for () {
|
||||||
|
fn owo(_: u8) {}
|
||||||
|
//~^ ERROR method `owo` has an incompatible type for trait
|
||||||
|
}
|
||||||
|
|
||||||
|
trait AsyncUwu {
|
||||||
|
async fn owo(x: ()) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncUwu for () {
|
||||||
|
async fn owo(_: u8) {}
|
||||||
|
//~^ ERROR method `owo` has an incompatible type for trait
|
||||||
|
}
|
||||||
|
|
||||||
|
trait TooMuch {
|
||||||
|
fn calm_down_please() -> impl Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TooMuch for () {
|
||||||
|
fn calm_down_please(_: (), _: (), _: ()) {}
|
||||||
|
//~^ ERROR method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
|
||||||
|
}
|
||||||
|
|
||||||
|
trait TooLittle {
|
||||||
|
fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TooLittle for () {
|
||||||
|
fn come_on_a_little_more_effort() {}
|
||||||
|
//~^ ERROR method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Lifetimes {
|
||||||
|
fn early<'early, T>(x: &'early T) -> impl Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Lifetimes for () {
|
||||||
|
fn early<'late, T>(_: &'late ()) {}
|
||||||
|
//~^ ERROR method `early` has an incompatible type for trait
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,84 @@
|
||||||
|
error[E0053]: method `owo` has an incompatible type for trait
|
||||||
|
--> $DIR/method-signature-matches.rs:11:15
|
||||||
|
|
|
||||||
|
LL | fn owo(_: u8) {}
|
||||||
|
| ^^
|
||||||
|
| |
|
||||||
|
| expected `()`, found `u8`
|
||||||
|
| help: change the parameter type to match the trait: `()`
|
||||||
|
|
|
||||||
|
note: type in trait
|
||||||
|
--> $DIR/method-signature-matches.rs:7:15
|
||||||
|
|
|
||||||
|
LL | fn owo(x: ()) -> impl Sized;
|
||||||
|
| ^^
|
||||||
|
= note: expected fn pointer `fn(())`
|
||||||
|
found fn pointer `fn(u8)`
|
||||||
|
|
||||||
|
error[E0053]: method `owo` has an incompatible type for trait
|
||||||
|
--> $DIR/method-signature-matches.rs:20:21
|
||||||
|
|
|
||||||
|
LL | async fn owo(_: u8) {}
|
||||||
|
| ^^
|
||||||
|
| |
|
||||||
|
| expected `()`, found `u8`
|
||||||
|
| help: change the parameter type to match the trait: `()`
|
||||||
|
|
|
||||||
|
note: while checking the return type of the `async fn`
|
||||||
|
--> $DIR/method-signature-matches.rs:20:25
|
||||||
|
|
|
||||||
|
LL | async fn owo(_: u8) {}
|
||||||
|
| ^ checked the `Output` of this `async fn`, expected opaque type
|
||||||
|
note: while checking the return type of the `async fn`
|
||||||
|
--> $DIR/method-signature-matches.rs:20:25
|
||||||
|
|
|
||||||
|
LL | async fn owo(_: u8) {}
|
||||||
|
| ^ checked the `Output` of this `async fn`, found opaque type
|
||||||
|
note: type in trait
|
||||||
|
--> $DIR/method-signature-matches.rs:16:21
|
||||||
|
|
|
||||||
|
LL | async fn owo(x: ()) {}
|
||||||
|
| ^^
|
||||||
|
= note: expected fn pointer `fn(()) -> _`
|
||||||
|
found fn pointer `fn(u8) -> _`
|
||||||
|
|
||||||
|
error[E0050]: method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
|
||||||
|
--> $DIR/method-signature-matches.rs:29:28
|
||||||
|
|
|
||||||
|
LL | fn calm_down_please() -> impl Sized;
|
||||||
|
| ------------------------------------ trait requires 0 parameters
|
||||||
|
...
|
||||||
|
LL | fn calm_down_please(_: (), _: (), _: ()) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^ expected 0 parameters, found 3
|
||||||
|
|
||||||
|
error[E0050]: method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3
|
||||||
|
--> $DIR/method-signature-matches.rs:38:5
|
||||||
|
|
|
||||||
|
LL | fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
|
||||||
|
| ---------------- trait requires 3 parameters
|
||||||
|
...
|
||||||
|
LL | fn come_on_a_little_more_effort() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 3 parameters, found 0
|
||||||
|
|
||||||
|
error[E0053]: method `early` has an incompatible type for trait
|
||||||
|
--> $DIR/method-signature-matches.rs:47:27
|
||||||
|
|
|
||||||
|
LL | fn early<'late, T>(_: &'late ()) {}
|
||||||
|
| - ^^^^^^^^^
|
||||||
|
| | |
|
||||||
|
| | expected type parameter `T`, found `()`
|
||||||
|
| | help: change the parameter type to match the trait: `&'early T`
|
||||||
|
| this type parameter
|
||||||
|
|
|
||||||
|
note: type in trait
|
||||||
|
--> $DIR/method-signature-matches.rs:43:28
|
||||||
|
|
|
||||||
|
LL | fn early<'early, T>(x: &'early T) -> impl Sized;
|
||||||
|
| ^^^^^^^^^
|
||||||
|
= note: expected fn pointer `fn(&'early T)`
|
||||||
|
found fn pointer `fn(&())`
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0050, E0053.
|
||||||
|
For more information about an error, try `rustc --explain E0050`.
|
Loading…
Add table
Add a link
Reference in a new issue