From 8464396a19da9cbba15a815eaa7448a2fc3b5fa8 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 20 Jul 2022 17:33:45 +0000 Subject: [PATCH 1/2] Fix hack that remaps env constness. WARNING: might have perf implications. Are there any more problems with having a constness in the `ParamEnv` now? :) --- compiler/rustc_middle/src/ty/mod.rs | 13 ++++ .../src/traits/select/confirmation.rs | 73 +++++++------------ src/test/ui/unsized/issue-30355.rs | 1 - src/test/ui/unsized/issue-30355.stderr | 16 +--- 4 files changed, 41 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 3536d946db2..893700ca5d8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -575,6 +575,19 @@ pub fn flip_polarity(self, tcx: TyCtxt<'tcx>) -> Option> { 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().map_bound(|_| PredicateKind::Trait(TraitPredicate { + trait_ref, + constness: BoundConstness::NotConst, + polarity, + }))); + } + self + } } impl<'a, 'tcx> HashStable> for Predicate<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index da8ca6e5749..d4c9fd1c5f9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -42,115 +42,96 @@ pub(super) fn confirm_candidate( obligation: &TraitObligation<'tcx>, candidate: SelectionCandidate<'tcx>, ) -> Result, 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 const Super for &A where A: ~const Super {} - // impl 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 { + let mut impl_src = match candidate { BuiltinCandidate { has_nested } => { let data = self.confirm_builtin_candidate(obligation, has_nested); - Ok(ImplSource::Builtin(data)) + ImplSource::Builtin(data) } ParamCandidate(param) => { let obligations = 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) => { - 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) => { let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); - Ok(ImplSource::AutoImpl(data)) + ImplSource::AutoImpl(data) } ProjectionCandidate(idx) => { let obligations = self.confirm_projection_candidate(obligation, idx)?; // FIXME(jschievink): constness - Ok(ImplSource::Param(obligations, ty::BoundConstness::NotConst)) + ImplSource::Param(obligations, ty::BoundConstness::NotConst) } ObjectCandidate(idx) => { let data = self.confirm_object_candidate(obligation, idx)?; - Ok(ImplSource::Object(data)) + ImplSource::Object(data) } ClosureCandidate => { let vtable_closure = self.confirm_closure_candidate(obligation)?; - Ok(ImplSource::Closure(vtable_closure)) + ImplSource::Closure(vtable_closure) } GeneratorCandidate => { let vtable_generator = self.confirm_generator_candidate(obligation)?; - Ok(ImplSource::Generator(vtable_generator)) + ImplSource::Generator(vtable_generator) } FnPointerCandidate { .. } => { let data = self.confirm_fn_pointer_candidate(obligation)?; - Ok(ImplSource::FnPointer(data)) + ImplSource::FnPointer(data) } DiscriminantKindCandidate => { - Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)) + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) } - PointeeCandidate => Ok(ImplSource::Pointee(ImplSourcePointeeData)), + PointeeCandidate => ImplSource::Pointee(ImplSourcePointeeData), TraitAliasCandidate(alias_def_id) => { let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); - Ok(ImplSource::TraitAlias(data)) + ImplSource::TraitAlias(data) } BuiltinObjectCandidate => { // 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 // 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 => { let data = self.confirm_builtin_unsize_candidate(obligation)?; - Ok(ImplSource::Builtin(data)) + ImplSource::Builtin(data) } TraitUpcastingUnsizeCandidate(idx) => { let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?; - Ok(ImplSource::TraitUpcasting(data)) + ImplSource::TraitUpcasting(data) } ConstDestructCandidate(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( diff --git a/src/test/ui/unsized/issue-30355.rs b/src/test/ui/unsized/issue-30355.rs index 01811090503..6ff5b37f6e5 100644 --- a/src/test/ui/unsized/issue-30355.rs +++ b/src/test/ui/unsized/issue-30355.rs @@ -4,7 +4,6 @@ const Y: &'static [u8] = b""; &X(*Y) //~^ ERROR E0277 - //~| ERROR E0277 }; fn main() {} diff --git a/src/test/ui/unsized/issue-30355.stderr b/src/test/ui/unsized/issue-30355.stderr index 62b6007a15a..71bbdf5dec7 100644 --- a/src/test/ui/unsized/issue-30355.stderr +++ b/src/test/ui/unsized/issue-30355.stderr @@ -8,20 +8,6 @@ LL | &X(*Y) = note: all function arguments must have a statically known size = 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 - --> $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 +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. From a0ebb2ed8b59e8eec9add6acda0673dcf468596f Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 21 Jul 2022 07:45:49 +0000 Subject: [PATCH 2/2] change `map_bound(|_| x` to `rebind(x` --- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_trait_selection/src/traits/relationships.rs | 4 ++-- compiler/rustc_typeck/src/check/closure.rs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 893700ca5d8..12da0b8b3d8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -580,7 +580,7 @@ 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().map_bound(|_| PredicateKind::Trait(TraitPredicate { + self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Trait(TraitPredicate { trait_ref, constness: BoundConstness::NotConst, polarity, diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs index 56bdeafeeca..8148e2b7871 100644 --- a/compiler/rustc_trait_selection/src/traits/relationships.rs +++ b/compiler/rustc_trait_selection/src/traits/relationships.rs @@ -31,14 +31,14 @@ pub(crate) fn update<'tcx, T>( obligation .predicate .kind() - .map_bound(|_| { + .rebind( // (*) binder moved here ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: tpred.constness, polarity: tpred.polarity, }) - }) + ) .to_predicate(infcx.tcx), ); // Don't report overflow errors. Otherwise equivalent to may_hold. diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 1681e6af812..2005fc24ed0 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -182,9 +182,9 @@ fn deduce_expectations_from_expected_type( ty::PredicateKind::Projection(proj_predicate) => self .deduce_sig_from_projection( Some(span.0), - pred.0.kind().rebind( - pred.map_bound(|_| proj_predicate).subst(self.tcx, substs), - ), + pred.0 + .kind() + .rebind(pred.rebind(proj_predicate).subst(self.tcx, substs)), ), _ => None, });