Skip to content

Commit

Permalink
support revealing defined opaque post borrowck
Browse files Browse the repository at this point in the history
  • Loading branch information
lcnr committed Nov 28, 2024
1 parent 18e2253 commit 34a8c2d
Show file tree
Hide file tree
Showing 21 changed files with 226 additions and 58 deletions.
14 changes: 11 additions & 3 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,12 @@ fn check_opaque_meets_bounds<'tcx>(
};
let param_env = tcx.param_env(defining_use_anchor);

// FIXME(#132279): This should eventually use the already defined hidden types.
let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, defining_use_anchor));
// FIXME(#132279): Once `PostBorrowckAnalysis` is supported in the old solver, this branch should be removed.
let infcx = tcx.infer_ctxt().build(if tcx.next_trait_solver_globally() {
TypingMode::post_borrowck_analysis(tcx, defining_use_anchor)
} else {
TypingMode::analysis_in_body(tcx, defining_use_anchor)
});
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);

let args = match origin {
Expand Down Expand Up @@ -417,7 +421,11 @@ 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 {
if infcx.next_trait_solver() {
Ok(())
} else 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
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1574,7 +1574,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// Thus we need to prevent them from trying to match the `&_` autoref
// candidates that get created for `&self` trait methods.
ty::Alias(ty::Opaque, alias_ty)
if self.infcx.can_define_opaque_ty(alias_ty.def_id)
if !self.next_trait_solver()
&& self.infcx.can_define_opaque_ty(alias_ty.def_id)
&& !xform_self_ty.is_ty_var() =>
{
return ProbeResult::NoMatch;
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_infer/src/infer/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_middle::ty::relate::combine::PredicateEmittingRelation;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::{DUMMY_SP, ErrorGuaranteed};

use super::{BoundRegionConversionTime, InferCtxt, SubregionOrigin};
use super::{BoundRegionConversionTime, InferCtxt, RegionVariableOrigin, SubregionOrigin};

impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
type Interner = TyCtxt<'tcx>;
Expand Down Expand Up @@ -87,6 +87,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
}

fn next_region_infer(&self) -> ty::Region<'tcx> {
self.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
}

fn next_ty_infer(&self) -> Ty<'tcx> {
self.next_ty_var(DUMMY_SP)
}
Expand Down
13 changes: 10 additions & 3 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -990,11 +990,17 @@ impl<'tcx> InferCtxt<'tcx> {

#[inline(always)]
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
debug_assert!(!self.next_trait_solver());
match self.typing_mode() {
TypingMode::Analysis { defining_opaque_types } => {
id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id))
}
TypingMode::Coherence | TypingMode::PostAnalysis => false,
// FIXME(#132279): This function is quite weird in post-analysis
// and post-borrowck analysis mode. We may need to modify its uses
// to support PostBorrowckAnalysis in the old solver as well.
TypingMode::Coherence
| TypingMode::PostBorrowckAnalysis { .. }
| TypingMode::PostAnalysis => false,
}
}

Expand Down Expand Up @@ -1276,15 +1282,16 @@ impl<'tcx> InferCtxt<'tcx> {
/// using canonicalization or carrying this inference context around.
pub fn typing_env(&self, param_env: ty::ParamEnv<'tcx>) -> ty::TypingEnv<'tcx> {
let typing_mode = match self.typing_mode() {
ty::TypingMode::Coherence => ty::TypingMode::Coherence,
// FIXME(#132279): This erases the `defining_opaque_types` as it isn't possible
// to handle them without proper canonicalization. This means we may cause cycle
// errors and fail to reveal opaques while inside of bodies. We should rename this
// function and require explicit comments on all use-sites in the future.
ty::TypingMode::Analysis { defining_opaque_types: _ } => {
TypingMode::non_body_analysis()
}
ty::TypingMode::PostAnalysis => ty::TypingMode::PostAnalysis,
mode @ (ty::TypingMode::Coherence
| ty::TypingMode::PostBorrowckAnalysis { .. }
| ty::TypingMode::PostAnalysis) => mode,
};
ty::TypingEnv { typing_mode, param_env }
}
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_infer/src/infer/opaque_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ impl<'tcx> InferCtxt<'tcx> {
span: Span,
param_env: ty::ParamEnv<'tcx>,
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, TypeError<'tcx>> {
debug_assert!(!self.next_trait_solver());
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();
Expand Down Expand Up @@ -546,7 +547,9 @@ impl<'tcx> InferCtxt<'tcx> {
);
}
}
ty::TypingMode::PostAnalysis => bug!("insert hidden type post-analysis"),
mode @ (ty::TypingMode::PostBorrowckAnalysis { .. } | ty::TypingMode::PostAnalysis) => {
bug!("insert hidden type in {mode:?}")
}
}

Ok(())
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,9 @@ where

match self.typing_mode() {
TypingMode::Coherence => {}
TypingMode::Analysis { .. } | TypingMode::PostAnalysis => {
TypingMode::Analysis { .. }
| TypingMode::PostBorrowckAnalysis { .. }
| TypingMode::PostAnalysis => {
self.discard_impls_shadowed_by_env(goal, &mut candidates);
}
}
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,12 @@ where
}
}

pub(super) fn next_region_var(&mut self) -> I::Region {
let region = self.delegate.next_region_infer();
self.inspect.add_var_value(region);
region
}

pub(super) fn next_ty_infer(&mut self) -> I::Ty {
let ty = self.delegate.next_ty_infer();
self.inspect.add_var_value(ty);
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_next_trait_solver/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ mod trait_goals;

use rustc_type_ir::inherent::*;
pub use rustc_type_ir::solve::*;
use rustc_type_ir::{self as ty, Interner};
use rustc_type_ir::{self as ty, Interner, TypingMode};
use tracing::instrument;

pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt};
Expand Down Expand Up @@ -321,6 +321,19 @@ where
Ok(ct)
}
}

fn opaque_type_is_rigid(&self, def_id: I::DefId) -> bool {
match self.typing_mode() {
// Opaques are never rigid outside of analysis mode.
TypingMode::Coherence | TypingMode::PostAnalysis => false,
// During analysis, opaques are rigid unless they may be defined by
// the current body.
TypingMode::Analysis { defining_opaque_types: non_rigid_opaques }
| TypingMode::PostBorrowckAnalysis { defined_opaque_types: non_rigid_opaques } => {
!def_id.as_local().is_some_and(|def_id| non_rigid_opaques.contains(&def_id))
}
}
}
}

fn response_no_constraints_raw<I: Interner>(
Expand Down
21 changes: 5 additions & 16 deletions compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod weak_types;
use rustc_type_ir::fast_reject::DeepRejectCtxt;
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem;
use rustc_type_ir::{self as ty, Interner, NormalizesTo, TypingMode, Upcast as _};
use rustc_type_ir::{self as ty, Interner, NormalizesTo, Upcast as _};
use tracing::instrument;

use crate::delegate::SolverDelegate;
Expand Down Expand Up @@ -71,21 +71,10 @@ where
Ok(())
}
ty::AliasTermKind::OpaqueTy => {
match self.typing_mode() {
// Opaques are never rigid outside of analysis mode.
TypingMode::Coherence | TypingMode::PostAnalysis => Err(NoSolution),
// During analysis, opaques are only rigid if we may not define it.
TypingMode::Analysis { defining_opaque_types } => {
if rigid_alias
.def_id
.as_local()
.is_some_and(|def_id| defining_opaque_types.contains(&def_id))
{
Err(NoSolution)
} else {
Ok(())
}
}
if self.opaque_type_is_rigid(rigid_alias.def_id) {
Ok(())
} else {
Err(NoSolution)
}
}
// FIXME(generic_const_exprs): we would need to support generic consts here
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! behaves differently depending on the current `TypingMode`.

use rustc_index::bit_set::GrowableBitSet;
use rustc_type_ir::fold::fold_regions;
use rustc_type_ir::inherent::*;
use rustc_type_ir::{self as ty, Interner, TypingMode};

Expand Down Expand Up @@ -95,6 +96,26 @@ where
);
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
TypingMode::PostBorrowckAnalysis { defined_opaque_types } => {
let Some(def_id) = opaque_ty.def_id.as_local() else {
return Err(NoSolution);
};

if !defined_opaque_types.contains(&def_id) {
return Err(NoSolution);
}

let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args);
// FIXME: Actually use a proper binder here instead of relying on `ReErased`.
//
// This is also probably unsound or sth :shrug:
let actual = fold_regions(cx, actual, |re, _dbi| match re.kind() {
ty::ReErased => self.next_region_var(),
_ => re,
});
self.eq(goal.param_env, expected, actual)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
TypingMode::PostAnalysis => {
// FIXME: Add an assertion that opaque type storage is empty.
let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args);
Expand Down
19 changes: 4 additions & 15 deletions compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ where
// it's not a real impl.
(ty::ImplPolarity::Reservation, _) => match ecx.typing_mode() {
TypingMode::Coherence => Certainty::AMBIGUOUS,
TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Err(NoSolution),
TypingMode::Analysis { .. }
| TypingMode::PostBorrowckAnalysis { .. }
| TypingMode::PostAnalysis => return Err(NoSolution),
},

// Impl matches polarity
Expand Down Expand Up @@ -174,20 +176,7 @@ where
// ideally we want to avoid, since we can make progress on this goal
// via an alias bound or a locally-inferred hidden type instead.
if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
match ecx.typing_mode() {
TypingMode::Coherence | TypingMode::PostAnalysis => {
unreachable!("rigid opaque outside of analysis: {goal:?}");
}
TypingMode::Analysis { defining_opaque_types } => {
if opaque_ty
.def_id
.as_local()
.is_some_and(|def_id| defining_opaque_types.contains(&def_id))
{
return Err(NoSolution);
}
}
}
debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
}

ecx.probe_and_evaluate_goal_for_constituent_tys(
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_trait_selection/src/solve/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,9 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
match self.typing_mode() {
TypingMode::Coherence | TypingMode::Analysis { .. } => false,
TypingMode::Coherence
| TypingMode::Analysis { .. }
| TypingMode::PostBorrowckAnalysis { .. } => false,
TypingMode::PostAnalysis => {
let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
!poly_trait_ref.still_further_specializable()
Expand Down
14 changes: 8 additions & 6 deletions compiler/rustc_trait_selection/src/traits/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,10 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
// Opaques are treated as rigid outside of `TypingMode::PostAnalysis`,
// so we can ignore those.
match infcx.typing_mode() {
TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
flags.remove(ty::TypeFlags::HAS_TY_OPAQUE)
}
// FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
TypingMode::Coherence
| TypingMode::Analysis { .. }
| TypingMode::PostBorrowckAnalysis { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE),
TypingMode::PostAnalysis => {}
}

Expand Down Expand Up @@ -213,9 +214,10 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
ty::Opaque => {
// Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.selcx.infcx.typing_mode() {
TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
ty.super_fold_with(self)
}
// FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
TypingMode::Coherence
| TypingMode::Analysis { .. }
| TypingMode::PostBorrowckAnalysis { .. } => ty.super_fold_with(self),
TypingMode::PostAnalysis => {
let recursion_limit = self.cx().recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -975,7 +975,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
match selcx.infcx.typing_mode() {
TypingMode::Coherence | TypingMode::Analysis { .. } => {
TypingMode::Coherence
| TypingMode::Analysis { .. }
| TypingMode::PostBorrowckAnalysis { .. } => {
debug!(
assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
?obligation.predicate,
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_trait_selection/src/traits/query/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,9 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
ty::Opaque => {
// Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.infcx.typing_mode() {
TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
ty.try_super_fold_with(self)?
}
TypingMode::Coherence
| TypingMode::Analysis { .. }
| TypingMode::PostBorrowckAnalysis { .. } => ty.try_super_fold_with(self)?,

TypingMode::PostAnalysis => {
let args = data.args.try_fold_with(self)?;
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1471,7 +1471,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let obligation = &stack.obligation;
match self.infcx.typing_mode() {
TypingMode::Coherence => {}
TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Ok(()),
TypingMode::Analysis { .. }
| TypingMode::PostBorrowckAnalysis { .. }
| TypingMode::PostAnalysis => return Ok(()),
}

debug!("is_knowable()");
Expand Down Expand Up @@ -1518,6 +1520,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
TypingMode::Analysis { defining_opaque_types } => {
defining_opaque_types.is_empty() || !pred.has_opaque_types()
}
// The hidden types of `defined_opaque_types` is not local to the current
// inference context, so we can freely move this to the global cache.
TypingMode::PostBorrowckAnalysis { .. } => true,
// The global cache is only used if there are no opaque types in
// the defining scope or we're outside of analysis.
//
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ty_utils/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ fn resolve_associated_item<'tcx>(
// get a result which isn't correct for all monomorphizations.
match typing_env.typing_mode {
ty::TypingMode::Coherence
| ty::TypingMode::Analysis { defining_opaque_types: _ } => false,
| ty::TypingMode::Analysis { .. }
| ty::TypingMode::PostBorrowckAnalysis { .. } => false,
ty::TypingMode::PostAnalysis => !trait_ref.still_further_specializable(),
}
};
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_type_ir/src/infer_ctxt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ pub enum TypingMode<I: Interner> {
/// }
/// ```
Analysis { defining_opaque_types: I::DefiningOpaqueTypes },
/// Any analysis after borrowck for a given body should be able to use all the
/// hidden types defined by borrowck, without being able to define any new ones.
///
/// This is currently only used by the new solver, but should be implemented in
/// the old solver as well.
PostBorrowckAnalysis { defined_opaque_types: I::DefiningOpaqueTypes },
/// After analysis, mostly during codegen and MIR optimizations, we're able to
/// reveal all opaque types. As the concrete type should *never* be observable
/// directly by the user, this should not be used by checks which may expose
Expand All @@ -85,6 +91,12 @@ impl<I: Interner> TypingMode<I> {
pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
}

pub fn post_borrowck_analysis(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
TypingMode::PostBorrowckAnalysis {
defined_opaque_types: cx.opaque_types_defined_by(body_def_id),
}
}
}

pub trait InferCtxtLike: Sized {
Expand Down Expand Up @@ -126,6 +138,7 @@ pub trait InferCtxtLike: Sized {
vid: ty::RegionVid,
) -> <Self::Interner as Interner>::Region;

fn next_region_infer(&self) -> <Self::Interner as Interner>::Region;
fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
fn fresh_args_for_item(
Expand Down
Loading

0 comments on commit 34a8c2d

Please sign in to comment.