Skip to content

Commit fc87f6c

Browse files
committed
deduplicate code and address review
1 parent 7ffb868 commit fc87f6c

6 files changed

Lines changed: 62 additions & 84 deletions

File tree

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
401401

402402
const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
403403

404+
const SHOULD_RESPECT_CONST_BOUNDS_WHEN_RESOLVING_INSTANCES: bool = true;
405+
404406
#[inline(always)]
405407
fn enforce_alignment(ecx: &InterpCx<'tcx, Self>) -> bool {
406408
matches!(ecx.machine.check_alignment, CheckAlignment::Error)
@@ -952,8 +954,6 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
952954

953955
fn get_default_alloc_params(&self) -> <Self::Bytes as mir::interpret::AllocBytes>::AllocParams {
954956
}
955-
956-
const SHOULD_RESPECT_CONST_BOUNDS_WHEN_RESOLVING_INSTANCES: bool = true;
957957
}
958958

959959
// Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups

compiler/rustc_const_eval/src/interpret/machine.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ pub trait Machine<'tcx>: Sized {
161161
/// already been checked before.
162162
const ALL_CONSTS_ARE_PRECHECKED: bool = true;
163163

164+
/// Should we resolve instances as if we are in a const context? This means specialized impls whose
165+
/// `T: [const] Trait` bounds that are not satisfied will not be selected.
166+
const SHOULD_RESPECT_CONST_BOUNDS_WHEN_RESOLVING_INSTANCES: bool = false;
167+
164168
/// Whether memory accesses should be alignment-checked.
165169
fn enforce_alignment(ecx: &InterpCx<'tcx, Self>) -> bool;
166170

@@ -638,8 +642,6 @@ pub trait Machine<'tcx>: Sized {
638642
fn enter_trace_span(_span: impl FnOnce() -> tracing::Span) -> impl EnteredTraceSpan {
639643
()
640644
}
641-
642-
const SHOULD_RESPECT_CONST_BOUNDS_WHEN_RESOLVING_INSTANCES: bool = false;
643645
}
644646

645647
/// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines

compiler/rustc_middle/src/queries.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1606,6 +1606,13 @@ rustc_queries! {
16061606
desc { "computing candidate for `{}`", key.value }
16071607
}
16081608

1609+
query codegen_select_candidate_for_ctfe(
1610+
key: PseudoCanonicalInput<'tcx, ty::TraitRef<'tcx>>
1611+
) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
1612+
cache_on_disk
1613+
desc { "computing const candidate for `{}`", key.value }
1614+
}
1615+
16091616
/// Return all `impl` blocks in the current crate.
16101617
query all_local_trait_impls(_: ()) -> &'tcx rustc_data_structures::fx::FxIndexMap<DefId, Vec<LocalDefId>> {
16111618
desc { "finding local trait impls" }

compiler/rustc_traits/src/codegen.rs

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_middle::bug;
88
use rustc_middle::traits::CodegenObligationError;
99
use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeVisitableExt, Unnormalized};
1010
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
11+
use rustc_trait_selection::solve::InferCtxtSelectExt as _;
1112
use rustc_trait_selection::traits::{
1213
ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext,
1314
SelectionError,
@@ -21,11 +22,15 @@ use tracing::debug;
2122
/// obligations *could be* resolved if we wanted to.
2223
///
2324
/// This also expects that `trait_ref` is fully normalized.
24-
pub(crate) fn codegen_select_candidate<'tcx>(
25+
///
26+
/// When `use_const` is set, we assume the new trait solver is enabled and use
27+
/// `HostEffectPredicate` with `constness` set to `Const`.
28+
pub(crate) fn codegen_select_candidate_inner<'tcx>(
2529
tcx: TyCtxt<'tcx>,
26-
key: PseudoCanonicalInput<'tcx, ty::TraitRef<'tcx>>,
30+
typing_env: ty::TypingEnv<'tcx>,
31+
trait_ref: ty::TraitRef<'tcx>,
32+
use_const: bool,
2733
) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
28-
let PseudoCanonicalInput { typing_env, value: trait_ref } = key;
2934
// We expect the input to be fully normalized.
3035
debug_assert_eq!(
3136
trait_ref,
@@ -38,14 +43,26 @@ pub(crate) fn codegen_select_candidate<'tcx>(
3843
let mut selcx = SelectionContext::new(&infcx);
3944

4045
let obligation_cause = ObligationCause::dummy();
41-
let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref);
4246

43-
let selection = match selcx.select(&obligation) {
47+
let selection = if use_const {
48+
let host_predicate =
49+
ty::HostEffectPredicate { trait_ref, constness: ty::BoundConstness::Const };
50+
let obligation = Obligation::new(tcx, obligation_cause, param_env, host_predicate);
51+
52+
infcx.select_host_effect_predicate_in_new_trait_solver(&obligation)
53+
} else {
54+
let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref);
55+
selcx.select(&obligation)
56+
};
57+
58+
let selection = match selection {
4459
Ok(Some(selection)) => selection,
4560
Ok(None) => return Err(CodegenObligationError::Ambiguity),
4661
Err(SelectionError::Unimplemented) => return Err(CodegenObligationError::Unimplemented),
4762
Err(e) => {
48-
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
63+
bug!(
64+
"Encountered error `{e:?}` selecting `{trait_ref:?}` during codegen (use_const: {use_const})"
65+
)
4966
}
5067
};
5168

@@ -94,3 +111,17 @@ pub(crate) fn codegen_select_candidate<'tcx>(
94111

95112
Ok(&*tcx.arena.alloc(impl_source))
96113
}
114+
115+
pub(crate) fn codegen_select_candidate<'tcx>(
116+
tcx: TyCtxt<'tcx>,
117+
key: PseudoCanonicalInput<'tcx, ty::TraitRef<'tcx>>,
118+
) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
119+
codegen_select_candidate_inner(tcx, key.typing_env, key.value, false)
120+
}
121+
122+
pub(crate) fn codegen_select_candidate_for_ctfe<'tcx>(
123+
tcx: TyCtxt<'tcx>,
124+
key: PseudoCanonicalInput<'tcx, ty::TraitRef<'tcx>>,
125+
) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
126+
codegen_select_candidate_inner(tcx, key.typing_env, key.value, true)
127+
}

compiler/rustc_traits/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ pub fn provide(p: &mut Providers) {
2525
normalize_erasing_regions::provide(p);
2626
type_op::provide(p);
2727
p.codegen_select_candidate = codegen::codegen_select_candidate;
28+
p.codegen_select_candidate_for_ctfe = codegen::codegen_select_candidate_for_ctfe;
2829
p.coroutine_hidden_types = coroutine_witnesses::coroutine_hidden_types;
2930
}

compiler/rustc_ty_utils/src/instance.rs

Lines changed: 11 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ use rustc_errors::ErrorGuaranteed;
22
use rustc_hir::def_id::DefId;
33
use rustc_hir::{Constness, LangItem};
44
use rustc_infer::infer::TyCtxtInferExt;
5-
use rustc_infer::traits::{
6-
ImplSource, Obligation, ObligationCause, ScrubbedTraitError, SelectionError,
7-
};
85
use rustc_middle::bug;
96
use rustc_middle::query::Providers;
107
use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError};
@@ -13,9 +10,7 @@ use rustc_middle::ty::{
1310
Unnormalized,
1411
};
1512
use rustc_span::sym;
16-
use rustc_trait_selection::error_reporting::InferCtxtErrorExt as _;
17-
use rustc_trait_selection::solve::InferCtxtSelectExt as _;
18-
use rustc_trait_selection::traits::{self, ObligationCtxt};
13+
use rustc_trait_selection::traits;
1914
use tracing::debug;
2015
use traits::translate_args;
2116

@@ -119,81 +114,23 @@ fn resolve_associated_item<'tcx>(
119114
let trait_ref = ty::TraitRef::from_assoc(tcx, trait_id, rcvr_args);
120115

121116
let input = typing_env.as_query_input(trait_ref);
122-
let vtbl = if constness == Constness::Const && tcx.next_trait_solver_globally() {
123-
let (infcx, param_env) =
124-
tcx.infer_ctxt().ignoring_regions().build_with_typing_env(typing_env);
125-
126-
let obligation_cause = ObligationCause::dummy();
127-
let host_predicate =
128-
ty::HostEffectPredicate { trait_ref, constness: ty::BoundConstness::Const };
129-
let obligation = Obligation::new(tcx, obligation_cause, param_env, host_predicate);
130-
131-
let selection = match infcx.select_host_effect_predicate_in_new_trait_solver(&obligation) {
132-
Ok(Some(selection)) => selection,
133-
Ok(None) => return Ok(None),
134-
Err(SelectionError::Unimplemented) => return Ok(None),
135-
Err(e) => {
136-
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, host_predicate)
137-
}
138-
};
139-
140-
debug!(?selection);
141-
142-
// Currently, we use a fulfillment context to completely resolve
143-
// all nested obligations. This is because they can inform the
144-
// inference of the impl's type parameters.
145-
let ocx = ObligationCtxt::new(&infcx);
146-
let impl_source = selection.map(|obligation| {
147-
ocx.register_obligation(obligation);
148-
});
117+
let candidate = if constness == Constness::Const && tcx.next_trait_solver_globally() {
118+
tcx.codegen_select_candidate_for_ctfe(input)
119+
} else {
120+
tcx.codegen_select_candidate(input)
121+
};
149122

150-
// In principle, we only need to do this so long as `impl_source`
151-
// contains unbound type parameters. It could be a slight
152-
// optimization to stop iterating early.
153-
let errors = ocx.evaluate_obligations_error_on_ambiguity();
154-
if !errors.is_empty() {
155-
// `rustc_monomorphize::collector` assumes there are no type errors.
156-
// Cycle errors are the only post-monomorphization errors possible; emit them now so
157-
// `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
158-
for err in errors {
159-
if let ScrubbedTraitError::Cycle(cycle) = err {
160-
infcx.err_ctxt().report_overflow_obligation_cycle(&cycle);
161-
}
162-
}
123+
let impl_src = match candidate {
124+
Ok(impl_src) => impl_src,
125+
Err(CodegenObligationError::Ambiguity | CodegenObligationError::Unimplemented) => {
163126
return Ok(None);
164127
}
165-
166-
let impl_source = infcx.resolve_vars_if_possible(impl_source);
167-
let impl_source = tcx.erase_and_anonymize_regions(impl_source);
168-
if impl_source.has_non_region_infer() {
169-
// Unused generic types or consts on an impl get replaced with inference vars,
170-
// but never resolved, causing the return value of a query to contain inference
171-
// vars. We do not have a concept for this and will in fact ICE in stable hashing
172-
// of the return value. So bail out instead.
173-
let guar = match impl_source {
174-
ImplSource::UserDefined(impl_) => tcx.dcx().span_delayed_bug(
175-
tcx.def_span(impl_.impl_def_id),
176-
"this impl has unconstrained generic parameters",
177-
),
178-
_ => unreachable!(),
179-
};
180-
return Err(guar);
181-
}
182-
183-
&*tcx.arena.alloc(impl_source)
184-
} else {
185-
match tcx.codegen_select_candidate(input) {
186-
Ok(vtbl) => vtbl,
187-
Err(CodegenObligationError::Ambiguity | CodegenObligationError::Unimplemented) => {
188-
return Ok(None);
189-
}
190-
Err(CodegenObligationError::UnconstrainedParam(guar)) => return Err(guar),
191-
}
128+
Err(CodegenObligationError::UnconstrainedParam(guar)) => return Err(guar),
192129
};
193130

194131
// Now that we know which impl is being used, we can dispatch to
195132
// the actual function:
196-
Ok(match vtbl {
133+
Ok(match impl_src {
197134
traits::ImplSource::UserDefined(impl_data) => {
198135
debug!(
199136
"resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}",

0 commit comments

Comments
 (0)