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

Implement const Destruct in old solver #134875

Merged
merged 1 commit into from
Jan 9, 2025
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: 2 additions & 2 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1417,8 +1417,8 @@ impl Hash for FieldDef {
impl<'tcx> FieldDef {
/// Returns the type of this field. The resulting type is not normalized. The `arg` is
/// typically obtained via the second field of [`TyKind::Adt`].
pub fn ty(&self, tcx: TyCtxt<'tcx>, arg: GenericArgsRef<'tcx>) -> Ty<'tcx> {
tcx.type_of(self.did).instantiate(tcx, arg)
pub fn ty(&self, tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
tcx.type_of(self.did).instantiate(tcx, args)
}

/// Computes the `Ident` of this variant by looking up the `Span`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,8 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
}
}

// NOTE: Keep this in sync with `evaluate_host_effect_for_destruct_goal` in
// the old solver, for as long as that exists.
pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
cx: I,
self_ty: I::Ty,
Expand Down
106 changes: 105 additions & 1 deletion compiler/rustc_trait_selection/src/traits/effects.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use rustc_hir as hir;
use rustc_hir::{self as hir, LangItem};
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
use rustc_infer::traits::{
ImplDerivedHostCause, ImplSource, Obligation, ObligationCauseCode, PredicateObligation,
Expand Down Expand Up @@ -48,6 +48,12 @@ pub fn evaluate_host_effect_obligation<'tcx>(
Err(EvaluationFailure::NoSolution) => {}
}

match evaluate_host_effect_from_builtin_impls(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),
Expand Down Expand Up @@ -228,6 +234,104 @@ fn evaluate_host_effect_from_item_bounds<'tcx>(
}
}

fn evaluate_host_effect_from_builtin_impls<'tcx>(
selcx: &mut SelectionContext<'_, 'tcx>,
obligation: &HostEffectObligation<'tcx>,
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
match selcx.tcx().as_lang_item(obligation.predicate.def_id()) {
Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation),
_ => Err(EvaluationFailure::NoSolution),
}
}

// NOTE: Keep this in sync with `const_conditions_for_destruct` in the new solver.
fn evaluate_host_effect_for_destruct_goal<'tcx>(
selcx: &mut SelectionContext<'_, 'tcx>,
obligation: &HostEffectObligation<'tcx>,
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
let tcx = selcx.tcx();
let destruct_def_id = tcx.require_lang_item(LangItem::Destruct, None);
let self_ty = obligation.predicate.self_ty();

let const_conditions = match *self_ty.kind() {
// An ADT is `~const Destruct` only if all of the fields are,
// *and* if there is a `Drop` impl, that `Drop` impl is also `~const`.
ty::Adt(adt_def, args) => {
let mut const_conditions: ThinVec<_> = adt_def
.all_fields()
.map(|field| ty::TraitRef::new(tcx, destruct_def_id, [field.ty(tcx, args)]))
.collect();
match adt_def.destructor(tcx).map(|dtor| dtor.constness) {
// `Drop` impl exists, but it's not const. Type cannot be `~const Destruct`.
Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution),
// `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold.
Some(hir::Constness::Const) => {
let drop_def_id = tcx.require_lang_item(LangItem::Drop, None);
let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]);
const_conditions.push(drop_trait_ref);
}
// No `Drop` impl, no need to require anything else.
None => {}
}
const_conditions
}

ty::Array(ty, _) | ty::Pat(ty, _) | ty::Slice(ty) => {
thin_vec![ty::TraitRef::new(tcx, destruct_def_id, [ty])]
}

ty::Tuple(tys) => {
tys.iter().map(|field_ty| ty::TraitRef::new(tcx, destruct_def_id, [field_ty])).collect()
}

// Trivially implement `~const Destruct`
ty::Bool
| ty::Char
| ty::Int(..)
| ty::Uint(..)
| ty::Float(..)
| ty::Str
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::Never
| ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_))
| ty::Error(_) => thin_vec![],

// Coroutines and closures could implement `~const Drop`,
// but they don't really need to right now.
ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(_, _) => return Err(EvaluationFailure::NoSolution),

// FIXME(unsafe_binders): Unsafe binders could implement `~const Drop`
// if their inner type implements it.
ty::UnsafeBinder(_) => return Err(EvaluationFailure::NoSolution),

ty::Dynamic(..) | ty::Param(_) | ty::Alias(..) | ty::Placeholder(_) | ty::Foreign(_) => {
return Err(EvaluationFailure::NoSolution);
}

ty::Bound(..)
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
panic!("unexpected type `{self_ty:?}`")
}
};

Ok(const_conditions
.into_iter()
.map(|trait_ref| {
obligation.with(
tcx,
ty::Binder::dummy(trait_ref)
.to_host_effect_clause(tcx, obligation.predicate.constness),
)
})
.collect())
}

fn evaluate_host_effect_from_selection_candiate<'tcx>(
selcx: &mut SelectionContext<'_, 'tcx>,
obligation: &HostEffectObligation<'tcx>,
Expand Down
93 changes: 12 additions & 81 deletions tests/ui/consts/fn_trait_refs.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -155,90 +155,21 @@ note: `FnMut` can't be used with `~const` because it isn't annotated with `#[con
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0277]: the trait bound `fn() -> i32 {one}: const Destruct` is not satisfied
--> $DIR/fn_trait_refs.rs:70:32
error[E0015]: cannot call non-const operator in constants
--> $DIR/fn_trait_refs.rs:71:17
|
LL | let test_one = test_fn(one);
| ------- ^^^
| |
| required by a bound introduced by this call
LL | assert!(test_one == (1, 1, 1));
| ^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `test_fn`
--> $DIR/fn_trait_refs.rs:35:24
|
LL | const fn test_fn<T>(mut f: T) -> (T::Output, T::Output, T::Output)
| ------- required by a bound in this function
LL | where
LL | T: ~const Fn<()> + ~const Destruct,
| ^^^^^^ required by this bound in `test_fn`

error[E0277]: the trait bound `fn() -> i32 {two}: const Destruct` is not satisfied
--> $DIR/fn_trait_refs.rs:73:36
|
LL | let test_two = test_fn_mut(two);
| ----------- ^^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `test_fn_mut`
--> $DIR/fn_trait_refs.rs:49:27
|
LL | const fn test_fn_mut<T>(mut f: T) -> (T::Output, T::Output)
| ----------- required by a bound in this function
LL | where
LL | T: ~const FnMut<()> + ~const Destruct,
| ^^^^^^ required by this bound in `test_fn_mut`
= note: calls in constants are limited to constant functions, tuple structs and tuple variants

error[E0277]: the trait bound `&T: ~const Destruct` is not satisfied
--> $DIR/fn_trait_refs.rs:39:19
|
LL | tester_fn(&f),
| --------- ^^
| |
| required by a bound introduced by this call
error[E0015]: cannot call non-const operator in constants
--> $DIR/fn_trait_refs.rs:74:17
|
note: required by a bound in `tester_fn`
--> $DIR/fn_trait_refs.rs:14:24
LL | assert!(test_two == (2, 2));
| ^^^^^^^^^^^^^^^^^^
|
LL | const fn tester_fn<T>(f: T) -> T::Output
| --------- required by a bound in this function
LL | where
LL | T: ~const Fn<()> + ~const Destruct,
| ^^^^^^ required by this bound in `tester_fn`

error[E0277]: the trait bound `&T: ~const Destruct` is not satisfied
--> $DIR/fn_trait_refs.rs:41:23
|
LL | tester_fn_mut(&f),
| ------------- ^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `tester_fn_mut`
--> $DIR/fn_trait_refs.rs:21:27
|
LL | const fn tester_fn_mut<T>(mut f: T) -> T::Output
| ------------- required by a bound in this function
LL | where
LL | T: ~const FnMut<()> + ~const Destruct,
| ^^^^^^ required by this bound in `tester_fn_mut`

error[E0277]: the trait bound `&mut T: ~const Destruct` is not satisfied
--> $DIR/fn_trait_refs.rs:53:23
|
LL | tester_fn_mut(&mut f),
| ------------- ^^^^^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `tester_fn_mut`
--> $DIR/fn_trait_refs.rs:21:27
|
LL | const fn tester_fn_mut<T>(mut f: T) -> T::Output
| ------------- required by a bound in this function
LL | where
LL | T: ~const FnMut<()> + ~const Destruct,
| ^^^^^^ required by this bound in `tester_fn_mut`
= note: calls in constants are limited to constant functions, tuple structs and tuple variants

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

error: aborting due to 25 previous errors
error: aborting due to 22 previous errors

Some errors have detailed explanations: E0015, E0277, E0635.
Some errors have detailed explanations: E0015, E0635.
For more information about an error, try `rustc --explain E0015`.
4 changes: 4 additions & 0 deletions tests/ui/consts/promoted_const_call.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ LL | let _: &'static _ = &id(&Panic);
| ^^^^^ - value is dropped here
| |
| the destructor for this type cannot be evaluated in constants
|
= note: see issue #133214 <https://github.com/rust-lang/rust/issues/133214> for more information
= help: add `#![feature(const_destruct)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0716]: temporary value dropped while borrowed
--> $DIR/promoted_const_call.rs:16:26
Expand Down
19 changes: 2 additions & 17 deletions tests/ui/impl-trait/normalize-tait-in-const.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,6 @@ note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0277]: the trait bound `for<'a, 'b> fn(&'a foo::Alias<'b>) {foo}: const Destruct` is not satisfied
--> $DIR/normalize-tait-in-const.rs:33:19
|
LL | with_positive(foo);
| ------------- ^^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `with_positive`
--> $DIR/normalize-tait-in-const.rs:26:62
|
LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
| ^^^^^^ required by this bound in `with_positive`

error[E0015]: cannot call non-const closure in constant functions
--> $DIR/normalize-tait-in-const.rs:27:5
|
Expand All @@ -39,7 +25,6 @@ LL | fun(filter_positive());
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error: aborting due to 4 previous errors
error: aborting due to 3 previous errors

Some errors have detailed explanations: E0015, E0277.
For more information about an error, try `rustc --explain E0015`.
For more information about this error, try `rustc --explain E0015`.
3 changes: 1 addition & 2 deletions tests/ui/traits/const-traits/const-drop-bound.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//@ known-bug: #110395
// FIXME check-pass
//@ check-pass

#![feature(const_trait_impl)]
#![feature(const_precise_live_drops, const_destruct)]
Expand Down
17 changes: 0 additions & 17 deletions tests/ui/traits/const-traits/const-drop-bound.stderr

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: const Destruct` is not satisfied
error[E0277]: the trait bound `NonTrivialDrop: const A` is not satisfied
--> $DIR/const-drop-fail-2.rs:31:23
|
LL | const _: () = check::<ConstDropImplWithBounds<NonTrivialDrop>>(
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `const Drop`
--> $DIR/const-drop-fail-2.rs:25:25
|
LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
| ------ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `check`
--> $DIR/const-drop-fail-2.rs:21:19
|
Expand Down
9 changes: 8 additions & 1 deletion tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: const Destruct` is not satisfied
error[E0277]: the trait bound `NonTrivialDrop: const A` is not satisfied
--> $DIR/const-drop-fail-2.rs:31:23
|
LL | const _: () = check::<ConstDropImplWithBounds<NonTrivialDrop>>(
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `const Drop`
--> $DIR/const-drop-fail-2.rs:25:25
|
LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
| ------ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `check`
--> $DIR/const-drop-fail-2.rs:21:19
|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:32:5
--> $DIR/const-drop-fail.rs:33:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
Expand All @@ -8,13 +8,13 @@ LL | NonTrivialDrop,
| ^^^^^^^^^^^^^^
|
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:23:19
--> $DIR/const-drop-fail.rs:24:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^ required by this bound in `check`

error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:34:5
--> $DIR/const-drop-fail.rs:35:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
Expand All @@ -23,7 +23,7 @@ LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:23:19
--> $DIR/const-drop-fail.rs:24:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^ required by this bound in `check`
Expand Down
Loading
Loading