Auto merge of #92257 - fee1-dead:fix_env_further_bounds, r=oli-obk

normalize env constness for nested obligations

Closes #92230.
This commit is contained in:
bors 2021-12-26 08:52:31 +00:00
commit f8abed9ed4
4 changed files with 63 additions and 1 deletions

View File

@ -8,6 +8,7 @@
//! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_hir::Constness;
use rustc_index::bit_set::GrowableBitSet; use rustc_index::bit_set::GrowableBitSet;
use rustc_infer::infer::InferOk; use rustc_infer::infer::InferOk;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
@ -51,6 +52,38 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &TraitObligation<'tcx>, obligation: &TraitObligation<'tcx>,
candidate: SelectionCandidate<'tcx>, candidate: SelectionCandidate<'tcx>,
) -> Result<Selection<'tcx>, SelectionError<'tcx>> { ) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
let mut obligation = obligation;
let new_obligation;
// HACK(const_trait_impl): the surrounding environment is remapped to a non-const context
// because nested obligations might be actually `~const` then (incorrectly) requiring
// const impls. for example:
// ```
// pub trait Super {}
// pub trait Sub: Super {}
//
// impl<A> const Super for &A where A: ~const Super {}
// impl<A> const Sub for &A where A: ~const Sub {}
// ```
//
// The procedure to check the code above without the remapping code is as follows:
// ```
// CheckWf(impl const Sub for &A where A: ~const Sub) // <- const env
// CheckPredicate(&A: Super)
// CheckPredicate(A: ~const Super) // <- still const env, failure
// ```
if obligation.param_env.constness() == Constness::Const
&& obligation.predicate.skip_binder().constness == ty::BoundConstness::NotConst
{
new_obligation = TraitObligation {
cause: obligation.cause.clone(),
param_env: obligation.param_env.without_const(),
..*obligation
};
obligation = &new_obligation;
}
match candidate { match candidate {
BuiltinCandidate { has_nested } => { BuiltinCandidate { has_nested } => {
let data = self.confirm_builtin_candidate(obligation, has_nested); let data = self.confirm_builtin_candidate(obligation, has_nested);

View File

@ -0,0 +1,14 @@
// Regression test for #92230.
//
// check-pass
#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
pub trait Super {}
pub trait Sub: Super {}
impl<A> const Super for &A where A: ~const Super {}
impl<A> const Sub for &A where A: ~const Sub {}
fn main() {}

View File

@ -4,6 +4,7 @@ pub static Y: &'static X = {
const Y: &'static [u8] = b""; const Y: &'static [u8] = b"";
&X(*Y) &X(*Y)
//~^ ERROR E0277 //~^ ERROR E0277
//~| ERROR E0277
}; };
fn main() {} fn main() {}

View File

@ -8,6 +8,20 @@ LL | &X(*Y)
= note: all function arguments must have a statically known size = note: all function arguments must have a statically known size
= help: unsized fn params are gated as an unstable feature = help: unsized fn params are gated as an unstable feature
error: aborting due to previous error error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/issue-30355.rs:5:6
|
LL | &X(*Y)
| ^ doesn't have a size known at compile-time
|
= help: within `X`, the trait `Sized` is not implemented for `[u8]`
note: required because it appears within the type `X`
--> $DIR/issue-30355.rs:1:12
|
LL | pub struct X([u8]);
| ^
= note: the return type of a function must have a statically known size
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`. For more information about this error, try `rustc --explain E0277`.