From 16ebc9d86e146f0b8703473ae9b1567192d67901 Mon Sep 17 00:00:00 2001 From: Ash Walker Date: Thu, 9 Oct 2025 13:05:47 -0400 Subject: [PATCH 01/10] Document `pub` items in `clippy_utils::usage` - `is_potentially_mutated()` - `is_potentially_local_place()` - `ParamBindingIdCollector` - `BindingUsageFinder` - `contains_return_break_continue_macro()` - `local_used_in()` - `local_used_after_expr()` --- clippy_utils/src/usage.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index e27f1dabeefa..03684ae76a2d 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -1,3 +1,5 @@ +//! Contains utility functions for checking expression usage. + use crate::macros::root_macro_call_first_node; use crate::res::MaybeResPath; use crate::visitors::{Descend, Visitable, for_each_expr, for_each_expr_without_closures}; @@ -29,10 +31,13 @@ pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Some(delegate.used_mutably) } +/// Checks whether it is possible that the given variable is mutated within the given +/// [`Expr`]. pub fn is_potentially_mutated<'tcx>(variable: HirId, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool { mutated_variables(expr, cx).is_none_or(|mutated| mutated.contains(&variable)) } +/// Checks whether it is possible that the given [Place] refers to the given local. pub fn is_potentially_local_place(local_id: HirId, place: &Place<'_>) -> bool { match place.base { PlaceBase::Local(id) => id == local_id, @@ -84,7 +89,9 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } +/// A [`Visitor`] that collects all [`HirId`s](HirId) bound by visited [patterns](hir::Pat). pub struct ParamBindingIdCollector { + /// [`HirId`s](HirId) collected during calls to [`visit_pat`](Self::visit_pat). pub binding_hir_ids: Vec, } impl<'tcx> ParamBindingIdCollector { @@ -111,11 +118,14 @@ impl<'tcx> Visitor<'tcx> for ParamBindingIdCollector { } } +/// A [`Visitor`] providing [`are_params_used()`](Self::are_params_used), which can be used to check +/// parameter binding usage within a [`Body`](hir::Body). pub struct BindingUsageFinder<'a, 'tcx> { cx: &'a LateContext<'tcx>, binding_ids: Vec, } impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> { + /// Checks whether the parameter bindings of the given [`Body`](hir::Body) are used within it. pub fn are_params_used(cx: &'a LateContext<'tcx>, body: &'tcx hir::Body<'tcx>) -> bool { let mut finder = BindingUsageFinder { cx, @@ -181,6 +191,7 @@ pub fn contains_todo_unimplement_macro(cx: &LateContext<'_>, expr: &'_ Expr<'_>) .is_some() } +/// Checks whether the given expression contains `return`, `break`, `continue`, or a macro call. pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { for_each_expr_without_closures(expression, |e| { match e.kind { @@ -195,6 +206,7 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { .is_some() } +/// Checks whether the given [`Visitable`] (ex. an [`Expr`]) contains the given local. pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visitable<'tcx>) -> bool { for_each_expr(cx, v, |e| { if e.res_local_id() == Some(local_id) { @@ -206,6 +218,7 @@ pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visi .is_some() } +/// Checks whether the given local is used after the given [`Expr`]. pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr<'_>) -> bool { let Some(block) = utils::get_enclosing_block(cx, local_id) else { return false; From 37f35049c2b7aec82c406b2ed59c9e6e6f4f273f Mon Sep 17 00:00:00 2001 From: Ash Walker Date: Sun, 12 Oct 2025 09:56:22 -0400 Subject: [PATCH 02/10] Document `pub` items in `clippy_utils::higher` - `IfLetOrMatch::scrutinee()` - `While.label` - `WhileLet.label` --- clippy_utils/src/higher.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 3383e66fe368..36fe914ea9b9 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -171,6 +171,7 @@ impl<'hir> IfLetOrMatch<'hir> { } } + /// Returns the [expression](Expr) scrutinized by this `if let` or `match` expression. pub fn scrutinee(&self) -> &'hir Expr<'hir> { match self { Self::Match(scrutinee, _, _) | Self::IfLet(scrutinee, _, _, _, _) => scrutinee, @@ -319,6 +320,7 @@ pub struct While<'hir> { pub body: &'hir Expr<'hir>, /// Span of the loop header pub span: Span, + /// The loop's label, if present pub label: Option, } @@ -360,6 +362,7 @@ pub struct WhileLet<'hir> { pub let_expr: &'hir Expr<'hir>, /// `while let` loop body pub if_then: &'hir Expr<'hir>, + /// The loop's label, if present pub label: Option, /// `while let PAT = EXPR` /// ^^^^^^^^^^^^^^ From a0be34b793f82a53eeca27d2234285f6198e7a19 Mon Sep 17 00:00:00 2001 From: Ash Walker Date: Sun, 12 Oct 2025 10:16:40 -0400 Subject: [PATCH 03/10] Document `pub` items in `clippy_utils::macros` - module - `MacroCall::is_local()` - `PanicExpn` - `PanicExpn::parse()` - `HirNode::hir_id()` - `HirNode::span()` --- clippy_utils/src/macros.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 7cd5a16f5b46..319272d386d8 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,3 +1,5 @@ +//! Utilities for analyzing macro invocations and expansions. + #![allow(clippy::similar_names)] // `expr` and `expn` use std::sync::{Arc, OnceLock}; @@ -65,6 +67,7 @@ pub struct MacroCall { } impl MacroCall { + /// Returns true if this macro call is from the root expansion or a locally defined macro pub fn is_local(&self) -> bool { span_is_local(self.span) } @@ -228,6 +231,7 @@ pub fn is_assert_macro(cx: &LateContext<'_>, def_id: DefId) -> bool { matches!(name, sym::assert_macro | sym::debug_assert_macro) } +/// A `panic!()` expression, which may contain arguments #[derive(Debug)] pub enum PanicExpn<'a> { /// No arguments - `panic!()` @@ -241,6 +245,7 @@ pub enum PanicExpn<'a> { } impl<'a> PanicExpn<'a> { + /// Parses a `panic!()` expression pub fn parse(expr: &'a Expr<'a>) -> Option { let ExprKind::Call(callee, args) = &expr.kind else { return None; @@ -516,7 +521,9 @@ pub enum FormatParamUsage { /// A node with a `HirId` and a `Span` pub trait HirNode { + /// Returns this node's [`HirId`] fn hir_id(&self) -> HirId; + /// Returns this node's [`Span`] fn span(&self) -> Span; } From 457978c23b1cbe9c38252487c48057341e3af234 Mon Sep 17 00:00:00 2001 From: Ash Walker Date: Sun, 12 Oct 2025 10:22:14 -0400 Subject: [PATCH 04/10] Document `clippy_utils::paths::PathNS::{Type, Value, Macro}` I'm not really sure how to document the `PathLookup` statics, so I'm skipping those for now. --- clippy_utils/src/paths.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 8aa663163caf..734adc41b8e4 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -23,8 +23,11 @@ use std::sync::OnceLock; /// arbitrary namespace #[derive(Clone, Copy, PartialEq, Debug)] pub enum PathNS { + /// The [type namespace](TypeNS) Type, + /// The [value namespace](ValueNS) Value, + /// The [macro namespace](MacroNS) Macro, /// Resolves to the name in the first available namespace, e.g. for `std::vec` this would return From 6ddaa2c092368cf9c97ef5e6853370fe9aba12dc Mon Sep 17 00:00:00 2001 From: Ash Walker Date: Sun, 12 Oct 2025 10:37:03 -0400 Subject: [PATCH 05/10] Document `pub` items in `clippy_utils::res` - module - `HasHirId::hir_id()` - `MaybeTypeckRes` - `MaybeDef::opt_def_id()` --- clippy_utils/src/res.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clippy_utils/src/res.rs b/clippy_utils/src/res.rs index 90b952927896..f36264f2f977 100644 --- a/clippy_utils/src/res.rs +++ b/clippy_utils/src/res.rs @@ -1,3 +1,5 @@ +//! Utilities for node resolution. + use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ @@ -10,6 +12,7 @@ use rustc_span::{Ident, Symbol}; /// Either a `HirId` or a type which can be identified by one. pub trait HasHirId: Copy { + /// Returns the [`HirId`] identifying `self`. fn hir_id(self) -> HirId; } impl HasHirId for HirId { @@ -27,6 +30,7 @@ impl HasHirId for &Expr<'_> { type DefRes = (DefKind, DefId); +/// Either a [`TypeckResults`] or a type that may contain one. pub trait MaybeTypeckRes<'tcx> { /// Gets the contained `TypeckResults`. /// @@ -469,6 +473,7 @@ impl<'a, T: MaybeResPath<'a>> MaybeResPath<'a> for Option { /// A type which may either contain a `DefId` or be referred to by a `DefId`. pub trait MaybeDef: Copy { + /// Gets the [`DefId`] contained by or referring to `self` fn opt_def_id(self) -> Option; /// Gets this definition's id and kind. This will lookup the kind in the def From 211134b7e8727880d39c59fb5f011a7f106ca6d1 Mon Sep 17 00:00:00 2001 From: Ash Walker Date: Sun, 12 Oct 2025 11:02:07 -0400 Subject: [PATCH 06/10] Document `pub` items in `clippy_utils::source` - `HasSession` - `HasSession::sess()` - `SpanRange::into_range()` - `IntoSpan::into_span()` - `IntoSpan::with_ctxt()` - `SpanRangeExt` - May want to be more specific with this one. - `SourceFileRange` and its fields - `is_present_in_source()` - This one feels a bit clunky to me; might want to rephrase. - `snippet_block_with_context()` --- clippy_utils/src/source.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 8b1ec7e62e4d..24cd96d76fba 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -20,7 +20,9 @@ use std::borrow::Cow; use std::fmt; use std::ops::{Deref, Index, Range}; +/// Either a [`Session`] or a type which can be associated with one. pub trait HasSession { + /// Gets the [`Session`] associated with `self`. fn sess(&self) -> &Session; } impl HasSession for Session { @@ -46,6 +48,7 @@ impl HasSession for LateContext<'_> { /// Conversion of a value into the range portion of a `Span`. pub trait SpanRange: Sized { + /// Converts `self` into the range portion of a [`Span`]. fn into_range(self) -> Range; } impl SpanRange for Span { @@ -67,7 +70,9 @@ impl SpanRange for Range { /// Conversion of a value into a `Span` pub trait IntoSpan: Sized { + /// Converts `self` into a [`Span`]. fn into_span(self) -> Span; + /// Converts `self` into a [`Span`], with [context](SyntaxContext). fn with_ctxt(self, ctxt: SyntaxContext) -> Span; } impl IntoSpan for Span { @@ -95,6 +100,7 @@ impl IntoSpan for Range { } } +/// Extensions to [`SpanRange`]. pub trait SpanRangeExt: SpanRange { /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed, /// or the source text is not accessible. @@ -339,8 +345,11 @@ fn trim_start(sm: &SourceMap, sp: Range) -> Range { .unwrap_or(sp) } +/// A range within a specific [source file](SourceFile). pub struct SourceFileRange { + /// The [source file](SourceFile) referred to by this range pub sf: Arc, + /// The range within the associated [source file](SourceFile) pub range: Range, } impl SourceFileRange { @@ -442,6 +451,11 @@ pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option { // sources that the user has no control over. // For some reason these attributes don't have any expansion info on them, so // we have to check it this way until there is a better way. +// +/// Checks whether the code snippet referred to by the given [`Span`] is present in the source code. +/// +/// For example, if the span refers to an attribute inserted during macro expansion, this will +/// return false. pub fn is_present_in_source(sess: &impl HasSession, span: Span) -> bool { if let Some(snippet) = snippet_opt(sess, span) && snippet.is_empty() @@ -631,6 +645,8 @@ pub fn snippet_block_with_applicability( reindent_multiline(&snip, true, indent) } +/// Same as [`snippet_block_with_applicability()`], but first walks the span up to the given context +/// using [`snippet_with_context()`]. pub fn snippet_block_with_context( sess: &impl HasSession, span: Span, From ec2ca3f5d771bf3dc1dcefd285243377ddb3c055 Mon Sep 17 00:00:00 2001 From: Ash Walker Date: Sun, 12 Oct 2025 11:11:29 -0400 Subject: [PATCH 07/10] Document `pub` items in `clippy_utils::str_utils` - module - fields of `StrIndex` - `StrIndex::new()` - fields of `StrCount` - `StrCount::new()` `StrIndex` and `StrCount` don't seem to guarantee that their fields are internally consistent; should this be documented? --- clippy_utils/src/str_utils.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/clippy_utils/src/str_utils.rs b/clippy_utils/src/str_utils.rs index f0f82c8dddcf..089ed95ec811 100644 --- a/clippy_utils/src/str_utils.rs +++ b/clippy_utils/src/str_utils.rs @@ -1,12 +1,17 @@ +//! Utilities for analyzing and transforming strings. + /// Dealing with string indices can be hard, this struct ensures that both the /// character and byte index are provided for correct indexing. #[derive(Debug, Default, PartialEq, Eq)] pub struct StrIndex { + /// The character-relative index within a string pub char_index: usize, + /// The byte-relative index within a string pub byte_index: usize, } impl StrIndex { + /// Creates a `StrIndex` from character and byte indices. pub fn new(char_index: usize, byte_index: usize) -> Self { Self { char_index, byte_index } } @@ -169,11 +174,14 @@ pub fn camel_case_split(s: &str) -> Vec<&str> { /// character and byte count are provided for correct indexing. #[derive(Debug, Default, PartialEq, Eq)] pub struct StrCount { + /// The number of characters in a string. pub char_count: usize, + /// The number of bytes in a string. pub byte_count: usize, } impl StrCount { + /// Creates a `StrCount` from character and byte counts. pub fn new(char_count: usize, byte_count: usize) -> Self { Self { char_count, byte_count } } From 273f4e492acc8a48d5396cb7c25d4ad7f3c09e49 Mon Sep 17 00:00:00 2001 From: Ash Walker Date: Sun, 12 Oct 2025 11:14:15 -0400 Subject: [PATCH 08/10] Document `pub` items in `clippy_utils::sugg` - `Sugg::into_string()` I'm not sure that this is correct, but it does seem to be how its used elsewhere. --- clippy_utils/src/sugg.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 581c2b02839d..4ece0b7ea0cb 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -361,6 +361,7 @@ impl<'a> Sugg<'a> { } } + /// Convert this suggestion into a [`String`] to be displayed to the user. pub fn into_string(self) -> String { match self { Sugg::NonParen(p) | Sugg::MaybeParen(p) => p.into_owned(), From 2bfdddddec9ee606230e425d5f598496622e30f6 Mon Sep 17 00:00:00 2001 From: Ash Walker Date: Sun, 12 Oct 2025 11:41:26 -0400 Subject: [PATCH 09/10] Document `pub` items in `clippy_utils::visitors` - module - `Descend::{Yes, No}` - `find_all_ret_expressions()` - `for_each_unconsumed_temporary()` - this one was mostly just reformatting the non-doc comment that was already there - `any_temporaries_need_ordered_drop()` - `contains_break_or_continue()` --- clippy_utils/src/visitors.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 84e4f043e34f..7426daec090e 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -1,3 +1,5 @@ +//! Utilities for analyzing the contents of expressions and other [visitable](Visitable) items. + use crate::get_enclosing_block; use crate::msrvs::Msrv; use crate::qualify_min_const_fn::is_stable_const_fn; @@ -36,7 +38,9 @@ impl Continue for () { /// descending into child nodes. #[derive(Clone, Copy)] pub enum Descend { + /// Controlled [`Visitor`] should descend into child nodes. Yes, + /// Controlled [`Visitor`] should not descend into child nodes. No, } impl From for Descend { @@ -204,6 +208,9 @@ fn contains_try(expr: &Expr<'_>) -> bool { .is_some() } +/// Calls a given function of the form `|return_expr: &Expr| -> bool` for all `return` expressions +/// in the given [expression](Expr), and returns whether that callback returned true for all found +/// `return`s. pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir Expr<'hir>, callback: F) -> bool where F: FnMut(&'hir Expr<'hir>) -> bool, @@ -589,9 +596,11 @@ pub fn for_each_local_use_after_expr<'tcx, B>( } } -// Calls the given function for every unconsumed temporary created by the expression. Note the -// function is only guaranteed to be called for types which need to be dropped, but it may be called -// for other types. +/// Calls a given function of the form `|temporary_type: Ty| -> ControlFlow` for every unconsumed +/// temporary created by the given [expression](Expr), and returns the result of that function. +/// +/// Note the function is only guaranteed to be called for types which need to be dropped, but it may +/// be called for other types. #[expect(clippy::too_many_lines)] pub fn for_each_unconsumed_temporary<'tcx, B>( cx: &LateContext<'tcx>, @@ -708,6 +717,8 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( helper(cx.typeck_results(), true, e, &mut f) } +/// Checks whether the drop order matters for any unconsumed temporary created by the given +/// [expression](Expr). pub fn any_temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool { for_each_unconsumed_temporary(cx, e, |ty| { if needs_ordered_drop(cx, ty) { @@ -765,6 +776,8 @@ pub fn for_each_local_assignment<'tcx, B>( } } +/// Checks whether the given [expression](Expr) contains any `break` or `continue` expressions. This +/// does not enter any bodies or nested items. pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool { for_each_expr_without_closures(expr, |e| { if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) { From 07d0db91d8110b183f2d26e1d9b2c45337b3b8bb Mon Sep 17 00:00:00 2001 From: Ash Walker Date: Sun, 12 Oct 2025 12:51:41 -0400 Subject: [PATCH 10/10] Document `pub` items in `clippy_utils::consts` - `Constant::Adt` - `Constant::partial_cmp()` - `Constant::peel_refs()` - `Constant::new_numeric_min()` - `Constant::new_numeric_max()` - `Constant::is_numeric_min()` - `Constant::is_numeric_max()` - `Constant::is_pos_infinity()` - `Constant::is_neg_infinity()` - `ConstantSource::is_local()` - `FullInt` and its variants - `ConstEvalCtxt::eval_pat_expr()` - `mir_to_const()` --- clippy_utils/src/consts.rs | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 7b8c7f3f0d6b..1970a91d7368 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -29,6 +29,7 @@ use std::iter; /// A `LitKind`-like enum to fold constant `Expr`s into. #[derive(Debug, Clone)] pub enum Constant { + /// A constant representing an algebraic data type Adt(ConstValue), /// A `String` (e.g., "abc"). Str(String), @@ -203,6 +204,15 @@ impl Hash for Constant { } impl Constant { + /// Returns an ordering between `left` and `right`, if one exists. `cmp_type` determines + /// comparison behavior for constants with ambiguous typing (ex. [`Constant::Int`], which may be + /// signed or unsigned). + /// + /// # Panics + /// + /// Panics if the compared type is ambiguous and `cmp_type` describes a nonsensical type. For + /// example, if `left` and `right` are [`Constant::Int`], `cmp_type.kind()` must be either + /// [`Int`](ty::Int) or [`Uint`](ty::Uint). pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option { match (left, right) { (Self::Str(ls), Self::Str(rs)) => Some(ls.cmp(rs)), @@ -273,6 +283,7 @@ impl Constant { } } + /// Recursively consume [`Constant::Ref`] and return the innermost value. #[must_use] pub fn peel_refs(mut self) -> Self { while let Constant::Ref(r) = self { @@ -291,6 +302,8 @@ impl Constant { Self::F128(f.to_bits()) } + /// Create a constant representing the minimum value of the type described by `ty`, if one + /// is defined. pub fn new_numeric_min<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { match *ty.kind() { ty::Uint(_) => Some(Self::Int(0)), @@ -312,6 +325,8 @@ impl Constant { } } + /// Create a constant representing the maximum value of the type described by `ty`, if one + /// is defined. pub fn new_numeric_max<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { match *ty.kind() { ty::Uint(ty) => Some(Self::Int(match ty.normalize(tcx.sess.target.pointer_width) { @@ -340,6 +355,8 @@ impl Constant { } } + /// Checks whether `self` is a numeric of the type `ty` and whether `self` is the minimum value + /// of that type. pub fn is_numeric_min<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { match (self, ty.kind()) { (&Self::Int(x), &ty::Uint(_)) => x == 0, @@ -361,6 +378,8 @@ impl Constant { } } + /// Checks whether `self` is a numeric of the type `ty` and whether `self` is the maximum value + /// of that type. pub fn is_numeric_max<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { match (self, ty.kind()) { (&Self::Int(x), &ty::Uint(ty)) => { @@ -392,6 +411,7 @@ impl Constant { } } + /// Checks whether `self` is a floating-point value representing positive infinity. pub fn is_pos_infinity(&self) -> bool { match *self { // FIXME(f16_f128): add f16 and f128 when constants are available @@ -401,6 +421,7 @@ impl Constant { } } + /// Checks whether `self` is a floating-point value representing negative infinity. pub fn is_neg_infinity(&self) -> bool { match *self { // FIXME(f16_f128): add f16 and f128 when constants are available @@ -448,14 +469,20 @@ pub enum ConstantSource { NonLocal, } impl ConstantSource { + /// Checks whether this constant value is determined solely from its expression, and is not + /// dependent on another definition. pub fn is_local(self) -> bool { matches!(self, Self::Local) } } +/// An integer type (signed or unsigned) with enough bits to represent any integer that can be +/// represented in Rust. #[derive(Copy, Clone, Debug, Eq)] pub enum FullInt { + /// Signed full int S(i128), + /// Unsigned full int U(u128), } @@ -564,6 +591,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { } } + /// Attempts to evaluate the given [pattern expression](PatExpr) as a [`Constant`]. pub fn eval_pat_expr(&self, pat_expr: &PatExpr<'_>) -> Option { match &pat_expr.kind { PatExprKind::Lit { lit, negated } => { @@ -1047,6 +1075,18 @@ impl<'tcx> ConstEvalCtxt<'tcx> { } } +/// Converts a [`ConstValue`] to a [`Constant`], if possible. +/// +/// - If `ty` is an [`Adt`](ty::Adt) describing a struct, returns a [`Constant::Adt`] containing +/// `val`. +/// - If `val` is a [`Int`](Scalar::Int), `ty` determines the variant of the returned constant. +/// Returns `None` if `val` cannot be converted to the type described by `ty`. +/// - If `ty` is a [`Ref`](ty::Ref) referring to a [`Str`](ty::Str) (i.e. a `&str`), returns a +/// [`Constant::Str`]. +/// - If `val` is a [`ConstValue::Indirect`] and `ty` is an [`Array`](ty::Array) of +/// [`Float`](ty::Float), returns a [`Constant::Vec`] +/// +/// Otherwise, returns `None`. pub fn mir_to_const<'tcx>(tcx: TyCtxt<'tcx>, val: ConstValue, ty: Ty<'tcx>) -> Option { match (val, ty.kind()) { (_, &ty::Adt(adt_def, _)) if adt_def.is_struct() => Some(Constant::Adt(val)),