diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index b72468a6ff98b..aa5b1c7315a4b 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 652f081e1761c..301b0ff350302 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 {