Add the core logic in old and new solvers

This commit is contained in:
tiif
2025-07-14 13:35:06 +00:00
parent 2586185831
commit 1e5c7b2877
7 changed files with 96 additions and 2 deletions

View File

@@ -833,6 +833,13 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu
fn associated_const_equality(self) -> bool { fn associated_const_equality(self) -> bool {
self.associated_const_equality() self.associated_const_equality()
} }
fn feature_bound_holds_in_crate(self, symbol: Symbol) -> bool {
// We don't consider feature bounds to hold in the crate when `staged_api` feature is
// enabled, even if it is enabled through `#[feature]`.
// This is to prevent accidentally leaking unstable APIs to stable.
!self.staged_api() && self.enabled(symbol)
}
} }
impl<'tcx> rustc_type_ir::inherent::Span<TyCtxt<'tcx>> for Span { impl<'tcx> rustc_type_ir::inherent::Span<TyCtxt<'tcx>> for Span {

View File

@@ -22,6 +22,7 @@ use crate::delegate::SolverDelegate;
use crate::placeholder::BoundVarReplacer; use crate::placeholder::BoundVarReplacer;
use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::inspect::{self, ProofTreeBuilder};
use crate::solve::search_graph::SearchGraph; use crate::solve::search_graph::SearchGraph;
use crate::solve::ty::may_use_unstable_feature;
use crate::solve::{ use crate::solve::{
CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalEvaluationKind, CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalEvaluationKind,
GoalSource, GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput, GoalSource, GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput,
@@ -550,6 +551,9 @@ where
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) }) self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })
} }
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
self.compute_unstable_feature_goal(param_env, symbol)
}
ty::PredicateKind::Subtype(predicate) => { ty::PredicateKind::Subtype(predicate) => {
self.compute_subtype_goal(Goal { param_env, predicate }) self.compute_subtype_goal(Goal { param_env, predicate })
} }
@@ -1177,6 +1181,14 @@ where
) -> T { ) -> T {
BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, t).0 BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, t).0
} }
pub(super) fn may_use_unstable_feature(
&self,
param_env: I::ParamEnv,
symbol: I::Symbol,
) -> bool {
may_use_unstable_feature(&**self.delegate, param_env, symbol)
}
} }
/// Eagerly replace aliases with inference variables, emitting `AliasRelate` /// Eagerly replace aliases with inference variables, emitting `AliasRelate`

View File

@@ -148,6 +148,20 @@ where
} }
} }
fn compute_unstable_feature_goal(
&mut self,
param_env: <I as Interner>::ParamEnv,
symbol: <I as Interner>::Symbol,
) -> QueryResult<I> {
if self.may_use_unstable_feature(param_env, symbol) {
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else {
self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe(
MaybeCause::Ambiguity,
))
}
}
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
fn compute_const_evaluatable_goal( fn compute_const_evaluatable_goal(
&mut self, &mut self,

View File

@@ -11,7 +11,9 @@ use rustc_infer::traits::{
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode}; use rustc_middle::ty::{
self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode, may_use_unstable_feature,
};
use thin_vec::{ThinVec, thin_vec}; use thin_vec::{ThinVec, thin_vec};
use tracing::{debug, debug_span, instrument}; use tracing::{debug, debug_span, instrument};
@@ -767,6 +769,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
} }
} }
} }
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
if may_use_unstable_feature(self.selcx.infcx, obligation.param_env, symbol) {
ProcessResult::Changed(Default::default())
} else {
ProcessResult::Unchanged
}
}
}, },
} }
} }

View File

@@ -28,7 +28,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt;
use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
use rustc_middle::ty::{ use rustc_middle::ty::{
self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, SizedTraitKind, Ty, TyCtxt, self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, SizedTraitKind, Ty, TyCtxt,
TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, may_use_unstable_feature,
}; };
use rustc_span::{Symbol, sym}; use rustc_span::{Symbol, sym};
use tracing::{debug, instrument, trace}; use tracing::{debug, instrument, trace};
@@ -832,6 +832,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
} }
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
if may_use_unstable_feature(self.infcx, obligation.param_env, symbol) {
Ok(EvaluatedToOk)
} else {
Ok(EvaluatedToAmbig)
}
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
match const_evaluatable::is_const_evaluatable( match const_evaluatable::is_const_evaluatable(
self.infcx, self.infcx,

View File

@@ -285,3 +285,45 @@ pub trait InferCtxtLike: Sized {
fn reset_opaque_types(&self); fn reset_opaque_types(&self);
} }
pub fn may_use_unstable_feature<'a, I: Interner, Infcx>(
infcx: &'a Infcx,
param_env: I::ParamEnv,
symbol: I::Symbol,
) -> bool
where
Infcx: InferCtxtLike<Interner = I>,
{
// Iterate through all goals in param_env to find the one that has the same symbol.
for pred in param_env.caller_bounds().iter() {
if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() {
if sym == symbol {
return true;
}
}
}
// During codegen we must assume that all feature bounds hold as we may be
// monomorphizing a body from an upstream crate which had an unstable feature
// enabled that we do not.
//
// Coherence should already report overlap errors involving unstable impls
// as the affected code would otherwise break when stabilizing this feature.
// It is also easily possible to accidentally cause unsoundness this way as
// we have to always enable unstable impls during codegen.
//
// Return ambiguity can also prevent people from writing code which depends on inference guidance
// that might no longer work after the impl is stabilised,
// tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs is one of the example.
//
// Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled
// if we are in std/core even if there is a corresponding `feature` attribute on the crate.
if (infcx.typing_mode() == TypingMode::PostAnalysis)
|| infcx.cx().features().feature_bound_holds_in_crate(symbol)
{
return true;
} else {
return false;
}
}

View File

@@ -630,6 +630,8 @@ pub trait Features<I: Interner>: Copy {
fn coroutine_clone(self) -> bool; fn coroutine_clone(self) -> bool;
fn associated_const_equality(self) -> bool; fn associated_const_equality(self) -> bool;
fn feature_bound_holds_in_crate(self, symbol: I::Symbol) -> bool;
} }
pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> { pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {