Skip to content

Commit

Permalink
Rollup merge of #112611 - compiler-errors:unconstrained-lt-in-rpitit,…
Browse files Browse the repository at this point in the history
… r=oli-obk

Error on unconstrained lifetime in RPITIT

Fixes #109468

The only thing is that I had to split `tests/ui/impl-trait/in-trait/method-signature-matches.rs` into a bunch of different revisions because some error aren't being emitted if all the different examples are all together in one file 🤔

r? `@oli-obk` just because i know you'll review it, feel free to re-roll
  • Loading branch information
matthiaskrgr authored Jun 14, 2023
2 parents 7240943 + bc78d0c commit 8aff112
Show file tree
Hide file tree
Showing 12 changed files with 188 additions and 102 deletions.
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

0 comments on commit 8aff112

Please sign in to comment.