Introduce min_generic_const_args
and directly represent paths
Co-authored-by: Boxy UwU <rust@boxyuwu.dev> Co-authored-by: León Orell Valerian Liehr <me@fmease.dev>
This commit is contained in:
parent
b71fb5edc0
commit
59e339f766
21 changed files with 361 additions and 195 deletions
|
@ -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 [`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,
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue