Skip to content

Commit

Permalink
Rollup merge of rust-lang#103827 - compiler-errors:rpitit-substs-comp…
Browse files Browse the repository at this point in the history
…at, r=wesleywiser

Properly remap and check for substs compatibility in `confirm_impl_trait_in_trait_candidate`

Fixes rust-lang#103824
  • Loading branch information
Manishearth authored Nov 8, 2022
2 parents 0dfd52b + 0f632c8 commit 04defb6
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 4 deletions.
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,9 @@ impl<'tcx> TyCtxt<'tcx> {
(ty::Projection(_), ty::Projection(_)) => {
diag.note("an associated type was expected, but a different one was found");
}
(ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), ty::Param(p)) => {
(ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), ty::Param(p))
if self.def_kind(proj.item_def_id) != DefKind::ImplTraitPlaceholder =>
{
let generics = self.generics_of(body_owner_def_id);
let p_span = self.def_span(generics.type_param(p, self).def_id);
if !sp.contains(p_span) {
Expand Down
25 changes: 22 additions & 3 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2187,7 +2187,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
// Verify that the trait item and its implementation have compatible substs lists
fn check_substs_compatible<'tcx>(
tcx: TyCtxt<'tcx>,
assoc_ty: &ty::AssocItem,
assoc_item: &ty::AssocItem,
substs: ty::SubstsRef<'tcx>,
) -> bool {
fn check_substs_compatible_inner<'tcx>(
Expand Down Expand Up @@ -2219,7 +2219,10 @@ fn check_substs_compatible<'tcx>(
true
}

check_substs_compatible_inner(tcx, tcx.generics_of(assoc_ty.def_id), substs.as_slice())
let generics = tcx.generics_of(assoc_item.def_id);
// Chop off any additional substs (RPITIT) substs
let substs = &substs[0..generics.count().min(substs.len())];
check_substs_compatible_inner(tcx, generics, substs)
}

fn confirm_impl_trait_in_trait_candidate<'tcx>(
Expand Down Expand Up @@ -2248,11 +2251,27 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
};
}

let impl_fn_def_id = leaf_def.item.def_id;
// Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque},
// since `data.substs` are the impl substs.
let impl_fn_substs =
obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs);
let impl_fn_substs = translate_substs(
selcx.infcx(),
obligation.param_env,
data.impl_def_id,
impl_fn_substs,
leaf_def.defining_node,
);

if !check_substs_compatible(tcx, &leaf_def.item, impl_fn_substs) {
let err = tcx.ty_error_with_message(
obligation.cause.span,
"impl method and trait method have different parameters",
);
return Progress { term: err.into(), obligations };
}

let impl_fn_def_id = leaf_def.item.def_id;

let cause = ObligationCause::new(
obligation.cause.span,
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/impl-trait/in-trait/generics-mismatch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![feature(return_position_impl_trait_in_trait)]
#![allow(incomplete_features)]

struct U;

trait Foo {
fn bar(&self) -> impl Sized;
}

impl Foo for U {
fn bar<T>(&self) {}
//~^ ERROR method `bar` has 1 type parameter but its trait declaration has 0 type parameters
}

fn main() {
U.bar();
}
12 changes: 12 additions & 0 deletions src/test/ui/impl-trait/in-trait/generics-mismatch.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters
--> $DIR/generics-mismatch.rs:11:12
|
LL | fn bar(&self) -> impl Sized;
| - expected 0 type parameters
...
LL | fn bar<T>(&self) {}
| ^ found 1 type parameter

error: aborting due to previous error

For more information about this error, try `rustc --explain E0049`.
26 changes: 26 additions & 0 deletions src/test/ui/impl-trait/in-trait/specialization-broken.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// FIXME(compiler-errors): I'm not exactly sure if this is expected to pass or not.
// But we fixed an ICE anyways.

#![feature(specialization)]
#![feature(return_position_impl_trait_in_trait)]
#![allow(incomplete_features)]

trait Foo {
fn bar(&self) -> impl Sized;
}

default impl<U> Foo for U
where
U: Copy,
{
fn bar(&self) -> U {
//~^ ERROR method `bar` has an incompatible type for trait
*self
}
}

impl Foo for i32 {}

fn main() {
1i32.bar();
}
23 changes: 23 additions & 0 deletions src/test/ui/impl-trait/in-trait/specialization-broken.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error[E0053]: method `bar` has an incompatible type for trait
--> $DIR/specialization-broken.rs:16:22
|
LL | default impl<U> Foo for U
| - this type parameter
...
LL | fn bar(&self) -> U {
| ^
| |
| expected associated type, found type parameter `U`
| help: change the output type to match the trait: `impl Sized`
|
note: type in trait
--> $DIR/specialization-broken.rs:9:22
|
LL | fn bar(&self) -> impl Sized;
| ^^^^^^^^^^
= note: expected fn pointer `fn(&U) -> impl Sized`
found fn pointer `fn(&U) -> U`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0053`.
24 changes: 24 additions & 0 deletions src/test/ui/impl-trait/in-trait/specialization-substs-remap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// check-pass

#![feature(specialization)]
#![feature(return_position_impl_trait_in_trait)]
#![allow(incomplete_features)]

trait Foo {
fn bar(&self) -> impl Sized;
}

impl<U> Foo for U
where
U: Copy,
{
fn bar(&self) -> U {
*self
}
}

impl Foo for i32 {}

fn main() {
let _: i32 = 1i32.bar();
}

0 comments on commit 04defb6

Please sign in to comment.