1
Fork 0

Use ConstArg for array lengths

This commit is contained in:
Noah Lev 2024-06-04 18:24:08 -07:00
parent 8818708a31
commit 67fccb7045
14 changed files with 77 additions and 45 deletions

View file

@ -2342,10 +2342,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
"using `_` for array lengths is unstable", "using `_` for array lengths is unstable",
) )
.stash(c.value.span, StashKey::UnderscoreForArrayLengths); .stash(c.value.span, StashKey::UnderscoreForArrayLengths);
hir::ArrayLen::Body(self.lower_anon_const_to_anon_const(c)) hir::ArrayLen::Body(self.lower_anon_const_to_const_arg(c))
} }
} }
_ => hir::ArrayLen::Body(self.lower_anon_const_to_anon_const(c)), _ => hir::ArrayLen::Body(self.lower_anon_const_to_const_arg(c)),
} }
} }

View file

@ -242,6 +242,11 @@ impl<'hir> ConstArg<'hir> {
} }
} }
// FIXME: convert to field, where ConstArg has its own HirId
pub fn hir_id(&self) -> HirId {
self.anon_const_hir_id()
}
pub fn anon_const_hir_id(&self) -> HirId { pub fn anon_const_hir_id(&self) -> HirId {
match self.kind { match self.kind {
ConstArgKind::Anon(anon) => anon.hir_id, ConstArgKind::Anon(anon) => anon.hir_id,
@ -288,7 +293,7 @@ impl GenericArg<'_> {
match self { match self {
GenericArg::Lifetime(l) => l.hir_id, GenericArg::Lifetime(l) => l.hir_id,
GenericArg::Type(t) => t.hir_id, GenericArg::Type(t) => t.hir_id,
GenericArg::Const(c) => c.anon_const_hir_id(), // FIXME GenericArg::Const(c) => c.hir_id(),
GenericArg::Infer(i) => i.hir_id, GenericArg::Infer(i) => i.hir_id,
} }
} }
@ -1617,15 +1622,14 @@ pub type Lit = Spanned<LitKind>;
#[derive(Copy, Clone, Debug, HashStable_Generic)] #[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum ArrayLen<'hir> { pub enum ArrayLen<'hir> {
Infer(InferArg), Infer(InferArg),
Body(&'hir AnonConst), Body(&'hir ConstArg<'hir>),
} }
impl ArrayLen<'_> { impl ArrayLen<'_> {
pub fn hir_id(&self) -> HirId { pub fn hir_id(&self) -> HirId {
match self { match self {
ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(AnonConst { hir_id, .. }) => { ArrayLen::Infer(InferArg { hir_id, .. }) => *hir_id,
*hir_id ArrayLen::Body(ct) => ct.hir_id(),
}
} }
} }
} }

View file

@ -711,7 +711,7 @@ pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen<'v>
match len { match len {
// FIXME: Use `visit_infer` here. // FIXME: Use `visit_infer` here.
ArrayLen::Infer(InferArg { hir_id, span: _ }) => visitor.visit_id(*hir_id), ArrayLen::Infer(InferArg { hir_id, span: _ }) => visitor.visit_id(*hir_id),
ArrayLen::Body(c) => visitor.visit_anon_const(c), ArrayLen::Body(c) => visitor.visit_const_arg(c),
} }
} }

View file

@ -2140,7 +2140,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let length = match length { let length = match length {
hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
hir::ArrayLen::Body(constant) => { hir::ArrayLen::Body(constant) => {
ty::Const::from_anon_const(tcx, constant.def_id) ty::Const::from_const_arg(tcx, constant, ty::FeedConstTy::No)
} }
}; };

View file

@ -983,7 +983,7 @@ impl<'a> State<'a> {
fn print_array_length(&mut self, len: &hir::ArrayLen<'_>) { fn print_array_length(&mut self, len: &hir::ArrayLen<'_>) {
match len { match len {
hir::ArrayLen::Infer(..) => self.word("_"), hir::ArrayLen::Infer(..) => self.word("_"),
hir::ArrayLen::Body(ct) => self.print_anon_const(ct), hir::ArrayLen::Body(ct) => self.print_const_arg(ct),
} }
} }

View file

@ -1439,9 +1439,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return; return;
}; };
if let hir::TyKind::Array(_, length) = ty.peel_refs().kind if let hir::TyKind::Array(_, length) = ty.peel_refs().kind
&& let hir::ArrayLen::Body(&hir::AnonConst { hir_id, .. }) = length && let hir::ArrayLen::Body(ct) = length
{ {
let span = self.tcx.hir().span(hir_id); let span = ct.span();
self.dcx().try_steal_modify_and_emit_err( self.dcx().try_steal_modify_and_emit_err(
span, span,
StashKey::UnderscoreForArrayLengths, StashKey::UnderscoreForArrayLengths,

View file

@ -457,9 +457,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn lower_array_length(&self, length: &hir::ArrayLen<'tcx>) -> ty::Const<'tcx> { pub fn lower_array_length(&self, length: &hir::ArrayLen<'tcx>) -> ty::Const<'tcx> {
match length { match length {
hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
hir::ArrayLen::Body(anon_const) => { hir::ArrayLen::Body(const_arg) => {
let span = self.tcx.def_span(anon_const.def_id); let span = const_arg.span();
let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id); let c = ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::No);
self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None)); self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None));
self.normalize(span, c) self.normalize(span, c)
} }

View file

@ -1762,9 +1762,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}; };
if let Some(tykind) = tykind if let Some(tykind) = tykind
&& let hir::TyKind::Array(_, length) = tykind && let hir::TyKind::Array(_, length) = tykind
&& let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length && let hir::ArrayLen::Body(ct) = length
{ {
let span = self.tcx.hir().span(*hir_id); let span = ct.span();
Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found }) Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found })
} else { } else {
None None

View file

@ -1822,7 +1822,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
TyKind::Array(ty, ref length) => { TyKind::Array(ty, ref length) => {
let length = match length { let length = match length {
hir::ArrayLen::Infer(..) => "_".to_string(), hir::ArrayLen::Infer(..) => "_".to_string(),
hir::ArrayLen::Body(anon_const) => { hir::ArrayLen::Body(const_arg) => {
// NOTE(min_const_generics): We can't use `const_eval_poly` for constants // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
// as we currently do not supply the parent generics to anonymous constants // as we currently do not supply the parent generics to anonymous constants
// but do allow `ConstKind::Param`. // but do allow `ConstKind::Param`.
@ -1830,9 +1830,19 @@ 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 // `const_eval_poly` tries to first substitute generic parameters which
// results in an ICE while manually constructing the constant and using `eval` // results in an ICE while manually constructing the constant and using `eval`
// does nothing for `ConstKind::Param`. // does nothing for `ConstKind::Param`.
let ct = ty::Const::from_anon_const(cx.tcx, anon_const.def_id); let ct = ty::Const::from_const_arg(cx.tcx, const_arg, ty::FeedConstTy::No);
let param_env = cx.tcx.param_env(anon_const.def_id); #[allow(irrefutable_let_patterns)] // FIXME
print_const(cx, ct.normalize(cx.tcx, param_env)) let ct = if let hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) =
const_arg.kind
{
// Only anon consts can implicitly capture params.
// FIXME: is this correct behavior?
let param_env = cx.tcx.param_env(*def_id);
ct.normalize(cx.tcx, param_env)
} else {
ct
};
print_const(cx, ct)
} }
}; };

View file

@ -106,13 +106,12 @@ fn might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
/// ///
/// This is a fail-safe to a case where even the `is_from_proc_macro` is unable to determain the /// This is a fail-safe to a case where even the `is_from_proc_macro` is unable to determain the
/// correct result. /// correct result.
fn repeat_expr_might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { fn repeat_expr_might_be_expanded<'tcx>(expr: &Expr<'tcx>) -> bool {
let ExprKind::Repeat(_, ArrayLen::Body(anon_const)) = expr.kind else { let ExprKind::Repeat(_, ArrayLen::Body(len_ct)) = expr.kind else {
return false; return false;
}; };
let len_span = cx.tcx.def_span(anon_const.def_id); !expr.span.contains(len_ct.span())
!expr.span.contains(len_span)
} }
expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(cx, expr) expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(expr)
} }

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::has_repr_attr; use clippy_utils::has_repr_attr;
use rustc_hir::{Item, ItemKind}; use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Const; use rustc_middle::ty::{Const, FeedConstTy};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
declare_clippy_lint! { declare_clippy_lint! {
@ -53,14 +53,14 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
} }
} }
fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_>) -> bool { fn is_struct_with_trailing_zero_sized_array<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool {
if let ItemKind::Struct(data, _) = &item.kind if let ItemKind::Struct(data, _) = &item.kind
// First check if last field is an array // First check if last field is an array
&& let Some(last_field) = data.fields().last() && let Some(last_field) = data.fields().last()
&& let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind && let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind
// Then check if that array is zero-sized // Then check if that array is zero-sized
&& let length = Const::from_anon_const(cx.tcx, length.def_id) && let length = Const::from_const_arg(cx.tcx, length, FeedConstTy::No)
&& let length = length.try_eval_target_usize(cx.tcx, cx.param_env) && let length = length.try_eval_target_usize(cx.tcx, cx.param_env)
&& let Some(length) = length && let Some(length) = length
{ {

View file

@ -5,10 +5,9 @@ use clippy_utils::{get_attr, higher};
use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::ast::{LitFloatType, LitKind};
use rustc_ast::LitIntType; use rustc_ast::LitIntType;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::{ use rustc_hir::{
ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit, PatKind, self as hir, ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind,
QPath, StmtKind, TyKind, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind,
}; };
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
@ -270,6 +269,22 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
} }
} }
fn const_arg(&self, const_arg: &Binding<&ConstArg<'_>>) {
match const_arg.value.kind {
// FIXME: uncomment for ConstArgKind::Path
// ConstArgKind::Path(ref qpath) => {
// bind!(self, qpath);
// chain!(self, "let ConstArgKind::Path(ref {qpath}) = {const_arg}.kind");
// self.qpath(qpath);
// },
ConstArgKind::Anon(anon_const) => {
bind!(self, anon_const);
chain!(self, "let ConstArgKind::({anon_const}) = {const_arg}.kind");
self.body(field!(anon_const.body));
},
}
}
fn lit(&self, lit: &Binding<&Lit>) { fn lit(&self, lit: &Binding<&Lit>) {
let kind = |kind| chain!(self, "let LitKind::{kind} = {lit}.node"); let kind = |kind| chain!(self, "let LitKind::{kind} = {lit}.node");
macro_rules! kind { macro_rules! kind {
@ -602,10 +617,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
self.expr(value); self.expr(value);
match length.value { match length.value {
ArrayLen::Infer(..) => chain!(self, "let ArrayLen::Infer(..) = length"), ArrayLen::Infer(..) => chain!(self, "let ArrayLen::Infer(..) = length"),
ArrayLen::Body(anon_const) => { ArrayLen::Body(const_arg) => {
bind!(self, anon_const); bind!(self, const_arg);
chain!(self, "let ArrayLen::Body({anon_const}) = {length}"); chain!(self, "let ArrayLen::Body({const_arg}) = {length}");
self.body(field!(anon_const.body)); self.const_arg(const_arg);
}, },
} }
}, },

View file

@ -227,7 +227,7 @@ impl HirEqInterExpr<'_, '_, '_> {
pub fn eq_array_length(&mut self, left: ArrayLen<'_>, right: ArrayLen<'_>) -> bool { pub fn eq_array_length(&mut self, left: ArrayLen<'_>, right: ArrayLen<'_>) -> bool {
match (left, right) { match (left, right) {
(ArrayLen::Infer(..), ArrayLen::Infer(..)) => true, (ArrayLen::Infer(..), ArrayLen::Infer(..)) => true,
(ArrayLen::Body(l_ct), ArrayLen::Body(r_ct)) => self.eq_body(l_ct.body, r_ct.body), (ArrayLen::Body(l_ct), ArrayLen::Body(r_ct)) => self.eq_const_arg(l_ct, r_ct),
(_, _) => false, (_, _) => false,
} }
} }
@ -1129,7 +1129,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
pub fn hash_array_length(&mut self, length: ArrayLen<'_>) { pub fn hash_array_length(&mut self, length: ArrayLen<'_>) {
match length { match length {
ArrayLen::Infer(..) => {}, ArrayLen::Infer(..) => {},
ArrayLen::Body(anon_const) => self.hash_body(anon_const.body), ArrayLen::Body(ct) => self.hash_const_arg(ct),
} }
} }

View file

@ -102,11 +102,11 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
use rustc_hir::{ use rustc_hir::{
self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstContext, self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind,
Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ConstContext, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem,
ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat, ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode,
PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef,
TyKind, UnOp, TraitRef, TyKind, UnOp,
}; };
use rustc_lexer::{tokenize, TokenKind}; use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_lint::{LateContext, Level, Lint, LintContext};
@ -904,7 +904,9 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
}, },
ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)), ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
ExprKind::Repeat(x, ArrayLen::Body(len)) => { ExprKind::Repeat(x, ArrayLen::Body(len)) => {
if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind #[allow(irrefutable_let_patterns)] // FIXME
if let ConstArgKind::Anon(anon_const) = len.kind
&& let ExprKind::Lit(const_lit) = cx.tcx.hir().body(anon_const.body).value.kind
&& let LitKind::Int(v, _) = const_lit.node && let LitKind::Int(v, _) = const_lit.node
&& v <= 32 && v <= 32
&& is_default_equivalent(cx, x) && is_default_equivalent(cx, x)
@ -933,7 +935,9 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
}) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String), }) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String),
ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec), ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
ExprKind::Repeat(_, ArrayLen::Body(len)) => { ExprKind::Repeat(_, ArrayLen::Body(len)) => {
if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind #[allow(irrefutable_let_patterns)] // FIXME
if let ConstArgKind::Anon(anon_const) = len.kind
&& let ExprKind::Lit(const_lit) = cx.tcx.hir().body(anon_const.body).value.kind
&& let LitKind::Int(v, _) = const_lit.node && let LitKind::Int(v, _) = const_lit.node
{ {
return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec); return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);