Auto merge of #114586 - oli-obk:patch_tait_rpit_order_check, r=lcnr,compiler-errors
Bubble up opaque <eq> opaque operations instead of picking an order In case we are in `Bubble` mode (meaning every opaque type that is defined in the current crate is treated as if it were in its defining scope), we don't try to register an opaque type as the hidden type of another opaque type, but instead bubble up an obligation to equate them at the query caller site. Usually that means we have a `DefiningAnchor::Bind` and thus can reliably figure out whether an opaque type is in its defining scope. Where we can't, we'll error out, so the default is sound. With this change we start using `AliasTyEq` predicates in the old solver, too. fixes https://github.com/rust-lang/rust/issues/108498 But also regresses `tests/ui/impl-trait/anon_scope_creep.rs`. Our use of `Bubble` for `check_opaque_type_well_formed` is going to keep biting us. r? `@lcnr` `@compiler-errors`
This commit is contained in:
commit
e2b3676733
1
.gitignore
vendored
1
.gitignore
vendored
@ -58,6 +58,7 @@ build/
|
||||
\#*
|
||||
\#*\#
|
||||
.#*
|
||||
rustc-ice-*.txt
|
||||
|
||||
## Tags
|
||||
tags
|
||||
|
@ -328,19 +328,26 @@ fn check_opaque_type_well_formed<'tcx>(
|
||||
|
||||
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
|
||||
// the bounds that the function supplies.
|
||||
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), identity_args);
|
||||
ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty)
|
||||
.map_err(|err| {
|
||||
infcx
|
||||
.err_ctxt()
|
||||
.report_mismatched_types(
|
||||
&ObligationCause::misc(definition_span, def_id),
|
||||
opaque_ty,
|
||||
definition_ty,
|
||||
err,
|
||||
)
|
||||
.emit()
|
||||
})?;
|
||||
let mut obligations = vec![];
|
||||
infcx
|
||||
.insert_hidden_type(
|
||||
OpaqueTypeKey { def_id, args: identity_args },
|
||||
&ObligationCause::misc(definition_span, def_id),
|
||||
param_env,
|
||||
definition_ty,
|
||||
true,
|
||||
&mut obligations,
|
||||
)
|
||||
.unwrap();
|
||||
infcx.add_item_bounds_for_hidden_type(
|
||||
def_id.to_def_id(),
|
||||
identity_args,
|
||||
ObligationCause::misc(definition_span, def_id),
|
||||
param_env,
|
||||
definition_ty,
|
||||
&mut obligations,
|
||||
);
|
||||
ocx.register_obligations(obligations);
|
||||
|
||||
// Require the hidden type to be well-formed with only the generics of the opaque type.
|
||||
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
||||
|
@ -145,7 +145,25 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
DefiningAnchor::Bubble => {}
|
||||
DefiningAnchor::Bubble => {
|
||||
if let ty::Alias(ty::Opaque, _) = b.kind() {
|
||||
// In bubble mode we don't know which of the two opaque types is supposed to have the other
|
||||
// as a hidden type (both, none or either one of them could be in its defining scope).
|
||||
let predicate = ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
ty::AliasRelationDirection::Equate,
|
||||
);
|
||||
let obligation = traits::Obligation::new(
|
||||
self.tcx,
|
||||
cause.clone(),
|
||||
param_env,
|
||||
predicate,
|
||||
);
|
||||
let obligations = vec![obligation];
|
||||
return Some(Ok(InferOk { value: (), obligations }));
|
||||
}
|
||||
}
|
||||
DefiningAnchor::Error => return None,
|
||||
};
|
||||
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
|
||||
|
@ -6,6 +6,7 @@ use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::traits::ProjectionCacheKey;
|
||||
use rustc_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::traits::DefiningAnchor;
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::GenericArgsRef;
|
||||
@ -623,9 +624,27 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
|
||||
ty::PredicateKind::AliasRelate(..) => {
|
||||
bug!("AliasRelate is only used for new solver")
|
||||
ty::PredicateKind::AliasRelate(..)
|
||||
if matches!(self.selcx.infcx.defining_use_anchor, DefiningAnchor::Bubble) =>
|
||||
{
|
||||
ProcessResult::Unchanged
|
||||
}
|
||||
ty::PredicateKind::AliasRelate(a, b, relate) => match relate {
|
||||
ty::AliasRelationDirection::Equate => match self
|
||||
.selcx
|
||||
.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(DefineOpaqueTypes::Yes, a, b)
|
||||
{
|
||||
Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())),
|
||||
Err(_) => ProcessResult::Error(FulfillmentErrorCode::CodeSelectionError(
|
||||
SelectionError::Unimplemented,
|
||||
)),
|
||||
},
|
||||
ty::AliasRelationDirection::Subtype => {
|
||||
bug!("AliasRelate with subtyping is only used for new solver")
|
||||
}
|
||||
},
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
|
||||
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
|
||||
DefineOpaqueTypes::No,
|
||||
|
@ -37,6 +37,7 @@ use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||
use rustc_infer::traits::TraitObligation;
|
||||
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::traits::DefiningAnchor;
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::fold::BottomUpFolder;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
@ -1000,9 +1001,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::PredicateKind::AliasRelate(..) => {
|
||||
bug!("AliasRelate is only used for new solver")
|
||||
ty::PredicateKind::AliasRelate(..)
|
||||
if matches!(self.infcx.defining_use_anchor, DefiningAnchor::Bubble) =>
|
||||
{
|
||||
Ok(EvaluatedToAmbig)
|
||||
}
|
||||
ty::PredicateKind::AliasRelate(a, b, relate) => match relate {
|
||||
ty::AliasRelationDirection::Equate => match self
|
||||
.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(DefineOpaqueTypes::Yes, a, b)
|
||||
{
|
||||
Ok(inf_ok) => self.evaluate_predicates_recursively(
|
||||
previous_stack,
|
||||
inf_ok.into_obligations(),
|
||||
),
|
||||
Err(_) => Ok(EvaluatedToErr),
|
||||
},
|
||||
ty::AliasRelationDirection::Subtype => {
|
||||
bug!("AliasRelate subtyping is only used for new solver")
|
||||
}
|
||||
},
|
||||
ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
|
||||
match self.infcx.at(&obligation.cause, obligation.param_env).eq(
|
||||
|
@ -1,6 +1,7 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
// edition:2021
|
||||
// check-pass
|
||||
//[rpit] check-pass
|
||||
// revisions: tait rpit
|
||||
|
||||
struct Pending {}
|
||||
|
||||
@ -12,15 +13,23 @@ impl AsyncRead for i32 {}
|
||||
|
||||
type PendingReader<'a> = impl AsyncRead + 'a;
|
||||
|
||||
type OpeningReadFuture<'a> =
|
||||
impl std::future::Future<Output = Result<PendingReader<'a>, CantOpen>>;
|
||||
#[cfg(tait)]
|
||||
type OpeningReadFuture<'a> = impl std::future::Future<Output = Result<PendingReader<'a>, CantOpen>>;
|
||||
|
||||
impl Pending {
|
||||
async fn read(&mut self) -> Result<impl AsyncRead + '_, CantOpen> {
|
||||
Ok(42)
|
||||
}
|
||||
|
||||
#[cfg(tait)]
|
||||
fn read_fut(&mut self) -> OpeningReadFuture<'_> {
|
||||
self.read() //[tait]~ ERROR: cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>`
|
||||
}
|
||||
|
||||
#[cfg(rpit)]
|
||||
fn read_fut(
|
||||
&mut self,
|
||||
) -> impl std::future::Future<Output = Result<PendingReader<'_>, CantOpen>> {
|
||||
self.read()
|
||||
}
|
||||
}
|
||||
|
9
tests/ui/impl-trait/async_scope_creep.tait.stderr
Normal file
9
tests/ui/impl-trait/async_scope_creep.tait.stderr
Normal file
@ -0,0 +1,9 @@
|
||||
error[E0284]: type annotations needed: cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>`
|
||||
--> $DIR/async_scope_creep.rs:26:9
|
||||
|
|
||||
LL | self.read()
|
||||
| ^^^^^^^^^^^ cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0284`.
|
@ -0,0 +1,25 @@
|
||||
//! This tries to prove the APIT's bounds in a canonical query,
|
||||
//! which doesn't know anything about the defining scope of either
|
||||
//! opaque type and thus makes a random choice as to which opaque type
|
||||
//! becomes the hidden type of the other. When we leave the canonical
|
||||
//! query, we attempt to actually check the defining anchor, but now we
|
||||
//! have a situation where the RPIT gets constrained outside its anchor.
|
||||
|
||||
// revisions: current next
|
||||
//[next] compile-flags: -Ztrait-solver=next
|
||||
// check-pass
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
type Opaque = impl Sized;
|
||||
|
||||
fn get_rpit() -> impl Clone {}
|
||||
|
||||
fn query(_: impl FnOnce() -> Opaque) {}
|
||||
|
||||
fn test() -> Opaque {
|
||||
query(get_rpit);
|
||||
get_rpit()
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
x
Reference in New Issue
Block a user