about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDeadbeef <ent3rm4n@gmail.com>2022-07-20 17:33:45 +0000
committerDeadbeef <ent3rm4n@gmail.com>2022-07-20 17:33:45 +0000
commit8464396a19da9cbba15a815eaa7448a2fc3b5fa8 (patch)
treecdf72a9d6a7c0508adbb8d9b390a56c1cd5a2e52
parentd695a497bbf4b20d2580b75075faa80230d41667 (diff)
downloadrust-8464396a19da9cbba15a815eaa7448a2fc3b5fa8.tar.gz
rust-8464396a19da9cbba15a815eaa7448a2fc3b5fa8.zip
Fix hack that remaps env constness.
WARNING: might have perf implications.

Are there any more problems with having a constness
in the `ParamEnv` now? :)
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs73
-rw-r--r--src/test/ui/unsized/issue-30355.rs1
-rw-r--r--src/test/ui/unsized/issue-30355.stderr16
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 @@ impl<'tcx> Predicate<'tcx> {
 
         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<StableHashingContext<'a>> 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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         candidate: SelectionCandidate<'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.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 @@ pub static Y: &'static X = {
     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`.