Skip to content

Commit

Permalink
Use ConstArg for array lengths
Browse files Browse the repository at this point in the history
  • Loading branch information
camelid committed Jul 17, 2024
1 parent 8818708 commit 67fccb7
Show file tree
Hide file tree
Showing 14 changed files with 77 additions and 45 deletions.
4 changes: 2 additions & 2 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2342,10 +2342,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
"using `_` for array lengths is unstable",
)
.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)),
}
}

Expand Down
14 changes: 9 additions & 5 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
match self.kind {
ConstArgKind::Anon(anon) => anon.hir_id,
Expand Down Expand Up @@ -288,7 +293,7 @@ impl GenericArg<'_> {
match self {
GenericArg::Lifetime(l) => l.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,
}
}
Expand Down Expand Up @@ -1617,15 +1622,14 @@ pub type Lit = Spanned<LitKind>;
#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum ArrayLen<'hir> {
Infer(InferArg),
Body(&'hir AnonConst),
Body(&'hir ConstArg<'hir>),
}

impl ArrayLen<'_> {
pub fn hir_id(&self) -> HirId {
match self {
ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(AnonConst { hir_id, .. }) => {
*hir_id
}
ArrayLen::Infer(InferArg { hir_id, .. }) => *hir_id,
ArrayLen::Body(ct) => ct.hir_id(),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen<'v>
match len {
// FIXME: Use `visit_infer` here.
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),
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2140,7 +2140,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_anon_const(tcx, constant.def_id)
ty::Const::from_const_arg(tcx, constant, ty::FeedConstTy::No)
}
};

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,7 @@ impl<'a> State<'a> {
fn print_array_length(&mut self, len: &hir::ArrayLen<'_>) {
match len {
hir::ArrayLen::Infer(..) => self.word("_"),
hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
hir::ArrayLen::Body(ct) => self.print_const_arg(ct),
}
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1439,9 +1439,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
};
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(
span,
StashKey::UnderscoreForArrayLengths,
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,9 +457,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn lower_array_length(&self, length: &hir::ArrayLen<'tcx>) -> ty::Const<'tcx> {
match length {
hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
hir::ArrayLen::Body(anon_const) => {
let span = self.tcx.def_span(anon_const.def_id);
let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id);
hir::ArrayLen::Body(const_arg) => {
let span = const_arg.span();
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.normalize(span, c)
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_infer/src/error_reporting/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1762,9 +1762,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
};
if let Some(tykind) = 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 })
} else {
None
Expand Down
18 changes: 14 additions & 4 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1822,17 +1822,27 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
TyKind::Array(ty, ref length) => {
let length = match length {
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
// as we currently do not supply the parent generics to anonymous constants
// but do allow `ConstKind::Param`.
//
// `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_anon_const(cx.tcx, anon_const.def_id);
let param_env = cx.tcx.param_env(anon_const.def_id);
print_const(cx, ct.normalize(cx.tcx, param_env))
let ct = ty::Const::from_const_arg(cx.tcx, const_arg, ty::FeedConstTy::No);
#[allow(irrefutable_let_patterns)] // FIXME
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)
}
};

Expand Down
9 changes: 4 additions & 5 deletions src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
/// correct result.
fn repeat_expr_might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
let ExprKind::Repeat(_, ArrayLen::Body(anon_const)) = expr.kind else {
fn repeat_expr_might_be_expanded<'tcx>(expr: &Expr<'tcx>) -> bool {
let ExprKind::Repeat(_, ArrayLen::Body(len_ct)) = expr.kind else {
return false;
};
let len_span = cx.tcx.def_span(anon_const.def_id);
!expr.span.contains(len_span)
!expr.span.contains(len_ct.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)
}
6 changes: 3 additions & 3 deletions src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::has_repr_attr;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Const;
use rustc_middle::ty::{Const, FeedConstTy};
use rustc_session::declare_lint_pass;

declare_clippy_lint! {
Expand Down Expand Up @@ -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
// First check if last field is an array
&& let Some(last_field) = data.fields().last()
&& let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind

// 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 Some(length) = length
{
Expand Down
29 changes: 22 additions & 7 deletions src/tools/clippy/clippy_lints/src/utils/author.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ use clippy_utils::{get_attr, higher};
use rustc_ast::ast::{LitFloatType, LitKind};
use rustc_ast::LitIntType;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::{
ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit, PatKind,
QPath, StmtKind, TyKind,
self as hir, ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind,
ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::declare_lint_pass;
Expand Down Expand Up @@ -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>) {
let kind = |kind| chain!(self, "let LitKind::{kind} = {lit}.node");
macro_rules! kind {
Expand Down Expand Up @@ -602,10 +617,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
self.expr(value);
match length.value {
ArrayLen::Infer(..) => chain!(self, "let ArrayLen::Infer(..) = length"),
ArrayLen::Body(anon_const) => {
bind!(self, anon_const);
chain!(self, "let ArrayLen::Body({anon_const}) = {length}");
self.body(field!(anon_const.body));
ArrayLen::Body(const_arg) => {
bind!(self, const_arg);
chain!(self, "let ArrayLen::Body({const_arg}) = {length}");
self.const_arg(const_arg);
},
}
},
Expand Down
4 changes: 2 additions & 2 deletions src/tools/clippy/clippy_utils/src/hir_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ impl HirEqInterExpr<'_, '_, '_> {
pub fn eq_array_length(&mut self, left: ArrayLen<'_>, right: ArrayLen<'_>) -> bool {
match (left, right) {
(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,
}
}
Expand Down Expand Up @@ -1129,7 +1129,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
pub fn hash_array_length(&mut self, length: ArrayLen<'_>) {
match length {
ArrayLen::Infer(..) => {},
ArrayLen::Body(anon_const) => self.hash_body(anon_const.body),
ArrayLen::Body(ct) => self.hash_const_arg(ct),
}
}

Expand Down
18 changes: 11 additions & 7 deletions src/tools/clippy/clippy_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,11 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
use rustc_hir::{
self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstContext,
Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind,
ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat,
PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef,
TyKind, UnOp,
self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind,
ConstContext, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem,
ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode,
Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef,
TraitRef, TyKind, UnOp,
};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, Level, Lint, LintContext};
Expand Down Expand Up @@ -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::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
&& v <= 32
&& is_default_equivalent(cx, x)
Expand Down Expand Up @@ -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),
ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
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
{
return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);
Expand Down

0 comments on commit 67fccb7

Please sign in to comment.