mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
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
This commit is contained in:
commit
8931edf746
@ -1893,6 +1893,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
) -> Result<Option<(Ty<'tcx>, DefId)>, ErrorGuaranteed> {
|
) -> Result<Option<(Ty<'tcx>, DefId)>, ErrorGuaranteed> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
|
// Don't attempt to look up inherent associated types when the feature is not enabled.
|
||||||
|
// Theoretically it'd be fine to do so since we feature-gate their definition site.
|
||||||
|
// However, due to current limitations of the implementation (caused by us performing
|
||||||
|
// selection in AstConv), IATs can lead to cycle errors (#108491, #110106) which mask the
|
||||||
|
// feature-gate error, needlessly confusing users that use IATs by accident (#113265).
|
||||||
|
if !tcx.features().inherent_associated_types {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
let candidates: Vec<_> = tcx
|
let candidates: Vec<_> = tcx
|
||||||
.inherent_impls(adt_did)
|
.inherent_impls(adt_did)
|
||||||
.iter()
|
.iter()
|
||||||
@ -1903,11 +1912,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !tcx.features().inherent_associated_types {
|
|
||||||
tcx.sess
|
|
||||||
.delay_span_bug(span, "found inherent assoc type without the feature being gated");
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Select applicable inherent associated type candidates modulo regions.
|
// Select applicable inherent associated type candidates modulo regions.
|
||||||
//
|
//
|
||||||
|
@ -49,7 +49,7 @@ pub(super) enum CandidateSource {
|
|||||||
/// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
|
/// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
|
||||||
/// For a list of all traits with builtin impls, check out the
|
/// For a list of all traits with builtin impls, check out the
|
||||||
/// [`EvalCtxt::assemble_builtin_impl_candidates`] method. Not
|
/// [`EvalCtxt::assemble_builtin_impl_candidates`] method. Not
|
||||||
BuiltinImpl,
|
BuiltinImpl(BuiltinImplSource),
|
||||||
/// An assumption from the environment.
|
/// An assumption from the environment.
|
||||||
///
|
///
|
||||||
/// More precisely we've used the `n-th` assumption in the `param_env`.
|
/// More precisely we've used the `n-th` assumption in the `param_env`.
|
||||||
@ -87,6 +87,16 @@ pub(super) enum CandidateSource {
|
|||||||
AliasBound,
|
AliasBound,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Records additional information about what kind of built-in impl this is.
|
||||||
|
/// This should only be used by selection.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(super) enum BuiltinImplSource {
|
||||||
|
TraitUpcasting,
|
||||||
|
Object,
|
||||||
|
Misc,
|
||||||
|
Ambiguity,
|
||||||
|
}
|
||||||
|
|
||||||
/// Methods used to assemble candidates for either trait or projection goals.
|
/// Methods used to assemble candidates for either trait or projection goals.
|
||||||
pub(super) trait GoalKind<'tcx>:
|
pub(super) trait GoalKind<'tcx>:
|
||||||
TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display
|
TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display
|
||||||
@ -295,7 +305,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
// least structurally resolve the type one layer.
|
// least structurally resolve the type one layer.
|
||||||
if goal.predicate.self_ty().is_ty_var() {
|
if goal.predicate.self_ty().is_ty_var() {
|
||||||
return vec![Candidate {
|
return vec![Candidate {
|
||||||
source: CandidateSource::BuiltinImpl,
|
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
|
||||||
result: self
|
result: self
|
||||||
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
@ -344,7 +354,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
let result = ecx.evaluate_added_goals_and_make_canonical_response(
|
let result = ecx.evaluate_added_goals_and_make_canonical_response(
|
||||||
Certainty::Maybe(MaybeCause::Overflow),
|
Certainty::Maybe(MaybeCause::Overflow),
|
||||||
)?;
|
)?;
|
||||||
Ok(vec![Candidate { source: CandidateSource::BuiltinImpl, result }])
|
Ok(vec![Candidate {
|
||||||
|
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
|
||||||
|
result,
|
||||||
|
}])
|
||||||
},
|
},
|
||||||
|ecx| {
|
|ecx| {
|
||||||
let normalized_ty = ecx.next_ty_infer();
|
let normalized_ty = ecx.next_ty_infer();
|
||||||
@ -447,9 +460,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(result) => {
|
Ok(result) => candidates.push(Candidate {
|
||||||
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
|
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
}
|
result,
|
||||||
|
}),
|
||||||
Err(NoSolution) => (),
|
Err(NoSolution) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,7 +471,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
// `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
|
// `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
|
||||||
if lang_items.unsize_trait() == Some(trait_def_id) {
|
if lang_items.unsize_trait() == Some(trait_def_id) {
|
||||||
for result in G::consider_builtin_dyn_upcast_candidates(self, goal) {
|
for result in G::consider_builtin_dyn_upcast_candidates(self, goal) {
|
||||||
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result });
|
candidates.push(Candidate {
|
||||||
|
source: CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting),
|
||||||
|
result,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -621,9 +638,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(result) => {
|
Ok(result) => candidates.push(Candidate {
|
||||||
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
|
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
}
|
result,
|
||||||
|
}),
|
||||||
Err(NoSolution) => (),
|
Err(NoSolution) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -688,9 +706,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match G::consider_object_bound_candidate(self, goal, assumption) {
|
match G::consider_object_bound_candidate(self, goal, assumption) {
|
||||||
Ok(result) => {
|
Ok(result) => candidates.push(Candidate {
|
||||||
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
|
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Object),
|
||||||
}
|
result,
|
||||||
|
}),
|
||||||
Err(NoSolution) => (),
|
Err(NoSolution) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -711,8 +730,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
Err(_) => match self
|
Err(_) => match self
|
||||||
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||||
{
|
{
|
||||||
Ok(result) => candidates
|
Ok(result) => candidates.push(Candidate {
|
||||||
.push(Candidate { source: CandidateSource::BuiltinImpl, result }),
|
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
|
||||||
|
result,
|
||||||
|
}),
|
||||||
// FIXME: This will be reachable at some point if we're in
|
// FIXME: This will be reachable at some point if we're in
|
||||||
// `assemble_candidates_after_normalizing_self_ty` and we get a
|
// `assemble_candidates_after_normalizing_self_ty` and we get a
|
||||||
// universe error. We'll deal with it at this point.
|
// universe error. We'll deal with it at this point.
|
||||||
|
@ -28,9 +28,11 @@ use super::inspect::ProofTreeBuilder;
|
|||||||
use super::search_graph::{self, OverflowHandler};
|
use super::search_graph::{self, OverflowHandler};
|
||||||
use super::SolverMode;
|
use super::SolverMode;
|
||||||
use super::{search_graph::SearchGraph, Goal};
|
use super::{search_graph::SearchGraph, Goal};
|
||||||
|
pub use select::InferCtxtSelectExt;
|
||||||
|
|
||||||
mod canonical;
|
mod canonical;
|
||||||
mod probe;
|
mod probe;
|
||||||
|
mod select;
|
||||||
|
|
||||||
pub struct EvalCtxt<'a, 'tcx> {
|
pub struct EvalCtxt<'a, 'tcx> {
|
||||||
/// The inference context that backs (mostly) inference and placeholder terms
|
/// The inference context that backs (mostly) inference and placeholder terms
|
||||||
@ -140,15 +142,34 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
|
|||||||
Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
|
Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
|
||||||
Option<inspect::GoalEvaluation<'tcx>>,
|
Option<inspect::GoalEvaluation<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
|
EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
|
||||||
let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode);
|
ecx.evaluate_goal(IsNormalizesToHack::No, goal)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
|
pub(super) fn solver_mode(&self) -> SolverMode {
|
||||||
|
self.search_graph.solver_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a root evaluation context and search graph. This should only be
|
||||||
|
/// used from outside of any evaluation, and other methods should be preferred
|
||||||
|
/// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]).
|
||||||
|
fn enter_root<R>(
|
||||||
|
infcx: &InferCtxt<'tcx>,
|
||||||
|
generate_proof_tree: GenerateProofTree,
|
||||||
|
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R,
|
||||||
|
) -> (R, Option<inspect::GoalEvaluation<'tcx>>) {
|
||||||
|
let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
|
||||||
|
let mut search_graph = search_graph::SearchGraph::new(infcx.tcx, mode);
|
||||||
|
|
||||||
let mut ecx = EvalCtxt {
|
let mut ecx = EvalCtxt {
|
||||||
search_graph: &mut search_graph,
|
search_graph: &mut search_graph,
|
||||||
infcx: self,
|
infcx: infcx,
|
||||||
// Only relevant when canonicalizing the response,
|
// Only relevant when canonicalizing the response,
|
||||||
// which we don't do within this evaluation context.
|
// which we don't do within this evaluation context.
|
||||||
predefined_opaques_in_body: self
|
predefined_opaques_in_body: infcx
|
||||||
.tcx
|
.tcx
|
||||||
.mk_predefined_opaques_in_body(PredefinedOpaquesData::default()),
|
.mk_predefined_opaques_in_body(PredefinedOpaquesData::default()),
|
||||||
// Only relevant when canonicalizing the response.
|
// Only relevant when canonicalizing the response.
|
||||||
@ -156,12 +177,12 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
|
|||||||
var_values: CanonicalVarValues::dummy(),
|
var_values: CanonicalVarValues::dummy(),
|
||||||
nested_goals: NestedGoals::new(),
|
nested_goals: NestedGoals::new(),
|
||||||
tainted: Ok(()),
|
tainted: Ok(()),
|
||||||
inspect: (self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree
|
inspect: (infcx.tcx.sess.opts.unstable_opts.dump_solver_proof_tree
|
||||||
|| matches!(generate_proof_tree, GenerateProofTree::Yes))
|
|| matches!(generate_proof_tree, GenerateProofTree::Yes))
|
||||||
.then(ProofTreeBuilder::new_root)
|
.then(ProofTreeBuilder::new_root)
|
||||||
.unwrap_or_else(ProofTreeBuilder::new_noop),
|
.unwrap_or_else(ProofTreeBuilder::new_noop),
|
||||||
};
|
};
|
||||||
let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal);
|
let result = f(&mut ecx);
|
||||||
|
|
||||||
let tree = ecx.inspect.finalize();
|
let tree = ecx.inspect.finalize();
|
||||||
if let Some(tree) = &tree {
|
if let Some(tree) = &tree {
|
||||||
@ -177,11 +198,66 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
|
|||||||
assert!(search_graph.is_empty());
|
assert!(search_graph.is_empty());
|
||||||
(result, tree)
|
(result, tree)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
/// Creates a nested evaluation context that shares the same search graph as the
|
||||||
pub(super) fn solver_mode(&self) -> SolverMode {
|
/// one passed in. This is suitable for evaluation, granted that the search graph
|
||||||
self.search_graph.solver_mode()
|
/// has had the nested goal recorded on its stack ([`SearchGraph::with_new_goal`]),
|
||||||
|
/// but it's preferable to use other methods that call this one rather than this
|
||||||
|
/// method directly.
|
||||||
|
///
|
||||||
|
/// This function takes care of setting up the inference context, setting the anchor,
|
||||||
|
/// and registering opaques from the canonicalized input.
|
||||||
|
fn enter_canonical<R>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
search_graph: &'a mut search_graph::SearchGraph<'tcx>,
|
||||||
|
canonical_input: CanonicalInput<'tcx>,
|
||||||
|
goal_evaluation: &mut ProofTreeBuilder<'tcx>,
|
||||||
|
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>, Goal<'tcx, ty::Predicate<'tcx>>) -> R,
|
||||||
|
) -> R {
|
||||||
|
let intercrate = match search_graph.solver_mode() {
|
||||||
|
SolverMode::Normal => false,
|
||||||
|
SolverMode::Coherence => true,
|
||||||
|
};
|
||||||
|
let (ref infcx, input, var_values) = tcx
|
||||||
|
.infer_ctxt()
|
||||||
|
.intercrate(intercrate)
|
||||||
|
.with_next_trait_solver(true)
|
||||||
|
.with_opaque_type_inference(canonical_input.value.anchor)
|
||||||
|
.build_with_canonical(DUMMY_SP, &canonical_input);
|
||||||
|
|
||||||
|
let mut ecx = EvalCtxt {
|
||||||
|
infcx,
|
||||||
|
var_values,
|
||||||
|
predefined_opaques_in_body: input.predefined_opaques_in_body,
|
||||||
|
max_input_universe: canonical_input.max_universe,
|
||||||
|
search_graph,
|
||||||
|
nested_goals: NestedGoals::new(),
|
||||||
|
tainted: Ok(()),
|
||||||
|
inspect: goal_evaluation.new_goal_evaluation_step(input),
|
||||||
|
};
|
||||||
|
|
||||||
|
for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
|
||||||
|
ecx.insert_hidden_type(key, input.goal.param_env, ty)
|
||||||
|
.expect("failed to prepopulate opaque types");
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ecx.nested_goals.is_empty() {
|
||||||
|
panic!("prepopulating opaque types shouldn't add goals: {:?}", ecx.nested_goals);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = f(&mut ecx, input.goal);
|
||||||
|
|
||||||
|
goal_evaluation.goal_evaluation_step(ecx.inspect);
|
||||||
|
|
||||||
|
// When creating a query response we clone the opaque type constraints
|
||||||
|
// instead of taking them. This would cause an ICE here, since we have
|
||||||
|
// assertions against dropping an `InferCtxt` without taking opaques.
|
||||||
|
// FIXME: Once we remove support for the old impl we can remove this.
|
||||||
|
if input.anchor != DefiningAnchor::Error {
|
||||||
|
let _ = infcx.take_opaque_types();
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The entry point of the solver.
|
/// The entry point of the solver.
|
||||||
@ -210,53 +286,17 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||||||
canonical_input,
|
canonical_input,
|
||||||
goal_evaluation,
|
goal_evaluation,
|
||||||
|search_graph, goal_evaluation| {
|
|search_graph, goal_evaluation| {
|
||||||
let intercrate = match search_graph.solver_mode() {
|
EvalCtxt::enter_canonical(
|
||||||
SolverMode::Normal => false,
|
tcx,
|
||||||
SolverMode::Coherence => true,
|
|
||||||
};
|
|
||||||
let (ref infcx, input, var_values) = tcx
|
|
||||||
.infer_ctxt()
|
|
||||||
.intercrate(intercrate)
|
|
||||||
.with_next_trait_solver(true)
|
|
||||||
.with_opaque_type_inference(canonical_input.value.anchor)
|
|
||||||
.build_with_canonical(DUMMY_SP, &canonical_input);
|
|
||||||
|
|
||||||
let mut ecx = EvalCtxt {
|
|
||||||
infcx,
|
|
||||||
var_values,
|
|
||||||
predefined_opaques_in_body: input.predefined_opaques_in_body,
|
|
||||||
max_input_universe: canonical_input.max_universe,
|
|
||||||
search_graph,
|
search_graph,
|
||||||
nested_goals: NestedGoals::new(),
|
canonical_input,
|
||||||
tainted: Ok(()),
|
goal_evaluation,
|
||||||
inspect: goal_evaluation.new_goal_evaluation_step(input),
|
|ecx, goal| {
|
||||||
};
|
let result = ecx.compute_goal(goal);
|
||||||
|
ecx.inspect.query_result(result);
|
||||||
for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
|
result
|
||||||
ecx.insert_hidden_type(key, input.goal.param_env, ty)
|
},
|
||||||
.expect("failed to prepopulate opaque types");
|
)
|
||||||
}
|
|
||||||
|
|
||||||
if !ecx.nested_goals.is_empty() {
|
|
||||||
panic!(
|
|
||||||
"prepopulating opaque types shouldn't add goals: {:?}",
|
|
||||||
ecx.nested_goals
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = ecx.compute_goal(input.goal);
|
|
||||||
ecx.inspect.query_result(result);
|
|
||||||
goal_evaluation.goal_evaluation_step(ecx.inspect);
|
|
||||||
|
|
||||||
// When creating a query response we clone the opaque type constraints
|
|
||||||
// instead of taking them. This would cause an ICE here, since we have
|
|
||||||
// assertions against dropping an `InferCtxt` without taking opaques.
|
|
||||||
// FIXME: Once we remove support for the old impl we can remove this.
|
|
||||||
if input.anchor != DefiningAnchor::Error {
|
|
||||||
let _ = infcx.take_opaque_types();
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ use rustc_middle::traits::query::NoSolution;
|
|||||||
use rustc_middle::traits::solve::{
|
use rustc_middle::traits::solve::{
|
||||||
ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
|
ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty};
|
use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::DUMMY_SP;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
@ -28,10 +28,10 @@ use std::ops::Deref;
|
|||||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
/// Canonicalizes the goal remembering the original values
|
/// Canonicalizes the goal remembering the original values
|
||||||
/// for each bound variable.
|
/// for each bound variable.
|
||||||
pub(super) fn canonicalize_goal(
|
pub(super) fn canonicalize_goal<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||||
&self,
|
&self,
|
||||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
goal: Goal<'tcx, T>,
|
||||||
) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx>) {
|
) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx, T>) {
|
||||||
let mut orig_values = Default::default();
|
let mut orig_values = Default::default();
|
||||||
let canonical_goal = Canonicalizer::canonicalize(
|
let canonical_goal = Canonicalizer::canonicalize(
|
||||||
self.infcx,
|
self.infcx,
|
||||||
|
286
compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
Normal file
286
compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
|
||||||
|
use rustc_infer::traits::util::supertraits;
|
||||||
|
use rustc_infer::traits::{
|
||||||
|
Obligation, PredicateObligation, Selection, SelectionResult, TraitObligation,
|
||||||
|
};
|
||||||
|
use rustc_middle::traits::solve::{CanonicalInput, Certainty, Goal};
|
||||||
|
use rustc_middle::traits::{
|
||||||
|
ImplSource, ImplSourceObjectData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
|
||||||
|
ObligationCause, SelectionError,
|
||||||
|
};
|
||||||
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
|
use rustc_span::DUMMY_SP;
|
||||||
|
|
||||||
|
use crate::solve::assembly::{BuiltinImplSource, Candidate, CandidateSource};
|
||||||
|
use crate::solve::eval_ctxt::{EvalCtxt, GenerateProofTree};
|
||||||
|
use crate::solve::inspect::ProofTreeBuilder;
|
||||||
|
use crate::solve::search_graph::OverflowHandler;
|
||||||
|
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
|
||||||
|
|
||||||
|
pub trait InferCtxtSelectExt<'tcx> {
|
||||||
|
fn select_in_new_trait_solver(
|
||||||
|
&self,
|
||||||
|
obligation: &TraitObligation<'tcx>,
|
||||||
|
) -> SelectionResult<'tcx, Selection<'tcx>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
|
||||||
|
fn select_in_new_trait_solver(
|
||||||
|
&self,
|
||||||
|
obligation: &TraitObligation<'tcx>,
|
||||||
|
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
||||||
|
assert!(self.next_trait_solver());
|
||||||
|
|
||||||
|
let trait_goal = Goal::new(
|
||||||
|
self.tcx,
|
||||||
|
obligation.param_env,
|
||||||
|
self.instantiate_binder_with_placeholders(obligation.predicate),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (result, _) = EvalCtxt::enter_root(self, GenerateProofTree::No, |ecx| {
|
||||||
|
let goal = Goal::new(ecx.tcx(), trait_goal.param_env, trait_goal.predicate);
|
||||||
|
let (orig_values, canonical_goal) = ecx.canonicalize_goal(goal);
|
||||||
|
let mut candidates = ecx.compute_canonical_trait_candidates(canonical_goal);
|
||||||
|
|
||||||
|
// pseudo-winnow
|
||||||
|
if candidates.len() == 0 {
|
||||||
|
return Err(SelectionError::Unimplemented);
|
||||||
|
} else if candidates.len() > 1 {
|
||||||
|
let mut i = 0;
|
||||||
|
while i < candidates.len() {
|
||||||
|
let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| {
|
||||||
|
candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j])
|
||||||
|
});
|
||||||
|
if should_drop_i {
|
||||||
|
candidates.swap_remove(i);
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
if i > 1 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let candidate = candidates.pop().unwrap();
|
||||||
|
let (certainty, nested_goals) = ecx
|
||||||
|
.instantiate_and_apply_query_response(
|
||||||
|
trait_goal.param_env,
|
||||||
|
orig_values,
|
||||||
|
candidate.result,
|
||||||
|
)
|
||||||
|
.map_err(|_| SelectionError::Unimplemented)?;
|
||||||
|
|
||||||
|
Ok(Some((candidate, certainty, nested_goals)))
|
||||||
|
});
|
||||||
|
|
||||||
|
let (candidate, certainty, nested_goals) = match result {
|
||||||
|
Ok(Some((candidate, certainty, nested_goals))) => (candidate, certainty, nested_goals),
|
||||||
|
Ok(None) => return Ok(None),
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
|
|
||||||
|
let nested_obligations: Vec<_> = nested_goals
|
||||||
|
.into_iter()
|
||||||
|
.map(|goal| {
|
||||||
|
Obligation::new(self.tcx, ObligationCause::dummy(), goal.param_env, goal.predicate)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let goal = self.resolve_vars_if_possible(trait_goal);
|
||||||
|
match (certainty, candidate.source) {
|
||||||
|
// Rematching the implementation will instantiate the same nested goals that
|
||||||
|
// would have caused the ambiguity, so we can still make progress here regardless.
|
||||||
|
(_, CandidateSource::Impl(def_id)) => {
|
||||||
|
rematch_impl(self, goal, def_id, nested_obligations)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rematching the dyn upcast or object goal will instantiate the same nested
|
||||||
|
// goals that would have caused the ambiguity, so we can still make progress here
|
||||||
|
// regardless.
|
||||||
|
// FIXME: This doesn't actually check the object bounds hold here.
|
||||||
|
(
|
||||||
|
_,
|
||||||
|
CandidateSource::BuiltinImpl(
|
||||||
|
BuiltinImplSource::Object | BuiltinImplSource::TraitUpcasting,
|
||||||
|
),
|
||||||
|
) => rematch_object(self, goal, nested_obligations),
|
||||||
|
|
||||||
|
// Technically some builtin impls have nested obligations, but if
|
||||||
|
// `Certainty::Yes`, then they should've all been verified and don't
|
||||||
|
// need re-checking.
|
||||||
|
(Certainty::Yes, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc)) => {
|
||||||
|
Ok(Some(ImplSource::Builtin(nested_obligations)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's fine not to do anything to rematch these, since there are no
|
||||||
|
// nested obligations.
|
||||||
|
(Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => {
|
||||||
|
Ok(Some(ImplSource::Param(nested_obligations, ty::BoundConstness::NotConst)))
|
||||||
|
}
|
||||||
|
|
||||||
|
(_, CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity))
|
||||||
|
| (Certainty::Maybe(_), _) => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
|
fn compute_canonical_trait_candidates(
|
||||||
|
&mut self,
|
||||||
|
canonical_input: CanonicalInput<'tcx>,
|
||||||
|
) -> Vec<Candidate<'tcx>> {
|
||||||
|
// This doesn't record the canonical goal on the stack during the
|
||||||
|
// candidate assembly step, but that's fine. Selection is conceptually
|
||||||
|
// outside of the solver, and if there were any cycles, we'd encounter
|
||||||
|
// the cycle anyways one step later.
|
||||||
|
EvalCtxt::enter_canonical(
|
||||||
|
self.tcx(),
|
||||||
|
self.search_graph(),
|
||||||
|
canonical_input,
|
||||||
|
// FIXME: This is wrong, idk if we even want to track stuff here.
|
||||||
|
&mut ProofTreeBuilder::new_noop(),
|
||||||
|
|ecx, goal| {
|
||||||
|
let trait_goal = Goal {
|
||||||
|
param_env: goal.param_env,
|
||||||
|
predicate: goal
|
||||||
|
.predicate
|
||||||
|
.to_opt_poly_trait_pred()
|
||||||
|
.expect("we canonicalized a trait goal")
|
||||||
|
.no_bound_vars()
|
||||||
|
.expect("we instantiated all bound vars"),
|
||||||
|
};
|
||||||
|
ecx.assemble_and_evaluate_candidates(trait_goal)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn candidate_should_be_dropped_in_favor_of<'tcx>(
|
||||||
|
victim: &Candidate<'tcx>,
|
||||||
|
other: &Candidate<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
match (victim.source, other.source) {
|
||||||
|
(CandidateSource::ParamEnv(i), CandidateSource::ParamEnv(j)) => i >= j,
|
||||||
|
(_, CandidateSource::ParamEnv(_)) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rematch_impl<'tcx>(
|
||||||
|
infcx: &InferCtxt<'tcx>,
|
||||||
|
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
|
||||||
|
impl_def_id: DefId,
|
||||||
|
mut nested: Vec<PredicateObligation<'tcx>>,
|
||||||
|
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
||||||
|
let substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
|
||||||
|
let impl_trait_ref = infcx.tcx.impl_trait_ref(impl_def_id).unwrap().subst(infcx.tcx, substs);
|
||||||
|
|
||||||
|
nested.extend(
|
||||||
|
infcx
|
||||||
|
.at(&ObligationCause::dummy(), goal.param_env)
|
||||||
|
.eq(DefineOpaqueTypes::No, goal.predicate.trait_ref, impl_trait_ref)
|
||||||
|
.map_err(|_| SelectionError::Unimplemented)?
|
||||||
|
.into_obligations(),
|
||||||
|
);
|
||||||
|
|
||||||
|
nested.extend(
|
||||||
|
infcx.tcx.predicates_of(impl_def_id).instantiate(infcx.tcx, substs).into_iter().map(
|
||||||
|
|(pred, _)| Obligation::new(infcx.tcx, ObligationCause::dummy(), goal.param_env, pred),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Some(ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id, substs, nested })))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rematch_object<'tcx>(
|
||||||
|
infcx: &InferCtxt<'tcx>,
|
||||||
|
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
|
||||||
|
mut nested: Vec<PredicateObligation<'tcx>>,
|
||||||
|
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
||||||
|
let self_ty = goal.predicate.self_ty();
|
||||||
|
let source_trait_ref = if let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind() {
|
||||||
|
data.principal().unwrap().with_self_ty(infcx.tcx, self_ty)
|
||||||
|
} else {
|
||||||
|
bug!()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (is_upcasting, target_trait_ref_unnormalized) = if Some(goal.predicate.def_id())
|
||||||
|
== infcx.tcx.lang_items().unsize_trait()
|
||||||
|
{
|
||||||
|
if let ty::Dynamic(data, _, ty::Dyn) = goal.predicate.trait_ref.substs.type_at(1).kind() {
|
||||||
|
(true, data.principal().unwrap().with_self_ty(infcx.tcx, self_ty))
|
||||||
|
} else {
|
||||||
|
bug!()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(false, ty::Binder::dummy(goal.predicate.trait_ref))
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut target_trait_ref = None;
|
||||||
|
for candidate_trait_ref in supertraits(infcx.tcx, source_trait_ref) {
|
||||||
|
let result = infcx.commit_if_ok(|_| {
|
||||||
|
infcx.at(&ObligationCause::dummy(), goal.param_env).eq(
|
||||||
|
DefineOpaqueTypes::No,
|
||||||
|
target_trait_ref_unnormalized,
|
||||||
|
candidate_trait_ref,
|
||||||
|
)
|
||||||
|
|
||||||
|
// FIXME: We probably should at least shallowly verify these...
|
||||||
|
});
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(InferOk { value: (), obligations }) => {
|
||||||
|
target_trait_ref = Some(candidate_trait_ref);
|
||||||
|
nested.extend(obligations);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(_) => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let target_trait_ref = target_trait_ref.unwrap();
|
||||||
|
|
||||||
|
let mut offset = 0;
|
||||||
|
let Some((vtable_base, vtable_vptr_slot)) =
|
||||||
|
prepare_vtable_segments(infcx.tcx, source_trait_ref, |segment| {
|
||||||
|
match segment {
|
||||||
|
VtblSegment::MetadataDSA => {
|
||||||
|
offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
|
||||||
|
}
|
||||||
|
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
|
||||||
|
let own_vtable_entries = count_own_vtable_entries(infcx.tcx, trait_ref);
|
||||||
|
|
||||||
|
if trait_ref == target_trait_ref {
|
||||||
|
if emit_vptr {
|
||||||
|
return ControlFlow::Break((
|
||||||
|
offset,
|
||||||
|
Some(offset + count_own_vtable_entries(infcx.tcx, trait_ref)),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
return ControlFlow::Break((offset, None));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += own_vtable_entries;
|
||||||
|
if emit_vptr {
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
})
|
||||||
|
else {
|
||||||
|
bug!();
|
||||||
|
};
|
||||||
|
|
||||||
|
// If we're upcasting, get the offset of the vtable pointer, which is
|
||||||
|
Ok(Some(if is_upcasting {
|
||||||
|
ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData { vtable_vptr_slot, nested })
|
||||||
|
} else {
|
||||||
|
ImplSource::Object(ImplSourceObjectData { vtable_base, nested })
|
||||||
|
}))
|
||||||
|
}
|
@ -33,7 +33,7 @@ mod search_graph;
|
|||||||
mod trait_goals;
|
mod trait_goals;
|
||||||
mod weak_types;
|
mod weak_types;
|
||||||
|
|
||||||
pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt};
|
pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt, InferCtxtSelectExt};
|
||||||
pub use fulfill::FulfillmentCtxt;
|
pub use fulfill::FulfillmentCtxt;
|
||||||
pub(crate) use normalize::deeply_normalize;
|
pub(crate) use normalize::deeply_normalize;
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ use super::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
||||||
|
use crate::solve::InferCtxtSelectExt;
|
||||||
use crate::traits::error_reporting::TypeErrCtxtExt;
|
use crate::traits::error_reporting::TypeErrCtxtExt;
|
||||||
use crate::traits::project::try_normalize_with_depth_to;
|
use crate::traits::project::try_normalize_with_depth_to;
|
||||||
use crate::traits::project::ProjectAndUnifyResult;
|
use crate::traits::project::ProjectAndUnifyResult;
|
||||||
@ -264,6 +265,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
obligation: &TraitObligation<'tcx>,
|
obligation: &TraitObligation<'tcx>,
|
||||||
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
||||||
|
if self.infcx.next_trait_solver() {
|
||||||
|
return self.infcx.select_in_new_trait_solver(obligation);
|
||||||
|
}
|
||||||
|
|
||||||
let candidate = match self.select_from_obligation(obligation) {
|
let candidate = match self.select_from_obligation(obligation) {
|
||||||
Err(SelectionError::Overflow(OverflowError::Canonical)) => {
|
Err(SelectionError::Overflow(OverflowError::Canonical)) => {
|
||||||
// In standard mode, overflow must have been caught and reported
|
// In standard mode, overflow must have been caught and reported
|
||||||
@ -290,7 +295,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn select_from_obligation(
|
fn select_from_obligation(
|
||||||
&mut self,
|
&mut self,
|
||||||
obligation: &TraitObligation<'tcx>,
|
obligation: &TraitObligation<'tcx>,
|
||||||
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
|
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
|
||||||
|
@ -971,6 +971,8 @@ so that we can apply CSS-filters to change the arrow color in themes */
|
|||||||
display: flex;
|
display: flex;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
|
align-items: center;
|
||||||
|
vertical-align: text-bottom;
|
||||||
}
|
}
|
||||||
.item-name .stab {
|
.item-name .stab {
|
||||||
margin-left: 0.3125em;
|
margin-left: 0.3125em;
|
||||||
@ -982,11 +984,9 @@ so that we can apply CSS-filters to change the arrow color in themes */
|
|||||||
color: var(--main-color);
|
color: var(--main-color);
|
||||||
background-color: var(--stab-background-color);
|
background-color: var(--stab-background-color);
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
align-items: center;
|
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
display: inline-flex;
|
display: inline;
|
||||||
vertical-align: text-bottom;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stab.portability > code {
|
.stab.portability > code {
|
||||||
|
@ -37,7 +37,6 @@ compare-elements-position: (
|
|||||||
("y"),
|
("y"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// Mobile view
|
// Mobile view
|
||||||
set-window-size: (600, 600)
|
set-window-size: (600, 600)
|
||||||
// staggered layout with 2em spacing
|
// staggered layout with 2em spacing
|
||||||
@ -64,3 +63,14 @@ compare-elements-position-false: (
|
|||||||
"//*[@class='desc docblock-short'][text()='a thing with a label']",
|
"//*[@class='desc docblock-short'][text()='a thing with a label']",
|
||||||
("y"),
|
("y"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Ensure it doesn't expand.
|
||||||
|
set-window-size: (800, 800)
|
||||||
|
go-to: "file://" + |DOC_PATH| + "/test_docs/cfgs/index.html"
|
||||||
|
// This part of the tags should not be on the same line as the beginning since the width
|
||||||
|
// is too small for that.
|
||||||
|
compare-elements-position-false: (
|
||||||
|
"//*[@class='stab portability']/code[text()='appservice-api-c']",
|
||||||
|
"//*[@class='stab portability']/code[text()='server']",
|
||||||
|
("y"),
|
||||||
|
)
|
||||||
|
@ -507,3 +507,12 @@ pub mod fields {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod cfgs {
|
||||||
|
#[doc(cfg(all(
|
||||||
|
any(not(feature = "appservice-api-c"), not(feature = "appservice-api-s")),
|
||||||
|
any(not(feature = "client"), not(feature = "server")),
|
||||||
|
)))]
|
||||||
|
/// Some docs.
|
||||||
|
pub mod cfgs {}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
// aux-crate:aux=assoc-inherent-unstable.rs
|
// aux-crate:aux=assoc-inherent-unstable.rs
|
||||||
// edition: 2021
|
// edition: 2021
|
||||||
|
|
||||||
|
#![feature(inherent_associated_types)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
type Data = aux::Owner::Data; //~ ERROR use of unstable library feature 'data'
|
type Data = aux::Owner::Data; //~ ERROR use of unstable library feature 'data'
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error[E0658]: use of unstable library feature 'data'
|
error[E0658]: use of unstable library feature 'data'
|
||||||
--> $DIR/assoc-inherent-unstable.rs:4:13
|
--> $DIR/assoc-inherent-unstable.rs:7:13
|
||||||
|
|
|
|
||||||
LL | type Data = aux::Owner::Data;
|
LL | type Data = aux::Owner::Data;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
// known-bug: #108491
|
// known-bug: #108491
|
||||||
|
|
||||||
|
#![feature(inherent_associated_types)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
// FIXME(inherent_associated_types): This should pass.
|
// FIXME(inherent_associated_types): This should pass.
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
@ -8,3 +10,5 @@ struct Foo {
|
|||||||
impl Foo {
|
impl Foo {
|
||||||
pub type Bar = usize;
|
pub type Bar = usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
@ -1,49 +1,43 @@
|
|||||||
error[E0601]: `main` function not found in crate `cycle_iat_inside_of_adt`
|
|
||||||
--> $DIR/cycle-iat-inside-of-adt.rs:10:2
|
|
||||||
|
|
|
||||||
LL | }
|
|
||||||
| ^ consider adding a `main` function to `$DIR/cycle-iat-inside-of-adt.rs`
|
|
||||||
|
|
||||||
error[E0391]: cycle detected when computing predicates of `Foo`
|
error[E0391]: cycle detected when computing predicates of `Foo`
|
||||||
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
|
||||||
|
|
|
|
||||||
LL | struct Foo {
|
LL | struct Foo {
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: ...which requires computing predicates of `Foo`...
|
note: ...which requires computing predicates of `Foo`...
|
||||||
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
|
||||||
|
|
|
|
||||||
LL | struct Foo {
|
LL | struct Foo {
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
note: ...which requires computing inferred outlives predicates of `Foo`...
|
note: ...which requires computing inferred outlives predicates of `Foo`...
|
||||||
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
|
||||||
|
|
|
|
||||||
LL | struct Foo {
|
LL | struct Foo {
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
= note: ...which requires computing the inferred outlives predicates for items in this crate...
|
= note: ...which requires computing the inferred outlives predicates for items in this crate...
|
||||||
note: ...which requires computing type of `Foo::bar`...
|
note: ...which requires computing type of `Foo::bar`...
|
||||||
--> $DIR/cycle-iat-inside-of-adt.rs:6:5
|
--> $DIR/cycle-iat-inside-of-adt.rs:8:5
|
||||||
|
|
|
|
||||||
LL | bar: Self::Bar,
|
LL | bar: Self::Bar,
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
note: ...which requires computing normalized predicates of `Foo`...
|
note: ...which requires computing normalized predicates of `Foo`...
|
||||||
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
|
||||||
|
|
|
|
||||||
LL | struct Foo {
|
LL | struct Foo {
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
= note: ...which again requires computing predicates of `Foo`, completing the cycle
|
= note: ...which again requires computing predicates of `Foo`, completing the cycle
|
||||||
note: cycle used when collecting item types in top-level module
|
note: cycle used when collecting item types in top-level module
|
||||||
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
--> $DIR/cycle-iat-inside-of-adt.rs:3:1
|
||||||
|
|
|
|
||||||
LL | / struct Foo {
|
LL | / #![feature(inherent_associated_types)]
|
||||||
LL | | bar: Self::Bar,
|
LL | | #![allow(incomplete_features)]
|
||||||
LL | | }
|
LL | | // FIXME(inherent_associated_types): This should pass.
|
||||||
LL | | impl Foo {
|
LL | |
|
||||||
LL | | pub type Bar = usize;
|
... |
|
||||||
LL | | }
|
LL | |
|
||||||
| |_^
|
LL | | fn main() {}
|
||||||
|
| |____________^
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to previous error
|
||||||
|
|
||||||
Some errors have detailed explanations: E0391, E0601.
|
For more information about this error, try `rustc --explain E0391`.
|
||||||
For more information about an error, try `rustc --explain E0391`.
|
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
// Regression test for #113265.
|
||||||
|
|
||||||
|
// Don't perform selection if the feature is not enabled to prevent cycle errors
|
||||||
|
// that exist due to current limitations of the implementation from masking the
|
||||||
|
// feature-gate error. See the aforementioned issue.
|
||||||
|
// This does lead to rustc not mentioning inherent associated types at usage-sites of
|
||||||
|
// IATs that were defined in an external crate but that's acceptable for now.
|
||||||
|
|
||||||
|
// FIXME(inherent_associated_types): Revisit this decision once the implementation is smarter.
|
||||||
|
|
||||||
|
// The following program would currently lead to a cycle if IATs were enabled.
|
||||||
|
|
||||||
|
struct S(S::P); //~ ERROR ambiguous associated type
|
||||||
|
|
||||||
|
impl S { type P = (); } //~ ERROR inherent associated types are unstable
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,24 @@
|
|||||||
|
error[E0223]: ambiguous associated type
|
||||||
|
--> $DIR/dont-select-if-disabled.rs:13:10
|
||||||
|
|
|
||||||
|
LL | struct S(S::P);
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
help: if there were a trait named `Example` with associated type `P` implemented for `S`, you could use the fully-qualified path
|
||||||
|
|
|
||||||
|
LL | struct S(<S as Example>::P);
|
||||||
|
| ~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
error[E0658]: inherent associated types are unstable
|
||||||
|
--> $DIR/dont-select-if-disabled.rs:15:10
|
||||||
|
|
|
||||||
|
LL | impl S { type P = (); }
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #8995 <https://github.com/rust-lang/rust/issues/8995> for more information
|
||||||
|
= help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0223, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0223`.
|
@ -29,7 +29,13 @@ LL | type Item = &[T];
|
|||||||
= note: see issue #8995 <https://github.com/rust-lang/rust/issues/8995> for more information
|
= note: see issue #8995 <https://github.com/rust-lang/rust/issues/8995> for more information
|
||||||
= help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable
|
= help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error[E0223]: ambiguous associated type
|
||||||
|
--> $DIR/issue-109071.rs:15:22
|
||||||
|
|
|
||||||
|
LL | fn T() -> Option<Self::Item> {}
|
||||||
|
| ^^^^^^^^^^ help: use the fully-qualified path: `<Windows<T> as IntoIterator>::Item`
|
||||||
|
|
||||||
Some errors have detailed explanations: E0107, E0637, E0658.
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0107, E0223, E0637, E0658.
|
||||||
For more information about an error, try `rustc --explain E0107`.
|
For more information about an error, try `rustc --explain E0107`.
|
||||||
|
@ -13,6 +13,7 @@ impl<T> Windows { //~ ERROR: missing generics for struct `Windows`
|
|||||||
|
|
||||||
impl<T> Windows<T> {
|
impl<T> Windows<T> {
|
||||||
fn T() -> Option<Self::Item> {}
|
fn T() -> Option<Self::Item> {}
|
||||||
|
//[no_gate]~^ ERROR: ambiguous associated type
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
error: `Self` is not valid in the self type of an impl block
|
||||||
|
--> $DIR/resolve-self-in-impl.rs:14:13
|
||||||
|
|
|
||||||
|
LL | impl Tr for Self {}
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
= note: replace `Self` with a different type
|
||||||
|
|
||||||
|
error: `Self` is not valid in the self type of an impl block
|
||||||
|
--> $DIR/resolve-self-in-impl.rs:15:15
|
||||||
|
|
|
||||||
|
LL | impl Tr for S<Self> {}
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
= note: replace `Self` with a different type
|
||||||
|
|
||||||
error: `Self` is not valid in the self type of an impl block
|
error: `Self` is not valid in the self type of an impl block
|
||||||
--> $DIR/resolve-self-in-impl.rs:16:6
|
--> $DIR/resolve-self-in-impl.rs:16:6
|
||||||
|
|
|
|
||||||
@ -22,22 +38,6 @@ LL | impl (Self, Self) {}
|
|||||||
|
|
|
|
||||||
= note: replace `Self` with a different type
|
= note: replace `Self` with a different type
|
||||||
|
|
||||||
error: `Self` is not valid in the self type of an impl block
|
|
||||||
--> $DIR/resolve-self-in-impl.rs:14:13
|
|
||||||
|
|
|
||||||
LL | impl Tr for Self {}
|
|
||||||
| ^^^^
|
|
||||||
|
|
|
||||||
= note: replace `Self` with a different type
|
|
||||||
|
|
||||||
error: `Self` is not valid in the self type of an impl block
|
|
||||||
--> $DIR/resolve-self-in-impl.rs:15:15
|
|
||||||
|
|
|
||||||
LL | impl Tr for S<Self> {}
|
|
||||||
| ^^^^
|
|
||||||
|
|
|
||||||
= note: replace `Self` with a different type
|
|
||||||
|
|
||||||
error[E0391]: cycle detected when computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:19:1: 19:23>`
|
error[E0391]: cycle detected when computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:19:1: 19:23>`
|
||||||
--> $DIR/resolve-self-in-impl.rs:19:1
|
--> $DIR/resolve-self-in-impl.rs:19:1
|
||||||
|
|
|
|
||||||
|
Loading…
Reference in New Issue
Block a user