Implement MVP for opaque generic const arguments
This is meant to be the interim successor to generic const expressions. Essentially, const item RHS's will be allowed to do arbitrary const operations using generics. The limitation is that these const items will be treated opaquely, like ADTs in nominal typing, such that uses of them will only be equal if the same const item is referenced. In other words, two const items with the exact same RHS will not be considered equal. I also added some logic to check feature gates that depend on others being enabled (like oGCA depending on mGCA). = Coherence = During coherence, OGCA consts should be normalized ambiguously because they are opaque but eventually resolved to a real value. We don't want two OGCAs that have the same value to be treated as distinct for coherence purposes. (Just like opaque types.) This actually doesn't work yet because there are pre-existing fundamental issues with equate relations involving consts that need to be normalized. The problem is that we normalize only one layer of the const item and don't actually process the resulting anon const. Normally the created inference variable should be handled, which in this case would cause us to hit the anon const, but that's not happening. Specifically, `visit_const` on `Generalizer` should be updated to be similar to `visit_ty`.
This commit is contained in:
parent
c7f5f3e0d5
commit
9a30ec8149
48 changed files with 347 additions and 53 deletions
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
use std::cell::Cell;
|
||||
use std::iter;
|
||||
use std::ops::Bound;
|
||||
use std::ops::{Bound, ControlFlow};
|
||||
|
||||
use rustc_abi::{ExternAbi, Size};
|
||||
use rustc_ast::Recovered;
|
||||
|
|
@ -26,12 +26,13 @@ use rustc_errors::{
|
|||
Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey, struct_span_code_err,
|
||||
};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt};
|
||||
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
|
||||
use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgKind, find_attr};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
||||
use rustc_middle::ty::{
|
||||
|
|
@ -1511,6 +1512,20 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin
|
|||
let parent_hir_node = tcx.hir_node(tcx.parent_hir_id(const_arg_id));
|
||||
if tcx.features().generic_const_exprs() {
|
||||
ty::AnonConstKind::GCE
|
||||
} else if tcx.features().opaque_generic_const_args() {
|
||||
// Only anon consts that are the RHS of a const item can be OGCA.
|
||||
// Note: We can't just check tcx.parent because it needs to be EXACTLY
|
||||
// the RHS, not just part of the RHS.
|
||||
if !is_anon_const_rhs_of_const_item(tcx, def) {
|
||||
return ty::AnonConstKind::MCG;
|
||||
}
|
||||
|
||||
let body = tcx.hir_body_owned_by(def);
|
||||
let mut visitor = OGCAParamVisitor(tcx);
|
||||
match visitor.visit_body(body) {
|
||||
ControlFlow::Break(UsesParam) => ty::AnonConstKind::OGCA,
|
||||
ControlFlow::Continue(()) => ty::AnonConstKind::MCG,
|
||||
}
|
||||
} else if tcx.features().min_generic_const_args() {
|
||||
ty::AnonConstKind::MCG
|
||||
} else if let hir::Node::Expr(hir::Expr {
|
||||
|
|
@ -1528,6 +1543,49 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin
|
|||
}
|
||||
}
|
||||
|
||||
fn is_anon_const_rhs_of_const_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
|
||||
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||
let Some((_, grandparent_node)) = tcx.hir_parent_iter(hir_id).nth(1) else { return false };
|
||||
let (Node::Item(hir::Item { kind: hir::ItemKind::Const(_, _, _, ct_rhs), .. })
|
||||
| Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(_, ct_rhs), .. })
|
||||
| Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Const(_, Some(ct_rhs)), ..
|
||||
})) = grandparent_node
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
let hir::ConstItemRhs::TypeConst(hir::ConstArg {
|
||||
kind: hir::ConstArgKind::Anon(rhs_anon), ..
|
||||
}) = ct_rhs
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
def_id == rhs_anon.def_id
|
||||
}
|
||||
|
||||
struct OGCAParamVisitor<'tcx>(TyCtxt<'tcx>);
|
||||
|
||||
struct UsesParam;
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for OGCAParamVisitor<'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
type Result = ControlFlow<UsesParam>;
|
||||
|
||||
fn maybe_tcx(&mut self) -> TyCtxt<'tcx> {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: HirId) -> ControlFlow<UsesParam> {
|
||||
if let Res::Def(DefKind::TyParam | DefKind::ConstParam | DefKind::LifetimeParam, _) =
|
||||
path.res
|
||||
{
|
||||
return ControlFlow::Break(UsesParam);
|
||||
}
|
||||
|
||||
intravisit::walk_path(self, path)
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(tcx), ret)]
|
||||
fn const_of_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
match tcx.anon_const_kind(def_id) {
|
||||
// Stable: anon consts are not able to use any generic parameters...
|
||||
ty::AnonConstKind::MCG => None,
|
||||
// OGCA anon consts inherit their parent's generics.
|
||||
ty::AnonConstKind::OGCA => Some(parent_did),
|
||||
// we provide generics to repeat expr counts as a backwards compatibility hack. #76200
|
||||
ty::AnonConstKind::RepeatExprCount => Some(parent_did),
|
||||
|
||||
|
|
|
|||
|
|
@ -404,6 +404,11 @@ impl<'tcx> ForbidMCGParamUsesFolder<'tcx> {
|
|||
diag.span_note(impl_.self_ty.span, "not a concrete type");
|
||||
}
|
||||
}
|
||||
if self.tcx.features().min_generic_const_args()
|
||||
&& !self.tcx.features().opaque_generic_const_args()
|
||||
{
|
||||
diag.help("add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items");
|
||||
}
|
||||
diag.emit()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue