Skip to content

Commit

Permalink
Hack out effects support for old solver
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Oct 28, 2024
1 parent 3f1be1e commit 8b7b8e5
Show file tree
Hide file tree
Showing 37 changed files with 302 additions and 192 deletions.
4 changes: 0 additions & 4 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,6 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
.label = parameter captured again here
hir_analysis_effects_without_next_solver = using `#![feature(effects)]` without enabling next trait solver globally
.note = the next trait solver must be enabled globally for the effects feature to work correctly
.help = use `-Znext-solver` to enable
hir_analysis_empty_specialization = specialization impl does not specialize any associated items
.note = impl is a specialization of this impl
Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1623,12 +1623,6 @@ pub(crate) struct InvalidReceiverTy<'tcx> {
pub receiver_ty: Ty<'tcx>,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_effects_without_next_solver)]
#[note]
#[help]
pub(crate) struct EffectsWithoutNextSolver;

#[derive(Diagnostic)]
#[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)]
#[note]
Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_hir_analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,6 @@ pub fn provide(providers: &mut Providers) {
pub fn check_crate(tcx: TyCtxt<'_>) {
let _prof_timer = tcx.sess.timer("type_check_crate");

// FIXME(effects): remove once effects is implemented in old trait solver
// or if the next solver is stabilized.
if tcx.features().effects() && !tcx.next_trait_solver_globally() {
tcx.dcx().emit_err(errors::EffectsWithoutNextSolver);
}

tcx.sess.time("coherence_checking", || {
tcx.hir().par_for_each_module(|module| {
let _ = tcx.ensure().check_mod_type_wf(module);
Expand Down
152 changes: 152 additions & 0 deletions compiler/rustc_trait_selection/src/traits/effects.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use rustc_hir as hir;
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt};
use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation};
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::{span_bug, ty};
use rustc_type_ir::solve::NoSolution;
use thin_vec::ThinVec;

use super::SelectionContext;

pub type HostEffectObligation<'tcx> = Obligation<'tcx, ty::HostEffectPredicate<'tcx>>;

pub enum EvaluationFailure {
Ambiguous,
NoSolution,
}

pub fn evaluate_host_effect_obligation<'tcx>(
selcx: &mut SelectionContext<'_, 'tcx>,
obligation: &HostEffectObligation<'tcx>,
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
if selcx.infcx.intercrate {
span_bug!(
obligation.cause.span,
"should not select host obligation in old solver in intercrate mode"
);
}

match evaluate_host_effect_from_bounds(selcx, obligation) {
Ok(result) => return Ok(result),
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
Err(EvaluationFailure::NoSolution) => {}
}

match evaluate_host_effect_from_selection_candiate(selcx, obligation) {
Ok(result) => return Ok(result),
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
Err(EvaluationFailure::NoSolution) => {}
}

Err(EvaluationFailure::NoSolution)
}

fn match_candidate<'tcx>(
infcx: &InferCtxt<'tcx>,
obligation: &HostEffectObligation<'tcx>,
candidate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
) -> Result<ThinVec<PredicateObligation<'tcx>>, NoSolution> {
if !candidate.skip_binder().host.satisfies(obligation.predicate.host) {
return Err(NoSolution);
}

let candidate = infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span,
BoundRegionConversionTime::HigherRankedType,
candidate,
);

let mut nested = infcx
.at(&obligation.cause, obligation.param_env)
.eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)?
.into_obligations();

for nested in &mut nested {
nested.set_depth_from_parent(obligation.recursion_depth);
}

Ok(nested)
}

fn evaluate_host_effect_from_bounds<'tcx>(
selcx: &mut SelectionContext<'_, 'tcx>,
obligation: &HostEffectObligation<'tcx>,
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
let infcx = selcx.infcx;
let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
let mut candidate = None;

for predicate in obligation.param_env.caller_bounds() {
let bound_predicate = predicate.kind();
if let ty::ClauseKind::HostEffect(data) = predicate.kind().skip_binder() {
let data = bound_predicate.rebind(data);
if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
continue;
}

if !drcx.args_may_unify(
obligation.predicate.trait_ref.args,
data.skip_binder().trait_ref.args,
) {
continue;
}

let is_match = infcx.probe(|_| match_candidate(infcx, obligation, data).is_ok());

if is_match {
if candidate.is_some() {
return Err(EvaluationFailure::Ambiguous);
} else {
candidate = Some(data);
}
}
}
}

if let Some(data) = candidate {
Ok(match_candidate(infcx, obligation, data)
.expect("candidate matched before, so it should match again"))
} else {
Err(EvaluationFailure::NoSolution)
}
}

fn evaluate_host_effect_from_selection_candiate<'tcx>(
selcx: &mut SelectionContext<'_, 'tcx>,
obligation: &HostEffectObligation<'tcx>,
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
let tcx = selcx.tcx();
selcx.infcx.commit_if_ok(|_| {
match selcx.select(&obligation.with(tcx, obligation.predicate.trait_ref)) {
Ok(None) => Err(EvaluationFailure::Ambiguous),
Err(_) => Err(EvaluationFailure::NoSolution),
Ok(Some(source)) => match source {
ImplSource::UserDefined(impl_) => {
if tcx.constness(impl_.impl_def_id) != hir::Constness::Const {
return Err(EvaluationFailure::NoSolution);
}

let mut nested = impl_.nested;
nested.extend(
tcx.const_conditions(impl_.impl_def_id)
.instantiate(tcx, impl_.args)
.into_iter()
.map(|(trait_ref, _)| {
obligation.with(
tcx,
trait_ref.to_host_effect_clause(tcx, obligation.predicate.host),
)
}),
);

for nested in &mut nested {
nested.set_depth_from_parent(obligation.recursion_depth);
}

Ok(nested)
}
_ => Err(EvaluationFailure::NoSolution),
},
}
})
}
31 changes: 29 additions & 2 deletions compiler/rustc_trait_selection/src/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt};
use thin_vec::ThinVec;
use tracing::{debug, debug_span, instrument};

use super::effects::{self, HostEffectObligation};
use super::project::{self, ProjectAndUnifyResult};
use super::select::SelectionContext;
use super::{
Expand Down Expand Up @@ -402,8 +403,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
)
}

ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {
ProcessResult::Changed(Default::default())
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => {
let host_obligation = obligation.with(infcx.tcx, data);

self.process_host_obligation(
host_obligation,
&mut pending_obligation.stalled_on,
)
}

ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => {
Expand Down Expand Up @@ -854,6 +860,27 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
}
}
}

fn process_host_obligation(
&mut self,
host_obligation: HostEffectObligation<'tcx>,
stalled_on: &mut Vec<TyOrConstInferVar>,
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
match effects::evaluate_host_effect_obligation(&mut self.selcx, &host_obligation) {
Ok(nested) => ProcessResult::Changed(mk_pending(nested)),
Err(effects::EvaluationFailure::Ambiguous) => {
stalled_on.clear();
stalled_on.extend(args_infer_vars(
&self.selcx,
ty::Binder::dummy(host_obligation.predicate.trait_ref.args),
));
ProcessResult::Unchanged
}
Err(effects::EvaluationFailure::NoSolution) => {
ProcessResult::Error(FulfillmentErrorCode::Select(SelectionError::Unimplemented))
}
}
}
}

/// Returns the set of inference variables contained in `args`.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_trait_selection/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod auto_trait;
pub(crate) mod coherence;
pub mod const_evaluatable;
mod dyn_compatibility;
pub mod effects;
mod engine;
mod fulfill;
pub mod misc;
Expand Down
20 changes: 14 additions & 6 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener};
use crate::solve::InferCtxtSelectExt as _;
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
use crate::traits::{ProjectionCacheKey, Unimplemented};
use crate::traits::{ProjectionCacheKey, Unimplemented, effects};

mod _match;
mod candidate_assembly;
Expand Down Expand Up @@ -645,11 +645,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.evaluate_trait_predicate_recursively(previous_stack, obligation)
}

ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {
// FIXME(effects): It should be relatively straightforward to implement
// old trait solver support for `HostEffect` bounds; or at least basic
// support for them.
todo!()
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => {
self.infcx.enter_forall(bound_predicate.rebind(data), |data| {
match effects::evaluate_host_effect_obligation(
self,
&obligation.with(self.tcx(), data),
) {
Ok(nested) => {
self.evaluate_predicates_recursively(previous_stack, nested)
}
Err(effects::EvaluationFailure::Ambiguous) => Ok(EvaluatedToAmbig),
Err(effects::EvaluationFailure::NoSolution) => Ok(EvaluatedToErr),
}
})
}

ty::PredicateKind::Subtype(p) => {
Expand Down
17 changes: 9 additions & 8 deletions tests/ui/consts/constifconst-call-in-const-position.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
error: using `#![feature(effects)]` without enabling next trait solver globally
|
= note: the next trait solver must be enabled globally for the effects feature to work correctly
= help: use `-Znext-solver` to enable

error[E0080]: evaluation of `foo::<()>::{constant#0}` failed
error[E0277]: the trait bound `T: const Tr` is not satisfied
--> $DIR/constifconst-call-in-const-position.rs:17:38
|
LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] {
| ^^^^^^ calling non-const function `<() as Tr>::a`
| ^^^^^^

error[E0277]: the trait bound `T: const Tr` is not satisfied
--> $DIR/constifconst-call-in-const-position.rs:18:9
|
LL | [0; T::a()]
| ^^^^^^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0080`.
For more information about this error, try `rustc --explain E0277`.
7 changes: 1 addition & 6 deletions tests/ui/delegation/unsupported.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
error: using `#![feature(effects)]` without enabling next trait solver globally
|
= note: the next trait solver must be enabled globally for the effects feature to work correctly
= help: use `-Znext-solver` to enable

error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:26:5: 26:24>::{synthetic#0}`
--> $DIR/unsupported.rs:27:25
|
Expand Down Expand Up @@ -89,7 +84,7 @@ LL | reuse Trait::foo;
|
= note: cannot satisfy `_: effects::Trait`

error: aborting due to 5 previous errors; 2 warnings emitted
error: aborting due to 4 previous errors; 2 warnings emitted

Some errors have detailed explanations: E0283, E0391.
For more information about an error, try `rustc --explain E0283`.
7 changes: 1 addition & 6 deletions tests/ui/dropck/const_drop_is_valid.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,6 @@ LL | #![feature(effects)]
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default

error: using `#![feature(effects)]` without enabling next trait solver globally
|
= note: the next trait solver must be enabled globally for the effects feature to work correctly
= help: use `-Znext-solver` to enable

error: const `impl` for trait `Drop` which is not marked with `#[const_trait]`
--> $DIR/const_drop_is_valid.rs:6:12
|
Expand All @@ -39,7 +34,7 @@ LL | impl const Drop for A {}
|
= help: implement the missing item: `fn drop(&mut self) { todo!() }`

error: aborting due to 4 previous errors; 1 warning emitted
error: aborting due to 3 previous errors; 1 warning emitted

Some errors have detailed explanations: E0046, E0658.
For more information about an error, try `rustc --explain E0046`.
7 changes: 1 addition & 6 deletions tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
error: using `#![feature(effects)]` without enabling next trait solver globally
|
= note: the next trait solver must be enabled globally for the effects feature to work correctly
= help: use `-Znext-solver` to enable

error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
--> $DIR/safe-intrinsic-mismatch.rs:11:5
|
Expand Down Expand Up @@ -47,6 +42,6 @@ LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
= note: expected signature `unsafe fn(_, _, _)`
found signature `fn(_, _, _)`

error: aborting due to 7 previous errors
error: aborting due to 6 previous errors

For more information about this error, try `rustc --explain E0308`.
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ LL | #![feature(const_trait_impl, effects)]
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default

error: using `#![feature(effects)]` without enabling next trait solver globally
|
= note: the next trait solver must be enabled globally for the effects feature to work correctly
= help: use `-Znext-solver` to enable

error: `~const` can only be applied to `#[const_trait]` traits
--> $DIR/const-bounds-non-const-trait.rs:6:21
|
Expand All @@ -32,5 +27,5 @@ error: `const` can only be applied to `#[const_trait]` traits
LL | fn operate<T: const NonConst>() {}
| ^^^^^

error: aborting due to 4 previous errors; 1 warning emitted
error: aborting due to 3 previous errors; 1 warning emitted

Loading

0 comments on commit 8b7b8e5

Please sign in to comment.