Rollup merge of #128171 - compiler-errors:arg-compat, r=oli-obk

Make sure that args are compatible in `resolve_associated_item`

Implements a similar check to the one that we have in projection for GATs (#102488, #123240), where we check that the args of an impl item are compatible before returning it. This is done in `resolve_assoc_item`, which is backing `Instance::resolve`, so this is conceptually generalizing the check from GATs to methods/assoc consts. This is important to make sure that the inliner will only visit and substitute MIR bodies that are compatible w/ their trait definitions.

This shouldn't happen in codegen, but there are a few ways to get the inliner to be invoked (via calls to `optimized_mir`) before codegen, namely polymorphization and CTFE.

Fixes #121957
Fixes #120792
Fixes #120793
Fixes #121063
This commit is contained in:
Matthias Krüger
2024-07-25 16:48:21 +02:00
committed by GitHub
11 changed files with 108 additions and 130 deletions
+13 -2
View File
@@ -191,11 +191,22 @@ fn resolve_associated_item<'tcx>(
// Any final impl is required to define all associated items.
if !leaf_def.item.defaultness(tcx).has_value() {
let guard = tcx.dcx().span_delayed_bug(
let guar = tcx.dcx().span_delayed_bug(
tcx.def_span(leaf_def.item.def_id),
"missing value for assoc item in impl",
);
return Err(guard);
return Err(guar);
}
// Make sure that we're projecting to an item that has compatible args.
// This may happen if we are resolving an instance before codegen, such
// as during inlining. This check is also done in projection.
if !tcx.check_args_compatible(leaf_def.item.def_id, args) {
let guar = tcx.dcx().span_delayed_bug(
tcx.def_span(leaf_def.item.def_id),
"missing value for assoc item in impl",
);
return Err(guar);
}
let args = tcx.erase_regions(args);
-25
View File
@@ -1,25 +0,0 @@
//@ known-bug: #120792
//@ compile-flags: -Zpolymorphize=on -Zinline-mir=yes
impl Trait<()> for () {
fn foo<'a, K>(self, _: (), _: K) {
todo!();
}
}
trait Foo<T> {}
impl<F, T> Foo<T> for F {
fn main() {
().foo((), ());
}
}
trait Trait<T> {
fn foo<'a, K>(self, _: T, _: K)
where
T: 'a,
K: 'a;
}
pub fn main() {}
-22
View File
@@ -1,22 +0,0 @@
//@ known-bug: #120793
// can't use build-fail, because this also fails check-fail, but
// the ICE from #120787 only reproduces on build-fail.
//@ compile-flags: --emit=mir
#![feature(effects)]
trait Dim {
fn dim() -> usize;
}
enum Dim3 {}
impl Dim for Dim3 {
fn dim(x: impl Sized) -> usize {
3
}
}
fn main() {
[0; Dim3::dim()];
}
-21
View File
@@ -1,21 +0,0 @@
//@ known-bug: #120793
#![feature(effects)]
trait Dim {
fn dim() -> usize;
}
enum Dim3 {}
impl Dim for Dim3 {
fn dim(mut x: impl Iterator<Item = &'_ ()>) -> usize {
3
}
}
fn main() {
let array: [usize; Dim3::dim()]
//~^ ERROR E0015
= [0; Dim3::dim()];
//~^ ERROR E0015
}
-20
View File
@@ -1,20 +0,0 @@
//@ known-bug: #121063
//@ compile-flags: -Zpolymorphize=on --edition=2021 -Zinline-mir=yes
use std::{
fmt, ops,
path::{Component, Path, PathBuf},
};
pub struct AbsPathBuf(PathBuf);
impl TryFrom<PathBuf> for AbsPathBuf {
type Error = PathBuf;
fn try_from(path: impl AsRef<Path>) -> Result<AbsPathBuf, PathBuf> {}
}
impl TryFrom<&str> for AbsPathBuf {
fn try_from(path: &str) -> Result<AbsPathBuf, PathBuf> {
AbsPathBuf::try_from(PathBuf::from(path))
}
}
-20
View File
@@ -1,20 +0,0 @@
//@ known-bug: #121957
#![feature(const_trait_impl, effects)]
#[const_trait]
trait Main {
fn compute<T: ~const Aux>() -> u32;
}
impl const Main for () {
fn compute<'x, 'y, 'z: 'x>() -> u32 {}
}
#[const_trait]
trait Aux {}
impl const Aux for () {}
fn main() {
const _: u32 = <()>::compute::<()>();
}
-20
View File
@@ -1,20 +0,0 @@
//@ known-bug: #121957
#![feature(const_trait_impl, effects)]
#[const_trait]
trait Main {
fn compute<T: ~const Aux>() -> u32;
}
impl const Main for () {
fn compute<'x, 'y, 'z: 'x>() -> u32 {}
}
#[const_trait]
trait Aux {}
impl const Aux for () {}
fn main() {
const _: u32 = <()>::compute::<()>();
}
@@ -0,0 +1,27 @@
// This test demonstrates an ICE that may occur when we try to resolve the instance
// of a impl that has different generics than the trait it's implementing. This ensures
// we first check that the args are compatible before resolving the body, just like
// we do in projection before substituting a GAT.
//
// When polymorphization is enabled, we check the optimized MIR for unused parameters.
// This will invoke the inliner, leading to this ICE.
//@ compile-flags: -Zpolymorphize=on -Zinline-mir=yes
trait Trait {
fn foo<'a, K: 'a>(self, _: K);
}
impl Trait for () {
#[inline]
fn foo<K>(self, _: K) {
//~^ ERROR lifetime parameters or bounds on method `foo` do not match the trait declaration
todo!();
}
}
pub fn qux<T>() {
().foo(());
}
fn main() {}
@@ -0,0 +1,15 @@
error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
--> $DIR/inline-incorrect-early-bound.rs:17:11
|
LL | fn foo<'a, K: 'a>(self, _: K);
| -----------
| | |
| | this bound might be missing in the impl
| lifetimes in impl do not match this method in trait
...
LL | fn foo<K>(self, _: K) {
| ^^^ lifetimes do not match method in trait
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0195`.
@@ -0,0 +1,32 @@
// This test demonstrates an ICE that may occur when we try to resolve the instance
// of a impl that has different generics than the trait it's implementing. This ensures
// we first check that the args are compatible before resolving the body, just like
// we do in projection before substituting a GAT.
//
// Const traits aren't the only way to achieve this ICE, but it's a convenient way
// to ensure the inliner is called.
//@ compile-flags: -Znext-solver -Zinline-mir=yes
#![feature(const_trait_impl, effects)]
//~^ WARN the feature `effects` is incomplete
trait Trait {
fn foo(self);
}
impl Trait for () {
#[inline]
fn foo<T>(self) {
//~^ ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters
todo!();
}
}
const fn foo() {
().foo();
}
const UWU: () = foo();
fn main() {}
@@ -0,0 +1,21 @@
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/inline-incorrect-early-bound-in-ctfe.rs:11:30
|
LL | #![feature(const_trait_impl, effects)]
| ^^^^^^^
|
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters
--> $DIR/inline-incorrect-early-bound-in-ctfe.rs:20:12
|
LL | fn foo(self);
| - expected 0 type parameters
...
LL | fn foo<T>(self) {
| ^ found 1 type parameter
error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0049`.