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
This commit is contained in:
commit
c85f63561e
@ -2330,22 +2330,43 @@ pub fn eval(
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ParamEnv<'tcx>,
|
param_env: ParamEnv<'tcx>,
|
||||||
) -> &Const<'tcx> {
|
) -> &Const<'tcx> {
|
||||||
// FIXME(const_generics): this doesn't work right now,
|
let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs| {
|
||||||
// because it tries to relate an `Infer` to a `Param`.
|
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 {
|
match self.val {
|
||||||
ConstKind::Unevaluated(did, substs) => {
|
ConstKind::Unevaluated(did, substs) => {
|
||||||
// if `substs` has no unresolved components, use and empty param_env
|
// HACK(eddyb) when substs contain e.g. inference variables,
|
||||||
let (param_env, substs) = param_env.with_reveal_all().and(substs).into_parts();
|
// attempt using identity substs instead, that will succeed
|
||||||
// try to resolve e.g. associated constants to their definition on an impl
|
// when the expression doesn't depend on any parameters.
|
||||||
let instance = match ty::Instance::resolve(tcx, param_env, did, substs) {
|
// FIXME(eddyb) make `const_eval` a canonical query instead,
|
||||||
Some(instance) => instance,
|
// that would properly handle inference variables in `substs`.
|
||||||
None => return self,
|
if substs.has_local_value() {
|
||||||
};
|
let identity_substs = InternalSubsts::identity_for_item(tcx, did);
|
||||||
let gid = GlobalId {
|
// The `ParamEnv` needs to match the `identity_substs`.
|
||||||
instance,
|
let identity_param_env = tcx.param_env(did);
|
||||||
promoted: None,
|
match try_const_eval(did, identity_param_env, identity_substs) {
|
||||||
};
|
Some(ct) => ct.subst(tcx, substs),
|
||||||
tcx.const_eval(param_env.and(gid)).unwrap_or(self)
|
None => self,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try_const_eval(did, param_env, substs).unwrap_or(self)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
|
@ -909,14 +909,12 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
|
|||||||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||||
Some(tcx.hir().local_def_id(parent_id))
|
Some(tcx.hir().local_def_id(parent_id))
|
||||||
}
|
}
|
||||||
// FIXME(#43408) enable this in all cases when we get lazy normalization.
|
// FIXME(#43408) enable this always when we get lazy normalization.
|
||||||
Node::AnonConst(&anon_const) => {
|
Node::AnonConst(_) => {
|
||||||
// HACK(eddyb) this provides the correct generics when the workaround
|
// HACK(eddyb) this provides the correct generics when
|
||||||
// for a const parameter `AnonConst` is being used elsewhere, as then
|
// `feature(const_generics)` is enabled, so that const expressions
|
||||||
// there won't be the kind of cyclic dependency blocking #43408.
|
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
|
||||||
let expr = &tcx.hir().body(anon_const.body).value;
|
if tcx.features().const_generics {
|
||||||
let icx = ItemCtxt::new(tcx, def_id);
|
|
||||||
if AstConv::const_param_def_id(&icx, expr).is_some() {
|
|
||||||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||||
Some(tcx.hir().local_def_id(parent_id))
|
Some(tcx.hir().local_def_id(parent_id))
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user