about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-11-30 16:56:53 +0100
committerGitHub <noreply@github.com>2019-11-30 16:56:53 +0100
commitc85f63561e1224cec657bcf1a51d78e762f628e5 (patch)
treea63e7c6c4771453357959ba49d3d466e978319af /src
parent472bee260e9a748721691dd6e5e7c0e4ca71aae0 (diff)
parent584ede5f3034af8b1b64518385e201de4942637c (diff)
downloadrust-c85f63561e1224cec657bcf1a51d78e762f628e5.tar.gz
rust-c85f63561e1224cec657bcf1a51d78e762f628e5.zip
Rollup merge of #66883 - eddyb:we-cant-have-nice-things, r=oli-obk
rustc_typeck: gate AnonConst's generics on feature(const_generics).

This PR employs the fix for #43408 when `#![feature(const_generics)]` is enabled, making the feature-gate the opt-in for all the possible breakage this may incur.

For example, if this PR lands, this will cause a cycle error (due to #60471):
```rust
#![feature(const_generics)]

fn foo<T: Into<[u8; 4]>>() {}
```
And so will anything with type-level const expressions, in its bounds.
Surprisingly, `impl`s don't seem to be affected (if they were, even libcore wouldn't compile).

One thing I'm worried about is not knowing how much unstable code out there, using const-generics, will be broken. But types like `Foo<{N+1}>` never really worked, and do after this PR, just not in bounds - so ironically, it's type-level const expressions that don't depend on generics, which will break (in bounds).

Also, if we do this, we'll have effectively blocked stabilization of const generics on #60471.

r? @oli-obk cc @varkor @yodaldevoid @nikomatsakis
Diffstat (limited to 'src')
-rw-r--r--src/librustc/ty/sty.rs49
-rw-r--r--src/librustc_typeck/collect.rs14
2 files changed, 41 insertions, 22 deletions
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index b72468a6ff9..aa5b1c7315a 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -2330,22 +2330,43 @@ impl<'tcx> Const<'tcx> {
         tcx: TyCtxt<'tcx>,
         param_env: ParamEnv<'tcx>,
     ) -> &Const<'tcx> {
-        // FIXME(const_generics): this doesn't work right now,
-        // because it tries to relate an `Infer` to a `Param`.
+        let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs| {
+            let param_env_and_substs = param_env.with_reveal_all().and(substs);
+
+            // Avoid querying `tcx.const_eval(...)` with any e.g. inference vars.
+            if param_env_and_substs.has_local_value() {
+                return None;
+            }
+
+            let (param_env, substs) = param_env_and_substs.into_parts();
+
+            // try to resolve e.g. associated constants to their definition on an impl
+            let instance = ty::Instance::resolve(tcx, param_env, did, substs)?;
+            let gid = GlobalId {
+                instance,
+                promoted: None,
+            };
+            tcx.const_eval(param_env.and(gid)).ok()
+        };
+
         match self.val {
             ConstKind::Unevaluated(did, substs) => {
-                // if `substs` has no unresolved components, use and empty param_env
-                let (param_env, substs) = param_env.with_reveal_all().and(substs).into_parts();
-                // try to resolve e.g. associated constants to their definition on an impl
-                let instance = match ty::Instance::resolve(tcx, param_env, did, substs) {
-                    Some(instance) => instance,
-                    None => return self,
-                };
-                let gid = GlobalId {
-                    instance,
-                    promoted: None,
-                };
-                tcx.const_eval(param_env.and(gid)).unwrap_or(self)
+                // HACK(eddyb) when substs contain e.g. inference variables,
+                // attempt using identity substs instead, that will succeed
+                // when the expression doesn't depend on any parameters.
+                // FIXME(eddyb) make `const_eval` a canonical query instead,
+                // that would properly handle inference variables in `substs`.
+                if substs.has_local_value() {
+                    let identity_substs = InternalSubsts::identity_for_item(tcx, did);
+                    // The `ParamEnv` needs to match the `identity_substs`.
+                    let identity_param_env = tcx.param_env(did);
+                    match try_const_eval(did, identity_param_env, identity_substs) {
+                        Some(ct) => ct.subst(tcx, substs),
+                        None => self,
+                    }
+                } else {
+                    try_const_eval(did, param_env, substs).unwrap_or(self)
+                }
             },
             _ => self,
         }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 652f081e176..301b0ff3503 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -909,14 +909,12 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
             let parent_id = tcx.hir().get_parent_item(hir_id);
             Some(tcx.hir().local_def_id(parent_id))
         }
-        // FIXME(#43408) enable this in all cases when we get lazy normalization.
-        Node::AnonConst(&anon_const) => {
-            // HACK(eddyb) this provides the correct generics when the workaround
-            // for a const parameter `AnonConst` is being used elsewhere, as then
-            // there won't be the kind of cyclic dependency blocking #43408.
-            let expr = &tcx.hir().body(anon_const.body).value;
-            let icx = ItemCtxt::new(tcx, def_id);
-            if AstConv::const_param_def_id(&icx, expr).is_some() {
+        // FIXME(#43408) enable this always when we get lazy normalization.
+        Node::AnonConst(_) => {
+            // HACK(eddyb) this provides the correct generics when
+            // `feature(const_generics)` is enabled, so that const expressions
+            // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
+            if tcx.features().const_generics {
                 let parent_id = tcx.hir().get_parent_item(hir_id);
                 Some(tcx.hir().local_def_id(parent_id))
             } else {