diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-11-30 16:56:53 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-11-30 16:56:53 +0100 |
| commit | c85f63561e1224cec657bcf1a51d78e762f628e5 (patch) | |
| tree | a63e7c6c4771453357959ba49d3d466e978319af /src | |
| parent | 472bee260e9a748721691dd6e5e7c0e4ca71aae0 (diff) | |
| parent | 584ede5f3034af8b1b64518385e201de4942637c (diff) | |
| download | rust-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.rs | 49 | ||||
| -rw-r--r-- | src/librustc_typeck/collect.rs | 14 |
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 { |
