Skip to content

Commit 1e5c7b2

Browse files
committed
Add the core logic in old and new solvers
1 parent 2586185 commit 1e5c7b2

File tree

7 files changed

+96
-2
lines changed

7 files changed

+96
-2
lines changed

compiler/rustc_middle/src/ty/context.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,13 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu
833833
fn associated_const_equality(self) -> bool {
834834
self.associated_const_equality()
835835
}
836+
837+
fn feature_bound_holds_in_crate(self, symbol: Symbol) -> bool {
838+
// We don't consider feature bounds to hold in the crate when `staged_api` feature is
839+
// enabled, even if it is enabled through `#[feature]`.
840+
// This is to prevent accidentally leaking unstable APIs to stable.
841+
!self.staged_api() && self.enabled(symbol)
842+
}
836843
}
837844

838845
impl<'tcx> rustc_type_ir::inherent::Span<TyCtxt<'tcx>> for Span {

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use crate::delegate::SolverDelegate;
2222
use crate::placeholder::BoundVarReplacer;
2323
use crate::solve::inspect::{self, ProofTreeBuilder};
2424
use crate::solve::search_graph::SearchGraph;
25+
use crate::solve::ty::may_use_unstable_feature;
2526
use crate::solve::{
2627
CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalEvaluationKind,
2728
GoalSource, GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput,
@@ -550,6 +551,9 @@ where
550551
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
551552
self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })
552553
}
554+
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
555+
self.compute_unstable_feature_goal(param_env, symbol)
556+
}
553557
ty::PredicateKind::Subtype(predicate) => {
554558
self.compute_subtype_goal(Goal { param_env, predicate })
555559
}
@@ -1177,6 +1181,14 @@ where
11771181
) -> T {
11781182
BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, t).0
11791183
}
1184+
1185+
pub(super) fn may_use_unstable_feature(
1186+
&self,
1187+
param_env: I::ParamEnv,
1188+
symbol: I::Symbol,
1189+
) -> bool {
1190+
may_use_unstable_feature(&**self.delegate, param_env, symbol)
1191+
}
11801192
}
11811193

11821194
/// Eagerly replace aliases with inference variables, emitting `AliasRelate`

compiler/rustc_next_trait_solver/src/solve/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,20 @@ where
148148
}
149149
}
150150

151+
fn compute_unstable_feature_goal(
152+
&mut self,
153+
param_env: <I as Interner>::ParamEnv,
154+
symbol: <I as Interner>::Symbol,
155+
) -> QueryResult<I> {
156+
if self.may_use_unstable_feature(param_env, symbol) {
157+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
158+
} else {
159+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe(
160+
MaybeCause::Ambiguity,
161+
))
162+
}
163+
}
164+
151165
#[instrument(level = "trace", skip(self))]
152166
fn compute_const_evaluatable_goal(
153167
&mut self,

compiler/rustc_trait_selection/src/traits/fulfill.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ use rustc_infer::traits::{
1111
use rustc_middle::bug;
1212
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
1313
use rustc_middle::ty::error::{ExpectedFound, TypeError};
14-
use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode};
14+
use rustc_middle::ty::{
15+
self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode, may_use_unstable_feature,
16+
};
1517
use thin_vec::{ThinVec, thin_vec};
1618
use tracing::{debug, debug_span, instrument};
1719

@@ -767,6 +769,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
767769
}
768770
}
769771
}
772+
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
773+
if may_use_unstable_feature(self.selcx.infcx, obligation.param_env, symbol) {
774+
ProcessResult::Changed(Default::default())
775+
} else {
776+
ProcessResult::Unchanged
777+
}
778+
}
770779
},
771780
}
772781
}

compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt;
2828
use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
2929
use rustc_middle::ty::{
3030
self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, SizedTraitKind, Ty, TyCtxt,
31-
TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate,
31+
TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, may_use_unstable_feature,
3232
};
3333
use rustc_span::{Symbol, sym};
3434
use tracing::{debug, instrument, trace};
@@ -832,6 +832,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
832832
}
833833
}
834834

835+
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
836+
if may_use_unstable_feature(self.infcx, obligation.param_env, symbol) {
837+
Ok(EvaluatedToOk)
838+
} else {
839+
Ok(EvaluatedToAmbig)
840+
}
841+
}
842+
835843
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
836844
match const_evaluatable::is_const_evaluatable(
837845
self.infcx,

compiler/rustc_type_ir/src/infer_ctxt.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,45 @@ pub trait InferCtxtLike: Sized {
285285

286286
fn reset_opaque_types(&self);
287287
}
288+
289+
pub fn may_use_unstable_feature<'a, I: Interner, Infcx>(
290+
infcx: &'a Infcx,
291+
param_env: I::ParamEnv,
292+
symbol: I::Symbol,
293+
) -> bool
294+
where
295+
Infcx: InferCtxtLike<Interner = I>,
296+
{
297+
// Iterate through all goals in param_env to find the one that has the same symbol.
298+
for pred in param_env.caller_bounds().iter() {
299+
if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() {
300+
if sym == symbol {
301+
return true;
302+
}
303+
}
304+
}
305+
306+
// During codegen we must assume that all feature bounds hold as we may be
307+
// monomorphizing a body from an upstream crate which had an unstable feature
308+
// enabled that we do not.
309+
//
310+
// Coherence should already report overlap errors involving unstable impls
311+
// as the affected code would otherwise break when stabilizing this feature.
312+
// It is also easily possible to accidentally cause unsoundness this way as
313+
// we have to always enable unstable impls during codegen.
314+
//
315+
// Return ambiguity can also prevent people from writing code which depends on inference guidance
316+
// that might no longer work after the impl is stabilised,
317+
// tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs is one of the example.
318+
//
319+
// Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled
320+
// if we are in std/core even if there is a corresponding `feature` attribute on the crate.
321+
322+
if (infcx.typing_mode() == TypingMode::PostAnalysis)
323+
|| infcx.cx().features().feature_bound_holds_in_crate(symbol)
324+
{
325+
return true;
326+
} else {
327+
return false;
328+
}
329+
}

compiler/rustc_type_ir/src/inherent.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,8 @@ pub trait Features<I: Interner>: Copy {
630630
fn coroutine_clone(self) -> bool;
631631

632632
fn associated_const_equality(self) -> bool;
633+
634+
fn feature_bound_holds_in_crate(self, symbol: I::Symbol) -> bool;
633635
}
634636

635637
pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {

0 commit comments

Comments
 (0)