Auto merge of #99521 - fee1-dead-contrib:const_fix_hax, r=oli-obk

Fix hack that remaps env constness.

WARNING: might have perf implications.

Are there any more problems with having a constness in the `ParamEnv` now? :)

r? `@oli-obk`
This commit is contained in:
bors 2022-07-22 12:48:29 +00:00
commit 22d25f21dc
6 changed files with 46 additions and 67 deletions

View File

@ -575,6 +575,19 @@ impl<'tcx> Predicate<'tcx> {
Some(tcx.mk_predicate(kind)) Some(tcx.mk_predicate(kind))
} }
pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> Self {
if let PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) = self.kind().skip_binder()
&& constness != BoundConstness::NotConst
{
self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Trait(TraitPredicate {
trait_ref,
constness: BoundConstness::NotConst,
polarity,
})));
}
self
}
} }
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> { impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {

View File

@ -31,14 +31,14 @@ pub(crate) fn update<'tcx, T>(
obligation obligation
.predicate .predicate
.kind() .kind()
.map_bound(|_| { .rebind(
// (*) binder moved here // (*) binder moved here
ty::PredicateKind::Trait(ty::TraitPredicate { ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref, trait_ref,
constness: tpred.constness, constness: tpred.constness,
polarity: tpred.polarity, polarity: tpred.polarity,
}) })
}) )
.to_predicate(infcx.tcx), .to_predicate(infcx.tcx),
); );
// Don't report overflow errors. Otherwise equivalent to may_hold. // Don't report overflow errors. Otherwise equivalent to may_hold.

View File

@ -42,115 +42,96 @@ 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 mut impl_src = match candidate {
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.is_const() && !obligation.predicate.is_const_if_const() {
new_obligation = TraitObligation {
cause: obligation.cause.clone(),
param_env: obligation.param_env.without_const(),
..*obligation
};
obligation = &new_obligation;
}
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);
Ok(ImplSource::Builtin(data)) ImplSource::Builtin(data)
} }
ParamCandidate(param) => { ParamCandidate(param) => {
let obligations = let obligations =
self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref)); self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
Ok(ImplSource::Param(obligations, param.skip_binder().constness)) ImplSource::Param(obligations, param.skip_binder().constness)
} }
ImplCandidate(impl_def_id) => { ImplCandidate(impl_def_id) => {
Ok(ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id))) ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id))
} }
AutoImplCandidate(trait_def_id) => { AutoImplCandidate(trait_def_id) => {
let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); let data = self.confirm_auto_impl_candidate(obligation, trait_def_id);
Ok(ImplSource::AutoImpl(data)) ImplSource::AutoImpl(data)
} }
ProjectionCandidate(idx) => { ProjectionCandidate(idx) => {
let obligations = self.confirm_projection_candidate(obligation, idx)?; let obligations = self.confirm_projection_candidate(obligation, idx)?;
// FIXME(jschievink): constness // FIXME(jschievink): constness
Ok(ImplSource::Param(obligations, ty::BoundConstness::NotConst)) ImplSource::Param(obligations, ty::BoundConstness::NotConst)
} }
ObjectCandidate(idx) => { ObjectCandidate(idx) => {
let data = self.confirm_object_candidate(obligation, idx)?; let data = self.confirm_object_candidate(obligation, idx)?;
Ok(ImplSource::Object(data)) ImplSource::Object(data)
} }
ClosureCandidate => { ClosureCandidate => {
let vtable_closure = self.confirm_closure_candidate(obligation)?; let vtable_closure = self.confirm_closure_candidate(obligation)?;
Ok(ImplSource::Closure(vtable_closure)) ImplSource::Closure(vtable_closure)
} }
GeneratorCandidate => { GeneratorCandidate => {
let vtable_generator = self.confirm_generator_candidate(obligation)?; let vtable_generator = self.confirm_generator_candidate(obligation)?;
Ok(ImplSource::Generator(vtable_generator)) ImplSource::Generator(vtable_generator)
} }
FnPointerCandidate { .. } => { FnPointerCandidate { .. } => {
let data = self.confirm_fn_pointer_candidate(obligation)?; let data = self.confirm_fn_pointer_candidate(obligation)?;
Ok(ImplSource::FnPointer(data)) ImplSource::FnPointer(data)
} }
DiscriminantKindCandidate => { DiscriminantKindCandidate => {
Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)) ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
} }
PointeeCandidate => Ok(ImplSource::Pointee(ImplSourcePointeeData)), PointeeCandidate => ImplSource::Pointee(ImplSourcePointeeData),
TraitAliasCandidate(alias_def_id) => { TraitAliasCandidate(alias_def_id) => {
let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
Ok(ImplSource::TraitAlias(data)) ImplSource::TraitAlias(data)
} }
BuiltinObjectCandidate => { BuiltinObjectCandidate => {
// This indicates something like `Trait + Send: Send`. In this case, we know that // This indicates something like `Trait + Send: Send`. In this case, we know that
// this holds because that's what the object type is telling us, and there's really // this holds because that's what the object type is telling us, and there's really
// no additional obligations to prove and no types in particular to unify, etc. // no additional obligations to prove and no types in particular to unify, etc.
Ok(ImplSource::Param(Vec::new(), ty::BoundConstness::NotConst)) ImplSource::Param(Vec::new(), ty::BoundConstness::NotConst)
} }
BuiltinUnsizeCandidate => { BuiltinUnsizeCandidate => {
let data = self.confirm_builtin_unsize_candidate(obligation)?; let data = self.confirm_builtin_unsize_candidate(obligation)?;
Ok(ImplSource::Builtin(data)) ImplSource::Builtin(data)
} }
TraitUpcastingUnsizeCandidate(idx) => { TraitUpcastingUnsizeCandidate(idx) => {
let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?; let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
Ok(ImplSource::TraitUpcasting(data)) ImplSource::TraitUpcasting(data)
} }
ConstDestructCandidate(def_id) => { ConstDestructCandidate(def_id) => {
let data = self.confirm_const_destruct_candidate(obligation, def_id)?; let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
Ok(ImplSource::ConstDestruct(data)) ImplSource::ConstDestruct(data)
} }
};
if !obligation.predicate.is_const_if_const() {
// normalize nested predicates according to parent predicate's constness.
impl_src = impl_src.map(|mut o| {
o.predicate = o.predicate.without_const(self.tcx());
o
});
} }
Ok(impl_src)
} }
fn confirm_projection_candidate( fn confirm_projection_candidate(

View File

@ -182,9 +182,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::PredicateKind::Projection(proj_predicate) => self ty::PredicateKind::Projection(proj_predicate) => self
.deduce_sig_from_projection( .deduce_sig_from_projection(
Some(span.0), Some(span.0),
pred.0.kind().rebind( pred.0
pred.map_bound(|_| proj_predicate).subst(self.tcx, substs), .kind()
), .rebind(pred.rebind(proj_predicate).subst(self.tcx, substs)),
), ),
_ => None, _ => None,
}); });

View File

@ -4,7 +4,6 @@ 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,20 +8,6 @@ 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[E0277]: the size for values of type `[u8]` cannot be known at compilation time error: aborting due to previous error
--> $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`.