feat(tvix/eval): Forbid Hash{Map,Set}, use Fx instead

Per https://nnethercote.github.io/perf-book/hashing.html, we have
basically no reason to use the default hasher over a faster,
non-DoS-resistant hasher. This gives a nice perf boost basically for
free:

hello outpath           time:   [704.76 ms 714.91 ms 725.63 ms]
                        change: [-7.2391% -6.1018% -4.9189%] (p = 0.00 < 0.05)
                        Performance has improved.

Change-Id: If5587f444ed3af69f8af4eead6af3ea303b4ae68
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12046
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
Reviewed-by: Ilan Joselevich <personal@ilanjoselevich.com>
Autosubmit: aspen <root@gws.fyi>
This commit is contained in:
Aspen Smith 2024-07-28 12:11:41 -04:00 committed by clbot
parent 1d7ba89c19
commit b8f92a6d53
17 changed files with 116 additions and 46 deletions

14
tvix/Cargo.lock generated
View file

@ -3085,7 +3085,7 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
"quinn-proto", "quinn-proto",
"quinn-udp", "quinn-udp",
"rustc-hash", "rustc-hash 1.1.0",
"rustls 0.23.7", "rustls 0.23.7",
"thiserror", "thiserror",
"tokio", "tokio",
@ -3101,7 +3101,7 @@ dependencies = [
"bytes", "bytes",
"rand", "rand",
"ring", "ring",
"rustc-hash", "rustc-hash 1.1.0",
"rustls 0.23.7", "rustls 0.23.7",
"slab", "slab",
"thiserror", "thiserror",
@ -3416,7 +3416,7 @@ dependencies = [
"countme", "countme",
"hashbrown 0.14.3", "hashbrown 0.14.3",
"memoffset 0.9.0", "memoffset 0.9.0",
"rustc-hash", "rustc-hash 1.1.0",
"text-size", "text-size",
] ]
@ -3473,6 +3473,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc-hash"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
[[package]] [[package]]
name = "rustc_version" name = "rustc_version"
version = "0.4.0" version = "0.4.0"
@ -4864,6 +4870,7 @@ dependencies = [
"nix-compat", "nix-compat",
"rnix", "rnix",
"rowan", "rowan",
"rustc-hash 2.0.0",
"rustyline", "rustyline",
"smol_str", "smol_str",
"thiserror", "thiserror",
@ -4905,6 +4912,7 @@ dependencies = [
"rnix", "rnix",
"rowan", "rowan",
"rstest", "rstest",
"rustc-hash 2.0.0",
"serde", "serde",
"serde_json", "serde_json",
"sha1", "sha1",

View file

@ -9701,7 +9701,7 @@ rec {
} }
{ {
name = "rustc-hash"; name = "rustc-hash";
packageId = "rustc-hash"; packageId = "rustc-hash 1.1.0";
} }
{ {
name = "rustls"; name = "rustls";
@ -9768,7 +9768,7 @@ rec {
} }
{ {
name = "rustc-hash"; name = "rustc-hash";
packageId = "rustc-hash"; packageId = "rustc-hash 1.1.0";
} }
{ {
name = "rustls"; name = "rustls";
@ -10901,7 +10901,7 @@ rec {
} }
{ {
name = "rustc-hash"; name = "rustc-hash";
packageId = "rustc-hash"; packageId = "rustc-hash 1.1.0";
} }
{ {
name = "text-size"; name = "text-size";
@ -11051,7 +11051,7 @@ rec {
"rustc-dep-of-std" = [ "core" "compiler_builtins" ]; "rustc-dep-of-std" = [ "core" "compiler_builtins" ];
}; };
}; };
"rustc-hash" = rec { "rustc-hash 1.1.0" = rec {
crateName = "rustc-hash"; crateName = "rustc-hash";
version = "1.1.0"; version = "1.1.0";
edition = "2015"; edition = "2015";
@ -11064,6 +11064,20 @@ rec {
}; };
resolvedDefaultFeatures = [ "default" "std" ]; resolvedDefaultFeatures = [ "default" "std" ];
}; };
"rustc-hash 2.0.0" = rec {
crateName = "rustc-hash";
version = "2.0.0";
edition = "2021";
sha256 = "0lni0lf846bzrf3jvci6jaf4142n1mdqxvcpczk5ch9pfgyk8c2q";
authors = [
"The Rust Project Developers"
];
features = {
"default" = [ "std" ];
"rand" = [ "dep:rand" "std" ];
};
resolvedDefaultFeatures = [ "default" "std" ];
};
"rustc_version" = rec { "rustc_version" = rec {
crateName = "rustc_version"; crateName = "rustc_version";
version = "0.4.0"; version = "0.4.0";
@ -15892,6 +15906,10 @@ rec {
name = "rowan"; name = "rowan";
packageId = "rowan"; packageId = "rowan";
} }
{
name = "rustc-hash";
packageId = "rustc-hash 2.0.0";
}
{ {
name = "rustyline"; name = "rustyline";
packageId = "rustyline"; packageId = "rustyline";
@ -16049,6 +16067,10 @@ rec {
name = "rowan"; name = "rowan";
packageId = "rowan"; packageId = "rowan";
} }
{
name = "rustc-hash";
packageId = "rustc-hash 2.0.0";
}
{ {
name = "serde"; name = "serde";
packageId = "serde"; packageId = "serde";

View file

@ -26,6 +26,7 @@ thiserror = "1.0.38"
tokio = "1.28.0" tokio = "1.28.0"
tracing = "0.1.40" tracing = "0.1.40"
tracing-indicatif = "0.3.6" tracing-indicatif = "0.3.6"
rustc-hash = "2.0.0"
[dependencies.wu-manber] [dependencies.wu-manber]
git = "https://github.com/tvlfyi/wu-manber.git" git = "https://github.com/tvlfyi/wu-manber.git"

View file

@ -1,5 +1,7 @@
use std::{collections::HashMap, path::PathBuf, rc::Rc}; use std::path::PathBuf;
use std::rc::Rc;
use rustc_hash::FxHashMap;
use smol_str::SmolStr; use smol_str::SmolStr;
use std::fmt::Write; use std::fmt::Write;
use tracing::{instrument, Span}; use tracing::{instrument, Span};
@ -86,7 +88,7 @@ pub fn evaluate(
path: Option<PathBuf>, path: Option<PathBuf>,
args: &Args, args: &Args,
allow_incomplete: AllowIncomplete, allow_incomplete: AllowIncomplete,
env: Option<&HashMap<SmolStr, Value>>, env: Option<&FxHashMap<SmolStr, Value>>,
globals: Option<Rc<GlobalsMap>>, globals: Option<Rc<GlobalsMap>>,
source_map: Option<SourceCode>, source_map: Option<SourceCode>,
) -> Result<EvalResult, IncompleteInput> { ) -> Result<EvalResult, IncompleteInput> {
@ -218,7 +220,7 @@ pub fn interpret(
args: &Args, args: &Args,
explain: bool, explain: bool,
allow_incomplete: AllowIncomplete, allow_incomplete: AllowIncomplete,
env: Option<&HashMap<SmolStr, Value>>, env: Option<&FxHashMap<SmolStr, Value>>,
globals: Option<Rc<GlobalsMap>>, globals: Option<Rc<GlobalsMap>>,
source_map: Option<SourceCode>, source_map: Option<SourceCode>,
) -> Result<InterpretResult, IncompleteInput> { ) -> Result<InterpretResult, IncompleteInput> {

View file

@ -1,6 +1,7 @@
use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::{collections::HashMap, path::PathBuf};
use rustc_hash::FxHashMap;
use rustyline::{error::ReadlineError, Editor}; use rustyline::{error::ReadlineError, Editor};
use smol_str::SmolStr; use smol_str::SmolStr;
use tvix_eval::{GlobalsMap, SourceCode, Value}; use tvix_eval::{GlobalsMap, SourceCode, Value};
@ -88,7 +89,7 @@ pub struct Repl<'a> {
multiline_input: Option<String>, multiline_input: Option<String>,
rl: Editor<()>, rl: Editor<()>,
/// Local variables defined at the top-level in the repl /// Local variables defined at the top-level in the repl
env: HashMap<SmolStr, Value>, env: FxHashMap<SmolStr, Value>,
io_handle: Rc<TvixStoreIO>, io_handle: Rc<TvixStoreIO>,
args: &'a Args, args: &'a Args,
@ -102,7 +103,7 @@ impl<'a> Repl<'a> {
Self { Self {
multiline_input: None, multiline_input: None,
rl, rl,
env: HashMap::new(), env: FxHashMap::default(),
io_handle, io_handle,
args, args,
source_map: Default::default(), source_map: Default::default(),

View file

@ -34,6 +34,7 @@ sha2 = "0.10.8"
sha1 = "0.10.6" sha1 = "0.10.6"
md-5 = "0.10.6" md-5 = "0.10.6"
data-encoding = "2.6.0" data-encoding = "2.6.0"
rustc-hash = "2.0.0"
[dev-dependencies] [dev-dependencies]
criterion = "0.5" criterion = "0.5"

3
tvix/eval/clippy.toml Normal file
View file

@ -0,0 +1,3 @@
# See https://nnethercote.github.io/perf-book/hashing.html. Use FxHashMap and
# FxHashSet, not HashMap and HashSet
disallowed-types = ["std::collections::HashMap", "std::collections::HashSet"]

View file

@ -9,8 +9,8 @@ use genawaiter::rc::Gen;
use imbl::OrdMap; use imbl::OrdMap;
use regex::Regex; use regex::Regex;
use std::cmp::{self, Ordering}; use std::cmp::{self, Ordering};
use std::collections::BTreeMap;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::collections::{BTreeMap, HashSet};
use std::path::PathBuf; use std::path::PathBuf;
use crate::arithmetic_op; use crate::arithmetic_op;
@ -88,6 +88,7 @@ mod pure_builtins {
use imbl::Vector; use imbl::Vector;
use itertools::Itertools; use itertools::Itertools;
use os_str_bytes::OsStringBytes; use os_str_bytes::OsStringBytes;
use rustc_hash::FxHashSet;
use crate::{value::PointerEquality, AddContext, NixContext, NixContextElement}; use crate::{value::PointerEquality, AddContext, NixContext, NixContextElement};
@ -700,7 +701,7 @@ mod pure_builtins {
// //
// In this implementation, we do none of that, no syntax checks, no realization. // In this implementation, we do none of that, no syntax checks, no realization.
// The next `TODO` are the checks that Nix implements. // The next `TODO` are the checks that Nix implements.
let mut ctx_elements: HashSet<NixContextElement> = HashSet::new(); let mut ctx_elements: FxHashSet<NixContextElement> = FxHashSet::default();
let span = generators::request_span(&co).await; let span = generators::request_span(&co).await;
let origin = origin let origin = origin
.coerce_to_string( .coerce_to_string(
@ -1115,7 +1116,7 @@ mod pure_builtins {
.to_list()? .to_list()?
.into_iter() .into_iter()
.map(|v| v.to_str()) .map(|v| v.to_str())
.collect::<Result<HashSet<_>, _>>()?; .collect::<Result<FxHashSet<_>, _>>()?;
let res = attrs.iter().filter_map(|(k, v)| { let res = attrs.iter().filter_map(|(k, v)| {
if !keys.contains(k) { if !keys.contains(k) {
Some((k.clone(), v.clone())) Some((k.clone(), v.clone()))

View file

@ -560,7 +560,7 @@ impl Compiler<'_, '_> {
/// Emit definitions for all variables in the top-level global env passed to the evaluation (eg /// Emit definitions for all variables in the top-level global env passed to the evaluation (eg
/// local variables in the REPL) /// local variables in the REPL)
pub(super) fn compile_env(&mut self, env: &HashMap<SmolStr, Value>) { pub(super) fn compile_env(&mut self, env: &FxHashMap<SmolStr, Value>) {
for (name, value) in env { for (name, value) in env {
self.scope_mut().declare_constant(name.to_string()); self.scope_mut().declare_constant(name.to_string());
self.emit_constant(value.clone(), &EntireFile); self.emit_constant(value.clone(), &EntireFile);

View file

@ -20,8 +20,9 @@ mod scope;
use codemap::Span; use codemap::Span;
use rnix::ast::{self, AstToken}; use rnix::ast::{self, AstToken};
use rustc_hash::FxHashMap;
use smol_str::SmolStr; use smol_str::SmolStr;
use std::collections::{BTreeMap, HashMap}; use std::collections::BTreeMap;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::{Rc, Weak}; use std::rc::{Rc, Weak};
@ -117,7 +118,7 @@ impl TrackedFormal {
/// The map of globally available functions and other values that /// The map of globally available functions and other values that
/// should implicitly be resolvable in the global scope. /// should implicitly be resolvable in the global scope.
pub type GlobalsMap = HashMap<&'static str, Value>; pub type GlobalsMap = FxHashMap<&'static str, Value>;
/// Set of builtins that (if they exist) should be made available in /// Set of builtins that (if they exist) should be made available in
/// the global scope, meaning that they can be accessed not just /// the global scope, meaning that they can be accessed not just
@ -187,7 +188,7 @@ impl<'source, 'observer> Compiler<'source, 'observer> {
pub(crate) fn new( pub(crate) fn new(
location: Option<PathBuf>, location: Option<PathBuf>,
globals: Rc<GlobalsMap>, globals: Rc<GlobalsMap>,
env: Option<&HashMap<SmolStr, Value>>, env: Option<&FxHashMap<SmolStr, Value>>,
source: &'source SourceCode, source: &'source SourceCode,
file: &'source codemap::File, file: &'source codemap::File,
observer: &'observer mut dyn CompilerObserver, observer: &'observer mut dyn CompilerObserver,
@ -1588,7 +1589,7 @@ pub fn prepare_globals(
Rc::new_cyclic(Box::new(move |weak: &Weak<GlobalsMap>| { Rc::new_cyclic(Box::new(move |weak: &Weak<GlobalsMap>| {
// First step is to construct the builtins themselves as // First step is to construct the builtins themselves as
// `NixAttrs`. // `NixAttrs`.
let mut builtins: GlobalsMap = HashMap::from_iter(builtins); let mut builtins: GlobalsMap = FxHashMap::from_iter(builtins);
// At this point, optionally insert `import` if enabled. To // At this point, optionally insert `import` if enabled. To
// "tie the knot" of `import` needing the full set of globals // "tie the knot" of `import` needing the full set of globals
@ -1601,7 +1602,7 @@ pub fn prepare_globals(
// Next, the actual map of globals which the compiler will use // Next, the actual map of globals which the compiler will use
// to resolve identifiers is constructed. // to resolve identifiers is constructed.
let mut globals: GlobalsMap = HashMap::new(); let mut globals: GlobalsMap = FxHashMap::default();
// builtins contain themselves (`builtins.builtins`), which we // builtins contain themselves (`builtins.builtins`), which we
// can resolve by manually constructing a suspended thunk that // can resolve by manually constructing a suspended thunk that
@ -1654,7 +1655,7 @@ pub fn compile(
expr: &ast::Expr, expr: &ast::Expr,
location: Option<PathBuf>, location: Option<PathBuf>,
globals: Rc<GlobalsMap>, globals: Rc<GlobalsMap>,
env: Option<&HashMap<SmolStr, Value>>, env: Option<&FxHashMap<SmolStr, Value>>,
source: &SourceCode, source: &SourceCode,
file: &codemap::File, file: &codemap::File,
observer: &mut dyn CompilerObserver, observer: &mut dyn CompilerObserver,

View file

@ -10,10 +10,8 @@
//! stack indices. To do this, the compiler simulates where locals //! stack indices. To do this, the compiler simulates where locals
//! will be at runtime using the data structures implemented here. //! will be at runtime using the data structures implemented here.
use std::{ use rustc_hash::FxHashMap;
collections::{hash_map, HashMap}, use std::{collections::hash_map, ops::Index};
ops::Index,
};
use smol_str::SmolStr; use smol_str::SmolStr;
@ -168,7 +166,7 @@ pub struct Scope {
pub upvalues: Vec<Upvalue>, pub upvalues: Vec<Upvalue>,
/// Secondary by-name index over locals. /// Secondary by-name index over locals.
by_name: HashMap<String, ByName>, by_name: FxHashMap<String, ByName>,
/// How many scopes "deep" are these locals? /// How many scopes "deep" are these locals?
scope_depth: usize, scope_depth: usize,

View file

@ -36,7 +36,7 @@ mod test_utils;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use std::collections::HashMap; use rustc_hash::FxHashMap;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::str::FromStr; use std::str::FromStr;
@ -86,7 +86,7 @@ enum BuilderGlobals {
pub struct EvaluationBuilder<'co, 'ro, 'env, IO> { pub struct EvaluationBuilder<'co, 'ro, 'env, IO> {
source_map: Option<SourceCode>, source_map: Option<SourceCode>,
globals: BuilderGlobals, globals: BuilderGlobals,
env: Option<&'env HashMap<SmolStr, Value>>, env: Option<&'env FxHashMap<SmolStr, Value>>,
io_handle: IO, io_handle: IO,
enable_import: bool, enable_import: bool,
strict: bool, strict: bool,
@ -264,7 +264,7 @@ impl<'co, 'ro, 'env, IO> EvaluationBuilder<'co, 'ro, 'env, IO> {
Self { nix_path, ..self } Self { nix_path, ..self }
} }
pub fn env(self, env: Option<&'env HashMap<SmolStr, Value>>) -> Self { pub fn env(self, env: Option<&'env FxHashMap<SmolStr, Value>>) -> Self {
Self { env, ..self } Self { env, ..self }
} }
@ -352,7 +352,7 @@ pub struct Evaluation<'co, 'ro, 'env, IO> {
globals: Rc<GlobalsMap>, globals: Rc<GlobalsMap>,
/// Top-level variables to define in the evaluation /// Top-level variables to define in the evaluation
env: Option<&'env HashMap<SmolStr, Value>>, env: Option<&'env FxHashMap<SmolStr, Value>>,
/// Implementation of file-IO to use during evaluation, e.g. for /// Implementation of file-IO to use during evaluation, e.g. for
/// impure builtins. /// impure builtins.
@ -570,7 +570,7 @@ fn parse_compile_internal(
location: Option<PathBuf>, location: Option<PathBuf>,
source: SourceCode, source: SourceCode,
globals: Rc<GlobalsMap>, globals: Rc<GlobalsMap>,
env: Option<&HashMap<SmolStr, Value>>, env: Option<&FxHashMap<SmolStr, Value>>,
compiler_observer: &mut dyn CompilerObserver, compiler_observer: &mut dyn CompilerObserver,
) -> Option<Rc<Lambda>> { ) -> Option<Rc<Lambda>> {
let parsed = rnix::ast::Root::parse(code); let parsed = rnix::ast::Root::parse(code);

View file

@ -5,9 +5,9 @@
//! paying the cost when creating new strings. //! paying the cost when creating new strings.
use bstr::{BStr, BString, ByteSlice, Chars}; use bstr::{BStr, BString, ByteSlice, Chars};
use rnix::ast; use rnix::ast;
use rustc_hash::FxHashSet;
use std::alloc::{alloc, dealloc, handle_alloc_error, Layout}; use std::alloc::{alloc, dealloc, handle_alloc_error, Layout};
use std::borrow::{Borrow, Cow}; use std::borrow::{Borrow, Cow};
use std::collections::HashSet;
use std::ffi::c_void; use std::ffi::c_void;
use std::fmt::{self, Debug, Display}; use std::fmt::{self, Debug, Display};
use std::hash::Hash; use std::hash::Hash;
@ -40,23 +40,29 @@ pub enum NixContextElement {
/// operations, e.g. concatenation, interpolation and other string operations. /// operations, e.g. concatenation, interpolation and other string operations.
#[repr(transparent)] #[repr(transparent)]
#[derive(Clone, Debug, Serialize, Default)] #[derive(Clone, Debug, Serialize, Default)]
pub struct NixContext(HashSet<NixContextElement>); pub struct NixContext(FxHashSet<NixContextElement>);
impl From<NixContextElement> for NixContext { impl From<NixContextElement> for NixContext {
fn from(value: NixContextElement) -> Self { fn from(value: NixContextElement) -> Self {
Self([value].into()) let mut set = FxHashSet::default();
set.insert(value);
Self(set)
} }
} }
impl From<HashSet<NixContextElement>> for NixContext { impl From<FxHashSet<NixContextElement>> for NixContext {
fn from(value: HashSet<NixContextElement>) -> Self { fn from(value: FxHashSet<NixContextElement>) -> Self {
Self(value) Self(value)
} }
} }
impl<const N: usize> From<[NixContextElement; N]> for NixContext { impl<const N: usize> From<[NixContextElement; N]> for NixContext {
fn from(value: [NixContextElement; N]) -> Self { fn from(value: [NixContextElement; N]) -> Self {
Self(HashSet::from(value)) let mut set = FxHashSet::default();
for elt in value {
set.insert(elt);
}
Self(set)
} }
} }

View file

@ -18,9 +18,9 @@
//! object, but when forcing a thunk, the runtime *must* mutate the //! object, but when forcing a thunk, the runtime *must* mutate the
//! memoisable slot. //! memoisable slot.
use rustc_hash::FxHashSet;
use std::{ use std::{
cell::{Ref, RefCell, RefMut}, cell::{Ref, RefCell, RefMut},
collections::HashSet,
fmt::Debug, fmt::Debug,
rc::Rc, rc::Rc,
}; };
@ -413,7 +413,7 @@ impl TotalDisplay for Thunk {
/// The inner `HashSet` is not available on the outside, as it would be /// The inner `HashSet` is not available on the outside, as it would be
/// potentially unsafe to interact with the pointers in the set. /// potentially unsafe to interact with the pointers in the set.
#[derive(Default)] #[derive(Default)]
pub struct ThunkSet(HashSet<*const ThunkRepr>); pub struct ThunkSet(FxHashSet<*const ThunkRepr>);
impl ThunkSet { impl ThunkSet {
/// Check whether the given thunk has already been seen. Will mark the thunk /// Check whether the given thunk has already been seen. Will mark the thunk

View file

@ -14,8 +14,9 @@ mod macros;
use bstr::{BString, ByteSlice, ByteVec}; use bstr::{BString, ByteSlice, ByteVec};
use codemap::Span; use codemap::Span;
use rustc_hash::FxHashMap;
use serde_json::json; use serde_json::json;
use std::{cmp::Ordering, collections::HashMap, ops::DerefMut, path::PathBuf, rc::Rc}; use std::{cmp::Ordering, ops::DerefMut, path::PathBuf, rc::Rc};
use crate::{ use crate::{
arithmetic_op, arithmetic_op,
@ -211,7 +212,7 @@ impl Frame {
} }
#[derive(Default)] #[derive(Default)]
struct ImportCache(HashMap<PathBuf, Value>); struct ImportCache(FxHashMap<PathBuf, Value>);
/// The `ImportCache` holds the `Value` resulting from `import`ing a certain /// The `ImportCache` holds the `Value` resulting from `import`ing a certain
/// file, so that the same file doesn't need to be re-evaluated multiple times. /// file, so that the same file doesn't need to be re-evaluated multiple times.

View file

@ -1223,7 +1223,7 @@ dependencies = [
"countme", "countme",
"hashbrown 0.14.5", "hashbrown 0.14.5",
"memoffset", "memoffset",
"rustc-hash", "rustc-hash 1.1.0",
"text-size", "text-size",
] ]
@ -1239,6 +1239,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc-hash"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.17" version = "1.0.17"
@ -1561,6 +1567,7 @@ dependencies = [
"regex", "regex",
"rnix", "rnix",
"rowan", "rowan",
"rustc-hash 2.0.0",
"serde", "serde",
"serde_json", "serde_json",
"sha1", "sha1",

View file

@ -3668,7 +3668,7 @@ rec {
} }
{ {
name = "rustc-hash"; name = "rustc-hash";
packageId = "rustc-hash"; packageId = "rustc-hash 1.1.0";
} }
{ {
name = "text-size"; name = "text-size";
@ -3695,7 +3695,7 @@ rec {
"rustc-dep-of-std" = [ "core" "compiler_builtins" ]; "rustc-dep-of-std" = [ "core" "compiler_builtins" ];
}; };
}; };
"rustc-hash" = rec { "rustc-hash 1.1.0" = rec {
crateName = "rustc-hash"; crateName = "rustc-hash";
version = "1.1.0"; version = "1.1.0";
edition = "2015"; edition = "2015";
@ -3708,6 +3708,20 @@ rec {
}; };
resolvedDefaultFeatures = [ "default" "std" ]; resolvedDefaultFeatures = [ "default" "std" ];
}; };
"rustc-hash 2.0.0" = rec {
crateName = "rustc-hash";
version = "2.0.0";
edition = "2021";
sha256 = "0lni0lf846bzrf3jvci6jaf4142n1mdqxvcpczk5ch9pfgyk8c2q";
authors = [
"The Rust Project Developers"
];
features = {
"default" = [ "std" ];
"rand" = [ "dep:rand" "std" ];
};
resolvedDefaultFeatures = [ "default" "std" ];
};
"rustversion" = rec { "rustversion" = rec {
crateName = "rustversion"; crateName = "rustversion";
version = "1.0.17"; version = "1.0.17";
@ -4642,6 +4656,10 @@ rec {
name = "rowan"; name = "rowan";
packageId = "rowan"; packageId = "rowan";
} }
{
name = "rustc-hash";
packageId = "rustc-hash 2.0.0";
}
{ {
name = "serde"; name = "serde";
packageId = "serde"; packageId = "serde";