Skip to content

Commit aa32766

Browse files
authored
Unrolled build for rust-lang#132119
Rollup merge of rust-lang#132119 - compiler-errors:effects-old-solver, r=lcnr Hack out effects support for old solver Opening this for vibes ✨ Turns out that a basic, somewhat incomplete implementation of host effects is achievable in the old trait solver pretty easily. This should be sufficient for us to use in the standard library itself. Regarding incompleteness, maybe we should always treat host predicates as ambiguous in intercrate mode (at least in the old solver) to avoid any worries about accidental impl overlap or something. r? ```@lcnr``` cc ```@fee1-dead```
2 parents c8a8c82 + 8b7b8e5 commit aa32766

37 files changed

+302
-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,152 @@
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::fast_reject::DeepRejectCtxt;
5+
use rustc_middle::{span_bug, ty};
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+
if selcx.infcx.intercrate {
23+
span_bug!(
24+
obligation.cause.span,
25+
"should not select host obligation in old solver in intercrate mode"
26+
);
27+
}
28+
29+
match evaluate_host_effect_from_bounds(selcx, obligation) {
30+
Ok(result) => return Ok(result),
31+
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
32+
Err(EvaluationFailure::NoSolution) => {}
33+
}
34+
35+
match evaluate_host_effect_from_selection_candiate(selcx, obligation) {
36+
Ok(result) => return Ok(result),
37+
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
38+
Err(EvaluationFailure::NoSolution) => {}
39+
}
40+
41+
Err(EvaluationFailure::NoSolution)
42+
}
43+
44+
fn match_candidate<'tcx>(
45+
infcx: &InferCtxt<'tcx>,
46+
obligation: &HostEffectObligation<'tcx>,
47+
candidate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
48+
) -> Result<ThinVec<PredicateObligation<'tcx>>, NoSolution> {
49+
if !candidate.skip_binder().host.satisfies(obligation.predicate.host) {
50+
return Err(NoSolution);
51+
}
52+
53+
let candidate = infcx.instantiate_binder_with_fresh_vars(
54+
obligation.cause.span,
55+
BoundRegionConversionTime::HigherRankedType,
56+
candidate,
57+
);
58+
59+
let mut nested = infcx
60+
.at(&obligation.cause, obligation.param_env)
61+
.eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)?
62+
.into_obligations();
63+
64+
for nested in &mut nested {
65+
nested.set_depth_from_parent(obligation.recursion_depth);
66+
}
67+
68+
Ok(nested)
69+
}
70+
71+
fn evaluate_host_effect_from_bounds<'tcx>(
72+
selcx: &mut SelectionContext<'_, 'tcx>,
73+
obligation: &HostEffectObligation<'tcx>,
74+
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
75+
let infcx = selcx.infcx;
76+
let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
77+
let mut candidate = None;
78+
79+
for predicate in obligation.param_env.caller_bounds() {
80+
let bound_predicate = predicate.kind();
81+
if let ty::ClauseKind::HostEffect(data) = predicate.kind().skip_binder() {
82+
let data = bound_predicate.rebind(data);
83+
if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
84+
continue;
85+
}
86+
87+
if !drcx.args_may_unify(
88+
obligation.predicate.trait_ref.args,
89+
data.skip_binder().trait_ref.args,
90+
) {
91+
continue;
92+
}
93+
94+
let is_match = infcx.probe(|_| match_candidate(infcx, obligation, data).is_ok());
95+
96+
if is_match {
97+
if candidate.is_some() {
98+
return Err(EvaluationFailure::Ambiguous);
99+
} else {
100+
candidate = Some(data);
101+
}
102+
}
103+
}
104+
}
105+
106+
if let Some(data) = candidate {
107+
Ok(match_candidate(infcx, obligation, data)
108+
.expect("candidate matched before, so it should match again"))
109+
} else {
110+
Err(EvaluationFailure::NoSolution)
111+
}
112+
}
113+
114+
fn evaluate_host_effect_from_selection_candiate<'tcx>(
115+
selcx: &mut SelectionContext<'_, 'tcx>,
116+
obligation: &HostEffectObligation<'tcx>,
117+
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
118+
let tcx = selcx.tcx();
119+
selcx.infcx.commit_if_ok(|_| {
120+
match selcx.select(&obligation.with(tcx, obligation.predicate.trait_ref)) {
121+
Ok(None) => Err(EvaluationFailure::Ambiguous),
122+
Err(_) => Err(EvaluationFailure::NoSolution),
123+
Ok(Some(source)) => match source {
124+
ImplSource::UserDefined(impl_) => {
125+
if tcx.constness(impl_.impl_def_id) != hir::Constness::Const {
126+
return Err(EvaluationFailure::NoSolution);
127+
}
128+
129+
let mut nested = impl_.nested;
130+
nested.extend(
131+
tcx.const_conditions(impl_.impl_def_id)
132+
.instantiate(tcx, impl_.args)
133+
.into_iter()
134+
.map(|(trait_ref, _)| {
135+
obligation.with(
136+
tcx,
137+
trait_ref.to_host_effect_clause(tcx, obligation.predicate.host),
138+
)
139+
}),
140+
);
141+
142+
for nested in &mut nested {
143+
nested.set_depth_from_parent(obligation.recursion_depth);
144+
}
145+
146+
Ok(nested)
147+
}
148+
_ => Err(EvaluationFailure::NoSolution),
149+
},
150+
}
151+
})
152+
}

compiler/rustc_trait_selection/src/traits/fulfill.rs

+29-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,13 @@ 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+
host_obligation,
411+
&mut pending_obligation.stalled_on,
412+
)
407413
}
408414

409415
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => {
@@ -854,6 +860,27 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
854860
}
855861
}
856862
}
863+
864+
fn process_host_obligation(
865+
&mut self,
866+
host_obligation: HostEffectObligation<'tcx>,
867+
stalled_on: &mut Vec<TyOrConstInferVar>,
868+
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
869+
match effects::evaluate_host_effect_obligation(&mut self.selcx, &host_obligation) {
870+
Ok(nested) => ProcessResult::Changed(mk_pending(nested)),
871+
Err(effects::EvaluationFailure::Ambiguous) => {
872+
stalled_on.clear();
873+
stalled_on.extend(args_infer_vars(
874+
&self.selcx,
875+
ty::Binder::dummy(host_obligation.predicate.trait_ref.args),
876+
));
877+
ProcessResult::Unchanged
878+
}
879+
Err(effects::EvaluationFailure::NoSolution) => {
880+
ProcessResult::Error(FulfillmentErrorCode::Select(SelectionError::Unimplemented))
881+
}
882+
}
883+
}
857884
}
858885

859886
/// 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:21
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)