Skip to content

Commit 8931edf

Browse files
committed
Auto merge of #113293 - GuillaumeGomez:rollup-2395uw0, r=GuillaumeGomez
Rollup of 3 pull requests Successful merges: - #112869 (Implement selection via new trait solver) - #113285 ([rustdoc] Fix display of long inline cfg labels) - #113286 (Don't perform selection if inherent associated types are not enabled) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 3ae0ef7 + 157bab6 commit 8931edf

File tree

19 files changed

+551
-127
lines changed

19 files changed

+551
-127
lines changed

compiler/rustc_hir_analysis/src/astconv/mod.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -1893,6 +1893,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
18931893
) -> Result<Option<(Ty<'tcx>, DefId)>, ErrorGuaranteed> {
18941894
let tcx = self.tcx();
18951895

1896+
// Don't attempt to look up inherent associated types when the feature is not enabled.
1897+
// Theoretically it'd be fine to do so since we feature-gate their definition site.
1898+
// However, due to current limitations of the implementation (caused by us performing
1899+
// selection in AstConv), IATs can lead to cycle errors (#108491, #110106) which mask the
1900+
// feature-gate error, needlessly confusing users that use IATs by accident (#113265).
1901+
if !tcx.features().inherent_associated_types {
1902+
return Ok(None);
1903+
}
1904+
18961905
let candidates: Vec<_> = tcx
18971906
.inherent_impls(adt_did)
18981907
.iter()
@@ -1903,11 +1912,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
19031912
return Ok(None);
19041913
}
19051914

1906-
if !tcx.features().inherent_associated_types {
1907-
tcx.sess
1908-
.delay_span_bug(span, "found inherent assoc type without the feature being gated");
1909-
}
1910-
19111915
//
19121916
// Select applicable inherent associated type candidates modulo regions.
19131917
//

compiler/rustc_trait_selection/src/solve/assembly/mod.rs

+36-15
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ pub(super) enum CandidateSource {
4949
/// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
5050
/// For a list of all traits with builtin impls, check out the
5151
/// [`EvalCtxt::assemble_builtin_impl_candidates`] method. Not
52-
BuiltinImpl,
52+
BuiltinImpl(BuiltinImplSource),
5353
/// An assumption from the environment.
5454
///
5555
/// More precisely we've used the `n-th` assumption in the `param_env`.
@@ -87,6 +87,16 @@ pub(super) enum CandidateSource {
8787
AliasBound,
8888
}
8989

90+
/// Records additional information about what kind of built-in impl this is.
91+
/// This should only be used by selection.
92+
#[derive(Debug, Clone, Copy)]
93+
pub(super) enum BuiltinImplSource {
94+
TraitUpcasting,
95+
Object,
96+
Misc,
97+
Ambiguity,
98+
}
99+
90100
/// Methods used to assemble candidates for either trait or projection goals.
91101
pub(super) trait GoalKind<'tcx>:
92102
TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display
@@ -295,7 +305,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
295305
// least structurally resolve the type one layer.
296306
if goal.predicate.self_ty().is_ty_var() {
297307
return vec![Candidate {
298-
source: CandidateSource::BuiltinImpl,
308+
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
299309
result: self
300310
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
301311
.unwrap(),
@@ -344,7 +354,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
344354
let result = ecx.evaluate_added_goals_and_make_canonical_response(
345355
Certainty::Maybe(MaybeCause::Overflow),
346356
)?;
347-
Ok(vec![Candidate { source: CandidateSource::BuiltinImpl, result }])
357+
Ok(vec![Candidate {
358+
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
359+
result,
360+
}])
348361
},
349362
|ecx| {
350363
let normalized_ty = ecx.next_ty_infer();
@@ -447,17 +460,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
447460
};
448461

449462
match result {
450-
Ok(result) => {
451-
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
452-
}
463+
Ok(result) => candidates.push(Candidate {
464+
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
465+
result,
466+
}),
453467
Err(NoSolution) => (),
454468
}
455469

456470
// There may be multiple unsize candidates for a trait with several supertraits:
457471
// `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
458472
if lang_items.unsize_trait() == Some(trait_def_id) {
459473
for result in G::consider_builtin_dyn_upcast_candidates(self, goal) {
460-
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result });
474+
candidates.push(Candidate {
475+
source: CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting),
476+
result,
477+
});
461478
}
462479
}
463480
}
@@ -621,9 +638,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
621638
};
622639

623640
match result {
624-
Ok(result) => {
625-
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
626-
}
641+
Ok(result) => candidates.push(Candidate {
642+
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
643+
result,
644+
}),
627645
Err(NoSolution) => (),
628646
}
629647
}
@@ -688,9 +706,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
688706
}
689707

690708
match G::consider_object_bound_candidate(self, goal, assumption) {
691-
Ok(result) => {
692-
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
693-
}
709+
Ok(result) => candidates.push(Candidate {
710+
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Object),
711+
result,
712+
}),
694713
Err(NoSolution) => (),
695714
}
696715
}
@@ -711,8 +730,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
711730
Err(_) => match self
712731
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
713732
{
714-
Ok(result) => candidates
715-
.push(Candidate { source: CandidateSource::BuiltinImpl, result }),
733+
Ok(result) => candidates.push(Candidate {
734+
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
735+
result,
736+
}),
716737
// FIXME: This will be reachable at some point if we're in
717738
// `assemble_candidates_after_normalizing_self_ty` and we get a
718739
// universe error. We'll deal with it at this point.

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+96-56
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ use super::inspect::ProofTreeBuilder;
2828
use super::search_graph::{self, OverflowHandler};
2929
use super::SolverMode;
3030
use super::{search_graph::SearchGraph, Goal};
31+
pub use select::InferCtxtSelectExt;
3132

3233
mod canonical;
3334
mod probe;
35+
mod select;
3436

3537
pub struct EvalCtxt<'a, 'tcx> {
3638
/// The inference context that backs (mostly) inference and placeholder terms
@@ -140,28 +142,47 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
140142
Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
141143
Option<inspect::GoalEvaluation<'tcx>>,
142144
) {
143-
let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
144-
let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode);
145+
EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
146+
ecx.evaluate_goal(IsNormalizesToHack::No, goal)
147+
})
148+
}
149+
}
150+
151+
impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
152+
pub(super) fn solver_mode(&self) -> SolverMode {
153+
self.search_graph.solver_mode()
154+
}
155+
156+
/// Creates a root evaluation context and search graph. This should only be
157+
/// used from outside of any evaluation, and other methods should be preferred
158+
/// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]).
159+
fn enter_root<R>(
160+
infcx: &InferCtxt<'tcx>,
161+
generate_proof_tree: GenerateProofTree,
162+
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R,
163+
) -> (R, Option<inspect::GoalEvaluation<'tcx>>) {
164+
let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
165+
let mut search_graph = search_graph::SearchGraph::new(infcx.tcx, mode);
145166

146167
let mut ecx = EvalCtxt {
147168
search_graph: &mut search_graph,
148-
infcx: self,
169+
infcx: infcx,
149170
// Only relevant when canonicalizing the response,
150171
// which we don't do within this evaluation context.
151-
predefined_opaques_in_body: self
172+
predefined_opaques_in_body: infcx
152173
.tcx
153174
.mk_predefined_opaques_in_body(PredefinedOpaquesData::default()),
154175
// Only relevant when canonicalizing the response.
155176
max_input_universe: ty::UniverseIndex::ROOT,
156177
var_values: CanonicalVarValues::dummy(),
157178
nested_goals: NestedGoals::new(),
158179
tainted: Ok(()),
159-
inspect: (self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree
180+
inspect: (infcx.tcx.sess.opts.unstable_opts.dump_solver_proof_tree
160181
|| matches!(generate_proof_tree, GenerateProofTree::Yes))
161182
.then(ProofTreeBuilder::new_root)
162183
.unwrap_or_else(ProofTreeBuilder::new_noop),
163184
};
164-
let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal);
185+
let result = f(&mut ecx);
165186

166187
let tree = ecx.inspect.finalize();
167188
if let Some(tree) = &tree {
@@ -177,11 +198,66 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
177198
assert!(search_graph.is_empty());
178199
(result, tree)
179200
}
180-
}
181201

182-
impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
183-
pub(super) fn solver_mode(&self) -> SolverMode {
184-
self.search_graph.solver_mode()
202+
/// Creates a nested evaluation context that shares the same search graph as the
203+
/// one passed in. This is suitable for evaluation, granted that the search graph
204+
/// has had the nested goal recorded on its stack ([`SearchGraph::with_new_goal`]),
205+
/// but it's preferable to use other methods that call this one rather than this
206+
/// method directly.
207+
///
208+
/// This function takes care of setting up the inference context, setting the anchor,
209+
/// and registering opaques from the canonicalized input.
210+
fn enter_canonical<R>(
211+
tcx: TyCtxt<'tcx>,
212+
search_graph: &'a mut search_graph::SearchGraph<'tcx>,
213+
canonical_input: CanonicalInput<'tcx>,
214+
goal_evaluation: &mut ProofTreeBuilder<'tcx>,
215+
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>, Goal<'tcx, ty::Predicate<'tcx>>) -> R,
216+
) -> R {
217+
let intercrate = match search_graph.solver_mode() {
218+
SolverMode::Normal => false,
219+
SolverMode::Coherence => true,
220+
};
221+
let (ref infcx, input, var_values) = tcx
222+
.infer_ctxt()
223+
.intercrate(intercrate)
224+
.with_next_trait_solver(true)
225+
.with_opaque_type_inference(canonical_input.value.anchor)
226+
.build_with_canonical(DUMMY_SP, &canonical_input);
227+
228+
let mut ecx = EvalCtxt {
229+
infcx,
230+
var_values,
231+
predefined_opaques_in_body: input.predefined_opaques_in_body,
232+
max_input_universe: canonical_input.max_universe,
233+
search_graph,
234+
nested_goals: NestedGoals::new(),
235+
tainted: Ok(()),
236+
inspect: goal_evaluation.new_goal_evaluation_step(input),
237+
};
238+
239+
for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
240+
ecx.insert_hidden_type(key, input.goal.param_env, ty)
241+
.expect("failed to prepopulate opaque types");
242+
}
243+
244+
if !ecx.nested_goals.is_empty() {
245+
panic!("prepopulating opaque types shouldn't add goals: {:?}", ecx.nested_goals);
246+
}
247+
248+
let result = f(&mut ecx, input.goal);
249+
250+
goal_evaluation.goal_evaluation_step(ecx.inspect);
251+
252+
// When creating a query response we clone the opaque type constraints
253+
// instead of taking them. This would cause an ICE here, since we have
254+
// assertions against dropping an `InferCtxt` without taking opaques.
255+
// FIXME: Once we remove support for the old impl we can remove this.
256+
if input.anchor != DefiningAnchor::Error {
257+
let _ = infcx.take_opaque_types();
258+
}
259+
260+
result
185261
}
186262

187263
/// The entry point of the solver.
@@ -210,53 +286,17 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
210286
canonical_input,
211287
goal_evaluation,
212288
|search_graph, goal_evaluation| {
213-
let intercrate = match search_graph.solver_mode() {
214-
SolverMode::Normal => false,
215-
SolverMode::Coherence => true,
216-
};
217-
let (ref infcx, input, var_values) = tcx
218-
.infer_ctxt()
219-
.intercrate(intercrate)
220-
.with_next_trait_solver(true)
221-
.with_opaque_type_inference(canonical_input.value.anchor)
222-
.build_with_canonical(DUMMY_SP, &canonical_input);
223-
224-
let mut ecx = EvalCtxt {
225-
infcx,
226-
var_values,
227-
predefined_opaques_in_body: input.predefined_opaques_in_body,
228-
max_input_universe: canonical_input.max_universe,
289+
EvalCtxt::enter_canonical(
290+
tcx,
229291
search_graph,
230-
nested_goals: NestedGoals::new(),
231-
tainted: Ok(()),
232-
inspect: goal_evaluation.new_goal_evaluation_step(input),
233-
};
234-
235-
for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
236-
ecx.insert_hidden_type(key, input.goal.param_env, ty)
237-
.expect("failed to prepopulate opaque types");
238-
}
239-
240-
if !ecx.nested_goals.is_empty() {
241-
panic!(
242-
"prepopulating opaque types shouldn't add goals: {:?}",
243-
ecx.nested_goals
244-
);
245-
}
246-
247-
let result = ecx.compute_goal(input.goal);
248-
ecx.inspect.query_result(result);
249-
goal_evaluation.goal_evaluation_step(ecx.inspect);
250-
251-
// When creating a query response we clone the opaque type constraints
252-
// instead of taking them. This would cause an ICE here, since we have
253-
// assertions against dropping an `InferCtxt` without taking opaques.
254-
// FIXME: Once we remove support for the old impl we can remove this.
255-
if input.anchor != DefiningAnchor::Error {
256-
let _ = infcx.take_opaque_types();
257-
}
258-
259-
result
292+
canonical_input,
293+
goal_evaluation,
294+
|ecx, goal| {
295+
let result = ecx.compute_goal(goal);
296+
ecx.inspect.query_result(result);
297+
result
298+
},
299+
)
260300
},
261301
)
262302
}

compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,18 @@ use rustc_middle::traits::query::NoSolution;
2020
use rustc_middle::traits::solve::{
2121
ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
2222
};
23-
use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty};
23+
use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
2424
use rustc_span::DUMMY_SP;
2525
use std::iter;
2626
use std::ops::Deref;
2727

2828
impl<'tcx> EvalCtxt<'_, 'tcx> {
2929
/// Canonicalizes the goal remembering the original values
3030
/// for each bound variable.
31-
pub(super) fn canonicalize_goal(
31+
pub(super) fn canonicalize_goal<T: TypeFoldable<TyCtxt<'tcx>>>(
3232
&self,
33-
goal: Goal<'tcx, ty::Predicate<'tcx>>,
34-
) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx>) {
33+
goal: Goal<'tcx, T>,
34+
) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx, T>) {
3535
let mut orig_values = Default::default();
3636
let canonical_goal = Canonicalizer::canonicalize(
3737
self.infcx,

0 commit comments

Comments
 (0)