Skip to content

Commit 07af01c

Browse files
committed
Elaborate structural destruct host effect clauses
1 parent 2d60410 commit 07af01c

10 files changed

+344
-12
lines changed

compiler/rustc_const_eval/src/check_consts/check.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,19 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
400400
ty::BoundConstness::Const
401401
}
402402
};
403+
404+
// Only elaborate host-effect destruct obligations when comparing impl method bounds
405+
// against the corresponding trait method bounds.
406+
let elaborate = matches!(
407+
tcx.hir_node_by_def_id(body_id),
408+
hir::Node::ImplItem(hir::ImplItem {
409+
trait_item_def_id: Some(did),
410+
..
411+
}) if *did == callee,
412+
);
413+
let param_env =
414+
if elaborate { param_env.elaborate_host_effect_destruct(tcx) } else { param_env };
415+
403416
let const_conditions =
404417
ocx.normalize(&ObligationCause::misc(call_span, body_id), param_env, const_conditions);
405418
ocx.register_obligations(const_conditions.into_iter().map(|(trait_ref, span)| {

compiler/rustc_hir_typeck/src/callee.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -922,10 +922,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
922922
ObligationCauseCode::WhereClause(callee_did, pred_span)
923923
},
924924
);
925+
926+
// Only elaborate host-effect destruct obligations when comparing impl method
927+
// bounds against the corresponding trait method bounds.
928+
let elaborate = matches!(
929+
self.tcx.hir_node_by_def_id(self.body_id),
930+
hir::Node::ImplItem(hir::ImplItem {
931+
trait_item_def_id: Some(did),
932+
..
933+
}) if *did == callee_did,
934+
);
935+
let param_env = if elaborate {
936+
self.param_env.elaborate_host_effect_destruct(self.tcx)
937+
} else {
938+
self.param_env
939+
};
940+
925941
self.register_predicate(Obligation::new(
926942
self.tcx,
927943
cause,
928-
self.param_env,
944+
param_env,
929945
cond.to_host_effect_clause(self.tcx, host),
930946
));
931947
}

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,6 +1011,15 @@ impl<'tcx> ParamEnv<'tcx> {
10111011
pub fn and<T: TypeVisitable<TyCtxt<'tcx>>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
10121012
ParamEnvAnd { param_env: self, value }
10131013
}
1014+
1015+
pub fn elaborate_host_effect_destruct(self, tcx: TyCtxt<'tcx>) -> Self {
1016+
// TODO: Feature gate
1017+
let caller_bounds = tcx.mk_clauses_from_iter(
1018+
ty::elaborate::elaborate(tcx, self.caller_bounds.iter())
1019+
.elaborate_host_effect_destruct(),
1020+
);
1021+
ParamEnv { caller_bounds }
1022+
}
10141023
}
10151024

10161025
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]

compiler/rustc_type_ir/src/elaborate.rs

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::data_structures::HashSet;
66
use crate::inherent::*;
77
use crate::lang_items::TraitSolverLangItem;
88
use crate::outlives::{Component, push_outlives_components};
9-
use crate::{self as ty, Interner, Upcast as _};
9+
use crate::{self as ty, Interner, Upcast as _, solve};
1010

1111
/// "Elaboration" is the process of identifying all the predicates that
1212
/// are implied by a source predicate. Currently, this basically means
@@ -20,6 +20,7 @@ pub struct Elaborator<I: Interner, O> {
2020
visited: HashSet<ty::Binder<I, ty::PredicateKind<I>>>,
2121
mode: Filter,
2222
elaborate_sized: ElaborateSized,
23+
elaborate_host_effect_destruct: ElaborateHostEffectDestruct,
2324
}
2425

2526
enum Filter {
@@ -33,6 +34,12 @@ enum ElaborateSized {
3334
No,
3435
}
3536

37+
#[derive(Eq, PartialEq)]
38+
enum ElaborateHostEffectDestruct {
39+
Yes,
40+
No,
41+
}
42+
3643
/// Describes how to elaborate an obligation into a sub-obligation.
3744
pub trait Elaboratable<I: Interner> {
3845
fn predicate(&self) -> I::Predicate;
@@ -91,6 +98,7 @@ pub fn elaborate<I: Interner, O: Elaboratable<I>>(
9198
visited: HashSet::default(),
9299
mode: Filter::All,
93100
elaborate_sized: ElaborateSized::No,
101+
elaborate_host_effect_destruct: ElaborateHostEffectDestruct::No,
94102
};
95103
elaborator.extend_deduped(obligations);
96104
elaborator
@@ -124,6 +132,12 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
124132
self
125133
}
126134

135+
/// Start elaborating `[const] Destruct`. Should only be used in narrowly scoped contexts.
136+
pub fn elaborate_host_effect_destruct(mut self) -> Self {
137+
self.elaborate_host_effect_destruct = ElaborateHostEffectDestruct::Yes;
138+
self
139+
}
140+
127141
fn elaborate(&mut self, elaboratable: &O) {
128142
let cx = self.cx;
129143

@@ -179,16 +193,43 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
179193
),
180194
};
181195
}
182-
// `T: [const] Trait` implies `T: [const] Supertrait`.
183-
ty::ClauseKind::HostEffect(data) => self.extend_deduped(
184-
cx.explicit_implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| {
185-
elaboratable.child(
186-
trait_ref
187-
.to_host_effect_clause(cx, data.constness)
188-
.instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)),
189-
)
190-
}),
191-
),
196+
ty::ClauseKind::HostEffect(data) => {
197+
// `T: [const] Trait` implies `T: [const] Supertrait`.
198+
self.extend_deduped(
199+
cx.explicit_implied_const_bounds(data.def_id()).iter_identity().map(
200+
|trait_ref| {
201+
elaboratable.child(
202+
trait_ref
203+
.to_host_effect_clause(cx, data.constness)
204+
.instantiate_supertrait(
205+
cx,
206+
bound_clause.rebind(data.trait_ref),
207+
),
208+
)
209+
},
210+
),
211+
);
212+
213+
// Elaborate structurally implied obligations:
214+
// e.g., `ADT: [const] Destruct` implies that each public field also implements
215+
// `[const] Destruct`.
216+
if self.elaborate_host_effect_destruct == ElaborateHostEffectDestruct::Yes {
217+
let destruct_def_id = cx.require_lang_item(TraitSolverLangItem::Destruct);
218+
if data.def_id() == destruct_def_id {
219+
match solve::const_conditions_for_destruct(cx, data.self_ty(), true) {
220+
solve::DestructConstCondition::Structural(trait_refs) => self
221+
.extend_deduped(trait_refs.into_iter().map(|trait_ref| {
222+
elaboratable.child(
223+
bound_clause
224+
.rebind(trait_ref)
225+
.to_host_effect_clause(cx, data.constness),
226+
)
227+
})),
228+
_ => {}
229+
}
230+
}
231+
}
232+
}
192233
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
193234
// We know that `T: 'a` for some type `T`. We can
194235
// often elaborate this. For example, if we know that
3.49 MB
Binary file not shown.
3.49 MB
Binary file not shown.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Demonstrates that `impl<T> const Clone for Option<T>` does not require const_hack bounds.
2+
// See issue #144207.
3+
//@ revisions: next old
4+
//@ [next] compile-flags: -Znext-solver
5+
//@ check-pass
6+
7+
#![feature(const_trait_impl, const_destruct)]
8+
9+
use std::marker::Destruct;
10+
11+
#[const_trait]
12+
pub trait CloneLike: Sized {
13+
fn clone(&self) -> Self;
14+
15+
fn clone_from(&mut self, source: &Self)
16+
where
17+
Self: [const] Destruct,
18+
{
19+
*self = source.clone()
20+
}
21+
}
22+
23+
pub enum OptionLike<T> {
24+
None,
25+
Some(T),
26+
}
27+
28+
impl<T> const CloneLike for OptionLike<T>
29+
where
30+
T: [const] CloneLike,
31+
{
32+
fn clone(&self) -> Self {
33+
match self {
34+
Self::Some(x) => Self::Some(x.clone()),
35+
Self::None => Self::None,
36+
}
37+
}
38+
39+
fn clone_from(&mut self, source: &Self)
40+
where
41+
Self: [const] Destruct,
42+
{
43+
match (self, source) {
44+
(Self::Some(to), Self::Some(from)) => to.clone_from(from),
45+
(to, from) => *to = from.clone(),
46+
}
47+
}
48+
}
49+
50+
fn main() {}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
error[E0277]: the trait bound `U: [const] Destruct` is not satisfied
2+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:41:11
3+
|
4+
LL | u.f();
5+
| ^
6+
|
7+
note: required by a bound in `TraitA::f`
8+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:14:15
9+
|
10+
LL | fn f(self)
11+
| - required by a bound in this associated function
12+
LL | where
13+
LL | Self: [const] Destruct;
14+
| ^^^^^^^^^^^^^^^^ required by this bound in `TraitA::f`
15+
16+
error[E0277]: the trait bound `T: const Destruct` is not satisfied
17+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:49:27
18+
|
19+
LL | ensure_const_destruct(x.unwrap())
20+
| --------------------- ^^^^^^^^^^
21+
| |
22+
| required by a bound introduced by this call
23+
|
24+
note: required by a bound in `ensure_const_destruct`
25+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:9:35
26+
|
27+
LL | const fn ensure_const_destruct<T: const Destruct>(_t: T) {}
28+
| ^^^^^^^^^^^^^^ required by this bound in `ensure_const_destruct`
29+
30+
error[E0277]: the trait bound `T: [const] Destruct` is not satisfied
31+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:64:16
32+
|
33+
LL | self.0.g()
34+
| ^
35+
|
36+
note: required by a bound in `TraitB::g`
37+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:56:15
38+
|
39+
LL | fn g(self)
40+
| - required by a bound in this associated function
41+
LL | where
42+
LL | Self: [const] Destruct;
43+
| ^^^^^^^^^^^^^^^^ required by this bound in `TraitB::g`
44+
45+
error[E0277]: the trait bound `T: [const] Destruct` is not satisfied
46+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:74:40
47+
|
48+
LL | ManuallyDrop::into_inner(self).f()
49+
| ^
50+
|
51+
note: required by a bound in `TraitA::f`
52+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:14:15
53+
|
54+
LL | fn f(self)
55+
| - required by a bound in this associated function
56+
LL | where
57+
LL | Self: [const] Destruct;
58+
| ^^^^^^^^^^^^^^^^ required by this bound in `TraitA::f`
59+
60+
error: aborting due to 4 previous errors
61+
62+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
error[E0277]: the trait bound `U: [const] Destruct` is not satisfied
2+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:41:11
3+
|
4+
LL | u.f();
5+
| ^
6+
|
7+
note: required by a bound in `TraitA::f`
8+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:14:15
9+
|
10+
LL | fn f(self)
11+
| - required by a bound in this associated function
12+
LL | where
13+
LL | Self: [const] Destruct;
14+
| ^^^^^^^^^^^^^^^^ required by this bound in `TraitA::f`
15+
16+
error[E0277]: the trait bound `T: const Destruct` is not satisfied
17+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:49:27
18+
|
19+
LL | ensure_const_destruct(x.unwrap())
20+
| --------------------- ^^^^^^^^^^
21+
| |
22+
| required by a bound introduced by this call
23+
|
24+
note: required by a bound in `ensure_const_destruct`
25+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:9:35
26+
|
27+
LL | const fn ensure_const_destruct<T: const Destruct>(_t: T) {}
28+
| ^^^^^^^^^^^^^^ required by this bound in `ensure_const_destruct`
29+
30+
error[E0277]: the trait bound `T: [const] Destruct` is not satisfied
31+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:64:16
32+
|
33+
LL | self.0.g()
34+
| ^
35+
|
36+
note: required by a bound in `TraitB::g`
37+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:56:15
38+
|
39+
LL | fn g(self)
40+
| - required by a bound in this associated function
41+
LL | where
42+
LL | Self: [const] Destruct;
43+
| ^^^^^^^^^^^^^^^^ required by this bound in `TraitB::g`
44+
45+
error[E0277]: the trait bound `T: [const] Destruct` is not satisfied
46+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:74:40
47+
|
48+
LL | ManuallyDrop::into_inner(self).f()
49+
| ^
50+
|
51+
note: required by a bound in `TraitA::f`
52+
--> $DIR/conditionally-const-trait-structural-destruct-implied-bounds.rs:14:15
53+
|
54+
LL | fn f(self)
55+
| - required by a bound in this associated function
56+
LL | where
57+
LL | Self: [const] Destruct;
58+
| ^^^^^^^^^^^^^^^^ required by this bound in `TraitA::f`
59+
60+
error: aborting due to 4 previous errors
61+
62+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)