Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE] bootstrap with next solver enabled #124812

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
omg wtf
  • Loading branch information
compiler-errors authored and lcnr committed May 24, 2024
commit c147f842ab3030a3e93044c035dcb5eeefd0451b
68 changes: 19 additions & 49 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,12 @@ fn check_opaque_meets_bounds<'tcx>(
};
let param_env = tcx.param_env(defining_use_anchor);

let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build();
let infcx = tcx
.infer_ctxt()
.with_opaque_type_mode(ty::OpaqueTypeMode::Reveal(
tcx.opaque_types_defined_by(defining_use_anchor),
))
.build();
let ocx = ObligationCtxt::new(&infcx);

let args = match *origin {
Expand All @@ -359,42 +364,23 @@ fn check_opaque_meets_bounds<'tcx>(
}),
};

let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);

// `ReErased` regions appear in the "parent_args" of closures/coroutines.
// We're ignoring them here and replacing them with fresh region variables.
// See tests in ui/type-alias-impl-trait/closure_{parent_args,wf_outlives}.rs.
//
// FIXME: Consider wrapping the hidden type in an existential `Binder` and instantiating it
// here rather than using ReErased.
let hidden_ty = tcx.type_of(def_id.to_def_id()).instantiate(tcx, args);
let hidden_ty = tcx.fold_regions(hidden_ty, |re, _dbi| match re.kind() {
ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)),
_ => re,
});

let misc_cause = traits::ObligationCause::misc(span, def_id);

match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
Ok(()) => {}
Err(ty_err) => {
// Some types may be left "stranded" if they can't be reached
// from a lowered rustc_middle bound but they're mentioned in the HIR.
// This will happen, e.g., when a nested opaque is inside of a non-
// existent associated type, like `impl Trait<Missing = impl Trait>`.
// See <tests/ui/impl-trait/stranded-opaque.rs>.
let ty_err = ty_err.to_string(tcx);
let guar = tcx.dcx().span_delayed_bug(
span,
format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
);
return Err(guar);
}
}
let predicates: Vec<_> = tcx.item_bounds(def_id).iter_instantiated(tcx, args).collect();
let predicates = ocx.normalize(&misc_cause, param_env, predicates);
ocx.register_obligations(
predicates
.into_iter()
.map(|clause| Obligation::new(tcx, misc_cause.clone(), param_env, clause)),
);

// Additionally 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
// hidden type is well formed even without those bounds.
let hidden_ty =
tcx.fold_regions(tcx.type_of(def_id).instantiate(tcx, args), |re, _| match *re {
ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)),
_ => re,
});
let predicate =
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(hidden_ty.into())));
ocx.register_obligation(Obligation::new(tcx, misc_cause.clone(), param_env, predicate));
Expand All @@ -412,23 +398,7 @@ fn check_opaque_meets_bounds<'tcx>(
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
// 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
// compare the hidden types via our type equivalence/relation infra instead of doing an
// identity check.
let _ = infcx.take_opaque_types();
Ok(())
} else {
// 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() {
ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty);
key = infcx.resolve_vars_if_possible(key);
sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?;
}
Ok(())
}
Ok(())
}

fn sanity_check_found_hidden_type<'tcx>(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/at.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn fork_with_intercrate(&self, intercrate: bool) -> Self {
Self {
tcx: self.tcx,
defining_opaque_types: self.defining_opaque_types,
opaque_type_mode: self.opaque_type_mode,
considering_regions: self.considering_regions,
skip_leak_check: self.skip_leak_check,
inner: self.inner.clone(),
Expand Down
10 changes: 4 additions & 6 deletions compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl<'tcx> InferCtxt<'tcx> {
},
);

param_env.defining_opaque_types = self.defining_opaque_types;
param_env.opaque_type_mode = self.opaque_type_mode;

Canonicalizer::canonicalize_with_base(
param_env,
Expand Down Expand Up @@ -544,7 +544,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
max_universe: ty::UniverseIndex::ROOT,
variables: List::empty(),
value: (),
defining_opaque_types: infcx.map(|i| i.defining_opaque_types).unwrap_or_default(),
opaque_type_mode: infcx.map(|i| i.opaque_type_mode).unwrap_or_default(),
};
Canonicalizer::canonicalize_with_base(
base,
Expand Down Expand Up @@ -614,14 +614,12 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
.max()
.unwrap_or(ty::UniverseIndex::ROOT);

assert!(
!infcx.is_some_and(|infcx| infcx.defining_opaque_types != base.defining_opaque_types)
);
assert!(!infcx.is_some_and(|infcx| infcx.opaque_type_mode != base.opaque_type_mode));
Canonical {
max_universe,
variables: canonical_variables,
value: (base.value, out_value),
defining_opaque_types: base.defining_opaque_types,
opaque_type_mode: base.opaque_type_mode,
}
}

Expand Down
65 changes: 44 additions & 21 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pub use relate::combine::CombineFields;
pub use relate::combine::ObligationEmittingRelation;
pub use relate::StructurallyRelateAliases;
pub use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::traits::Reveal;
use rustc_middle::traits::TreatOpaque;
pub use rustc_middle::ty::IntVarValue;
pub use BoundRegionConversionTime::*;
pub use RegionVariableOrigin::*;
Expand Down Expand Up @@ -246,7 +248,7 @@ pub struct InferCtxt<'tcx> {
pub tcx: TyCtxt<'tcx>,

/// The `DefIds` of the opaque types that may have their hidden types constrained.
defining_opaque_types: &'tcx ty::List<LocalDefId>,
opaque_type_mode: ty::OpaqueTypeMode<TyCtxt<'tcx>>,

/// Whether this inference context should care about region obligations in
/// the root universe. Most notably, this is used during hir typeck as region
Expand Down Expand Up @@ -373,8 +375,8 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
}

fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
self.defining_opaque_types
fn opaque_type_mode(&self) -> ty::OpaqueTypeMode<TyCtxt<'tcx>> {
self.opaque_type_mode
}

fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> {
Expand Down Expand Up @@ -621,7 +623,7 @@ impl fmt::Display for FixupError {
/// Used to configure inference contexts before their creation.
pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>,
defining_opaque_types: &'tcx ty::List<LocalDefId>,
opaque_type_mode: ty::OpaqueTypeMode<TyCtxt<'tcx>>,
considering_regions: bool,
skip_leak_check: bool,
/// Whether we are in coherence mode.
Expand All @@ -636,7 +638,7 @@ impl<'tcx> TyCtxt<'tcx> {
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
InferCtxtBuilder {
tcx: self,
defining_opaque_types: ty::List::empty(),
opaque_type_mode: Default::default(),
considering_regions: true,
skip_leak_check: false,
intercrate: false,
Expand All @@ -646,22 +648,23 @@ impl<'tcx> TyCtxt<'tcx> {
}

impl<'tcx> InferCtxtBuilder<'tcx> {
pub fn with_opaque_type_mode(
mut self,
opaque_type_mode: ty::OpaqueTypeMode<TyCtxt<'tcx>>,
) -> Self {
self.opaque_type_mode = opaque_type_mode;
self
}

/// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
/// you need to call this function. Otherwise the opaque type will be treated opaquely.
///
/// It is only meant to be called in two places, for typeck
/// (via `Inherited::build`) and for the inference context used
/// in mir borrowck.
pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self {
self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor);
self
}

pub fn with_defining_opaque_types(
mut self,
defining_opaque_types: &'tcx ty::List<LocalDefId>,
) -> Self {
self.defining_opaque_types = defining_opaque_types;
let types = self.tcx.opaque_types_defined_by(defining_anchor);
self.opaque_type_mode = ty::OpaqueTypeMode::Define(types);
self
}

Expand Down Expand Up @@ -700,23 +703,23 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
let infcx = self.with_defining_opaque_types(canonical.defining_opaque_types).build();
let infcx = self.with_opaque_type_mode(canonical.opaque_type_mode).build();
let (value, args) = infcx.instantiate_canonical(span, canonical);
(infcx, value, args)
}

pub fn build(&mut self) -> InferCtxt<'tcx> {
let InferCtxtBuilder {
tcx,
defining_opaque_types,
opaque_type_mode: defining_opaque_types,
considering_regions,
skip_leak_check,
intercrate,
next_trait_solver,
} = *self;
InferCtxt {
tcx,
defining_opaque_types,
opaque_type_mode: defining_opaque_types,
considering_regions,
skip_leak_check,
inner: RefCell::new(InferCtxtInner::new()),
Expand Down Expand Up @@ -1240,10 +1243,30 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow().opaque_type_storage.opaque_types.clone()
}

#[inline(always)]
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
let Some(id) = id.into().as_local() else { return false };
self.defining_opaque_types.contains(&id)
pub fn treat_opaque_ty(&self, reveal: Reveal, def_id: DefId) -> TreatOpaque {
if self.intercrate {
return TreatOpaque::Ambiguous;
}

match reveal {
Reveal::All => return TreatOpaque::Reveal,
Reveal::UserFacing => {}
}

match self.opaque_type_mode {
ty::OpaqueTypeMode::Define(list) => {
if def_id.as_local().is_some_and(|def_id| list.contains(&def_id)) {
return TreatOpaque::Define;
}
}
ty::OpaqueTypeMode::Reveal(list) => {
if def_id.as_local().is_some_and(|def_id| list.contains(&def_id)) {
return TreatOpaque::Reveal;
}
}
}

TreatOpaque::Rigid
}

pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
Expand Down
39 changes: 22 additions & 17 deletions compiler/rustc_infer/src/infer/opaque_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use hir::def_id::{DefId, LocalDefId};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::{ObligationCause, TreatOpaque};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::GenericArgKind;
Expand Down Expand Up @@ -58,7 +58,10 @@ impl<'tcx> InferCtxt<'tcx> {
ct_op: |ct| ct,
ty_op: |ty| match *ty.kind() {
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })
if self.can_define_opaque_ty(def_id) && !ty.has_escaping_bound_vars() =>
if matches!(
self.treat_opaque_ty(param_env.reveal(), def_id),
TreatOpaque::Define
) && !ty.has_escaping_bound_vars() =>
{
let def_span = self.tcx.def_span(def_id);
let span = if span.contains(def_span) { def_span } else { span };
Expand All @@ -85,16 +88,6 @@ impl<'tcx> InferCtxt<'tcx> {
) -> InferResult<'tcx, ()> {
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
let def_id = def_id.expect_local();
if self.intercrate {
// See comment on `insert_hidden_type` for why this is sufficient in coherence
return Some(self.register_hidden_type(
OpaqueTypeKey { def_id, args },
cause.clone(),
param_env,
b,
));
}
// Check that this is `impl Trait` type is
// declared by `parent_def_id` -- i.e., one whose
// value we are inferring. At present, this is
Expand Down Expand Up @@ -129,8 +122,18 @@ impl<'tcx> InferCtxt<'tcx> {
// let x = || foo(); // returns the Opaque assoc with `foo`
// }
// ```
if !self.can_define_opaque_ty(def_id) {
return None;
match self.treat_opaque_ty(param_env.reveal(), def_id) {
TreatOpaque::Define => {}
TreatOpaque::Reveal | TreatOpaque::Rigid => return None,
TreatOpaque::Ambiguous => {
// See comment on `insert_hidden_type` for why this is sufficient in coherence
return Some(self.register_hidden_type(
OpaqueTypeKey { def_id: def_id.expect_local(), args },
cause.clone(),
param_env,
b,
));
}
}

if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
Expand All @@ -139,8 +142,10 @@ impl<'tcx> InferCtxt<'tcx> {
// no one encounters it in practice.
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
// where it is of no concern, so we only check for TAITs.
if self.can_define_opaque_ty(b_def_id)
&& self.tcx.is_type_alias_impl_trait(b_def_id)
if matches!(
self.treat_opaque_ty(param_env.reveal(), b_def_id),
TreatOpaque::Define
) && self.tcx.is_type_alias_impl_trait(b_def_id)
{
self.tcx.dcx().emit_err(OpaqueHiddenTypeDiag {
span: cause.span,
Expand All @@ -150,7 +155,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
Some(self.register_hidden_type(
OpaqueTypeKey { def_id, args },
OpaqueTypeKey { def_id: def_id.expect_local(), args },
cause.clone(),
param_env,
b,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/infer/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> {
max_universe: ty::UniverseIndex::ROOT,
variables: List::empty(),
value: key,
defining_opaque_types: ty::List::empty(),
opaque_type_mode: Default::default(),
};
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ macro_rules! define_callbacks {
// Increase this limit if necessary, but do try to keep the size low if possible
#[cfg(target_pointer_width = "64")]
const _: () = {
if mem::size_of::<Key<'static>>() > 72 {
if mem::size_of::<Key<'static>>() > 84 {
panic!("{}", concat!(
"the query `",
stringify!($name),
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ pub enum Reveal {
All,
}

pub enum TreatOpaque {
Reveal,
Define,
Rigid,
Ambiguous,
}

/// The reason why we incurred this obligation; used for error reporting.
///
/// Non-misc `ObligationCauseCode`s are stored on the heap. This gives the
Expand Down
Loading