Skip to content
Merged
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
10 changes: 8 additions & 2 deletions compiler/rustc_middle/src/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId;
use rustc_macros::{HashStable, TypeVisitable};
use rustc_query_system::cache::Cache;
use rustc_type_ir::solve::AliasBoundKind;

use self::EvaluationResult::*;
use super::{SelectionError, SelectionResult};
Expand Down Expand Up @@ -116,8 +117,13 @@ pub enum SelectionCandidate<'tcx> {

/// This is a trait matching with a projected type as `Self`, and we found
/// an applicable bound in the trait definition. The `usize` is an index
/// into the list returned by `tcx.item_bounds`.
ProjectionCandidate(usize),
/// into the list returned by `tcx.item_bounds` and the `AliasBoundKind`
/// is whether this is candidate from recursion on the self type of a
/// projection.
ProjectionCandidate {
idx: usize,
kind: AliasBoundKind,
},

/// Implementation of a `Fn`-family trait by one of the anonymous types
/// generated for an `||` expression.
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.is_default_trait(def_id)
}

fn is_sizedness_trait(self, def_id: DefId) -> bool {
self.is_sizedness_trait(def_id)
}

fn as_lang_item(self, def_id: DefId) -> Option<SolverLangItem> {
lang_item_to_solver_lang_item(self.lang_items().from_def_id(def_id)?)
}
Expand Down Expand Up @@ -1787,6 +1791,10 @@ impl<'tcx> TyCtxt<'tcx> {
.any(|&default_trait| self.lang_items().get(default_trait) == Some(def_id))
}

pub fn is_sizedness_trait(self, def_id: DefId) -> bool {
matches!(self.as_lang_item(def_id), Some(LangItem::Sized | LangItem::MetaSized))
}

/// Returns a range of the start/end indices specified with the
/// `rustc_layout_scalar_valid_range` attribute.
// FIXME(eddyb) this is an awkward spot for this method, maybe move it?
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub use rustc_type_ir::fast_reject::DeepRejectCtxt;
)]
use rustc_type_ir::inherent;
pub use rustc_type_ir::relate::VarianceDiagInfo;
pub use rustc_type_ir::solve::SizedTraitKind;
pub use rustc_type_ir::solve::{CandidatePreferenceMode, SizedTraitKind};
pub use rustc_type_ir::*;
#[allow(hidden_glob_reexports, unused_imports)]
use rustc_type_ir::{InferCtxtLike, Interner};
Expand Down
17 changes: 6 additions & 11 deletions compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use derive_where::derive_where;
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::SolverTraitLangItem;
use rustc_type_ir::search_graph::CandidateHeadUsages;
use rustc_type_ir::solve::SizedTraitKind;
use rustc_type_ir::solve::{AliasBoundKind, SizedTraitKind};
use rustc_type_ir::{
self as ty, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
Expand All @@ -27,11 +27,6 @@ use crate::solve::{
has_no_inference_or_external_constraints,
};

enum AliasBoundKind {
SelfBounds,
NonSelfBounds,
}

/// A candidate is a possible way to prove a goal.
///
/// It consists of both the `source`, which describes how that goal would be proven,
Expand Down Expand Up @@ -451,7 +446,7 @@ where
matches!(
c.source,
CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)
| CandidateSource::AliasBound
| CandidateSource::AliasBound(_)
) && has_no_inference_or_external_constraints(c.result)
})
{
Expand Down Expand Up @@ -711,7 +706,7 @@ where
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
{
candidates.push(Candidate {
source: CandidateSource::AliasBound,
source: CandidateSource::AliasBound(consider_self_bounds),
result,
head_usages: CandidateHeadUsages::default(),
});
Expand All @@ -735,7 +730,7 @@ where
{
candidates.extend(G::probe_and_consider_implied_clause(
self,
CandidateSource::AliasBound,
CandidateSource::AliasBound(consider_self_bounds),
goal,
assumption,
[],
Expand All @@ -750,7 +745,7 @@ where
{
candidates.extend(G::probe_and_consider_implied_clause(
self,
CandidateSource::AliasBound,
CandidateSource::AliasBound(consider_self_bounds),
goal,
assumption,
[],
Expand Down Expand Up @@ -1030,7 +1025,7 @@ where
item_bound.fold_with(&mut ReplaceOpaque { cx: self.cx(), alias_ty, self_ty });
candidates.extend(G::probe_and_match_goal_against_assumption(
self,
CandidateSource::AliasBound,
CandidateSource::AliasBound(AliasBoundKind::SelfBounds),
goal,
assumption,
|ecx| {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
use rustc_type_ir::fast_reject::DeepRejectCtxt;
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::SolverTraitLangItem;
use rustc_type_ir::solve::SizedTraitKind;
use rustc_type_ir::solve::inspect::ProbeKind;
use rustc_type_ir::solve::{AliasBoundKind, SizedTraitKind};
use rustc_type_ir::{self as ty, Interner, TypingMode, elaborate};
use tracing::instrument;

Expand Down Expand Up @@ -96,7 +96,7 @@ where
) {
candidates.extend(Self::probe_and_match_goal_against_assumption(
ecx,
CandidateSource::AliasBound,
CandidateSource::AliasBound(AliasBoundKind::SelfBounds),
goal,
clause,
|ecx| {
Expand Down
31 changes: 27 additions & 4 deletions compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use rustc_type_ir::data_structures::IndexSet;
use rustc_type_ir::fast_reject::DeepRejectCtxt;
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::SolverTraitLangItem;
use rustc_type_ir::solve::{CanonicalResponse, SizedTraitKind};
use rustc_type_ir::solve::{
AliasBoundKind, CandidatePreferenceMode, CanonicalResponse, SizedTraitKind,
};
use rustc_type_ir::{
self as ty, Interner, Movability, PredicatePolarity, TraitPredicate, TraitRef,
TypeVisitableExt as _, TypingMode, Upcast as _, elaborate,
Expand Down Expand Up @@ -1355,6 +1357,7 @@ where
#[instrument(level = "debug", skip(self), ret)]
pub(super) fn merge_trait_candidates(
&mut self,
candidate_preference_mode: CandidatePreferenceMode,
mut candidates: Vec<Candidate<I>>,
failed_candidate_info: FailedCandidateInfo,
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
Expand All @@ -1380,6 +1383,23 @@ where
return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
}

// Extract non-nested alias bound candidates, will be preferred over where bounds if
// we're proving an auto-trait, sizedness trait or default trait.
if matches!(candidate_preference_mode, CandidatePreferenceMode::Marker)
&& candidates.iter().any(|c| {
matches!(c.source, CandidateSource::AliasBound(AliasBoundKind::SelfBounds))
})
{
let alias_bounds: Vec<_> = candidates
.extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound(..)))
.collect();
return if let Some((response, _)) = self.try_merge_candidates(&alias_bounds) {
Ok((response, Some(TraitGoalProvenVia::AliasBound)))
} else {
Ok((self.bail_with_ambiguity(&alias_bounds), None))
};
}

// If there are non-global where-bounds, prefer where-bounds
// (including global ones) over everything else.
let has_non_global_where_bounds = candidates
Expand Down Expand Up @@ -1427,9 +1447,10 @@ where
};
}

if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) {
// Next, prefer any alias bound (nested or otherwise).
if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound(_))) {
let alias_bounds: Vec<_> = candidates
.extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound))
.extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound(_)))
.collect();
return if let Some((response, _)) = self.try_merge_candidates(&alias_bounds) {
Ok((response, Some(TraitGoalProvenVia::AliasBound)))
Expand Down Expand Up @@ -1470,7 +1491,9 @@ where
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
let (candidates, failed_candidate_info) =
self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
self.merge_trait_candidates(candidates, failed_candidate_info)
let candidate_preference_mode =
CandidatePreferenceMode::compute(self.cx(), goal.predicate.def_id());
self.merge_trait_candidates(candidate_preference_mode, candidates, failed_candidate_info)
}

fn try_stall_coroutine(&mut self, self_ty: I::Ty) -> Option<Result<Candidate<I>, NoSolution>> {
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_trait_selection/src/solve/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>(
// Prefer dyn candidates over non-dyn candidates. This is necessary to
// handle the unsoundness between `impl<T: ?Sized> Any for T` and `dyn Any: Any`.
(
CandidateSource::Impl(_) | CandidateSource::ParamEnv(_) | CandidateSource::AliasBound,
CandidateSource::Impl(_)
| CandidateSource::ParamEnv(_)
| CandidateSource::AliasBound(_),
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
) => true,

Expand Down Expand Up @@ -175,7 +177,9 @@ fn to_selection<'tcx>(
})
}
CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, nested),
CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => ImplSource::Param(nested),
CandidateSource::ParamEnv(_) | CandidateSource::AliasBound(_) => {
ImplSource::Param(nested)
}
CandidateSource::CoherenceUnknowable => {
span_bug!(span, "didn't expect to select an unknowable candidate")
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
let mut ambiguous = false;
let _ = selcx.for_each_item_bound(
obligation.predicate.self_ty(),
|selcx, clause, _| {
|selcx, clause, _, _| {
let Some(clause) = clause.as_projection_clause() else {
return ControlFlow::Continue(());
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut distinct_normalized_bounds = FxHashSet::default();
let _ = self.for_each_item_bound::<!>(
placeholder_trait_predicate.self_ty(),
|selcx, bound, idx| {
|selcx, bound, idx, alias_bound_kind| {
let Some(bound) = bound.as_trait_clause() else {
return ControlFlow::Continue(());
};
Expand All @@ -230,12 +230,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
bound.map_bound(|pred| pred.trait_ref),
) {
Ok(None) => {
candidates.vec.push(ProjectionCandidate(idx));
candidates
.vec
.push(ProjectionCandidate { idx, kind: alias_bound_kind });
}
Ok(Some(normalized_trait))
if distinct_normalized_bounds.insert(normalized_trait) =>
{
candidates.vec.push(ProjectionCandidate(idx));
candidates
.vec
.push(ProjectionCandidate { idx, kind: alias_bound_kind });
}
_ => {}
}
Expand Down Expand Up @@ -825,7 +829,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}

ty::Alias(ty::Opaque, alias) => {
if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(_))) {
if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate { .. })) {
// We do not generate an auto impl candidate for `impl Trait`s which already
// reference our auto trait.
//
Expand Down
28 changes: 2 additions & 26 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, data)
}

ProjectionCandidate(idx) => {
ProjectionCandidate { idx, .. } => {
let obligations = self.confirm_projection_candidate(obligation, idx)?;
ImplSource::Param(obligations)
}
Expand Down Expand Up @@ -144,15 +144,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &PolyTraitObligation<'tcx>,
idx: usize,
) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let tcx = self.tcx();

let placeholder_trait_predicate =
self.infcx.enter_forall_and_leak_universe(obligation.predicate).trait_ref;
let placeholder_self_ty = self.infcx.shallow_resolve(placeholder_trait_predicate.self_ty());
let candidate_predicate = self
.for_each_item_bound(
placeholder_self_ty,
|_, clause, clause_idx| {
|_, clause, clause_idx, _| {
if clause_idx == idx {
ControlFlow::Break(clause)
} else {
Expand Down Expand Up @@ -194,28 +192,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map_err(|_| SelectionError::Unimplemented)?,
);

// FIXME(compiler-errors): I don't think this is needed.
if let ty::Alias(ty::Projection, alias_ty) = placeholder_self_ty.kind() {
let predicates = tcx.predicates_of(alias_ty.def_id).instantiate_own(tcx, alias_ty.args);
for (predicate, _) in predicates {
let normalized = normalize_with_depth_to(
self,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
predicate,
&mut obligations,
);
obligations.push(Obligation::with_depth(
self.tcx(),
obligation.cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
normalized,
));
}
}

Ok(obligations)
}

Expand Down
Loading
Loading