mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Rollup merge of #131081 - camelid:const-path-it-all, r=BoxyUwU
Use `ConstArgKind::Path` for all single-segment paths, not just params under `min_generic_const_args` r? `@BoxyUwU` edit by `@BoxyUwU:` This PR introduces a `min_generic_const_args` feature gate and implements some preliminary work for it, representing all const arguments that are single segment paths as `ConstArg::Path` instead of only those that resolve to a const generic parameter. There are a few bits of follow up work after this lands: - Figure out how to represent `Foo<{ STATIC }>` - Figure out how to evaluate `Foo<{ EnumVariantConstructor }>` - Make param env normalization handle non-anon-consts - Move `try_from_lit` and `from_anon_const` to hir ty lowering too
This commit is contained in:
commit
5f586efd3e
@ -2052,6 +2052,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Used when lowering a type argument that turned out to actually be a const argument.
|
||||
///
|
||||
/// Only use for that purpose since otherwise it will create a duplicate def.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_const_path_to_const_arg(
|
||||
&mut self,
|
||||
@ -2060,51 +2063,58 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
ty_id: NodeId,
|
||||
span: Span,
|
||||
) -> &'hir hir::ConstArg<'hir> {
|
||||
let ct_kind = match res {
|
||||
Res::Def(DefKind::ConstParam, _) => {
|
||||
let qpath = self.lower_qpath(
|
||||
ty_id,
|
||||
&None,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
hir::ConstArgKind::Path(qpath)
|
||||
}
|
||||
_ => {
|
||||
// Construct an AnonConst where the expr is the "ty"'s path.
|
||||
let tcx = self.tcx;
|
||||
|
||||
let parent_def_id = self.current_def_id_parent;
|
||||
let node_id = self.next_node_id();
|
||||
let span = self.lower_span(span);
|
||||
// FIXME(min_generic_const_args): we only allow one-segment const paths for now
|
||||
let ct_kind = if path.is_potential_trivial_const_arg()
|
||||
&& (tcx.features().min_generic_const_args()
|
||||
|| matches!(res, Res::Def(DefKind::ConstParam, _)))
|
||||
{
|
||||
let qpath = self.lower_qpath(
|
||||
ty_id,
|
||||
&None,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
// FIXME(min_generic_const_args): update for `fn foo() -> Bar<FOO<impl Trait>>` support
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
hir::ConstArgKind::Path(qpath)
|
||||
} else {
|
||||
// Construct an AnonConst where the expr is the "ty"'s path.
|
||||
|
||||
// Add a definition for the in-band const def.
|
||||
let def_id =
|
||||
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span);
|
||||
let hir_id = self.lower_node_id(node_id);
|
||||
let parent_def_id = self.current_def_id_parent;
|
||||
let node_id = self.next_node_id();
|
||||
let span = self.lower_span(span);
|
||||
|
||||
let path_expr = Expr {
|
||||
id: ty_id,
|
||||
kind: ExprKind::Path(None, path.clone()),
|
||||
// Add a definition for the in-band const def.
|
||||
// We're lowering a const argument that was originally thought to be a type argument,
|
||||
// so the def collector didn't create the def ahead of time. That's why we have to do
|
||||
// it here.
|
||||
let def_id =
|
||||
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span);
|
||||
let hir_id = self.lower_node_id(node_id);
|
||||
|
||||
let path_expr = Expr {
|
||||
id: ty_id,
|
||||
kind: ExprKind::Path(None, path.clone()),
|
||||
span,
|
||||
attrs: AttrVec::new(),
|
||||
tokens: None,
|
||||
};
|
||||
|
||||
let ct = self.with_new_scopes(span, |this| {
|
||||
self.arena.alloc(hir::AnonConst {
|
||||
def_id,
|
||||
hir_id,
|
||||
body: this.with_def_id_parent(def_id, |this| {
|
||||
this.lower_const_body(path_expr.span, Some(&path_expr))
|
||||
}),
|
||||
span,
|
||||
attrs: AttrVec::new(),
|
||||
tokens: None,
|
||||
};
|
||||
|
||||
let ct = self.with_new_scopes(span, |this| {
|
||||
self.arena.alloc(hir::AnonConst {
|
||||
def_id,
|
||||
hir_id,
|
||||
body: this.with_def_id_parent(def_id, |this| {
|
||||
this.lower_const_body(path_expr.span, Some(&path_expr))
|
||||
}),
|
||||
span,
|
||||
})
|
||||
});
|
||||
hir::ConstArgKind::Anon(ct)
|
||||
}
|
||||
})
|
||||
});
|
||||
hir::ConstArgKind::Anon(ct)
|
||||
};
|
||||
|
||||
self.arena.alloc(hir::ConstArg {
|
||||
@ -2122,6 +2132,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
|
||||
let tcx = self.tcx;
|
||||
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
|
||||
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
|
||||
let expr = if let ExprKind::Block(block, _) = &anon.value.kind
|
||||
@ -2135,18 +2146,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
};
|
||||
let maybe_res =
|
||||
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
|
||||
debug!("res={:?}", maybe_res);
|
||||
// FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path
|
||||
if let Some(res) = maybe_res
|
||||
&& let Res::Def(DefKind::ConstParam, _) = res
|
||||
&& let ExprKind::Path(qself, path) = &expr.kind
|
||||
// FIXME(min_generic_const_args): we only allow one-segment const paths for now
|
||||
if let ExprKind::Path(None, path) = &expr.kind
|
||||
&& path.is_potential_trivial_const_arg()
|
||||
&& (tcx.features().min_generic_const_args()
|
||||
|| matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))))
|
||||
{
|
||||
let qpath = self.lower_qpath(
|
||||
expr.id,
|
||||
qself,
|
||||
&None,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
// FIXME(min_generic_const_args): update for `fn foo() -> Bar<FOO<impl Trait>>` support
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
@ -529,6 +529,8 @@ declare_features! (
|
||||
(unstable, macro_metavar_expr_concat, "1.81.0", Some(124225)),
|
||||
/// Allows `#[marker]` on certain traits allowing overlapping implementations.
|
||||
(unstable, marker_trait_attr, "1.30.0", Some(29864)),
|
||||
/// Enables the generic const args MVP (only bare paths, not arbitrary computation).
|
||||
(incomplete, min_generic_const_args, "CURRENT_RUSTC_VERSION", Some(132980)),
|
||||
/// A minimal, sound subset of specialization intended to be used by the
|
||||
/// standard library until the soundness issues with specialization
|
||||
/// are fixed.
|
||||
|
@ -46,7 +46,7 @@ use tracing::{debug, instrument};
|
||||
|
||||
use crate::check::intrinsic::intrinsic_operation_unsafety;
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
|
||||
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
|
||||
|
||||
pub(crate) mod dump;
|
||||
mod generics_of;
|
||||
@ -88,6 +88,7 @@ pub fn provide(providers: &mut Providers) {
|
||||
coroutine_for_closure,
|
||||
opaque_ty_origin,
|
||||
rendered_precise_capturing_args,
|
||||
const_param_default,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
@ -1790,3 +1791,23 @@ fn rendered_precise_capturing_args<'tcx>(
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
fn const_param_default<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
|
||||
let default_ct = match tcx.hir_node_by_def_id(def_id) {
|
||||
hir::Node::GenericParam(hir::GenericParam {
|
||||
kind: hir::GenericParamKind::Const { default: Some(ct), .. },
|
||||
..
|
||||
}) => ct,
|
||||
_ => span_bug!(
|
||||
tcx.def_span(def_id),
|
||||
"`const_param_default` expected a generic parameter with a constant"
|
||||
),
|
||||
};
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
// FIXME(const_generics): investigate which places do and don't need const ty feeding
|
||||
let ct = icx.lowerer().lower_const_arg(default_ct, FeedConstTy::No);
|
||||
ty::EarlyBinder::bind(ct)
|
||||
}
|
||||
|
@ -223,11 +223,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
trace!(?predicates);
|
||||
}
|
||||
hir::GenericParamKind::Const { .. } => {
|
||||
let param_def_id = param.def_id.to_def_id();
|
||||
let ct_ty = tcx
|
||||
.type_of(param.def_id.to_def_id())
|
||||
.type_of(param_def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameters cannot be generic");
|
||||
let ct = icx.lowerer().lower_const_param(param.hir_id);
|
||||
let ct = icx.lowerer().lower_const_param(param_def_id, param.hir_id);
|
||||
predicates
|
||||
.insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span));
|
||||
}
|
||||
|
@ -19,7 +19,9 @@ use tracing::{debug, instrument};
|
||||
use super::errors::GenericsArgsErrExtend;
|
||||
use crate::bounds::Bounds;
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer, PredicateFilter, RegionInferReason};
|
||||
use crate::hir_ty_lowering::{
|
||||
AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason,
|
||||
};
|
||||
|
||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
/// Add a `Sized` bound to the `bounds` if appropriate.
|
||||
@ -346,9 +348,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
hir::AssocItemConstraintKind::Equality { term } => {
|
||||
let term = match term {
|
||||
hir::Term::Ty(ty) => self.lower_ty(ty).into(),
|
||||
hir::Term::Const(ct) => {
|
||||
ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No).into()
|
||||
}
|
||||
hir::Term::Const(ct) => self.lower_const_arg(ct, FeedConstTy::No).into(),
|
||||
};
|
||||
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
|
@ -115,17 +115,22 @@ fn generic_arg_mismatch_err(
|
||||
}
|
||||
}
|
||||
(GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => {
|
||||
// FIXME(min_generic_const_args): once ConstArgKind::Path is used for non-params too,
|
||||
// this should match against that instead of ::Anon
|
||||
if let hir::ConstArgKind::Anon(anon) = cnst.kind
|
||||
if let hir::ConstArgKind::Path(qpath) = cnst.kind
|
||||
&& let rustc_hir::QPath::Resolved(_, path) = qpath
|
||||
&& let Res::Def(DefKind::Fn { .. }, id) = path.res
|
||||
{
|
||||
err.help(format!("`{}` is a function item, not a type", tcx.item_name(id)));
|
||||
err.help("function item types cannot be named directly");
|
||||
} else if let hir::ConstArgKind::Anon(anon) = cnst.kind
|
||||
&& let body = tcx.hir().body(anon.body)
|
||||
&& let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) =
|
||||
body.value.kind
|
||||
&& let Res::Def(DefKind::Fn { .. }, id) = path.res
|
||||
{
|
||||
if let Res::Def(DefKind::Fn { .. }, id) = path.res {
|
||||
err.help(format!("`{}` is a function item, not a type", tcx.item_name(id)));
|
||||
err.help("function item types cannot be named directly");
|
||||
}
|
||||
// FIXME(min_generic_const_args): this branch is dead once new const path lowering
|
||||
// (for single-segment paths) is no longer gated
|
||||
err.help(format!("`{}` is a function item, not a type", tcx.item_name(id)));
|
||||
err.help("function item types cannot be named directly");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -30,7 +30,7 @@ use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{GenericArg, GenericArgs, HirId};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
@ -217,6 +217,23 @@ impl AssocItemQSelf {
|
||||
}
|
||||
}
|
||||
|
||||
/// In some cases, [`hir::ConstArg`]s that are being used in the type system
|
||||
/// through const generics need to have their type "fed" to them
|
||||
/// using the query system.
|
||||
///
|
||||
/// Use this enum with `<dyn HirTyLowerer>::lower_const_arg` to instruct it with the
|
||||
/// desired behavior.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum FeedConstTy {
|
||||
/// Feed the type.
|
||||
///
|
||||
/// The `DefId` belongs to the const param that we are supplying
|
||||
/// this (anon) const arg to.
|
||||
Param(DefId),
|
||||
/// Don't feed the type.
|
||||
No,
|
||||
}
|
||||
|
||||
/// New-typed boolean indicating whether explicit late-bound lifetimes
|
||||
/// are present in a set of generic arguments.
|
||||
///
|
||||
@ -500,8 +517,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
handle_ty_args(has_default, &inf.to_ty())
|
||||
}
|
||||
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
|
||||
ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::Param(param.def_id))
|
||||
.into()
|
||||
self.lowerer.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into()
|
||||
}
|
||||
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
|
||||
self.lowerer.ct_infer(Some(param), inf.span).into()
|
||||
@ -979,8 +995,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
let term: ty::Term<'_> = match term {
|
||||
hir::Term::Ty(ty) => self.lower_ty(ty).into(),
|
||||
hir::Term::Const(ct) => {
|
||||
ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No)
|
||||
.into()
|
||||
self.lower_const_arg(ct, FeedConstTy::No).into()
|
||||
}
|
||||
};
|
||||
// FIXME(#97583): This isn't syntactically well-formed!
|
||||
@ -2025,23 +2040,138 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
///
|
||||
/// Early-bound const parameters get lowered to [`ty::ConstKind::Param`]
|
||||
/// and late-bound ones to [`ty::ConstKind::Bound`].
|
||||
pub(crate) fn lower_const_param(&self, hir_id: HirId) -> Const<'tcx> {
|
||||
pub(crate) fn lower_const_param(&self, param_def_id: DefId, path_hir_id: HirId) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
match tcx.named_bound_var(hir_id) {
|
||||
Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
|
||||
|
||||
match tcx.named_bound_var(path_hir_id) {
|
||||
Some(rbv::ResolvedArg::EarlyBound(_)) => {
|
||||
// Find the name and index of the const parameter by indexing the generics of
|
||||
// the parent item and construct a `ParamConst`.
|
||||
let item_def_id = tcx.local_parent(def_id);
|
||||
let item_def_id = tcx.parent(param_def_id);
|
||||
let generics = tcx.generics_of(item_def_id);
|
||||
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
|
||||
let name = tcx.item_name(def_id.to_def_id());
|
||||
let index = generics.param_def_id_to_index[¶m_def_id];
|
||||
let name = tcx.item_name(param_def_id);
|
||||
ty::Const::new_param(tcx, ty::ParamConst::new(index, name))
|
||||
}
|
||||
Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
|
||||
ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index))
|
||||
}
|
||||
Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar),
|
||||
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id),
|
||||
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", path_hir_id),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a [`hir::ConstArg`] to a [`ty::Const`](Const).
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn lower_const_arg(
|
||||
&self,
|
||||
const_arg: &hir::ConstArg<'tcx>,
|
||||
feed: FeedConstTy,
|
||||
) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
if let FeedConstTy::Param(param_def_id) = feed
|
||||
&& let hir::ConstArgKind::Anon(anon) = &const_arg.kind
|
||||
{
|
||||
tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id));
|
||||
}
|
||||
|
||||
let hir_id = const_arg.hir_id;
|
||||
match const_arg.kind {
|
||||
hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
|
||||
debug!(?maybe_qself, ?path);
|
||||
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
|
||||
self.lower_const_path_resolved(opt_self_ty, path, hir_id)
|
||||
}
|
||||
hir::ConstArgKind::Path(qpath) => ty::Const::new_error_with_message(
|
||||
tcx,
|
||||
qpath.span(),
|
||||
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
|
||||
),
|
||||
hir::ConstArgKind::Anon(anon) => Const::from_anon_const(tcx, anon.def_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_const_path_resolved(
|
||||
&self,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
path: &hir::Path<'tcx>,
|
||||
hir_id: HirId,
|
||||
) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
let span = path.span;
|
||||
match path.res {
|
||||
Res::Def(DefKind::ConstParam, def_id) => {
|
||||
assert_eq!(opt_self_ty, None);
|
||||
let _ = self.prohibit_generic_args(
|
||||
path.segments.iter(),
|
||||
GenericsArgsErrExtend::Param(def_id),
|
||||
);
|
||||
self.lower_const_param(def_id, hir_id)
|
||||
}
|
||||
Res::Def(DefKind::Const | DefKind::Ctor(_, CtorKind::Const), did) => {
|
||||
assert_eq!(opt_self_ty, None);
|
||||
let _ = self.prohibit_generic_args(
|
||||
path.segments.split_last().unwrap().1.iter(),
|
||||
GenericsArgsErrExtend::None,
|
||||
);
|
||||
let args = self.lower_generic_args_of_path_segment(
|
||||
span,
|
||||
did,
|
||||
path.segments.last().unwrap(),
|
||||
);
|
||||
ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args))
|
||||
}
|
||||
Res::Def(DefKind::Static { .. }, _) => {
|
||||
span_bug!(span, "use of bare `static` ConstArgKind::Path's not yet supported")
|
||||
}
|
||||
// FIXME(const_generics): create real const to allow fn items as const paths
|
||||
Res::Def(DefKind::Fn | DefKind::AssocFn, _) => ty::Const::new_error_with_message(
|
||||
tcx,
|
||||
span,
|
||||
"fn items cannot be used as const args",
|
||||
),
|
||||
|
||||
// Exhaustive match to be clear about what exactly we're considering to be
|
||||
// an invalid Res for a const path.
|
||||
Res::Def(
|
||||
DefKind::Mod
|
||||
| DefKind::Enum
|
||||
| DefKind::Variant
|
||||
| DefKind::Ctor(CtorOf::Variant, CtorKind::Fn)
|
||||
| DefKind::Struct
|
||||
| DefKind::Ctor(CtorOf::Struct, CtorKind::Fn)
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::TyAlias
|
||||
| DefKind::TraitAlias
|
||||
| DefKind::AssocTy
|
||||
| DefKind::Union
|
||||
| DefKind::Trait
|
||||
| DefKind::ForeignTy
|
||||
| DefKind::AssocConst
|
||||
| DefKind::TyParam
|
||||
| DefKind::Macro(_)
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::Use
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::Field
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::Closure
|
||||
| DefKind::ExternCrate
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::SyntheticCoroutineBody,
|
||||
_,
|
||||
)
|
||||
| Res::PrimTy(_)
|
||||
| Res::SelfTyParam { .. }
|
||||
| Res::SelfTyAlias { .. }
|
||||
| Res::SelfCtor(_)
|
||||
| Res::Local(_)
|
||||
| Res::ToolMod
|
||||
| Res::NonMacroAttr(_)
|
||||
| Res::Err => Const::new_error_with_message(tcx, span, "invalid Res for const path"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2053,14 +2183,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower a type from the HIR to our internal notion of a type given some extra data for diagnostics.
|
||||
///
|
||||
/// Extra diagnostic data:
|
||||
///
|
||||
/// 1. `borrowed`: Whether trait object types are borrowed like in `&dyn Trait`.
|
||||
/// Used to avoid emitting redundant errors.
|
||||
/// 2. `in_path`: Whether the type appears inside of a path.
|
||||
/// Used to provide correct diagnostics for bare trait object types.
|
||||
/// Lower a type from the HIR to our internal notion of a type.
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
@ -2189,7 +2312,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
let length = match length {
|
||||
hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
|
||||
hir::ArrayLen::Body(constant) => {
|
||||
ty::Const::from_const_arg(tcx, constant, ty::FeedConstTy::No)
|
||||
self.lower_const_arg(constant, FeedConstTy::No)
|
||||
}
|
||||
};
|
||||
|
||||
@ -2247,7 +2370,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
.type_of(def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic");
|
||||
let ct = self.lower_const_param(expr.hir_id);
|
||||
let ct = self.lower_const_param(def_id, expr.hir_id);
|
||||
(ct, ty)
|
||||
}
|
||||
|
||||
|
@ -97,12 +97,14 @@ use rustc_hir::def::DefKind;
|
||||
use rustc_middle::middle;
|
||||
use rustc_middle::mir::interpret::GlobalId;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
use self::hir_ty_lowering::{FeedConstTy, HirTyLowerer};
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
fn require_c_abi_if_c_variadic(
|
||||
@ -226,3 +228,14 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
||||
let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
|
||||
collect::ItemCtxt::new(tcx, env_def_id.def_id).lower_ty(hir_ty)
|
||||
}
|
||||
|
||||
/// This is for rustdoc.
|
||||
// FIXME(const_generics): having special methods for rustdoc in `rustc_hir_analysis` is cursed
|
||||
pub fn lower_const_arg_for_rustdoc<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
hir_ct: &hir::ConstArg<'tcx>,
|
||||
feed: FeedConstTy,
|
||||
) -> Const<'tcx> {
|
||||
let env_def_id = tcx.hir().get_parent_item(hir_ct.hir_id);
|
||||
collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed)
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{
|
||||
check_generic_arg_count_for_call, lower_generic_args,
|
||||
};
|
||||
use rustc_hir_analysis::hir_ty_lowering::{
|
||||
ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer,
|
||||
GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason,
|
||||
ExplicitLateBound, FeedConstTy, GenericArgCountMismatch, GenericArgCountResult,
|
||||
GenericArgsLowerer, GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason,
|
||||
};
|
||||
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
|
||||
@ -491,7 +491,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
|
||||
hir::ArrayLen::Body(const_arg) => {
|
||||
let span = const_arg.span();
|
||||
let c = ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::No);
|
||||
let c = self.lowerer().lower_const_arg(const_arg, FeedConstTy::No);
|
||||
self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None));
|
||||
self.normalize(span, c)
|
||||
}
|
||||
@ -503,8 +503,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
const_arg: &'tcx hir::ConstArg<'tcx>,
|
||||
param_def_id: DefId,
|
||||
) -> ty::Const<'tcx> {
|
||||
let ct =
|
||||
ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::Param(param_def_id));
|
||||
let ct = self.lowerer().lower_const_arg(const_arg, FeedConstTy::Param(param_def_id));
|
||||
self.register_wf_obligation(
|
||||
ct.into(),
|
||||
self.tcx.hir().span(const_arg.hir_id),
|
||||
|
@ -1,13 +1,14 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_error_messages::MultiSpan;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{self as hir, HirId};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::{self as hir};
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::middle::resolve_bound_vars as rbv;
|
||||
use crate::mir::interpret::{LitToConstInput, Scalar};
|
||||
use crate::ty::{self, GenericArgs, Ty, TyCtxt, TypeVisitableExt};
|
||||
|
||||
@ -142,7 +143,7 @@ impl<'tcx> Const<'tcx> {
|
||||
pub fn new_error_with_message<S: Into<MultiSpan>>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: S,
|
||||
msg: &'static str,
|
||||
msg: impl Into<Cow<'static, str>>,
|
||||
) -> Const<'tcx> {
|
||||
let reported = tcx.dcx().span_delayed_bug(span, msg);
|
||||
Const::new_error(tcx, reported)
|
||||
@ -183,46 +184,8 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// In some cases, [`hir::ConstArg`]s that are being used in the type system
|
||||
/// through const generics need to have their type "fed" to them
|
||||
/// using the query system.
|
||||
///
|
||||
/// Use this enum with [`Const::from_const_arg`] to instruct it with the
|
||||
/// desired behavior.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum FeedConstTy {
|
||||
/// Feed the type.
|
||||
///
|
||||
/// The `DefId` belongs to the const param that we are supplying
|
||||
/// this (anon) const arg to.
|
||||
Param(DefId),
|
||||
/// Don't feed the type.
|
||||
No,
|
||||
}
|
||||
|
||||
impl<'tcx> Const<'tcx> {
|
||||
/// Convert a [`hir::ConstArg`] to a [`ty::Const`](Self).
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
pub fn from_const_arg(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
const_arg: &'tcx hir::ConstArg<'tcx>,
|
||||
feed: FeedConstTy,
|
||||
) -> Self {
|
||||
if let FeedConstTy::Param(param_def_id) = feed
|
||||
&& let hir::ConstArgKind::Anon(anon) = &const_arg.kind
|
||||
{
|
||||
tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id));
|
||||
}
|
||||
|
||||
match const_arg.kind {
|
||||
hir::ConstArgKind::Path(qpath) => {
|
||||
// FIXME(min_generic_const_args): for now only params are lowered to ConstArgKind::Path
|
||||
Self::from_param(tcx, qpath, const_arg.hir_id)
|
||||
}
|
||||
hir::ConstArgKind::Anon(anon) => Self::from_anon_const(tcx, anon.def_id),
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: move this and try_from_lit to hir_ty_lowering like lower_const_arg/from_const_arg
|
||||
/// Literals and const generic parameters are eagerly converted to a constant, everything else
|
||||
/// becomes `Unevaluated`.
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
@ -240,7 +203,7 @@ impl<'tcx> Const<'tcx> {
|
||||
|
||||
let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic");
|
||||
|
||||
match Self::try_from_lit_or_param(tcx, ty, expr) {
|
||||
match Self::try_from_lit(tcx, ty, expr) {
|
||||
Some(v) => v,
|
||||
None => ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst {
|
||||
def: def.to_def_id(),
|
||||
@ -249,40 +212,8 @@ impl<'tcx> Const<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower a const param to a [`Const`].
|
||||
///
|
||||
/// IMPORTANT: `qpath` must be a const param, otherwise this will panic
|
||||
fn from_param(tcx: TyCtxt<'tcx>, qpath: hir::QPath<'tcx>, hir_id: HirId) -> Self {
|
||||
let hir::QPath::Resolved(_, &hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. }) =
|
||||
qpath
|
||||
else {
|
||||
span_bug!(qpath.span(), "non-param {qpath:?} passed to Const::from_param")
|
||||
};
|
||||
|
||||
match tcx.named_bound_var(hir_id) {
|
||||
Some(rbv::ResolvedArg::EarlyBound(_)) => {
|
||||
// Find the name and index of the const parameter by indexing the generics of
|
||||
// the parent item and construct a `ParamConst`.
|
||||
let item_def_id = tcx.parent(def_id);
|
||||
let generics = tcx.generics_of(item_def_id);
|
||||
let index = generics.param_def_id_to_index[&def_id];
|
||||
let name = tcx.item_name(def_id);
|
||||
ty::Const::new_param(tcx, ty::ParamConst::new(index, name))
|
||||
}
|
||||
Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
|
||||
ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index))
|
||||
}
|
||||
Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar),
|
||||
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id),
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
fn try_from_lit_or_param(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
) -> Option<Self> {
|
||||
fn try_from_lit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>) -> Option<Self> {
|
||||
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
|
||||
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
|
||||
let expr = match &expr.kind {
|
||||
@ -321,7 +252,7 @@ impl<'tcx> Const<'tcx> {
|
||||
Err(e) => {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
expr.span,
|
||||
format!("Const::from_anon_const: couldn't lit_to_const {e:?}"),
|
||||
format!("Const::try_from_lit: couldn't lit_to_const {e:?}"),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -414,20 +345,3 @@ impl<'tcx> Const<'tcx> {
|
||||
matches!(self.kind(), ty::ConstKind::Infer(_))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn const_param_default<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
|
||||
let default_ct = match tcx.hir_node_by_def_id(def_id) {
|
||||
hir::Node::GenericParam(hir::GenericParam {
|
||||
kind: hir::GenericParamKind::Const { default: Some(ct), .. },
|
||||
..
|
||||
}) => ct,
|
||||
_ => span_bug!(
|
||||
tcx.def_span(def_id),
|
||||
"`const_param_default` expected a generic parameter with a constant"
|
||||
),
|
||||
};
|
||||
ty::EarlyBinder::bind(Const::from_const_arg(tcx, default_ct, FeedConstTy::No))
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def::{CtorKind, DefKind};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::definitions::Definitions;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
@ -230,7 +230,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
|
||||
DefKind::TyAlias => ty::AliasTermKind::WeakTy,
|
||||
DefKind::AssocConst => ty::AliasTermKind::ProjectionConst,
|
||||
DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst,
|
||||
DefKind::AnonConst | DefKind::Const | DefKind::Ctor(_, CtorKind::Const) => {
|
||||
ty::AliasTermKind::UnevaluatedConst
|
||||
}
|
||||
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ pub use self::closure::{
|
||||
place_to_string_for_capture,
|
||||
};
|
||||
pub use self::consts::{
|
||||
Const, ConstInt, ConstKind, Expr, ExprKind, FeedConstTy, ScalarInt, UnevaluatedConst, ValTree,
|
||||
Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree,
|
||||
};
|
||||
pub use self::context::{
|
||||
CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,
|
||||
@ -2249,7 +2249,6 @@ pub fn provide(providers: &mut Providers) {
|
||||
incoherent_impls: trait_def::incoherent_impls_provider,
|
||||
trait_impls_in_crate: trait_def::trait_impls_in_crate_provider,
|
||||
traits: trait_def::traits_provider,
|
||||
const_param_default: consts::const_param_default,
|
||||
vtable_allocation: vtable::vtable_allocation_provider,
|
||||
..*providers
|
||||
};
|
||||
|
@ -1226,6 +1226,7 @@ symbols! {
|
||||
min_const_generics,
|
||||
min_const_unsafe_fn,
|
||||
min_exhaustive_patterns,
|
||||
min_generic_const_args,
|
||||
min_specialization,
|
||||
min_type_alias_impl_trait,
|
||||
minnumf128,
|
||||
|
@ -42,7 +42,8 @@ use rustc_errors::{FatalError, struct_span_code_err};
|
||||
use rustc_hir::PredicateOrigin;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir_analysis::lower_ty;
|
||||
use rustc_hir_analysis::hir_ty_lowering::FeedConstTy;
|
||||
use rustc_hir_analysis::{lower_const_arg_for_rustdoc, lower_ty};
|
||||
use rustc_middle::metadata::Reexport;
|
||||
use rustc_middle::middle::resolve_bound_vars as rbv;
|
||||
use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
|
||||
@ -435,10 +436,10 @@ fn clean_middle_term<'tcx>(
|
||||
fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term {
|
||||
match term {
|
||||
hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)),
|
||||
hir::Term::Const(c) => Term::Constant(clean_middle_const(
|
||||
ty::Binder::dummy(ty::Const::from_const_arg(cx.tcx, c, ty::FeedConstTy::No)),
|
||||
cx,
|
||||
)),
|
||||
hir::Term::Const(c) => {
|
||||
let ct = lower_const_arg_for_rustdoc(cx.tcx, c, FeedConstTy::No);
|
||||
Term::Constant(clean_middle_const(ty::Binder::dummy(ct), cx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -625,7 +626,7 @@ fn clean_generic_param<'tcx>(
|
||||
(param.name.ident().name, GenericParamDefKind::Const {
|
||||
ty: Box::new(clean_ty(ty, cx)),
|
||||
default: default.map(|ct| {
|
||||
Box::new(ty::Const::from_const_arg(cx.tcx, ct, ty::FeedConstTy::No).to_string())
|
||||
Box::new(lower_const_arg_for_rustdoc(cx.tcx, ct, FeedConstTy::No).to_string())
|
||||
}),
|
||||
synthetic,
|
||||
})
|
||||
@ -1813,7 +1814,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
|
||||
// `const_eval_poly` tries to first substitute generic parameters which
|
||||
// results in an ICE while manually constructing the constant and using `eval`
|
||||
// does nothing for `ConstKind::Param`.
|
||||
let ct = ty::Const::from_const_arg(cx.tcx, const_arg, ty::FeedConstTy::No);
|
||||
let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No);
|
||||
let ct = if let hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) =
|
||||
const_arg.kind
|
||||
{
|
||||
|
17
tests/crashes/132985.rs
Normal file
17
tests/crashes/132985.rs
Normal file
@ -0,0 +1,17 @@
|
||||
//@ known-bug: #132985
|
||||
//@ aux-build:aux132985.rs
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(min_generic_const_args)]
|
||||
#![feature(adt_const_params)]
|
||||
|
||||
extern crate aux132985;
|
||||
use aux132985::Foo;
|
||||
|
||||
fn bar<const N: Foo>() {}
|
||||
|
||||
fn baz() {
|
||||
bar::<{ Foo }>();
|
||||
}
|
||||
|
||||
fn main() {}
|
6
tests/crashes/auxiliary/aux132985.rs
Normal file
6
tests/crashes/auxiliary/aux132985.rs
Normal file
@ -0,0 +1,6 @@
|
||||
#![feature(adt_const_params)]
|
||||
|
||||
use std::marker::ConstParamTy;
|
||||
|
||||
#[derive(Eq, PartialEq, ConstParamTy)]
|
||||
pub struct Foo;
|
6
tests/ui/const-generics/auxiliary/xcrate-const-ctor-a.rs
Normal file
6
tests/ui/const-generics/auxiliary/xcrate-const-ctor-a.rs
Normal file
@ -0,0 +1,6 @@
|
||||
#![feature(adt_const_params)]
|
||||
|
||||
use std::marker::ConstParamTy;
|
||||
|
||||
#[derive(Eq, PartialEq, ConstParamTy)]
|
||||
pub struct Foo;
|
7
tests/ui/const-generics/using-static-as-const-arg.rs
Normal file
7
tests/ui/const-generics/using-static-as-const-arg.rs
Normal file
@ -0,0 +1,7 @@
|
||||
//@ check-pass
|
||||
|
||||
pub static STATIC: u32 = 0;
|
||||
pub struct Foo<const N: u32>;
|
||||
pub const FOO: Foo<{STATIC}> = Foo;
|
||||
|
||||
fn main() {}
|
15
tests/ui/const-generics/xcrate-const-ctor-b.rs
Normal file
15
tests/ui/const-generics/xcrate-const-ctor-b.rs
Normal file
@ -0,0 +1,15 @@
|
||||
//@ check-pass
|
||||
//@ aux-build:xcrate-const-ctor-a.rs
|
||||
|
||||
#![feature(adt_const_params)]
|
||||
|
||||
extern crate xcrate_const_ctor_a;
|
||||
use xcrate_const_ctor_a::Foo;
|
||||
|
||||
fn bar<const N: Foo>() {}
|
||||
|
||||
fn baz() {
|
||||
bar::<{ Foo }>();
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,11 @@
|
||||
trait Trait {
|
||||
const ASSOC: usize;
|
||||
}
|
||||
|
||||
// FIXME(min_generic_const_args): implement support for this, behind the feature gate
|
||||
fn foo<T: Trait>() -> [u8; <T as Trait>::ASSOC] {
|
||||
//~^ ERROR generic parameters may not be used in const operations
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,11 @@
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/feature-gate-min-generic-const-args.rs:6:29
|
||||
|
|
||||
LL | fn foo<T: Trait>() -> [u8; <T as Trait>::ASSOC] {
|
||||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
Loading…
Reference in New Issue
Block a user