Skip to content

Commit b4e9eeb

Browse files
Hack out effects support for old solver
1 parent 1d4a767 commit b4e9eeb

37 files changed

+297
-192
lines changed

compiler/rustc_hir_analysis/messages.ftl

-4
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,6 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
149149
hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
150150
.label = parameter captured again here
151151
152-
hir_analysis_effects_without_next_solver = using `#![feature(effects)]` without enabling next trait solver globally
153-
.note = the next trait solver must be enabled globally for the effects feature to work correctly
154-
.help = use `-Znext-solver` to enable
155-
156152
hir_analysis_empty_specialization = specialization impl does not specialize any associated items
157153
.note = impl is a specialization of this impl
158154

compiler/rustc_hir_analysis/src/errors.rs

-6
Original file line numberDiff line numberDiff line change
@@ -1623,12 +1623,6 @@ pub(crate) struct InvalidReceiverTy<'tcx> {
16231623
pub receiver_ty: Ty<'tcx>,
16241624
}
16251625

1626-
#[derive(Diagnostic)]
1627-
#[diag(hir_analysis_effects_without_next_solver)]
1628-
#[note]
1629-
#[help]
1630-
pub(crate) struct EffectsWithoutNextSolver;
1631-
16321626
#[derive(Diagnostic)]
16331627
#[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)]
16341628
#[note]

compiler/rustc_hir_analysis/src/lib.rs

-6
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,6 @@ pub fn provide(providers: &mut Providers) {
153153
pub fn check_crate(tcx: TyCtxt<'_>) {
154154
let _prof_timer = tcx.sess.timer("type_check_crate");
155155

156-
// FIXME(effects): remove once effects is implemented in old trait solver
157-
// or if the next solver is stabilized.
158-
if tcx.features().effects() && !tcx.next_trait_solver_globally() {
159-
tcx.dcx().emit_err(errors::EffectsWithoutNextSolver);
160-
}
161-
162156
tcx.sess.time("coherence_checking", || {
163157
tcx.hir().par_for_each_module(|module| {
164158
let _ = tcx.ensure().check_mod_type_wf(module);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
use rustc_hir as hir;
2+
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt};
3+
use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation};
4+
use rustc_middle::ty;
5+
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
6+
use rustc_type_ir::solve::NoSolution;
7+
use thin_vec::ThinVec;
8+
9+
use super::SelectionContext;
10+
11+
pub type HostEffectObligation<'tcx> = Obligation<'tcx, ty::HostEffectPredicate<'tcx>>;
12+
13+
pub enum EvaluationFailure {
14+
Ambiguous,
15+
NoSolution,
16+
}
17+
18+
pub fn evaluate_host_effect_obligation<'tcx>(
19+
selcx: &mut SelectionContext<'_, 'tcx>,
20+
obligation: &HostEffectObligation<'tcx>,
21+
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
22+
match evaluate_host_effect_from_bounds(selcx, obligation) {
23+
Ok(result) => return Ok(result),
24+
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
25+
Err(EvaluationFailure::NoSolution) => {}
26+
}
27+
28+
match evaluate_host_effect_from_selection_candiate(selcx, obligation) {
29+
Ok(result) => return Ok(result),
30+
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
31+
Err(EvaluationFailure::NoSolution) => {}
32+
}
33+
34+
Err(EvaluationFailure::NoSolution)
35+
}
36+
37+
fn match_candidate<'tcx>(
38+
infcx: &InferCtxt<'tcx>,
39+
obligation: &HostEffectObligation<'tcx>,
40+
candidate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
41+
) -> Result<ThinVec<PredicateObligation<'tcx>>, NoSolution> {
42+
if !candidate.skip_binder().host.satisfies(obligation.predicate.host) {
43+
return Err(NoSolution);
44+
}
45+
46+
let candidate = infcx.instantiate_binder_with_fresh_vars(
47+
obligation.cause.span,
48+
BoundRegionConversionTime::HigherRankedType,
49+
candidate,
50+
);
51+
52+
Ok(infcx
53+
.at(&obligation.cause, obligation.param_env)
54+
.eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)?
55+
.into_obligations())
56+
}
57+
58+
fn evaluate_host_effect_from_bounds<'tcx>(
59+
selcx: &mut SelectionContext<'_, 'tcx>,
60+
obligation: &HostEffectObligation<'tcx>,
61+
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
62+
let infcx = selcx.infcx;
63+
let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
64+
let mut candidate = None;
65+
66+
for predicate in obligation.param_env.caller_bounds() {
67+
let bound_predicate = predicate.kind();
68+
if let ty::ClauseKind::HostEffect(data) = predicate.kind().skip_binder() {
69+
let data = bound_predicate.rebind(data);
70+
if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
71+
continue;
72+
}
73+
74+
if !drcx.args_may_unify(
75+
obligation.predicate.trait_ref.args,
76+
data.skip_binder().trait_ref.args,
77+
) {
78+
continue;
79+
}
80+
81+
let is_match = infcx.probe(|_| match_candidate(infcx, obligation, data).is_ok());
82+
83+
if is_match {
84+
if candidate.is_some() {
85+
} else {
86+
candidate = Some(data);
87+
}
88+
}
89+
}
90+
}
91+
92+
if let Some(data) = candidate {
93+
Ok(match_candidate(infcx, obligation, data)
94+
.expect("candidate matched before, so it should match again"))
95+
} else {
96+
Err(EvaluationFailure::NoSolution)
97+
}
98+
}
99+
100+
fn evaluate_host_effect_from_selection_candiate<'tcx>(
101+
selcx: &mut SelectionContext<'_, 'tcx>,
102+
obligation: &HostEffectObligation<'tcx>,
103+
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
104+
let tcx = selcx.tcx();
105+
selcx.infcx.commit_if_ok(|_| {
106+
match selcx.select(&obligation.with(tcx, obligation.predicate.trait_ref)) {
107+
Ok(None) => Err(EvaluationFailure::Ambiguous),
108+
Err(_) => Err(EvaluationFailure::NoSolution),
109+
Ok(Some(source)) => match source {
110+
ImplSource::UserDefined(impl_) => {
111+
if tcx.constness(impl_.impl_def_id) != hir::Constness::Const {
112+
return Err(EvaluationFailure::NoSolution);
113+
}
114+
115+
let mut nested = impl_.nested;
116+
nested.extend(
117+
tcx.const_conditions(impl_.impl_def_id)
118+
.instantiate(tcx, impl_.args)
119+
.into_iter()
120+
.map(|(trait_ref, _)| {
121+
obligation.with(
122+
tcx,
123+
trait_ref.to_host_effect_clause(tcx, obligation.predicate.host),
124+
)
125+
}),
126+
);
127+
Ok(nested)
128+
}
129+
_ => Err(EvaluationFailure::NoSolution),
130+
},
131+
}
132+
})
133+
}

compiler/rustc_trait_selection/src/traits/fulfill.rs

+43-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt};
1717
use thin_vec::ThinVec;
1818
use tracing::{debug, debug_span, instrument};
1919

20+
use super::effects::{self, HostEffectObligation};
2021
use super::project::{self, ProjectAndUnifyResult};
2122
use super::select::SelectionContext;
2223
use super::{
@@ -402,8 +403,14 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
402403
)
403404
}
404405

405-
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {
406-
ProcessResult::Changed(Default::default())
406+
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => {
407+
let host_obligation = obligation.with(infcx.tcx, data);
408+
409+
self.process_host_obligation(
410+
obligation,
411+
host_obligation,
412+
&mut pending_obligation.stalled_on,
413+
)
407414
}
408415

409416
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => {
@@ -854,6 +861,40 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
854861
}
855862
}
856863
}
864+
865+
fn process_host_obligation(
866+
&mut self,
867+
obligation: &PredicateObligation<'tcx>,
868+
host_obligation: HostEffectObligation<'tcx>,
869+
stalled_on: &mut Vec<TyOrConstInferVar>,
870+
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
871+
if obligation.predicate.is_global() && !self.selcx.is_intercrate() {
872+
// no type variables present, can use evaluation for better caching.
873+
// FIXME: consider caching errors too.
874+
if self.selcx.infcx.predicate_must_hold_considering_regions(obligation) {
875+
debug!(
876+
"selecting trait at depth {} evaluated to holds",
877+
obligation.recursion_depth
878+
);
879+
return ProcessResult::Changed(Default::default());
880+
}
881+
}
882+
883+
match effects::evaluate_host_effect_obligation(&mut self.selcx, &host_obligation) {
884+
Ok(nested) => ProcessResult::Changed(mk_pending(nested)),
885+
Err(effects::EvaluationFailure::Ambiguous) => {
886+
stalled_on.clear();
887+
stalled_on.extend(args_infer_vars(
888+
&self.selcx,
889+
ty::Binder::dummy(host_obligation.predicate.trait_ref.args),
890+
));
891+
ProcessResult::Unchanged
892+
}
893+
Err(effects::EvaluationFailure::NoSolution) => {
894+
ProcessResult::Error(FulfillmentErrorCode::Select(SelectionError::Unimplemented))
895+
}
896+
}
897+
}
857898
}
858899

859900
/// Returns the set of inference variables contained in `args`.

compiler/rustc_trait_selection/src/traits/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub mod auto_trait;
66
pub(crate) mod coherence;
77
pub mod const_evaluatable;
88
mod dyn_compatibility;
9+
pub mod effects;
910
mod engine;
1011
mod fulfill;
1112
pub mod misc;

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

+14-6
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener};
4949
use crate::solve::InferCtxtSelectExt as _;
5050
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
5151
use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
52-
use crate::traits::{ProjectionCacheKey, Unimplemented};
52+
use crate::traits::{ProjectionCacheKey, Unimplemented, effects};
5353

5454
mod _match;
5555
mod candidate_assembly;
@@ -645,11 +645,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
645645
self.evaluate_trait_predicate_recursively(previous_stack, obligation)
646646
}
647647

648-
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {
649-
// FIXME(effects): It should be relatively straightforward to implement
650-
// old trait solver support for `HostEffect` bounds; or at least basic
651-
// support for them.
652-
todo!()
648+
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => {
649+
self.infcx.enter_forall(bound_predicate.rebind(data), |data| {
650+
match effects::evaluate_host_effect_obligation(
651+
self,
652+
&obligation.with(self.tcx(), data),
653+
) {
654+
Ok(nested) => {
655+
self.evaluate_predicates_recursively(previous_stack, nested)
656+
}
657+
Err(effects::EvaluationFailure::Ambiguous) => Ok(EvaluatedToAmbig),
658+
Err(effects::EvaluationFailure::NoSolution) => Ok(EvaluatedToErr),
659+
}
660+
})
653661
}
654662

655663
ty::PredicateKind::Subtype(p) => {
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
error: using `#![feature(effects)]` without enabling next trait solver globally
2-
|
3-
= note: the next trait solver must be enabled globally for the effects feature to work correctly
4-
= help: use `-Znext-solver` to enable
5-
6-
error[E0080]: evaluation of `foo::<()>::{constant#0}` failed
1+
error[E0277]: the trait bound `T: const Tr` is not satisfied
72
--> $DIR/constifconst-call-in-const-position.rs:17:38
83
|
94
LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] {
10-
| ^^^^^^ calling non-const function `<() as Tr>::a`
5+
| ^^^^^^
6+
7+
error[E0277]: the trait bound `T: const Tr` is not satisfied
8+
--> $DIR/constifconst-call-in-const-position.rs:18:9
9+
|
10+
LL | [0; T::a()]
11+
| ^^^^^^
1112

1213
error: aborting due to 2 previous errors
1314

14-
For more information about this error, try `rustc --explain E0080`.
15+
For more information about this error, try `rustc --explain E0277`.

tests/ui/delegation/unsupported.stderr

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
error: using `#![feature(effects)]` without enabling next trait solver globally
2-
|
3-
= note: the next trait solver must be enabled globally for the effects feature to work correctly
4-
= help: use `-Znext-solver` to enable
5-
61
error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:26:5: 26:24>::{synthetic#0}`
72
--> $DIR/unsupported.rs:27:25
83
|
@@ -89,7 +84,7 @@ LL | reuse Trait::foo;
8984
|
9085
= note: cannot satisfy `_: effects::Trait`
9186

92-
error: aborting due to 5 previous errors; 2 warnings emitted
87+
error: aborting due to 4 previous errors; 2 warnings emitted
9388

9489
Some errors have detailed explanations: E0283, E0391.
9590
For more information about an error, try `rustc --explain E0283`.

tests/ui/dropck/const_drop_is_valid.stderr

+1-6
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ LL | #![feature(effects)]
1717
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
1818
= note: `#[warn(incomplete_features)]` on by default
1919

20-
error: using `#![feature(effects)]` without enabling next trait solver globally
21-
|
22-
= note: the next trait solver must be enabled globally for the effects feature to work correctly
23-
= help: use `-Znext-solver` to enable
24-
2520
error: const `impl` for trait `Drop` which is not marked with `#[const_trait]`
2621
--> $DIR/const_drop_is_valid.rs:6:12
2722
|
@@ -39,7 +34,7 @@ LL | impl const Drop for A {}
3934
|
4035
= help: implement the missing item: `fn drop(&mut self) { todo!() }`
4136

42-
error: aborting due to 4 previous errors; 1 warning emitted
37+
error: aborting due to 3 previous errors; 1 warning emitted
4338

4439
Some errors have detailed explanations: E0046, E0658.
4540
For more information about an error, try `rustc --explain E0046`.

tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
error: using `#![feature(effects)]` without enabling next trait solver globally
2-
|
3-
= note: the next trait solver must be enabled globally for the effects feature to work correctly
4-
= help: use `-Znext-solver` to enable
5-
61
error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
72
--> $DIR/safe-intrinsic-mismatch.rs:11:5
83
|
@@ -47,6 +42,6 @@ LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
4742
= note: expected signature `unsafe fn(_, _, _)`
4843
found signature `fn(_, _, _)`
4944

50-
error: aborting due to 7 previous errors
45+
error: aborting due to 6 previous errors
5146

5247
For more information about this error, try `rustc --explain E0308`.

tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr

+1-6
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@ LL | #![feature(const_trait_impl, effects)]
77
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
88
= note: `#[warn(incomplete_features)]` on by default
99

10-
error: using `#![feature(effects)]` without enabling next trait solver globally
11-
|
12-
= note: the next trait solver must be enabled globally for the effects feature to work correctly
13-
= help: use `-Znext-solver` to enable
14-
1510
error: `~const` can only be applied to `#[const_trait]` traits
1611
--> $DIR/const-bounds-non-const-trait.rs:6:28
1712
|
@@ -32,5 +27,5 @@ error: `const` can only be applied to `#[const_trait]` traits
3227
LL | fn operate<T: const NonConst>() {}
3328
| ^^^^^^^^
3429

35-
error: aborting due to 4 previous errors; 1 warning emitted
30+
error: aborting due to 3 previous errors; 1 warning emitted
3631

0 commit comments

Comments
 (0)