mirror of https://github.com/rust-lang/rust.git
Use `ConstArg` for array lengths
This commit is contained in:
parent
8818708a31
commit
67fccb7045
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1822,7 +1822,7 @@ 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`.
|
||||
|
@ -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
|
||||
// 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)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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! {
|
||||
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
},
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue