Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hack out effects support for old solver #132119

Merged
merged 1 commit into from
Oct 29, 2024
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
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(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Increment the depth correctly

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did this more manually. It's kinda ugly but 🤷

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(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pretty sure that can cause undetected overflow 🤔 too tired to explain my thoughts here via comment for today, can do so in sync or maybe you're able to come up with a test yourself

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, though it's the same way that we can encounter overflow in projection afaict.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a consequence of not tracking effect goals (or projections) on the trait stack.

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
Loading