Bubble up opaque <eq> opaque operations instead of picking an order
This commit is contained in:
parent
ad4dd759d8
commit
930affa39d
7 changed files with 127 additions and 21 deletions
|
@ -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
|
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
|
||||||
// the bounds that the function supplies.
|
// the bounds that the function supplies.
|
||||||
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), identity_args);
|
let mut obligations = vec![];
|
||||||
ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty)
|
infcx
|
||||||
.map_err(|err| {
|
.insert_hidden_type(
|
||||||
infcx
|
OpaqueTypeKey { def_id, args: identity_args },
|
||||||
.err_ctxt()
|
&ObligationCause::misc(definition_span, def_id),
|
||||||
.report_mismatched_types(
|
param_env,
|
||||||
&ObligationCause::misc(definition_span, def_id),
|
definition_ty,
|
||||||
opaque_ty,
|
true,
|
||||||
definition_ty,
|
&mut obligations,
|
||||||
err,
|
)
|
||||||
)
|
.unwrap();
|
||||||
.emit()
|
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.
|
// 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
|
// 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;
|
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,
|
DefiningAnchor::Error => return None,
|
||||||
};
|
};
|
||||||
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
|
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::ProjectionCacheKey;
|
||||||
use rustc_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine};
|
use rustc_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine};
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
|
use rustc_middle::traits::DefiningAnchor;
|
||||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||||
use rustc_middle::ty::GenericArgsRef;
|
use rustc_middle::ty::GenericArgsRef;
|
||||||
|
@ -623,9 +624,27 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
|
ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
|
||||||
ty::PredicateKind::AliasRelate(..) => {
|
ty::PredicateKind::AliasRelate(..)
|
||||||
bug!("AliasRelate is only used for new solver")
|
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)) => {
|
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
|
||||||
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
|
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
|
||||||
DefineOpaqueTypes::No,
|
DefineOpaqueTypes::No,
|
||||||
|
|
|
@ -37,6 +37,7 @@ use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||||
use rustc_infer::traits::TraitObligation;
|
use rustc_infer::traits::TraitObligation;
|
||||||
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
|
use rustc_middle::traits::DefiningAnchor;
|
||||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||||
use rustc_middle::ty::fold::BottomUpFolder;
|
use rustc_middle::ty::fold::BottomUpFolder;
|
||||||
use rustc_middle::ty::relate::TypeRelation;
|
use rustc_middle::ty::relate::TypeRelation;
|
||||||
|
@ -960,9 +961,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::PredicateKind::AliasRelate(..) => {
|
ty::PredicateKind::AliasRelate(..)
|
||||||
bug!("AliasRelate is only used for new solver")
|
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::Ambiguous => Ok(EvaluatedToAmbig),
|
||||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
|
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
|
||||||
match self.infcx.at(&obligation.cause, obligation.param_env).eq(
|
match self.infcx.at(&obligation.cause, obligation.param_env).eq(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
// edition:2021
|
// edition:2021
|
||||||
// check-pass
|
//[rpit] check-pass
|
||||||
|
// revisions: tait rpit
|
||||||
|
|
||||||
struct Pending {}
|
struct Pending {}
|
||||||
|
|
||||||
|
@ -12,15 +13,23 @@ impl AsyncRead for i32 {}
|
||||||
|
|
||||||
type PendingReader<'a> = impl AsyncRead + 'a;
|
type PendingReader<'a> = impl AsyncRead + 'a;
|
||||||
|
|
||||||
type OpeningReadFuture<'a> =
|
#[cfg(tait)]
|
||||||
impl std::future::Future<Output = Result<PendingReader<'a>, CantOpen>>;
|
type OpeningReadFuture<'a> = impl std::future::Future<Output = Result<PendingReader<'a>, CantOpen>>;
|
||||||
|
|
||||||
impl Pending {
|
impl Pending {
|
||||||
async fn read(&mut self) -> Result<impl AsyncRead + '_, CantOpen> {
|
async fn read(&mut self) -> Result<impl AsyncRead + '_, CantOpen> {
|
||||||
Ok(42)
|
Ok(42)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(tait)]
|
||||||
fn read_fut(&mut self) -> OpeningReadFuture<'_> {
|
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()
|
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…
Add table
Reference in a new issue