Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error on unconstrained lifetime in RPITIT #112611

Merged
merged 1 commit into from
Jun 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 38 additions & 21 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,7 @@ pub(super) fn compare_impl_method<'tcx>(
debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);

let _: Result<_, ErrorGuaranteed> = try {
compare_self_type(tcx, impl_m, trait_m, impl_trait_ref)?;
compare_number_of_generics(tcx, impl_m, trait_m, false)?;
compare_generic_param_kinds(tcx, impl_m, trait_m, false)?;
compare_number_of_method_arguments(tcx, impl_m, trait_m)?;
compare_synthetic_generics(tcx, impl_m, trait_m)?;
compare_asyncness(tcx, impl_m, trait_m)?;
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?;
compare_method_predicate_entailment(
tcx,
impl_m,
Expand All @@ -61,6 +56,26 @@ pub(super) fn compare_impl_method<'tcx>(
};
}

/// Checks a bunch of different properties of the impl/trait methods for
/// compatibility, such as asyncness, number of argument, self receiver kind,
/// and number of early- and late-bound generics.
fn check_method_is_structurally_compatible<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: ty::AssocItem,
trait_m: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
delay: bool,
) -> Result<(), ErrorGuaranteed> {
compare_self_type(tcx, impl_m, trait_m, impl_trait_ref, delay)?;
compare_number_of_generics(tcx, impl_m, trait_m, delay)?;
compare_generic_param_kinds(tcx, impl_m, trait_m, delay)?;
compare_number_of_method_arguments(tcx, impl_m, trait_m, delay)?;
compare_synthetic_generics(tcx, impl_m, trait_m, delay)?;
compare_asyncness(tcx, impl_m, trait_m, delay)?;
check_region_bounds_on_impl_item(tcx, impl_m, trait_m, delay)?;
Ok(())
}

/// This function is best explained by example. Consider a trait with it's implementation:
///
/// ```rust
Expand Down Expand Up @@ -177,9 +192,6 @@ fn compare_method_predicate_entailment<'tcx>(
let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
let trait_m_predicates = tcx.predicates_of(trait_m.def_id);

// Check region bounds.
check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?;

// 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`,
Expand Down Expand Up @@ -534,6 +546,7 @@ fn compare_asyncness<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: ty::AssocItem,
trait_m: ty::AssocItem,
delay: bool,
) -> Result<(), ErrorGuaranteed> {
if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() {
Expand All @@ -544,11 +557,14 @@ fn compare_asyncness<'tcx>(
// We don't know if it's ok, but at least it's already an error.
}
_ => {
return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
span: tcx.def_span(impl_m.def_id),
method_name: trait_m.name,
trait_item_span: tcx.hir().span_if_local(trait_m.def_id),
}));
return Err(tcx
.sess
.create_err(crate::errors::AsyncTraitImplShouldBeAsync {
span: tcx.def_span(impl_m.def_id),
method_name: trait_m.name,
trait_item_span: tcx.hir().span_if_local(trait_m.def_id),
})
.emit_unless(delay));
}
};
}
Expand Down Expand Up @@ -602,9 +618,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(

// First, check a few of the same things as `compare_impl_method`,
// just so we don't ICE during substitution later.
compare_number_of_generics(tcx, impl_m, trait_m, true)?;
compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;
check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?;
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;

let trait_to_impl_substs = impl_trait_ref.substs;

Expand Down Expand Up @@ -1097,6 +1111,7 @@ fn compare_self_type<'tcx>(
impl_m: ty::AssocItem,
trait_m: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
delay: bool,
) -> Result<(), ErrorGuaranteed> {
// Try to give more informative error messages about self typing
// mismatches. Note that any mismatch will also be detected
Expand Down Expand Up @@ -1145,7 +1160,7 @@ fn compare_self_type<'tcx>(
} else {
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
}
return Err(err.emit());
return Err(err.emit_unless(delay));
}

(true, false) => {
Expand All @@ -1166,7 +1181,7 @@ fn compare_self_type<'tcx>(
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
}

return Err(err.emit());
return Err(err.emit_unless(delay));
}
}

Expand Down Expand Up @@ -1352,6 +1367,7 @@ fn compare_number_of_method_arguments<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: ty::AssocItem,
trait_m: ty::AssocItem,
delay: bool,
) -> Result<(), ErrorGuaranteed> {
let impl_m_fty = tcx.fn_sig(impl_m.def_id);
let trait_m_fty = tcx.fn_sig(trait_m.def_id);
Expand Down Expand Up @@ -1422,7 +1438,7 @@ fn compare_number_of_method_arguments<'tcx>(
),
);

return Err(err.emit());
return Err(err.emit_unless(delay));
}

Ok(())
Expand All @@ -1432,6 +1448,7 @@ fn compare_synthetic_generics<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: ty::AssocItem,
trait_m: ty::AssocItem,
delay: bool,
) -> Result<(), ErrorGuaranteed> {
// FIXME(chrisvittal) Clean up this function, list of FIXME items:
// 1. Better messages for the span labels
Expand Down Expand Up @@ -1551,7 +1568,7 @@ fn compare_synthetic_generics<'tcx>(
}
_ => unreachable!(),
}
error_found = Some(err.emit());
error_found = Some(err.emit_unless(delay));
}
}
if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
Expand Down
17 changes: 15 additions & 2 deletions compiler/rustc_hir_analysis/src/impl_wf_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,23 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
if item.defaultness(tcx).has_value() {
cgp::parameters_for(&tcx.type_of(def_id).subst_identity(), true)
} else {
Vec::new()
vec![]
}
}
ty::AssocKind::Fn | ty::AssocKind::Const => Vec::new(),
ty::AssocKind::Fn => {
if !tcx.lower_impl_trait_in_trait_to_assoc_ty()
&& item.defaultness(tcx).has_value()
&& tcx.impl_method_has_trait_impl_trait_tys(item.def_id)
&& let Ok(table) = tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
{
table.values().copied().flat_map(|ty| {
cgp::parameters_for(&ty.subst_identity(), true)
}).collect()
} else {
vec![]
}
}
ty::AssocKind::Const => vec![],
}
})
.collect();
Expand Down
21 changes: 21 additions & 0 deletions tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0053]: method `early` has an incompatible type for trait
--> $DIR/method-signature-matches.rs:58: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:53:28
|
LL | fn early<'early, T>(x: &'early T) -> impl Sized;
| ^^^^^^^^^
= note: expected signature `fn(&'early T)`
found signature `fn(&())`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0053`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0053]: method `owo` has an incompatible type for trait
--> $DIR/method-signature-matches.rs:14: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:9:15
|
LL | fn owo(x: ()) -> impl Sized;
| ^^
= note: expected signature `fn(())`
found signature `fn(u8)`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0053`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0053]: method `owo` has an incompatible type for trait
--> $DIR/method-signature-matches.rs:25:21
|
LL | async fn owo(_: u8) {}
| ^^
| |
| expected `()`, found `u8`
| help: change the parameter type to match the trait: `()`
|
note: type in trait
--> $DIR/method-signature-matches.rs:20:21
|
LL | async fn owo(x: ()) {}
| ^^
= note: expected signature `fn(()) -> _`
found signature `fn(u8) -> _`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0053`.
21 changes: 16 additions & 5 deletions tests/ui/impl-trait/in-trait/method-signature-matches.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,62 @@
// edition: 2021
// revisions: mismatch mismatch_async too_many too_few lt

#![feature(return_position_impl_trait_in_trait, async_fn_in_trait)]
#![allow(incomplete_features)]

#[cfg(mismatch)]
trait Uwu {
fn owo(x: ()) -> impl Sized;
}

#[cfg(mismatch)]
impl Uwu for () {
fn owo(_: u8) {}
//~^ ERROR method `owo` has an incompatible type for trait
//[mismatch]~^ ERROR method `owo` has an incompatible type for trait
}

#[cfg(mismatch_async)]
trait AsyncUwu {
async fn owo(x: ()) {}
}

#[cfg(mismatch_async)]
impl AsyncUwu for () {
async fn owo(_: u8) {}
//~^ ERROR method `owo` has an incompatible type for trait
//[mismatch_async]~^ ERROR method `owo` has an incompatible type for trait
}

#[cfg(too_many)]
trait TooMuch {
fn calm_down_please() -> impl Sized;
}

#[cfg(too_many)]
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
//[too_many]~^ ERROR method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
}

#[cfg(too_few)]
trait TooLittle {
fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
}

#[cfg(too_few)]
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
//[too_few]~^ 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
}

#[cfg(lt)]
trait Lifetimes {
fn early<'early, T>(x: &'early T) -> impl Sized;
}

#[cfg(lt)]
impl Lifetimes for () {
fn early<'late, T>(_: &'late ()) {}
//~^ ERROR method `early` has an incompatible type for trait
//[lt]~^ ERROR method `early` has an incompatible type for trait
}

fn main() {}
74 changes: 0 additions & 74 deletions tests/ui/impl-trait/in-trait/method-signature-matches.stderr

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
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:47: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: aborting due to previous error

For more information about this error, try `rustc --explain E0050`.
Loading