Skip to content

Commit

Permalink
Auto merge of rust-lang#114586 - oli-obk:patch_tait_rpit_order_check,…
Browse files Browse the repository at this point in the history
… 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 rust-lang#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`
  • Loading branch information
bors committed Sep 11, 2023
2 parents 0a199e4 + 930affa commit e2b3676
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 21 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ build/
\#*
\#*\#
.#*
rustc-ice-*.txt

## Tags
tags
Expand Down
33 changes: 20 additions & 13 deletions compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 19 additions & 1 deletion compiler/rustc_infer/src/infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
23 changes: 21 additions & 2 deletions compiler/rustc_trait_selection/src/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
23 changes: 21 additions & 2 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand Down
15 changes: 12 additions & 3 deletions tests/ui/impl-trait/async_scope_creep.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![feature(type_alias_impl_trait)]
// edition:2021
// check-pass
//[rpit] check-pass
// revisions: tait rpit

struct Pending {}

Expand All @@ -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()
}
}
Expand Down
9 changes: 9 additions & 0 deletions tests/ui/impl-trait/async_scope_creep.tait.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit e2b3676

Please sign in to comment.