Auto merge of #121679 - lcnr:opaque-wf-check-2, r=oli-obk
stricter hidden type wf-check [based on #115008] Original work by `@aliemjay` in #115008. A huge thanks to them for originally figuring out this approach ❤️ Fixes https://github.com/rust-lang/rust/issues/114728 Fixes https://github.com/rust-lang/rust/issues/114572 Instead of adding the `WellFormed` obligations when relating opaque types, we now always emit such an obligation when defining the hidden type. This causes nested opaque types which aren't wf to error, see the comment below for the described impact. I believe this change to be desirable as it significantly reduces complexity by removing special-cases. It also caused an issue with RPITIT: in defaulted trait methods, we add a `Projection(synthetic_assoc, rpit_of_trait_method)` clause to the `param_env`. This clause is not added to the `ParamEnv` of the nested coroutines. This caused a normalization failure in `fn check_coroutine_obligations` with the new solver. I fixed that by using the env of the typeck root instead. r? `@oli-obk`
This commit is contained in:
commit
09bc67b915
21 changed files with 313 additions and 136 deletions
|
@ -402,32 +402,21 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||||
let guar = infcx.err_ctxt().report_fulfillment_errors(errors);
|
let guar = infcx.err_ctxt().report_fulfillment_errors(errors);
|
||||||
return Err(guar);
|
return Err(guar);
|
||||||
}
|
}
|
||||||
match origin {
|
|
||||||
// Checked when type checking the function containing them.
|
let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, defining_use_anchor)?;
|
||||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
|
let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, &wf_tys);
|
||||||
|
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||||
|
ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
|
||||||
|
|
||||||
|
if let hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) = origin {
|
||||||
// HACK: this should also fall through to the hidden type check below, but the original
|
// HACK: this should also fall through to the hidden type check below, but the original
|
||||||
// implementation had a bug where equivalent lifetimes are not identical. This caused us
|
// implementation had a bug where equivalent lifetimes are not identical. This caused us
|
||||||
// to reject existing stable code that is otherwise completely fine. The real fix is to
|
// to reject existing stable code that is otherwise completely fine. The real fix is to
|
||||||
// compare the hidden types via our type equivalence/relation infra instead of doing an
|
// compare the hidden types via our type equivalence/relation infra instead of doing an
|
||||||
// identity check.
|
// identity check.
|
||||||
let _ = infcx.take_opaque_types();
|
let _ = infcx.take_opaque_types();
|
||||||
return Ok(());
|
Ok(())
|
||||||
}
|
} else {
|
||||||
// Nested opaque types occur only in associated types:
|
|
||||||
// ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
|
|
||||||
// They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`.
|
|
||||||
// We don't have to check them here because their well-formedness follows from the WF of
|
|
||||||
// the projection input types in the defining- and use-sites.
|
|
||||||
hir::OpaqueTyOrigin::TyAlias { .. }
|
|
||||||
if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {}
|
|
||||||
// Can have different predicates to their defining use
|
|
||||||
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
|
||||||
let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?;
|
|
||||||
let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, &wf_tys);
|
|
||||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
|
||||||
ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
|
// Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
|
||||||
for (mut key, mut ty) in infcx.take_opaque_types() {
|
for (mut key, mut ty) in infcx.take_opaque_types() {
|
||||||
ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty);
|
ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty);
|
||||||
|
@ -435,6 +424,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||||
sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?;
|
sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sanity_check_found_hidden_type<'tcx>(
|
fn sanity_check_found_hidden_type<'tcx>(
|
||||||
|
@ -1549,6 +1539,8 @@ fn opaque_type_cycle_error(
|
||||||
err.emit()
|
err.emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(@lcnr): This should not be computed per coroutine, but instead once for
|
||||||
|
// each typeck root.
|
||||||
pub(super) fn check_coroutine_obligations(
|
pub(super) fn check_coroutine_obligations(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
def_id: LocalDefId,
|
def_id: LocalDefId,
|
||||||
|
@ -1556,7 +1548,7 @@ pub(super) fn check_coroutine_obligations(
|
||||||
debug_assert!(tcx.is_coroutine(def_id.to_def_id()));
|
debug_assert!(tcx.is_coroutine(def_id.to_def_id()));
|
||||||
|
|
||||||
let typeck = tcx.typeck(def_id);
|
let typeck = tcx.typeck(def_id);
|
||||||
let param_env = tcx.param_env(def_id);
|
let param_env = tcx.param_env(typeck.hir_owner.def_id);
|
||||||
|
|
||||||
let coroutine_interior_predicates = &typeck.coroutine_interior_predicates[&def_id];
|
let coroutine_interior_predicates = &typeck.coroutine_interior_predicates[&def_id];
|
||||||
debug!(?coroutine_interior_predicates);
|
debug!(?coroutine_interior_predicates);
|
||||||
|
|
|
@ -592,8 +592,25 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let item_bounds = tcx.explicit_item_bounds(def_id);
|
// Require that the hidden type is well-formed. We have to
|
||||||
|
// make sure we wf-check the hidden type to fix #114728.
|
||||||
|
//
|
||||||
|
// However, we don't check that all types are well-formed.
|
||||||
|
// We only do so for types provided by the user or if they are
|
||||||
|
// "used", e.g. for method selection.
|
||||||
|
//
|
||||||
|
// This means we never check the wf requirements of the hidden
|
||||||
|
// type during MIR borrowck, causing us to infer the wrong
|
||||||
|
// lifetime for its member constraints which then results in
|
||||||
|
// unexpected region errors.
|
||||||
|
obligations.push(traits::Obligation::new(
|
||||||
|
tcx,
|
||||||
|
cause.clone(),
|
||||||
|
param_env,
|
||||||
|
ty::ClauseKind::WellFormed(hidden_ty.into()),
|
||||||
|
));
|
||||||
|
|
||||||
|
let item_bounds = tcx.explicit_item_bounds(def_id);
|
||||||
for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
|
for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
|
||||||
let predicate = predicate.fold_with(&mut BottomUpFolder {
|
let predicate = predicate.fold_with(&mut BottomUpFolder {
|
||||||
tcx,
|
tcx,
|
||||||
|
|
|
@ -121,18 +121,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
|
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
|
||||||
DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) {
|
DefKind::OpaqueTy => bug!("implied bounds are not defined for opaques"),
|
||||||
DefKind::TyAlias => ty::List::empty(),
|
|
||||||
DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
|
|
||||||
// Nested opaque types only occur in associated types:
|
|
||||||
// ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
|
|
||||||
// assumed_wf_types should include those of `Opaque<T>`, `Opaque<T>` itself
|
|
||||||
// and `&'static T`.
|
|
||||||
DefKind::OpaqueTy => bug!("unimplemented implied bounds for nested opaque types"),
|
|
||||||
def_kind => {
|
|
||||||
bug!("unimplemented implied bounds for opaque types with parent {def_kind:?}")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DefKind::Mod
|
DefKind::Mod
|
||||||
| DefKind::Struct
|
| DefKind::Struct
|
||||||
| DefKind::Union
|
| DefKind::Union
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
fn server() -> impl {
|
fn server() -> impl {
|
||||||
//~^ ERROR at least one trait must be specified
|
//~^ ERROR at least one trait must be specified
|
||||||
|
//~| ERROR type annotations needed
|
||||||
().map2(|| "")
|
().map2(|| "")
|
||||||
//~^ ERROR type annotations needed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trait FilterBase2 {
|
trait FilterBase2 {
|
||||||
|
|
|
@ -23,10 +23,10 @@ LL | struct Map2<Segment2, F> {
|
||||||
| +++
|
| +++
|
||||||
|
|
||||||
error[E0282]: type annotations needed
|
error[E0282]: type annotations needed
|
||||||
--> $DIR/issue-78720.rs:3:5
|
--> $DIR/issue-78720.rs:1:16
|
||||||
|
|
|
|
||||||
LL | ().map2(|| "")
|
LL | fn server() -> impl {
|
||||||
| ^^^^^^^^^^^^^^ cannot infer type
|
| ^^^^ cannot infer type
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/issue-78720.rs:8:39
|
--> $DIR/issue-78720.rs:8:39
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
//@ edition:2021
|
//@ edition:2021
|
||||||
//@ compile-flags:-Z treat-err-as-bug=2
|
|
||||||
//@ error-pattern: due to `-Z treat-err-as-bug=2
|
|
||||||
//@ failure-status:101
|
|
||||||
//@ normalize-stderr-test ".*note: .*\n\n" -> ""
|
|
||||||
//@ normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> ""
|
|
||||||
//@ rustc-env:RUST_BACKTRACE=0
|
|
||||||
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
|
@ -29,6 +23,7 @@ struct Context {
|
||||||
type TransactionResult<O> = Result<O, ()>;
|
type TransactionResult<O> = Result<O, ()>;
|
||||||
|
|
||||||
type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
|
type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
|
||||||
|
//~^ ERROR unconstrained opaque type
|
||||||
|
|
||||||
fn execute_transaction_fut<'f, F, O>(
|
fn execute_transaction_fut<'f, F, O>(
|
||||||
f: F,
|
f: F,
|
||||||
|
@ -37,6 +32,7 @@ where
|
||||||
F: FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> + 'f
|
F: FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> + 'f
|
||||||
{
|
{
|
||||||
f
|
f
|
||||||
|
//~^ ERROR expected generic lifetime parameter, found `'_`
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
|
@ -44,6 +40,7 @@ impl Context {
|
||||||
&self, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O>
|
&self, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O>
|
||||||
) -> TransactionResult<O>
|
) -> TransactionResult<O>
|
||||||
{
|
{
|
||||||
|
//~^ ERROR expected generic lifetime parameter, found `'_`
|
||||||
let mut conn = Connection {};
|
let mut conn = Connection {};
|
||||||
let mut transaction = TestTransaction { conn: &mut conn };
|
let mut transaction = TestTransaction { conn: &mut conn };
|
||||||
f(&mut transaction).await
|
f(&mut transaction).await
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
error: unconstrained opaque type
|
error: unconstrained opaque type
|
||||||
--> $DIR/issue-86800.rs:31:34
|
--> $DIR/issue-86800.rs:25:34
|
||||||
|
|
|
|
||||||
LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
|
LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
error: internal compiler error[E0792]: expected generic lifetime parameter, found `'_`
|
= note: `TransactionFuture` must be used in combination with a concrete type within the same module
|
||||||
--> $DIR/issue-86800.rs:39:5
|
|
||||||
|
error[E0792]: expected generic lifetime parameter, found `'_`
|
||||||
|
--> $DIR/issue-86800.rs:34:5
|
||||||
|
|
|
|
||||||
LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
|
LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
|
||||||
| --- this generic parameter must be used with a generic lifetime parameter
|
| --- this generic parameter must be used with a generic lifetime parameter
|
||||||
|
@ -13,9 +15,20 @@ LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResu
|
||||||
LL | f
|
LL | f
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: the compiler unexpectedly panicked. this is a bug.
|
error[E0792]: expected generic lifetime parameter, found `'_`
|
||||||
|
--> $DIR/issue-86800.rs:42:5
|
||||||
|
|
|
||||||
|
LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
|
||||||
|
| --- this generic parameter must be used with a generic lifetime parameter
|
||||||
|
...
|
||||||
|
LL | / {
|
||||||
|
LL | |
|
||||||
|
LL | | let mut conn = Connection {};
|
||||||
|
LL | | let mut transaction = TestTransaction { conn: &mut conn };
|
||||||
|
LL | | f(&mut transaction).await
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
||||||
query stack during panic:
|
error: aborting due to 3 previous errors
|
||||||
#0 [mir_borrowck] borrow-checking `execute_transaction_fut`
|
|
||||||
#1 [type_of_opaque] computing type of opaque `execute_transaction_fut::{opaque#0}`
|
For more information about this error, try `rustc --explain E0792`.
|
||||||
end of query stack
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
error[E0282]: type annotations needed
|
error[E0282]: type annotations needed
|
||||||
--> $DIR/recursive-coroutine-boxed.rs:10:23
|
--> $DIR/recursive-coroutine-boxed.rs:11:23
|
||||||
|
|
|
|
||||||
LL | let mut gen = Box::pin(foo());
|
LL | let mut gen = Box::pin(foo());
|
||||||
| ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box`
|
| ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box`
|
||||||
...
|
LL |
|
||||||
LL | let mut r = gen.as_mut().resume(());
|
LL | let mut r = gen.as_mut().resume(());
|
||||||
| ------ type must be known at this point
|
| ------ type must be known at this point
|
||||||
|
|
|
|
||||||
|
@ -13,10 +13,10 @@ LL | let mut gen = Box::<T>::pin(foo());
|
||||||
| +++++
|
| +++++
|
||||||
|
|
||||||
error[E0282]: type annotations needed
|
error[E0282]: type annotations needed
|
||||||
--> $DIR/recursive-coroutine-boxed.rs:10:32
|
--> $DIR/recursive-coroutine-boxed.rs:8:13
|
||||||
|
|
|
|
||||||
LL | let mut gen = Box::pin(foo());
|
LL | fn foo() -> impl Coroutine<Yield = (), Return = ()> {
|
||||||
| ^^^^^ cannot infer type for opaque type `impl Coroutine<Yield = (), Return = ()>`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for opaque type `impl Coroutine<Yield = (), Return = ()>`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
use std::ops::{Coroutine, CoroutineState};
|
use std::ops::{Coroutine, CoroutineState};
|
||||||
|
|
||||||
fn foo() -> impl Coroutine<Yield = (), Return = ()> {
|
fn foo() -> impl Coroutine<Yield = (), Return = ()> {
|
||||||
|
//[next]~^ ERROR type annotations needed
|
||||||
|| {
|
|| {
|
||||||
let mut gen = Box::pin(foo());
|
let mut gen = Box::pin(foo());
|
||||||
//[next]~^ ERROR type annotations needed
|
//[next]~^ ERROR type annotations needed
|
||||||
//[next]~| ERROR type annotations needed
|
|
||||||
let mut r = gen.as_mut().resume(());
|
let mut r = gen.as_mut().resume(());
|
||||||
while let CoroutineState::Yielded(v) = r {
|
while let CoroutineState::Yielded(v) = r {
|
||||||
yield v;
|
yield v;
|
||||||
|
|
20
tests/ui/impl-trait/wf-check-hidden-type.rs
Normal file
20
tests/ui/impl-trait/wf-check-hidden-type.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//! Regression test for #114728.
|
||||||
|
|
||||||
|
trait Extend<'a, 'b> {
|
||||||
|
fn extend(self, _: &'a str) -> &'b str;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Extend<'a, 'b> for Option<&'b &'a ()> {
|
||||||
|
fn extend(self, s: &'a str) -> &'b str {
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn boom<'a, 'b>() -> impl Extend<'a, 'b> {
|
||||||
|
None::<&'_ &'_ ()> //~ ERROR lifetime may not live long enough
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let y = boom().extend(&String::from("temporary"));
|
||||||
|
println!("{}", y);
|
||||||
|
}
|
14
tests/ui/impl-trait/wf-check-hidden-type.stderr
Normal file
14
tests/ui/impl-trait/wf-check-hidden-type.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/wf-check-hidden-type.rs:14:5
|
||||||
|
|
|
||||||
|
LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> {
|
||||||
|
| -- -- lifetime `'b` defined here
|
||||||
|
| |
|
||||||
|
| lifetime `'a` defined here
|
||||||
|
LL | None::<&'_ &'_ ()>
|
||||||
|
| ^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
|
||||||
|
|
|
||||||
|
= help: consider adding the following bound: `'a: 'b`
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
|
@ -6,6 +6,7 @@ use std::future::Future;
|
||||||
async fn wrapper<F>(f: F)
|
async fn wrapper<F>(f: F)
|
||||||
//~^ ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
|
//~^ ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
|
||||||
//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
|
//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
|
||||||
|
//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
|
||||||
where
|
where
|
||||||
F:,
|
F:,
|
||||||
for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
|
for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
|
||||||
|
|
|
@ -4,6 +4,7 @@ error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32`
|
||||||
LL | / async fn wrapper<F>(f: F)
|
LL | / async fn wrapper<F>(f: F)
|
||||||
LL | |
|
LL | |
|
||||||
LL | |
|
LL | |
|
||||||
|
LL | |
|
||||||
LL | | where
|
LL | | where
|
||||||
LL | | F:,
|
LL | | F:,
|
||||||
LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
|
LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
|
||||||
|
@ -20,7 +21,21 @@ LL | async fn wrapper<F>(f: F)
|
||||||
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
|
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
|
||||||
|
|
||||||
error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32`
|
error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32`
|
||||||
--> $DIR/issue-76168-hr-outlives-3.rs:12:1
|
--> $DIR/issue-76168-hr-outlives-3.rs:6:1
|
||||||
|
|
|
||||||
|
LL | / async fn wrapper<F>(f: F)
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | where
|
||||||
|
LL | | F:,
|
||||||
|
LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
|
||||||
|
| |__________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32`
|
||||||
|
|
|
||||||
|
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
|
||||||
|
|
||||||
|
error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32`
|
||||||
|
--> $DIR/issue-76168-hr-outlives-3.rs:13:1
|
||||||
|
|
|
|
||||||
LL | / {
|
LL | / {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -31,6 +46,6 @@ LL | | }
|
||||||
|
|
|
|
||||||
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
|
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
|
|
@ -21,6 +21,20 @@ help: consider adding an explicit lifetime bound
|
||||||
LL | for<F> F: 'a, !1_"F": 'a
|
LL | for<F> F: 'a, !1_"F": 'a
|
||||||
| ~~~~~~~~~~~~
|
| ~~~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to 1 previous error; 1 warning emitted
|
error[E0309]: the placeholder type `!2_"F"` may not live long enough
|
||||||
|
--> $DIR/type-match-with-late-bound.rs:11:1
|
||||||
|
|
|
||||||
|
LL | async fn walk2<'a, T: 'a>(_: T)
|
||||||
|
| -- the placeholder type `!2_"F"` must be valid for the lifetime `'a` as defined here...
|
||||||
|
...
|
||||||
|
LL | {}
|
||||||
|
| ^^ ...so that the type `F` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound
|
||||||
|
|
|
||||||
|
LL | for<F> F: 'a, !2_"F": 'a
|
||||||
|
| ~~~~~~~~~~~~
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors; 1 warning emitted
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0309`.
|
For more information about this error, try `rustc --explain E0309`.
|
||||||
|
|
|
@ -2,15 +2,13 @@ error[E0277]: the trait bound `B: Bar` is not satisfied
|
||||||
--> $DIR/issue-90400-2.rs:25:9
|
--> $DIR/issue-90400-2.rs:25:9
|
||||||
|
|
|
|
||||||
LL | MyBaz(bar)
|
LL | MyBaz(bar)
|
||||||
| ^^^^^^^^^^ the trait `Bar` is not implemented for `B`, which is required by `MyBaz<B>: Baz`
|
| ^^^^^^^^^^ the trait `Bar` is not implemented for `B`
|
||||||
|
|
|
|
||||||
note: required for `MyBaz<B>` to implement `Baz`
|
note: required by a bound in `MyBaz`
|
||||||
--> $DIR/issue-90400-2.rs:30:14
|
--> $DIR/issue-90400-2.rs:29:17
|
||||||
|
|
|
|
||||||
LL | impl<B: Bar> Baz for MyBaz<B> {
|
LL | struct MyBaz<B: Bar>(B);
|
||||||
| --- ^^^ ^^^^^^^^
|
| ^^^ required by this bound in `MyBaz`
|
||||||
| |
|
|
||||||
| unsatisfied trait bound introduced here
|
|
||||||
help: consider restricting type parameter `B`
|
help: consider restricting type parameter `B`
|
||||||
|
|
|
|
||||||
LL | type FooFn<B: Bar> = impl Baz;
|
LL | type FooFn<B: Bar> = impl Baz;
|
||||||
|
|
40
tests/ui/type-alias-impl-trait/wf-check-definition-site.rs
Normal file
40
tests/ui/type-alias-impl-trait/wf-check-definition-site.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
// Regression test for #114572, We were inferring an ill-formed type:
|
||||||
|
//
|
||||||
|
// `Opaque<'a> = Static<&'a str>`, vs
|
||||||
|
// `Opaque<'a> = Static<&'static str>`.
|
||||||
|
//
|
||||||
|
// The hidden type of the opaque ends up as `Static<'?0 str>`. When
|
||||||
|
// computing member constraints we end up choosing `'a` for `?0` unless
|
||||||
|
// `?0` is already required to outlive `'a`. We achieve this by checking
|
||||||
|
// that `Static<'?0 str>` is well-formed.
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
struct Static<T: 'static>(T);
|
||||||
|
|
||||||
|
type OpaqueRet<'a> = impl Sized + 'a;
|
||||||
|
fn test_return<'a>(msg: Static<&'static u8>) -> OpaqueRet<'a> {
|
||||||
|
msg
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_rpit<'a>(msg: Static<&'static u8>) -> impl Sized + 'a {
|
||||||
|
msg
|
||||||
|
}
|
||||||
|
|
||||||
|
type OpaqueAssign<'a> = impl Sized + 'a;
|
||||||
|
fn test_assign<'a>(msg: Static<&'static u8>) -> Option<OpaqueAssign<'a>> {
|
||||||
|
let _: OpaqueAssign<'a> = msg;
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// `OpaqueRef<'a, T> = Ref<'a, T>`, vs
|
||||||
|
// `OpaqueRef<'a, T> = Ref<'static, T>`.
|
||||||
|
trait RefAt<'a>: 'a {}
|
||||||
|
struct Ref<'a, T: RefAt<'a>>(&'a T);
|
||||||
|
type OpaqueRef<'a, T: RefAt<'static>> = impl Sized + 'a;
|
||||||
|
fn test_trait<'a, T: RefAt<'static>>(msg: Ref<'static, T>) -> OpaqueRef<'a, T> {
|
||||||
|
msg
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -1,20 +1,15 @@
|
||||||
error[E0310]: the parameter type `T` may not live long enough
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
--> $DIR/wf-nested.rs:57:27
|
--> $DIR/wf-nested.rs:64:38
|
||||||
|
|
|
|
||||||
LL | type InnerOpaque<T> = impl Sized;
|
LL | fn define<T>() -> OuterOpaque<T> {}
|
||||||
| ^^^^^^^^^^
|
| ^^
|
||||||
| |
|
| |
|
||||||
| the parameter type `T` must be valid for the static lifetime...
|
| the parameter type `T` must be valid for the static lifetime...
|
||||||
| ...so that the type `T` will meet its required lifetime bounds...
|
| ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
|
|
||||||
note: ...that is required by this bound
|
|
||||||
--> $DIR/wf-nested.rs:12:20
|
|
||||||
|
|
|
||||||
LL | struct IsStatic<T: 'static>(T);
|
|
||||||
| ^^^^^^^
|
|
||||||
help: consider adding an explicit lifetime bound
|
help: consider adding an explicit lifetime bound
|
||||||
|
|
|
|
||||||
LL | type InnerOpaque<T: 'static> = impl Sized;
|
LL | fn define<T: 'static>() -> OuterOpaque<T> {}
|
||||||
| +++++++++
|
| +++++++++
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
31
tests/ui/type-alias-impl-trait/wf-nested.pass.stderr
Normal file
31
tests/ui/type-alias-impl-trait/wf-nested.pass.stderr
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
|
--> $DIR/wf-nested.rs:34:38
|
||||||
|
|
|
||||||
|
LL | fn define<T>() -> OuterOpaque<T> {}
|
||||||
|
| ^^
|
||||||
|
| |
|
||||||
|
| the parameter type `T` must be valid for the static lifetime...
|
||||||
|
| ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn define<T: 'static>() -> OuterOpaque<T> {}
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
|
--> $DIR/wf-nested.rs:37:69
|
||||||
|
|
|
||||||
|
LL | fn define_rpit<T>() -> impl Trait<&'static T, Out = impl Sized> {}
|
||||||
|
| ^^
|
||||||
|
| |
|
||||||
|
| the parameter type `T` must be valid for the static lifetime...
|
||||||
|
| ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn define_rpit<T: 'static>() -> impl Trait<&'static T, Out = impl Sized> {}
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0310`.
|
|
@ -1,5 +1,19 @@
|
||||||
error[E0310]: the parameter type `T` may not live long enough
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
--> $DIR/wf-nested.rs:46:17
|
--> $DIR/wf-nested.rs:46:38
|
||||||
|
|
|
||||||
|
LL | fn define<T>() -> OuterOpaque<T> {}
|
||||||
|
| ^^
|
||||||
|
| |
|
||||||
|
| the parameter type `T` must be valid for the static lifetime...
|
||||||
|
| ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn define<T: 'static>() -> OuterOpaque<T> {}
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
|
--> $DIR/wf-nested.rs:51:17
|
||||||
|
|
|
|
||||||
LL | let _ = outer.get();
|
LL | let _ = outer.get();
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
@ -13,7 +27,7 @@ LL | fn test<T: 'static>() {
|
||||||
| +++++++++
|
| +++++++++
|
||||||
|
|
||||||
error[E0310]: the parameter type `T` may not live long enough
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
--> $DIR/wf-nested.rs:46:17
|
--> $DIR/wf-nested.rs:51:17
|
||||||
|
|
|
|
||||||
LL | let _ = outer.get();
|
LL | let _ = outer.get();
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
@ -27,6 +41,6 @@ help: consider adding an explicit lifetime bound
|
||||||
LL | fn test<T: 'static>() {
|
LL | fn test<T: 'static>() {
|
||||||
| +++++++++
|
| +++++++++
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0310`.
|
For more information about this error, try `rustc --explain E0310`.
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
// Well-formedness of nested opaque types, i.e. `impl Sized` in
|
// Well-formedness of nested opaque types, i.e. `impl Sized` in
|
||||||
// `type Outer = impl Trait<Assoc = impl Sized>`.
|
// `type Outer = impl Trait<Assoc = impl Sized>`. We check that
|
||||||
// See the comments below.
|
// the nested type is well-formed, even though this would also
|
||||||
//
|
// be implied by the item bounds of the opaque being
|
||||||
//@ revisions: pass pass_sound fail
|
// well-formed. See the comments below.
|
||||||
//@ [pass] check-pass
|
|
||||||
//@ [pass_sound] check-fail
|
|
||||||
//@ [fail] check-fail
|
|
||||||
|
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
struct IsStatic<T: 'static>(T);
|
struct IsStatic<T: 'static>(T);
|
||||||
|
@ -23,40 +19,26 @@ impl<T> Trait<&'static T> for () {
|
||||||
type Out = IsStatic<T>;
|
type Out = IsStatic<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The hidden type for `impl Sized` is `IsStatic<T>`, which requires `T: 'static`.
|
|
||||||
// We know it is well-formed because it can *only* be referenced as a projection:
|
|
||||||
// <OuterOpaque<T> as Trait<&'static T>>::Out`.
|
|
||||||
// So any instantiation of the type already requires proving `T: 'static`.
|
|
||||||
#[cfg(pass)]
|
|
||||||
mod pass {
|
|
||||||
use super::*;
|
|
||||||
type OuterOpaque<T> = impl Trait<&'static T, Out = impl Sized>;
|
|
||||||
fn define<T>() -> OuterOpaque<T> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test the soundness of `pass` - We should require `T: 'static` at the use site.
|
// We could theoretically allow this (and previously did), as even
|
||||||
#[cfg(pass_sound)]
|
// though the nested opaque is not well-formed, it can only be
|
||||||
mod pass_sound {
|
// used by normalizing the projection
|
||||||
use super::*;
|
// <OuterOpaque1<T> as Trait<&'static T>>::Out
|
||||||
type OuterOpaque<T> = impl Trait<&'static T, Out = impl Sized>;
|
// Assuming that we check that this projection is well-formed, the wf
|
||||||
fn define<T>() -> OuterOpaque<T> {}
|
// of the nested opaque is implied.
|
||||||
|
type OuterOpaque1<T> = impl Trait<&'static T, Out = impl Sized>;
|
||||||
|
fn define<T>() -> OuterOpaque1<T> {}
|
||||||
|
//~^ ERROR `T` may not live long enough
|
||||||
|
|
||||||
fn test<T>() {
|
fn define_rpit<T>() -> impl Trait<&'static T, Out = impl Sized> {}
|
||||||
let outer = define::<T>();
|
//~^ ERROR the parameter type `T` may not live long enough
|
||||||
let _ = outer.get();
|
|
||||||
//[pass_sound]~^ ERROR `T` may not live long enough
|
|
||||||
//[pass_sound]~| ERROR `T` may not live long enough
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Similar to `pass` but here `impl Sized` can be referenced directly as
|
// Similar to `define` but here `impl Sized` can be referenced directly as
|
||||||
// InnerOpaque<T>, so we require an explicit bound `T: 'static`.
|
// InnerOpaque<T>, so the `'static` bound is definitely required for
|
||||||
#[cfg(fail)]
|
// soundness.
|
||||||
mod fail {
|
type InnerOpaque<T> = impl Sized;
|
||||||
use super::*;
|
type OuterOpaque2<T> = impl Trait<&'static T, Out = InnerOpaque<T>>;
|
||||||
type InnerOpaque<T> = impl Sized; //[fail]~ ERROR `T` may not live long enough
|
fn define_nested_rpit<T>() -> OuterOpaque2<T> {}
|
||||||
type OuterOpaque<T> = impl Trait<&'static T, Out = InnerOpaque<T>>;
|
//~^ ERROR the parameter type `T` may not live long enough
|
||||||
fn define<T>() -> OuterOpaque<T> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
45
tests/ui/type-alias-impl-trait/wf-nested.stderr
Normal file
45
tests/ui/type-alias-impl-trait/wf-nested.stderr
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
|
--> $DIR/wf-nested.rs:30:35
|
||||||
|
|
|
||||||
|
LL | fn define<T>() -> OuterOpaque1<T> {}
|
||||||
|
| ^^
|
||||||
|
| |
|
||||||
|
| the parameter type `T` must be valid for the static lifetime...
|
||||||
|
| ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn define<T: 'static>() -> OuterOpaque1<T> {}
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
|
--> $DIR/wf-nested.rs:33:65
|
||||||
|
|
|
||||||
|
LL | fn define_rpit<T>() -> impl Trait<&'static T, Out = impl Sized> {}
|
||||||
|
| ^^
|
||||||
|
| |
|
||||||
|
| the parameter type `T` must be valid for the static lifetime...
|
||||||
|
| ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn define_rpit<T: 'static>() -> impl Trait<&'static T, Out = impl Sized> {}
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
|
--> $DIR/wf-nested.rs:41:47
|
||||||
|
|
|
||||||
|
LL | fn define_nested_rpit<T>() -> OuterOpaque2<T> {}
|
||||||
|
| ^^
|
||||||
|
| |
|
||||||
|
| the parameter type `T` must be valid for the static lifetime...
|
||||||
|
| ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn define_nested_rpit<T: 'static>() -> OuterOpaque2<T> {}
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0310`.
|
Loading…
Add table
Add a link
Reference in a new issue