Skip to content

Commit 42a864a

Browse files
Implement const Destruct in old solver
1 parent 0b63477 commit 42a864a

13 files changed

+135
-191
lines changed

compiler/rustc_middle/src/ty/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1417,8 +1417,8 @@ impl Hash for FieldDef {
14171417
impl<'tcx> FieldDef {
14181418
/// Returns the type of this field. The resulting type is not normalized. The `arg` is
14191419
/// typically obtained via the second field of [`TyKind::Adt`].
1420-
pub fn ty(&self, tcx: TyCtxt<'tcx>, arg: GenericArgsRef<'tcx>) -> Ty<'tcx> {
1421-
tcx.type_of(self.did).instantiate(tcx, arg)
1420+
pub fn ty(&self, tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
1421+
tcx.type_of(self.did).instantiate(tcx, args)
14221422
}
14231423

14241424
/// Computes the `Ident` of this variant by looking up the `Span`

compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs

+2
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,8 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
712712
}
713713
}
714714

715+
// NOTE: Keep this in sync with `evaluate_host_effect_for_destruct_goal` in
716+
// the old solver, for as long as that exists.
715717
pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
716718
cx: I,
717719
self_ty: I::Ty,

compiler/rustc_trait_selection/src/traits/effects.rs

+106-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_hir as hir;
1+
use rustc_hir::{self as hir, LangItem};
22
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
33
use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation};
44
use rustc_middle::span_bug;
@@ -46,6 +46,12 @@ pub fn evaluate_host_effect_obligation<'tcx>(
4646
Err(EvaluationFailure::NoSolution) => {}
4747
}
4848

49+
match evaluate_host_effect_from_builtin_impls(selcx, obligation) {
50+
Ok(result) => return Ok(result),
51+
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
52+
Err(EvaluationFailure::NoSolution) => {}
53+
}
54+
4955
match evaluate_host_effect_from_selection_candiate(selcx, obligation) {
5056
Ok(result) => return Ok(result),
5157
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
@@ -226,6 +232,105 @@ fn evaluate_host_effect_from_item_bounds<'tcx>(
226232
}
227233
}
228234

235+
fn evaluate_host_effect_from_builtin_impls<'tcx>(
236+
selcx: &mut SelectionContext<'_, 'tcx>,
237+
obligation: &HostEffectObligation<'tcx>,
238+
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
239+
match selcx.tcx().as_lang_item(obligation.predicate.def_id()) {
240+
Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation),
241+
// Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) =>
242+
_ => Err(EvaluationFailure::NoSolution),
243+
}
244+
}
245+
246+
// NOTE: Keep this in sync with `const_conditions_for_destruct` in the new solver.
247+
fn evaluate_host_effect_for_destruct_goal<'tcx>(
248+
selcx: &mut SelectionContext<'_, 'tcx>,
249+
obligation: &HostEffectObligation<'tcx>,
250+
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
251+
let tcx = selcx.tcx();
252+
let destruct_def_id = tcx.require_lang_item(LangItem::Destruct, None);
253+
let self_ty = obligation.predicate.self_ty();
254+
255+
let const_conditions = match *self_ty.kind() {
256+
// An ADT is `~const Destruct` only if all of the fields are,
257+
// *and* if there is a `Drop` impl, that `Drop` impl is also `~const`.
258+
ty::Adt(adt_def, args) => {
259+
let mut const_conditions: ThinVec<_> = adt_def
260+
.all_fields()
261+
.map(|field| ty::TraitRef::new(tcx, destruct_def_id, [field.ty(tcx, args)]))
262+
.collect();
263+
match adt_def.destructor(tcx).map(|dtor| dtor.constness) {
264+
// `Drop` impl exists, but it's not const. Type cannot be `~const Destruct`.
265+
Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution),
266+
// `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold.
267+
Some(hir::Constness::Const) => {
268+
let drop_def_id = tcx.require_lang_item(LangItem::Drop, None);
269+
let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]);
270+
const_conditions.push(drop_trait_ref);
271+
}
272+
// No `Drop` impl, no need to require anything else.
273+
None => {}
274+
}
275+
const_conditions
276+
}
277+
278+
ty::Array(ty, _) | ty::Pat(ty, _) | ty::Slice(ty) => {
279+
thin_vec![ty::TraitRef::new(tcx, destruct_def_id, [ty])]
280+
}
281+
282+
ty::Tuple(tys) => {
283+
tys.iter().map(|field_ty| ty::TraitRef::new(tcx, destruct_def_id, [field_ty])).collect()
284+
}
285+
286+
// Trivially implement `~const Destruct`
287+
ty::Bool
288+
| ty::Char
289+
| ty::Int(..)
290+
| ty::Uint(..)
291+
| ty::Float(..)
292+
| ty::Str
293+
| ty::RawPtr(..)
294+
| ty::Ref(..)
295+
| ty::FnDef(..)
296+
| ty::FnPtr(..)
297+
| ty::Never
298+
| ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_))
299+
| ty::Error(_) => thin_vec![],
300+
301+
// Coroutines and closures could implement `~const Drop`,
302+
// but they don't really need to right now.
303+
ty::Closure(_, _)
304+
| ty::CoroutineClosure(_, _)
305+
| ty::Coroutine(_, _)
306+
| ty::CoroutineWitness(_, _) => return Err(EvaluationFailure::NoSolution),
307+
308+
// FIXME(unsafe_binders): Unsafe binders could implement `~const Drop`
309+
// if their inner type implements it.
310+
ty::UnsafeBinder(_) => return Err(EvaluationFailure::NoSolution),
311+
312+
ty::Dynamic(..) | ty::Param(_) | ty::Alias(..) | ty::Placeholder(_) | ty::Foreign(_) => {
313+
return Err(EvaluationFailure::NoSolution);
314+
}
315+
316+
ty::Bound(..)
317+
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
318+
panic!("unexpected type `{self_ty:?}`")
319+
}
320+
};
321+
322+
Ok(const_conditions
323+
.into_iter()
324+
.map(|trait_ref| {
325+
obligation.with(
326+
tcx,
327+
ty::Binder::dummy(trait_ref)
328+
.to_host_effect_clause(tcx, obligation.predicate.constness),
329+
)
330+
})
331+
.collect())
332+
}
333+
229334
fn evaluate_host_effect_from_selection_candiate<'tcx>(
230335
selcx: &mut SelectionContext<'_, 'tcx>,
231336
obligation: &HostEffectObligation<'tcx>,

tests/ui/consts/fn_trait_refs.stderr

+12-81
Original file line numberDiff line numberDiff line change
@@ -155,90 +155,21 @@ note: `FnMut` can't be used with `~const` because it isn't annotated with `#[con
155155
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
156156
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
157157

158-
error[E0277]: the trait bound `fn() -> i32 {one}: const Destruct` is not satisfied
159-
--> $DIR/fn_trait_refs.rs:70:32
158+
error[E0015]: cannot call non-const operator in constants
159+
--> $DIR/fn_trait_refs.rs:71:17
160160
|
161-
LL | let test_one = test_fn(one);
162-
| ------- ^^^
163-
| |
164-
| required by a bound introduced by this call
161+
LL | assert!(test_one == (1, 1, 1));
162+
| ^^^^^^^^^^^^^^^^^^^^^
165163
|
166-
note: required by a bound in `test_fn`
167-
--> $DIR/fn_trait_refs.rs:35:24
168-
|
169-
LL | const fn test_fn<T>(mut f: T) -> (T::Output, T::Output, T::Output)
170-
| ------- required by a bound in this function
171-
LL | where
172-
LL | T: ~const Fn<()> + ~const Destruct,
173-
| ^^^^^^ required by this bound in `test_fn`
174-
175-
error[E0277]: the trait bound `fn() -> i32 {two}: const Destruct` is not satisfied
176-
--> $DIR/fn_trait_refs.rs:73:36
177-
|
178-
LL | let test_two = test_fn_mut(two);
179-
| ----------- ^^^
180-
| |
181-
| required by a bound introduced by this call
182-
|
183-
note: required by a bound in `test_fn_mut`
184-
--> $DIR/fn_trait_refs.rs:49:27
185-
|
186-
LL | const fn test_fn_mut<T>(mut f: T) -> (T::Output, T::Output)
187-
| ----------- required by a bound in this function
188-
LL | where
189-
LL | T: ~const FnMut<()> + ~const Destruct,
190-
| ^^^^^^ required by this bound in `test_fn_mut`
164+
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
191165

192-
error[E0277]: the trait bound `&T: ~const Destruct` is not satisfied
193-
--> $DIR/fn_trait_refs.rs:39:19
194-
|
195-
LL | tester_fn(&f),
196-
| --------- ^^
197-
| |
198-
| required by a bound introduced by this call
166+
error[E0015]: cannot call non-const operator in constants
167+
--> $DIR/fn_trait_refs.rs:74:17
199168
|
200-
note: required by a bound in `tester_fn`
201-
--> $DIR/fn_trait_refs.rs:14:24
169+
LL | assert!(test_two == (2, 2));
170+
| ^^^^^^^^^^^^^^^^^^
202171
|
203-
LL | const fn tester_fn<T>(f: T) -> T::Output
204-
| --------- required by a bound in this function
205-
LL | where
206-
LL | T: ~const Fn<()> + ~const Destruct,
207-
| ^^^^^^ required by this bound in `tester_fn`
208-
209-
error[E0277]: the trait bound `&T: ~const Destruct` is not satisfied
210-
--> $DIR/fn_trait_refs.rs:41:23
211-
|
212-
LL | tester_fn_mut(&f),
213-
| ------------- ^^
214-
| |
215-
| required by a bound introduced by this call
216-
|
217-
note: required by a bound in `tester_fn_mut`
218-
--> $DIR/fn_trait_refs.rs:21:27
219-
|
220-
LL | const fn tester_fn_mut<T>(mut f: T) -> T::Output
221-
| ------------- required by a bound in this function
222-
LL | where
223-
LL | T: ~const FnMut<()> + ~const Destruct,
224-
| ^^^^^^ required by this bound in `tester_fn_mut`
225-
226-
error[E0277]: the trait bound `&mut T: ~const Destruct` is not satisfied
227-
--> $DIR/fn_trait_refs.rs:53:23
228-
|
229-
LL | tester_fn_mut(&mut f),
230-
| ------------- ^^^^^^
231-
| |
232-
| required by a bound introduced by this call
233-
|
234-
note: required by a bound in `tester_fn_mut`
235-
--> $DIR/fn_trait_refs.rs:21:27
236-
|
237-
LL | const fn tester_fn_mut<T>(mut f: T) -> T::Output
238-
| ------------- required by a bound in this function
239-
LL | where
240-
LL | T: ~const FnMut<()> + ~const Destruct,
241-
| ^^^^^^ required by this bound in `tester_fn_mut`
172+
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
242173

243174
error[E0015]: cannot call non-const closure in constant functions
244175
--> $DIR/fn_trait_refs.rs:16:5
@@ -264,7 +195,7 @@ LL | f()
264195
|
265196
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
266197

267-
error: aborting due to 25 previous errors
198+
error: aborting due to 22 previous errors
268199

269-
Some errors have detailed explanations: E0015, E0277, E0635.
200+
Some errors have detailed explanations: E0015, E0635.
270201
For more information about an error, try `rustc --explain E0015`.

tests/ui/consts/promoted_const_call.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ LL | let _: &'static _ = &id(&Panic);
55
| ^^^^^ - value is dropped here
66
| |
77
| the destructor for this type cannot be evaluated in constants
8+
|
9+
= note: see issue #133214 <https://github.com/rust-lang/rust/issues/133214> for more information
10+
= help: add `#![feature(const_destruct)]` to the crate attributes to enable
11+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
812

913
error[E0716]: temporary value dropped while borrowed
1014
--> $DIR/promoted_const_call.rs:16:26

tests/ui/impl-trait/normalize-tait-in-const.stderr

+2-17
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,6 @@ note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_
1717
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
1818
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
1919

20-
error[E0277]: the trait bound `for<'a, 'b> fn(&'a foo::Alias<'b>) {foo}: const Destruct` is not satisfied
21-
--> $DIR/normalize-tait-in-const.rs:33:19
22-
|
23-
LL | with_positive(foo);
24-
| ------------- ^^^
25-
| |
26-
| required by a bound introduced by this call
27-
|
28-
note: required by a bound in `with_positive`
29-
--> $DIR/normalize-tait-in-const.rs:26:62
30-
|
31-
LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
32-
| ^^^^^^ required by this bound in `with_positive`
33-
3420
error[E0015]: cannot call non-const closure in constant functions
3521
--> $DIR/normalize-tait-in-const.rs:27:5
3622
|
@@ -39,7 +25,6 @@ LL | fun(filter_positive());
3925
|
4026
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
4127

42-
error: aborting due to 4 previous errors
28+
error: aborting due to 3 previous errors
4329

44-
Some errors have detailed explanations: E0015, E0277.
45-
For more information about an error, try `rustc --explain E0015`.
30+
For more information about this error, try `rustc --explain E0015`.

tests/ui/traits/const-traits/const-drop-bound.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
//@ known-bug: #110395
2-
// FIXME check-pass
1+
//@ check-pass
32

43
#![feature(const_trait_impl)]
54
#![feature(const_precise_live_drops, const_destruct)]

tests/ui/traits/const-traits/const-drop-bound.stderr

-17
This file was deleted.

tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: const Destruct` is not satisfied
1+
error[E0277]: the trait bound `NonTrivialDrop: const A` is not satisfied
22
--> $DIR/const-drop-fail-2.rs:31:23
33
|
44
LL | const _: () = check::<ConstDropImplWithBounds<NonTrivialDrop>>(

tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: const Destruct` is not satisfied
1+
error[E0277]: the trait bound `NonTrivialDrop: const A` is not satisfied
22
--> $DIR/const-drop-fail-2.rs:31:23
33
|
44
LL | const _: () = check::<ConstDropImplWithBounds<NonTrivialDrop>>(

tests/ui/traits/const-traits/const-drop-fail.precise.stderr

-33
This file was deleted.

tests/ui/traits/const-traits/const-drop-fail.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
//@ compile-flags: -Znext-solver
2-
//@ revisions: stock precise
1+
//@[new_precise] compile-flags: -Znext-solver
2+
//@[new_stock] compile-flags: -Znext-solver
3+
//@ revisions: new_stock old_stock new_precise old_precise
34

45
#![feature(const_trait_impl, const_destruct)]
5-
#![cfg_attr(precise, feature(const_precise_live_drops))]
6+
#![cfg_attr(any(new_precise, old_precise), feature(const_precise_live_drops))]
67

78
use std::marker::{Destruct, PhantomData};
89

0 commit comments

Comments
 (0)