Skip to content

Commit

Permalink
Auto merge of rust-lang#134875 - compiler-errors:const-destruct-old-s…
Browse files Browse the repository at this point in the history
…olver, r=<try>

Implement `const Destruct` in old solver

Self-explanatory. Not totally settled that this is the best structure for built-in trait impls for effect goals in the new solver, but it's almost certainly the simplest.

r? lcnr or re-roll
  • Loading branch information
bors committed Dec 29, 2024
2 parents 0b63477 + 42a864a commit 950b5a5
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 191 deletions.
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
107 changes: 106 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::{ImplSource, Obligation, PredicateObligation};
use rustc_middle::span_bug;
Expand Down Expand Up @@ -46,6 +46,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 @@ -226,6 +232,105 @@ 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),
// Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) =>
_ => 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,4 +1,4 @@
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>>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
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>>(
Expand Down
33 changes: 0 additions & 33 deletions tests/ui/traits/const-traits/const-drop-fail.precise.stderr

This file was deleted.

7 changes: 4 additions & 3 deletions tests/ui/traits/const-traits/const-drop-fail.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//@ compile-flags: -Znext-solver
//@ revisions: stock precise
//@[new_precise] compile-flags: -Znext-solver
//@[new_stock] compile-flags: -Znext-solver
//@ revisions: new_stock old_stock new_precise old_precise

#![feature(const_trait_impl, const_destruct)]
#![cfg_attr(precise, feature(const_precise_live_drops))]
#![cfg_attr(any(new_precise, old_precise), feature(const_precise_live_drops))]

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

Expand Down
Loading

0 comments on commit 950b5a5

Please sign in to comment.