Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 2 additions & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ pub(crate) fn type_check<'tcx>(

let polonius_context = typeck.polonius_context;

if infcx.tcx.assumptions_on_binders() {
if infcx.tcx.assumptions_on_binders_any() {
let mut converter = constraint_conversion::ConstraintConversion::new(
typeck.infcx,
typeck.universal_regions,
Expand All @@ -186,6 +186,7 @@ pub(crate) fn type_check<'tcx>(
typeck.known_type_outlives_obligations,
typeck.region_bound_pairs,
universal_region_relations.outlives.clone(),
ty::Region::new_var(infcx.tcx, typeck.universal_regions.implicit_region_bound()),
);
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2425,6 +2425,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
match c {
LeafRegionConstraint::Ambiguity(_)
| LeafRegionConstraint::RegionOutlives(..)
| LeafRegionConstraint::AliasOutlives(..)
| LeafRegionConstraint::AliasTyOutlivesViaEnv(..) => (), // OK
LeafRegionConstraint::PlaceholderTyOutlives(ty, _, span) => {
// we can't check this during lowering, because the ty is a ty::Bound that gets
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_infer/src/infer/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
) -> U {
self.enter_forall(value, |value| {
let u = self.universe();
self.placeholder_assumptions_for_next_solver
.borrow_mut()
.insert(u, rustc_type_ir::region_constraint::Assumptions::empty());
if self.tcx.assumptions_on_binders_full() {
self.placeholder_assumptions_for_next_solver
.borrow_mut()
.insert(u, rustc_type_ir::region_constraint::Assumptions::empty());
}
f(value)
})
}
Expand Down
45 changes: 36 additions & 9 deletions compiler/rustc_infer/src/infer/outlives/obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ impl<'tcx> InferCtxt<'tcx> {
sub_region: Region<'tcx>,
cause: &ObligationCause<'tcx>,
) {
assert!(!self.tcx.assumptions_on_binders());
assert!(!self.tcx.assumptions_on_binders_any());

// `is_global` means the type has no params, infer, placeholder, or non-`'static`
// free regions. If the type has none of these things, then we can skip registering
Expand Down Expand Up @@ -238,7 +238,16 @@ impl<'tcx> InferCtxt<'tcx> {
region_outlives.freeze(),
ty::UniverseIndex::ROOT,
);
self.destructure_solver_region_constraints(assumptions, self);
self.destructure_solver_region_constraints(
assumptions,
TypeOutlives::new(
self,
self.tcx,
outlives_env.region_bound_pairs(),
None,
outlives_env.known_type_outlives(),
),
);
}

pub fn destructure_solver_region_constraints_for_borrowck(
Expand All @@ -248,23 +257,33 @@ impl<'tcx> InferCtxt<'tcx> {
known_type_outlives: &[PolyTypeOutlivesClause<'tcx>],
region_bound_pairs: &RegionBoundPairs<'tcx>,
region_outlives: TransitiveRelation<RegionVid>,
implicit_region_bound: Region<'tcx>,
) {
let assumptions = region_constraint::Assumptions::new(
self,
assumed_type_outlives(self.tcx, known_type_outlives, region_bound_pairs),
region_outlives.maybe_map(|r| Some(Region::new_var(self.tcx, r))).unwrap(),
ty::UniverseIndex::ROOT,
);
self.destructure_solver_region_constraints(assumptions, conversion);
self.destructure_solver_region_constraints(
assumptions,
TypeOutlives::new(
conversion,
self.tcx,
region_bound_pairs,
Some(implicit_region_bound),
known_type_outlives,
),
);
}

#[instrument(level = "debug", skip(self, conversion))]
pub fn destructure_solver_region_constraints(
#[instrument(level = "debug", skip(self, outlives))]
fn destructure_solver_region_constraints(
&self,
assumptions: rustc_type_ir::region_constraint::Assumptions<TyCtxt<'tcx>>,
mut conversion: impl TypeOutlivesDelegate<'tcx>,
mut outlives: TypeOutlives<'_, 'tcx, impl TypeOutlivesDelegate<'tcx>>,
) {
assert!(self.tcx.assumptions_on_binders());
assert!(self.tcx.assumptions_on_binders_any());
assert!(self.next_trait_solver());

let constraint = self.get_solver_region_constraint();
Expand Down Expand Up @@ -298,11 +317,19 @@ impl<'tcx> InferCtxt<'tcx> {
RegionOutlives(a, b, span) => {
let origin = SubregionOrigin::SolverRegionConstraint(span);
let category = origin.to_constraint_category();
conversion.push_sub_region_constraint(
outlives.delegate.push_sub_region_constraint(
origin, // we flip these because regionck is silly :>
b, a, category,
);
}
AliasOutlives(alias, region, span) => {
assert!(self.tcx.assumptions_on_binders_min_coroutines());
#[allow(rustc::usage_of_type_ir_traits)]
let (alias, region) =
self.deeply_resolve_via_unification_table((alias, region));
let origin = SubregionOrigin::SolverRegionConstraint(span);
outlives.alias_ty_must_outlive(origin, region, alias);
}
AliasTyOutlivesViaEnv(..) | PlaceholderTyOutlives(..) => {
unreachable!()
}
Expand All @@ -323,7 +350,7 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn process_registered_region_obligations(&self, outlives_env: &OutlivesEnvironment<'tcx>) {
assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");

if self.tcx.assumptions_on_binders() {
if self.tcx.assumptions_on_binders_any() {
self.destructure_solver_region_constraints_for_regionck(outlives_env);
}

Expand Down
28 changes: 18 additions & 10 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ use rustc_errors::ColorConfig;
use rustc_errors::emitter::HumanReadableErrorType;
use rustc_lint_defs::Level;
use rustc_session::config::{
AnnotateMoves, AutoDiff, BranchProtection, CFGuard, Cfg, CodegenRetagOptions, CoverageLevel,
CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation,
Externs, FmtDebug, FunctionReturn, IncrementalStateAssertion, InliningThreshold, Input,
InstrumentCoverage, InstrumentMcount, InstrumentMcountOpts, InstrumentXRay, LinkSelfContained,
LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, NextSolverConfig, Offload, Options,
OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, PatchableFunctionEntry,
Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion,
WasiExecModel, build_session_options, rustc_optgroups,
AnnotateMoves, AssumptionsOnBinders, AutoDiff, BranchProtection, CFGuard, Cfg,
CodegenRetagOptions, CoverageLevel, CoverageOptions, DebugInfo, DumpMonoStatsFormat,
ErrorOutputType, ExternEntry, ExternLocation, Externs, FmtDebug, FunctionReturn,
IncrementalStateAssertion, InliningThreshold, Input, InstrumentCoverage, InstrumentMcount,
InstrumentMcountOpts, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail,
LtoCli, MirIncludeSpans, NextSolverConfig, Offload, Options, OutFileName, OutputType,
OutputTypes, PAuthKey, PacRet, Passes, PatchableFunctionEntry, Polonius,
ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
build_session_options, rustc_optgroups,
};
use rustc_session::search_paths::SearchPath;
use rustc_session::utils::{CanonicalizedPath, NativeLib};
Expand Down Expand Up @@ -954,7 +955,14 @@ fn test_assumptions_on_binders_enables_next_solver_globally() {
// `-Zassumptions-on-binders` alone enables the next solver globally.
let matches = optgroups().parse(&["-Zassumptions-on-binders".to_string()]).unwrap();
let opts = build_session_options(&mut early_dcx, &matches, false);
assert!(opts.unstable_opts.assumptions_on_binders);
assert_eq!(opts.unstable_opts.assumptions_on_binders, AssumptionsOnBinders::All);
assert_eq!(opts.unstable_opts.next_solver, globally);

// The minimal coroutine mode also requires the next solver globally.
let matches =
optgroups().parse(&["-Zassumptions-on-binders=min_coroutines".to_string()]).unwrap();
let opts = build_session_options(&mut early_dcx, &matches, false);
assert_eq!(opts.unstable_opts.assumptions_on_binders, AssumptionsOnBinders::MinCoroutines);
assert_eq!(opts.unstable_opts.next_solver, globally);

// `-Zassumptions-on-binders` overrides `-Znext-solver=no` regardless of order, since
Expand All @@ -966,7 +974,7 @@ fn test_assumptions_on_binders_enables_next_solver_globally() {
] {
let matches = optgroups().parse(&args).unwrap();
let opts = build_session_options(&mut early_dcx, &matches, false);
assert!(opts.unstable_opts.assumptions_on_binders);
assert_eq!(opts.unstable_opts.assumptions_on_binders, AssumptionsOnBinders::All);
assert_eq!(opts.unstable_opts.next_solver, globally);
}
}
18 changes: 16 additions & 2 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2860,8 +2860,22 @@ impl<'tcx> TyCtxt<'tcx> {
|| self.sess.opts.unstable_opts.typing_mode_post_typeck_until_borrowck
}

pub fn assumptions_on_binders(self) -> bool {
self.sess.opts.unstable_opts.assumptions_on_binders
/// Whether any `-Zassumptions-on-binders` mode is enabled. Use this to gate
/// the shared machinery, e.g. tracking region constraints in the solver.
pub fn assumptions_on_binders_any(self) -> bool {
self.sess.opts.unstable_opts.assumptions_on_binders.any_is_enabled()
}

/// Whether the full `-Zassumptions-on-binders` mode is enabled, deducing
/// assumptions from every binder.
pub fn assumptions_on_binders_full(self) -> bool {
self.sess.opts.unstable_opts.assumptions_on_binders.is_full()
}

/// Whether `-Zassumptions-on-binders=min_coroutines` is enabled, deducing
/// assumptions only from coroutine-witness binders.
pub fn assumptions_on_binders_min_coroutines(self) -> bool {
self.sess.opts.unstable_opts.assumptions_on_binders.is_min_coroutines()
}

pub fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
Expand Down
12 changes: 10 additions & 2 deletions compiler/rustc_middle/src/ty/context/impl_interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,16 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.features()
}

fn assumptions_on_binders(self) -> bool {
self.assumptions_on_binders()
fn assumptions_on_binders_any(self) -> bool {
self.assumptions_on_binders_any()
}

fn assumptions_on_binders_full(self) -> bool {
self.assumptions_on_binders_full()
}

fn assumptions_on_binders_min_coroutines(self) -> bool {
self.assumptions_on_binders_min_coroutines()
}

fn renormalize_rigid_aliases(self) -> bool {
Expand Down
36 changes: 21 additions & 15 deletions compiler/rustc_next_trait_solver/src/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,20 +162,7 @@ where
let prev_universe = delegate.universe();
let universes_created_in_query = response.max_universe.index();
for _ in 0..universes_created_in_query {
let new_universe = delegate.create_next_universe();
if delegate.cx().assumptions_on_binders() {
// FIXME(-Zassumptions-on-binders): Remove this temporary workaround once
// opaque types no longer escape query responses with query-created placeholders.
// Region constraints involving query-created placeholders were handled inside
// the query. However, the placeholders can still escape in other response
// fields, such as opaque type constraints. To avoid triggering
// assertions, we explicitly insert empty assumptions for the
// recreated universes here.
delegate.insert_placeholder_assumptions(
new_universe,
rustc_type_ir::region_constraint::Assumptions::empty(),
);
}
create_next_universe_with_placeholder_assumptions(delegate);
}

compute_query_response_instantiation_values_in_universe(
Expand All @@ -187,6 +174,25 @@ where
)
}

fn create_next_universe_with_placeholder_assumptions<D, I>(delegate: &D)
where
D: SolverDelegate<Interner = I>,
I: Interner,
{
let new_universe = delegate.create_next_universe();
if delegate.cx().assumptions_on_binders_any() {
// FIXME(-Zassumptions-on-binders): Remove this temporary workaround once opaque types no
// longer escape query responses with query-created placeholders. Region constraints
// involving query-created placeholders were handled inside the query, but placeholders can
// still escape in other response fields. These contextless universes use empty assumptions:
// they cannot discharge constraints, but allow them to propagate back to their source.
delegate.insert_placeholder_assumptions(
new_universe,
rustc_type_ir::region_constraint::Assumptions::empty(),
);
}
}

fn compute_query_response_instantiation_values_in_universe<D, I, T>(
delegate: &D,
original_values: &[I::GenericArg],
Expand Down Expand Up @@ -592,7 +598,7 @@ where
// and the previous instantiation, extend `orig_values` for it.
let max_universe = prev_universe + state.max_universe.index();
while delegate.universe() < max_universe {
delegate.create_next_universe();
create_next_universe_with_placeholder_assumptions(delegate);
}
orig_values.extend(
state.value.var_values.as_slice()[orig_values.len()..]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_next_trait_solver/src/placeholder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ where
current_index: _,
} = replacer;

if infcx.cx().assumptions_on_binders() {
if infcx.cx().assumptions_on_binders_any() {
for (old, new) in old_universes.into_iter().zip(universe_indices.iter()) {
if let (None, Some(new)) = (old, new) {
// FIXME(-Zassumptions-on-binders): `replace_bound_vars` does not have enough
Expand Down
32 changes: 19 additions & 13 deletions compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use tracing::instrument;

use super::assembly::{Candidate, structural_traits};
use crate::delegate::SolverDelegate;
use crate::solve::eval_ctxt::ForallBinderKind;
use crate::solve::{
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution, assembly,
};
Expand Down Expand Up @@ -268,19 +269,24 @@ where
structural_traits::instantiate_constituent_tys_for_copy_clone_trait(ecx, self_ty)?;

ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
ecx.enter_forall_with_assumptions(constituent_tys, goal.param_env, |ecx, tys| {
ecx.add_goals(
GoalSource::ImplWhereBound,
tys.into_iter().map(|ty| {
goal.with(
cx,
ty::ClauseKind::HostEffect(
goal.predicate.with_replaced_self_ty(cx, ty),
),
)
}),
)
})?;
ecx.enter_forall_with_assumptions(
constituent_tys,
goal.param_env,
ForallBinderKind::for_self_ty::<I>(self_ty),
|ecx, tys| {
ecx.add_goals(
GoalSource::ImplWhereBound,
tys.into_iter().map(|ty| {
goal.with(
cx,
ty::ClauseKind::HostEffect(
goal.predicate.with_replaced_self_ty(cx, ty),
),
)
}),
)
},
)?;

ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
Expand Down
Loading
Loading