Skip to main content

CORE

Constant CORE 

Source
pub const CORE: &str = "//! The types and traits every module sees without an import.\n//!\n//! `Option` holds a value that may be absent, `Result` the outcome of an\n//! operation that can fail, and `Ordering` the result of a comparison. The\n//! traits `Display`, `Debug`, `Eq`, `Ord`, `Clone`, `Default` and `Hash`\n//! come with impls for `Int`, `Float`, `Bool`, `Char` and `String`, except\n//! `Hash` for `Float`. `Iterator` yields values one at a time, and its `map`\n//! and `filter` return a `MapIter` and a `FilterIter`. A module\'s own\n//! definition of one of these names shadows the one here.\n//!\n//! An absent value, a failure, and an iterator\'s lazy `filter` and `map`,\n//! run by `collect`:\n//!\n//! ```\n//! // `Option` holds a value that may be absent.\n//! let port: Option<Int> = Some(8080)\n//! assert_eq(port.map(|p| p + 1).unwrap_or(80), 8081)\n//! let missing: Option<Int> = None\n//! assert_eq(missing.unwrap_or(80), 80)\n//!\n//! // `Result` is the outcome of something that can fail.\n//! let checked: Result<Int, String> = missing.ok_or(\"no port given\")\n//! assert(checked.is_err(), \"None became an Err\")\n//!\n//! // An iterator\'s `filter` and `map` are lazy; `collect` runs them.\n//! let mut nums: Vec<Int> = Vec::new()\n//! for n in 1..6 { nums.push(n) }\n//! let tens = nums.iter().filter(|n| n % 2 == 0).map(|n| n * 10).collect()\n//! assert_eq(tens.len(), 2)\n//! assert_eq(tens.get(1).unwrap(), 40)\n//! ```\n\n// Nova standard library \u{2014} core.\n//\n// Compiled as an implicit module and glob-imported into every user module, so\n// these names need no `import`. A user definition of the same name shadows the\n// one here (see docs/adr/0004-stdlib-compile-model.md).\n\n/// A value that may be absent: `Some` value, or `None`.\npub type Option<T> =\n    /// Holds a value.\n    | Some(T)\n    /// Holds no value.\n    | None\n\n/// The outcome of an operation that can fail: `Ok` with a value, or `Err`\n/// with an error.\npub type Result<T, E> =\n    /// Holds the value of a success.\n    | Ok(T)\n    /// Holds the error of a failure.\n    | Err(E)\n\nimpl<T> Option<T> {\n    /// Returns `true` if the option is `Some`.\n    pub fn is_some(self) -> Bool {\n        match self {\n            Some(_) => true\n            None => false\n        }\n    }\n\n    /// Returns `true` if the option is `None`.\n    pub fn is_none(self) -> Bool { !self.is_some() }\n\n    /// Applies `f` to the value, if there is one.\n    ///\n    /// Returns `Some(f(v))` for `Some(v)`, and `None` for `None`.\n    pub fn map<U>(self, f: fn(T) -> U) -> Option<U> {\n        match self {\n            Some(v) => Some(f(v))\n            None => None\n        }\n    }\n\n    /// Calls `f` with the value, if there is one, and returns its result.\n    ///\n    /// Returns `None` for `None`, without calling `f`.\n    pub fn and_then<U>(self, f: fn(T) -> Option<U>) -> Option<U> {\n        match self {\n            Some(v) => f(v)\n            None => None\n        }\n    }\n\n    /// Returns the value.\n    ///\n    /// Panics if the option is `None`.\n    pub fn unwrap(self) -> T {\n        match self {\n            Some(v) => v\n            None => panic(\"called `unwrap` on a `None` value\")\n        }\n    }\n\n    /// Returns the value, or `default` if the option is `None`.\n    pub fn unwrap_or(self, default: T) -> T {\n        match self {\n            Some(v) => v\n            None => default\n        }\n    }\n\n    /// Converts the option to a `Result`: `Ok(v)` for `Some(v)`, and\n    /// `Err(err)` for `None`.\n    pub fn ok_or<E>(self, err: E) -> Result<T, E> {\n        match self {\n            Some(v) => Ok(v)\n            None => Err(err)\n        }\n    }\n}\n\nimpl<T, E> Result<T, E> {\n    /// Returns `true` if the result is `Ok`.\n    pub fn is_ok(self) -> Bool {\n        match self {\n            Ok(_) => true\n            Err(_) => false\n        }\n    }\n\n    /// Returns `true` if the result is `Err`.\n    pub fn is_err(self) -> Bool { !self.is_ok() }\n\n    /// Applies `f` to the value of an `Ok`, leaving an `Err` as it is.\n    pub fn map<U>(self, f: fn(T) -> U) -> Result<U, E> {\n        match self {\n            Ok(v) => Ok(f(v))\n            Err(e) => Err(e)\n        }\n    }\n\n    /// Applies `f` to the error of an `Err`, leaving an `Ok` as it is.\n    pub fn map_err<F>(self, f: fn(E) -> F) -> Result<T, F> {\n        match self {\n            Ok(v) => Ok(v)\n            Err(e) => Err(f(e))\n        }\n    }\n\n    /// Calls `f` with the value of an `Ok` and returns its result.\n    ///\n    /// Returns an `Err` as it is, without calling `f`.\n    pub fn and_then<U>(self, f: fn(T) -> Result<U, E>) -> Result<U, E> {\n        match self {\n            Ok(v) => f(v)\n            Err(e) => Err(e)\n        }\n    }\n\n    /// Returns the value of an `Ok`.\n    ///\n    /// Panics if the result is an `Err`.\n    pub fn unwrap(self) -> T {\n        match self {\n            Ok(v) => v\n            Err(_) => panic(\"called `unwrap` on an `Err` value\")\n        }\n    }\n\n    /// Returns the value of an `Ok`, or `default` for an `Err`.\n    pub fn unwrap_or(self, default: T) -> T {\n        match self {\n            Ok(v) => v\n            Err(_) => default\n        }\n    }\n}\n\n// Core traits, and their impls for the five primitive types.\n//\n// `Ord` cannot be written uniformly: `<` works for Int/Float/Char but not\n// for Bool or String (E0013 for both). Bool is ordered with `if` alone;\n// String has neither length nor indexing in Nova, so it goes through\n// `str_cmp`, a compiler builtin (see `nova-resolver`\'s `Builtin` enum) that\n// reaches the runtime\'s byte-lexicographic `nova_rt_str_cmp` directly: a\n// named function, resolved specially by the compiler and lowered straight to\n// a runtime call \u{2014} the same way `println`/`print`/`panic` reach the runtime.\n// This is *not* how `==` on `String` reaches `nova_rt_str_eq`: `==` is a\n// pure operator lowering (`binary_result_ty` permits `Eq`/`Ne` for\n// `Ty::String`; MIR\'s `lower_binary` intercepts it) that introduces no name\n// in any namespace, so it has no \"reserved word\" concern to begin with.\n// `str_cmp` does, and unlike `println`/`print`/`panic` it is not meant to be\n// user-visible language surface, so it is seeded only into std modules\' own\n// scopes (`Builtin::STD_ONLY`), not into every module \u{2014} a user program\n// may freely define its own `str_cmp` (String is not FFI-safe, and\n// `nova_`-prefixed extern symbols are reserved by the compiler, so a\n// user-visible `extern` was not an option either).\n\n// `Hash` reaches the runtime the same way, through two more std-only\n// builtins: `str_hash` (no primitive walks a `String`, so a NAMED operation\n// over its bytes needs a builtin -- `==` reaches the runtime as a plain\n// operator lowering and introduces no name, so it is not one; an absence\n// about the primitive layer, NOT\n// about what Nova code can reach, since `std/bytes` and `std/strings` build\n// byte and char access on builtins of this kind and this module walks a\n// string itself at `impl Debug for String` below; an earlier wording here\n// read as the wider claim and was quoted as one, which ADR 0005\'s 2026-08-27\n// amendment records) and `char_to_int` (Nova has no `as` casts and\n// no other `Char` -> `Int` conversion). `char_to_int` is the one builtin that\n// is *not* a runtime call \u{2014} `Char` and `Int` are the same machine class, so\n// nova-mir lowers it to a register move. See ADR 0005 section 2 for why\n// `Hash` is one-shot (`fn hash(self) -> Int`) rather than streaming, and why\n// there is deliberately no `Hash for Float`.\n\n/// The result of comparing two values, as `Ord::cmp` returns it.\npub type Ordering =\n    /// The first value is less than the second.\n    | Less\n    /// The two values are equal.\n    | Equal\n    /// The first value is greater than the second.\n    | Greater\n\n/// A type whose values can be shown as text for people to read.\n///\n/// String interpolation, `\"${value}\"`, uses it for a value of a type that\n/// implements it.\npub trait Display {\n    /// Returns the value as text.\n    fn fmt(self) -> String\n}\n\n/// A type whose values can be shown as text for debugging.\npub trait Debug {\n    /// Returns the value as text for debugging.\n    ///\n    /// For `Int`, `Float` and `Bool` it is the text `Display` gives. A `Char`\n    /// or `String` comes out as a quoted Nova literal, escaped so that it\n    /// reads back as the same value.\n    fn dbg(self) -> String\n}\n\n/// A type whose values can be compared for equality.\npub trait Eq {\n    /// Returns `true` if `self` equals `other`.\n    ///\n    /// For `Float`, `NaN` equals no value, not even itself.\n    fn eq(self, other: Self) -> Bool\n    /// Returns `true` if `self` does not equal `other`.\n    ///\n    /// By default it is the opposite of `eq`.\n    fn ne(self, other: Self) -> Bool { !self.eq(other) }\n}\n\n/// A type whose values are ordered.\npub trait Ord: Eq {\n    /// Returns whether `self` is less than, equal to or greater than `other`.\n    ///\n    /// std orders `false` before `true`, a `Char` by its code point, and a\n    /// `String` by its UTF-8 bytes. For `Float`, how `NaN` orders is\n    /// unspecified: today any comparison involving it gives `Greater`, even\n    /// `NaN` with itself.\n    fn cmp(self, other: Self) -> Ordering\n}\n\n/// A type whose values can be copied.\npub trait Clone {\n    /// Returns a copy of `self`.\n    fn clone(self) -> Self\n}\n\n/// A type with a default value.\npub trait Default {\n    /// Returns the type\'s default value.\n    ///\n    /// For `Int`, `Float`, `Bool`, `Char` and `String` it is `0`, `0.0`,\n    /// `false`, `\'\\0\'` and `\"\"`.\n    fn default() -> Self\n}\n\n// One-shot hashing: a value\'s hash is a single `Int`, not a stream folded into\n// a `Hasher` (ADR 0005 section 2). There is no `Hash for Float` on purpose:\n// NaN never equals itself, so a NaN key would be unreachable in a hash map,\n// and `0.0`/`-0.0` are `==` but would hash differently.\n//\n// An implementor\'s contract: if `a.eq(b)` then `a.hash() == b.hash()`.\n//\n// HOW TO USE A HASH: **mask it. Never shift it, and never read its high\n// bits.** `hash & (cap - 1)` over a power-of-two capacity is the only\n// supported way to turn a hash into a bucket index, for three separate\n// reasons:\n//\n//   - `hash % cap` can be *negative*: `str_hash` reinterprets an unsigned\n//     64-bit result as `Int`, and `mix64` spans the full `Int` range too, so a\n//     remainder inherits the sign. `&` with a positive mask is non-negative\n//     for every `Int`.\n//   - The high bits are not a usable second hash. A `hash >> 57`-style tag\n//     byte is *not* independent of the low bits used for the bucket, and for\n//     `str_hash` a negative hash sign-extends into any such tag, so the tag\n//     loses half its range on exactly the keys that need distinguishing.\n//   - `mix64`\'s guarantees are stated over its whole 64-bit result; nothing\n//     promises that any particular slice of it is uniform on its own.\n/// A type whose values can be hashed to an `Int`.\n///\n/// A `Map`\'s keys and a `Set`\'s values must implement it, and `Eq`.\n/// Two values equal by `eq` must have the same hash. `Float` has no impl:\n/// `NaN` equals no value, and `0.0` and `-0.0` are equal though their bits\n/// differ.\n///\n/// A record of your own as a `Map` key, with `Eq` and `Hash` that\n/// agree:\n///\n/// ```\n/// record Point { x: Int, y: Int }\n///\n/// impl Eq for Point {\n///     fn eq(self, other: Point) -> Bool { self.x == other.x && self.y == other.y }\n/// }\n///\n/// // Points equal by `eq` must hash alike, so combine the fields\' hashes.\n/// impl Hash for Point {\n///     fn hash(self) -> Int { self.x.hash() * 31 + self.y.hash() }\n/// }\n///\n/// fn main() {\n///     let mut names: Map<Point, String> = Map::new()\n///     names.insert(Point { x: 0, y: 0 }, \"origin\")\n///     assert_eq(names.get(Point { x: 0, y: 0 }).unwrap(), \"origin\")\n///     assert(!names.contains_key(Point { x: 1, y: 0 }), \"a different point\")\n/// }\n/// ```\npub trait Hash {\n    /// Returns the value\'s hash.\n    ///\n    /// A hash can be negative. To pick one of `n` buckets, where `n` is a\n    /// power of two, mask it, `hash & (n - 1)`, rather than taking a\n    /// remainder, which can be negative, or using its high bits. std seeds\n    /// the hashes of `Int`, `Bool`, `Char` and `String` once per run, so they\n    /// can differ from one run of a program to the next.\n    fn hash(self) -> Int\n}\n\n// The iteration protocol, and the first trait in this file with an associated\n// type. `next` advances the iterator and yields the next element, or `None`\n// once exhausted; `Item` is what it yields, chosen by the implementor.\n//\n// `mut self` is load-bearing rather than stylistic: an iterator has to advance,\n// which means mutating its own state, so a `next` taking plain `self` would\n// either not advance or advance invisibly. It is also the first `mut self` in\n// any `impl Trait for Type` in std \u{2014} closing the trait-method half of the\n// mutable-receiver rule was a hard gate before this trait could be declared at\n// all (ADR 0005 \u{a7}1). The consequence for callers: calling `next` itself needs\n// the iterator held in a `mut` binding or arriving as a `mut` parameter, or\n// the call is `E0060` \u{2014} true of `next` specifically, and no longer true of\n// the four default consumer methods below (see the comment above `fold`).\n//\n// `Option<Self::Item>` is the projection this whole increment exists to make\n// expressible. It is deliberately spelled with `::` and not the `.` that\n// nova-spec/20-STDLIB.md used, because `::` is already how Nova reaches into a\n// type (`Vec::new`, `T::default`) while `.` is field access everywhere else.\n//\n// `map`/`filter`/`fold`/`count`/`any`/`collect` are default methods below,\n// so a caller reaches `MapIter`/`FilterIter` (see below) through `.map()`/\n// `.filter()` and never has to name them directly. Still NOT YET, and still\n// deliberately deferred rather than overlooked: `IntoIterator`, so `for x in\n// v` does not work \u{2014} write `v.iter()`. `Map::iter` is not merely unwritten\n// but impossible \u{2014} it would yield a pair and Nova has no tuples. Iterating\n// means a hand-written `while` plus a `match` on the `Option`, or `for x in\n// it`, or now one of the six methods below.\n//\n// Unlike the traits above, this one is implemented for **no** primitive, so\n// `next` is not taken away from user code on `Int`/`Float`/`Bool`/`Char`/\n// `String` the way each of *their* methods is (ADR 0004, \"Method names are not\n// soft-reserved\"). A user `trait Feed { fn next(...) }` stays usable on those\n// types.\n//\n// Deliberately no count and no method list here. Both used to be written out \u{2014}\n// \"the **six** traits above\" and `fmt`/`eq`/`cmp`/`clone`/`default` \u{2014} and both\n// were wrong by the time anyone read them: `Hash` landing in Phase 2.2a left\n// the tally short, and the list silently omitted `dbg` and `hash`. \"Six\" was\n// correct when written, and the list was never complete. A hand-maintained\n// tally of \"the traits above\", in the one file that gains traits, drifts by\n// construction; grep `^pub trait` above this line for the current set, and the\n// `impl <Trait> for <primitive>` block near the bottom of this file for which\n// of their methods each primitive really has.\n/// A source of values, yielded one at a time by `next`.\n///\n/// A `for` loop runs over any iterator: `for x in v.iter()`. `map` and\n/// `filter` are lazy, and `fold`, `count`, `any` and `collect` consume the\n/// iterator. A record iterator is shared, not copied: the one these methods\n/// were called on is the one that advances, even when it is held in a\n/// binding that is not `mut`.\n///\n/// The adapters are lazy; a consumer runs them:\n///\n/// ```\n/// let mut words: Vec<String> = Vec::new()\n/// words.push(\"map\")\n/// words.push(\"filter\")\n/// words.push(\"fold\")\n///\n/// // `filter` and `map` do nothing until a consumer such as `fold` runs them.\n/// // A closure that calls a method on its parameter names the parameter\'s type.\n/// let lengths = words.iter().filter(|w: String| w.starts_with(\"f\")).map(|w: String| w.len())\n/// assert_eq(lengths.fold(0, |acc, n| acc + n), 10)\n/// assert(words.iter().any(|w| w == \"map\"), \"`any` stops at the first match\")\n/// ```\npub trait Iterator {\n    /// The type of the values the iterator yields.\n    type Item\n    /// Advances the iterator and returns its next value, or `None` when it\n    /// has no more.\n    ///\n    /// Calling it needs a mutable iterator, such as one held in a `mut`\n    /// binding.\n    fn next(mut self) -> Option<Self::Item>\n\n    // --- adapters (lazy: nothing is consumed until a consumer runs) ---\n\n    /// Returns an iterator that yields `f(x)` for each value `x` of this one.\n    ///\n    /// It is lazy: it calls `f` only as it is advanced.\n    fn map<U>(self, f: fn(Self::Item) -> U) -> MapIter<Self, U> { MapIter { it: self, f: f } }\n\n    /// Returns an iterator that yields the values of this one for which\n    /// `keep` returns `true`.\n    ///\n    /// It is lazy: it calls `keep` only as it is advanced.\n    fn filter(self, keep: fn(Self::Item) -> Bool) -> FilterIter<Self> {\n        FilterIter { it: self, keep: keep }\n    }\n\n    // --- consumers (each drives the iterator to exhaustion or short-circuits) ---\n\n    // Plain `self`, not `mut self`, on all four consumers below \u{2014} `next` is\n    // still `mut self` (it is the one method a caller invokes repeatedly on a\n    // binding they hold), but a consumer runs to exhaustion in one call, so it\n    // does not need its *own* receiver to already be a mutable place; it only\n    // needs a mutable place to drive `next` through, and it makes its own with\n    // `let mut it = self`. Records are heap objects with no copy semantics\n    // anywhere in this compiler, so for a record `Self` `it` is an alias of\n    // exactly the storage `self` pointed to, not a copy \u{2014} advancing `it`\n    // advances the same iterator the caller passed in.\n    // `an_iterators_own_storage_still_advances_when_a_consumer_takes_\n    // plain_self` (`crates/nova-cli/tests/run_tests.rs`) pins the aliasing.\n    //\n    // \"For a record `Self`\" is a real condition, not a hedge: nothing in this\n    // trait requires one. `impl Iterator for Int` compiles, a primitive is\n    // passed by value, so the rebind copies and all four consumers **diverge**\n    // rather than returning a wrong number. Pre-existing (hand-driving such an\n    // impl loops forever too) and measured \u{2014} see ADR 0007 \u{a7}2, \"Why it is safe\".\n    //\n    // This is what lets `v.iter().filter(f).map(g).collect()` \u{2014} the form this\n    // feature exists to make possible \u{2014} compile at all: `.filter()`/`.map()`\n    // each return a temporary, and only a plain-`self` method can be called on\n    // one (`place_root` classifies a call result `PlaceRoot::NotAPlace`, and a\n    // `mut self` receiver requires `PlaceRoot::Mutable`).\n    //\n    // Dropping `mut self` relaxes *two* of `place_root`\'s classifications, not\n    // only the one this design needed: `NotAPlace` (the temporary above, the\n    // actual goal) and, as a side effect, `ImmutableLocal` too \u{2014} a caller may\n    // now hold the iterator in a binding that is never declared `mut` at all,\n    // and one of these four methods still silently advances or fully consumes\n    // it:\n    //\n    //   let it = some_record   // NOT mut\n    //   it.count()             // 3\n    //   it.count()             // 0 -- silently advanced, no diagnostic\n    //\n    // Under `mut self` the first call alone was `E0060`. This is not a new\n    // capability, only a wider door to an old one: the compiler\'s own\n    // `for x in <expr>` desugar already launders exactly this way\n    // (`check_for_iterator`, `crates/nova-typeck/src/check.rs`:\n    // `let mut __it = <expr>`), so `for x in <an immutable local>` already\n    // advanced that local before this trait had a single default method \u{2014}\n    // this is that laundering\'s first appearance in a *library* API, not a\n    // new mechanism. Nor does any new iterator *state* become reachable: a\n    // `mut` binding could always be partially consumed and reused. The only\n    // thing that changed is which receivers these four methods accept\n    // syntactically.\n    // `iterator_any_short_circuits_and_does_not_scan_past_the_first_match`\n    // (`crates/nova-cli/tests/run_tests.rs`) pins a non-`mut` receiver being\n    // silently advanced through `any` as accepted, current behavior.\n\n    // The fold primitive. `count` and `collect` could be written over it;\n    // `any` cannot, because `fold` visits every element and `any` must stop.\n    /// Folds the values into one, calling `f(acc, x)` for each value `x`.\n    ///\n    /// `acc` starts as `init` and becomes each call\'s result, and the last\n    /// result is returned. Returns `init` if there are no values.\n    fn fold<A>(self, init: A, f: fn(A, Self::Item) -> A) -> A {\n        let mut it = self\n        let mut acc = init\n        while true {\n            let n = it.next()\n            if n.is_none() { return acc }\n            let g = f\n            acc = g(acc, n.unwrap())\n        }\n        acc\n    }\n\n    // `count`, not `len`: this consumes the iterator, where `Vec::len` is cheap\n    // and non-destructive. Naming it `len` would invite the wrong assumption.\n    /// Counts the values, consuming the iterator.\n    fn count(self) -> Int {\n        let mut it = self\n        let mut n = 0\n        while true {\n            let x = it.next()\n            if x.is_none() { return n }\n            n = n + 1\n        }\n        n\n    }\n\n    // Short-circuits, which is why it is not written over `fold`.\n    /// Returns `true` if `p` returns `true` for any value, and `false`\n    /// otherwise.\n    ///\n    /// It stops at the first value `p` accepts.\n    fn any(self, p: fn(Self::Item) -> Bool) -> Bool {\n        let mut it = self\n        while true {\n            let n = it.next()\n            if n.is_none() { return false }\n            let q = p\n            if q(n.unwrap()) { return true }\n        }\n        false\n    }\n\n    // Returns a `Vec`, which makes `std/core` depend on `std/collections` for\n    // the first time. Accepted deliberately: one method, one type, and the\n    // whole-program merge means there is no layering mechanism to violate, only\n    // a convention. The alternative was `Vec::from_iter(it)` in\n    // `std/collections`, which keeps `std/core` free of collections and reads\n    // worse at the call site.\n    /// Collects the values into a `Vec`, in order.\n    fn collect(self) -> Vec<Self::Item> {\n        let mut it = self\n        let mut out = Vec::new()\n        while true {\n            let n = it.next()\n            if n.is_none() { return out }\n            out.push(n.unwrap())\n        }\n        out\n    }\n}\n\n// A lazy `map`: yields `f(x)` for each `x` the inner iterator yields.\n//\n// `f: fn(I::Item) -> U` is why `I` carries a bound. A bound on a record\'s type\n// parameter is a resolution scope, not a constraint (ADR 0007): it lets this\n// field name `I::Item` at all, and it is not itself checked when a `MapIter`\n// is built \u{2014} `impl<I: Iterator, U> Iterator for MapIter<I, U>` below is what\n// makes a `MapIter` iterable, not this declaration.\n//\n// That does not make a `MapIter<Int, U>` freely buildable, though: `f`\'s own\n// field type names `I::Item`, and `Int::Item` has nothing to resolve to (`Int`\n// has no `Iterator` impl), so `f`\'s declared type never normalizes. What\n// happens then depends on the closure and on reachability, and it is ADR 0007\n// \u{a7}1 (case 1, and its routing table) that has the mechanism \u{2014} read it there\n// rather than reconstructing it from here. Two things this comment used to get\n// wrong, both measured:\n//\n//   - \"no closure \u{2014} none, for any `f` \u{2014} can unify against it\" is **false**.\n//     `MapIter { it: 5, f: |x| x }` produces no unification error at all:\n//     typeck accepts it and monomorphization refuses it with\n//     `error[E0079]: \'Int::Item\' is still an unresolved associated type after\n//     instantiating \'main\'`. A fresh inference variable binds to an\n//     unnormalized projection just as happily as to a concrete type. Only an\n//     *annotated* closure fails to unify \u{2014} `f: |x: Int| x` is\n//     `error[E0010]: field \'f\' expects \'fn(Int::Item) -> ?N\' but found\n//     \'fn(Int) -> Int\'`, plus four `E0011`s for the variables it left free.\n//   - \"unconstructible\" full stop, and \"caught at construction\" full stop, are\n//     **false when the construction is not reachable from `main`**, because the\n//     mechanism is monomorphization and it inherits monomorphization\'s reach. A\n//     `MapIter { it: 5, f: |x| x }` inside a function `main` never calls is\n//     accepted: `nova check` exits 0 with no diagnostic and the program runs.\n//     ADR 0007 \u{a7}1 states the qualifier and shows the measurement.\n//\n// So: a bad instantiation of these two shapes is refused wherever it is\n// actually instantiated, and nowhere else. That is still earlier and stronger\n// than the bound itself promises \u{2014} the bound was meant to leave construction\n// unconstrained and block only *use* as an iterator \u{2014} and it still has nothing\n// to do with the bound.\n//\n// Holds `it` by pointer, like every record, so it SHARES the source iterator\n// rather than copying it \u{2014} advancing this adapter advances the source, and\n// mutating the source mid-iteration is observable. Same alias visibility\n// `VecIter` documents; preventing it needs borrow tracking Nova lacks.\n/// An iterator that yields a function\'s result for each value of another.\n///\n/// `Iterator::map` returns one. It shares the iterator it wraps rather than\n/// copying it.\npub record MapIter<I: Iterator, U> { it: I, f: fn(I::Item) -> U }\n\nimpl<I: Iterator, U> Iterator for MapIter<I, U> {\n    type Item = U\n    fn next(mut self) -> Option<U> {\n        let n = self.it.next()\n        if n.is_none() {\n            None\n        } else {\n            // Bound to a local first: `(self.f)(x)` is `E0014: no method f`.\n            let g = self.f\n            Some(g(n.unwrap()))\n        }\n    }\n}\n\n// A lazy `filter`: yields only the elements `keep` accepts.\n//\n// `type Item = I::Item` is a projection-valued binding \u{2014} the associated type is\n// itself a projection \u{2014} which is the `Assoc { on: Assoc }` shape Phase 2.2c\n// could only reach from a hand-built unit test. This is its first appearance in\n// real source.\n//\n// `I`\'s bound is a resolution scope here for the same reason it is on `MapIter`\n// above \u{2014} it is what lets `keep` name `I::Item` at all, and it is not checked\n// when a `FilterIter` is built. See `MapIter`\'s comment and ADR 0007 \u{a7}1 (case 1\n// and its routing table) for the full account, including what actually happens\n// to a `FilterIter<Int>`: it is refused wherever it is instantiated \u{2014} measured,\n// `FilterIter { it: 5, keep: |x| true }` in `main` is one `E0079` from\n// monomorphization, and `keep: |x: Int| true` is instead one `E0010` naming\n// `fn(Int::Item) -> Bool` \u{2014} but **not** when the construction site is\n// unreachable from `main`, since the mechanism is monomorphization. This\n// comment previously said \"unconstructible\" without that qualifier.\n/// An iterator that yields the values of another that a predicate accepts.\n///\n/// `Iterator::filter` returns one. It shares the iterator it wraps rather\n/// than copying it.\npub record FilterIter<I: Iterator> { it: I, keep: fn(I::Item) -> Bool }\n\nimpl<I: Iterator> Iterator for FilterIter<I> {\n    type Item = I::Item\n    fn next(mut self) -> Option<I::Item> {\n        // `while true`, not `loop`: Nova has no `loop` keyword.\n        while true {\n            let n = self.it.next()\n            if n.is_none() { return None }\n            let p = self.keep\n            if p(n.unwrap()) { return Some(n.unwrap()) }\n        }\n        None\n    }\n}\n\nimpl Display for Int {\n    fn fmt(self) -> String { \"${self}\" }\n}\n\nimpl Display for Float {\n    fn fmt(self) -> String { \"${self}\" }\n}\n\nimpl Display for Bool {\n    fn fmt(self) -> String { \"${self}\" }\n}\n\nimpl Display for Char {\n    fn fmt(self) -> String { \"${self}\" }\n}\n\nimpl Display for String {\n    fn fmt(self) -> String { self }\n}\n\n// `Debug`\'s contract is that its output is a *Nova literal* for the value, so\n// `Char` and `String` are quoted where `Display` is not. Nova\'s lexer accepts\n// `\\n \\t \\r \\\\ \\0 \\u{\u{2026}}` plus `\\\"` in a string literal and `\\\'` in a char\n// literal (`nova-lexer`\'s string scanner and `lex_char`); `\\\"` is not valid in\n// a char literal, nor `\\\'` in a string one, so each form escapes the quote\n// that delimits it, plus the backslash. `String` also escapes every `$` (as\n// `\\u{24}`): a string literal, unlike a char literal, opens an interpolation\n// hole on `$` immediately followed by `{`, so a literal `$` left in the\n// output could silently reopen one when the output is pasted back as\n// source. `Char` never interpolates, so it needs no such rule.\nimpl Debug for Int {\n    fn dbg(self) -> String { \"${self}\" }\n}\n\nimpl Debug for Float {\n    fn dbg(self) -> String { \"${self}\" }\n}\n\nimpl Debug for Bool {\n    fn dbg(self) -> String { \"${self}\" }\n}\n\n// The escape sequence for `c` inside a string literal, or `None` when `c`\n// needs none. Quoting differs between a `Char` literal and a `String`\n// literal, so the quote characters are the callers\' business: `Debug for\n// Char` escapes `\'`, `Debug for String` escapes `\"`, and both need the rest\n// of this identically \u{2014} shared here rather than duplicated a second time, the\n// way `Map::get`/`remove`\'s probe scan was in Phase 2.2a.\nfn escape_common(c: Char) -> Option<String> {\n    if c == \'\\\\\' { return Some(\"\\\\\\\\\") }\n    if c == \'\\n\' { return Some(\"\\\\n\") }\n    if c == \'\\t\' { return Some(\"\\\\t\") }\n    if c == \'\\r\' { return Some(\"\\\\r\") }\n    if c == \'\\0\' { return Some(\"\\\\0\") }\n    None\n}\n\n// `\'` is the one escape `Char` needs that `escape_common` does not cover\n// (mirrored by `\"` in `Debug for String` below), so it is handled directly;\n// everything else comes from `escape_common`. The escaped set is exactly\n// what `lex_char` accepts, so every output here round-trips back through the\n// lexer to `self`. A raw newline/tab/NUL does lex inside `\'\u{2026}\'`, but emitting\n// one would put a control character in the middle of debug output, which\n// defeats the purpose.\nimpl Debug for Char {\n    fn dbg(self) -> String {\n        if self == \'\\\'\' {\n            \"\'\\\\\'\'\"\n        } else {\n            match escape_common(self) {\n                Some(e) => \"\'${e}\'\"\n                None => \"\'${self}\'\"\n            }\n        }\n    }\n}\n\n// `str_chars` (a `Builtin::STD_ONLY` member added for `std/strings`, so it is\n// already visible here with no import and no dependency on `std/strings`)\n// lets this inspect the string\'s contents directly \u{2014} which turned out to be\n// all that closing this ever needed. No dedicated ABI symbol was added: `\"`\n// is handled the same way `\'` is handled above; `$` gets its own arm too,\n// escaped unconditionally as `\\u{24}` rather than only when immediately\n// followed by `{` \u{2014} a plain per-character rule like every other entry here,\n// with no lookahead to get wrong, and it costs nothing since a `$` not\n// before `{` was already safe to leave alone. That arm has to live here\n// rather than in `escape_common`: `\\u{24}` does not lex inside a char\n// literal (`\'\\u{24}\'` fails with `unexpected character \'`), so routing it\n// through the shared helper would make `Debug for Char` emit `\'\\u{24}\'`,\n// which does not parse; `\\$` is not an escape sequence either. Everything\n// else comes from `escape_common`. Building `out` by repeated interpolation\n// (rather than `str_from_chars`) is quadratic in the string\'s length, since\n// each `${out}${piece}` copies `out` again; `dbg` is a diagnostic path, not\n// a hot one, so that trade is the right one rather than pretending\n// otherwise.\nimpl Debug for String {\n    fn dbg(self) -> String {\n        let cs = str_chars(self)\n        let mut out = \"\\\"\"\n        for i in 0..cs.len() {\n            let c = cs[i]\n            if c == \'\"\' {\n                out = \"${out}\\\\\\\"\"\n            } else if c == \'$\' {\n                out = \"${out}\\\\u{24}\"\n            } else {\n                match escape_common(c) {\n                    Some(e) => out = \"${out}${e}\"\n                    None => out = \"${out}${c}\"\n                }\n            }\n        }\n        \"${out}\\\"\"\n    }\n}\n\nimpl Eq for Int {\n    fn eq(self, other: Int) -> Bool { self == other }\n}\n\n// Not reflexive for NaN: `NaN == NaN` is `false`, so `eq(NaN, NaN)` is\n// `false` too (NaN is reachable, e.g. via `0.0 / 0.0`). See the `Ord for\n// Float` impl below for the related non-total-order caveat.\nimpl Eq for Float {\n    fn eq(self, other: Float) -> Bool { self == other }\n}\n\nimpl Eq for Bool {\n    fn eq(self, other: Bool) -> Bool { self == other }\n}\n\nimpl Eq for Char {\n    fn eq(self, other: Char) -> Bool { self == other }\n}\n\nimpl Eq for String {\n    fn eq(self, other: String) -> Bool { self == other }\n}\n\nimpl Ord for Int {\n    fn cmp(self, other: Int) -> Ordering {\n        if self < other { Less } else { if self == other { Equal } else { Greater } }\n    }\n}\n\nimpl Ord for Float {\n    // Not a total order for NaN: `<` and `==` are both `false` whenever\n    // either operand is NaN, so this falls through to `Greater` for any\n    // comparison involving NaN \u{2014} including `cmp(NaN, NaN)`, which is\n    // `Greater`, not `Equal`. Ordering NaN is unspecified; do not rely on it\n    // (e.g. for a future sorted collection) until addressed by design.\n    fn cmp(self, other: Float) -> Ordering {\n        if self < other { Less } else { if self == other { Equal } else { Greater } }\n    }\n}\n\nimpl Ord for Char {\n    fn cmp(self, other: Char) -> Ordering {\n        if self < other { Less } else { if self == other { Equal } else { Greater } }\n    }\n}\n\nimpl Ord for Bool {\n    // `<` is not defined for Bool; false sorts before true.\n    fn cmp(self, other: Bool) -> Ordering {\n        if self { if other { Equal } else { Greater } } else { if other { Less } else { Equal } }\n    }\n}\n\nimpl Ord for String {\n    // String has neither length nor indexing in Nova, so ordering comes from\n    // `str_cmp`, a compiler builtin backed by the runtime\'s byte-lexicographic\n    // compare (see the module-level note above for why not `extern`).\n    fn cmp(self, other: String) -> Ordering {\n        let c = str_cmp(self, other)\n        if c < 0 { Less } else { if c == 0 { Equal } else { Greater } }\n    }\n}\n\nimpl Clone for Int {\n    fn clone(self) -> Int { self }\n}\n\nimpl Clone for Float {\n    fn clone(self) -> Float { self }\n}\n\nimpl Clone for Bool {\n    fn clone(self) -> Bool { self }\n}\n\nimpl Clone for Char {\n    fn clone(self) -> Char { self }\n}\n\nimpl Clone for String {\n    fn clone(self) -> String { self }\n}\n\nimpl Default for Int {\n    fn default() -> Int { 0 }\n}\n\nimpl Default for Float {\n    fn default() -> Float { 0.0 }\n}\n\nimpl Default for Bool {\n    fn default() -> Bool { false }\n}\n\nimpl Default for Char {\n    fn default() -> Char { \'\\0\' }\n}\n\nimpl Default for String {\n    fn default() -> String { \"\" }\n}\n\n// The splitmix64 finalizer: three xor-shift/multiply rounds. `Map` selects\n// buckets with `hash & (cap - 1)`, so it is the *low* bits that must be\n// spread; `fn hash(self) -> Int { self }` would send every multiple of the\n// capacity to bucket 0. A known-good mixer is used rather than an invented\n// one, and this is bit-identical to the canonical splitmix64 finalizer.\n//\n// Getting there needs two workarounds for what `Int` cannot express, and both\n// are load-bearing rather than cosmetic:\n//\n//   - The constants are `0xbf58476d1ce4e5b9` and `0x94d049bb133111eb`, which\n//     exceed `Int`\'s range, so they are written as the two\'s-complement\n//     negatives of those bit patterns. Hex is not an option \u{2014} the lexer\'s\n//     `lex_hex_int` parses as `i64`, so `0xbf58\u{2026}` silently fails to lex \u{2014} but\n//     each negative *is* `-` applied to a decimal literal below `i64::MAX`,\n//     which lexes, and `*` wraps rather than trapping, so the arithmetic\n//     agrees modulo 2^64.\n//   - Nova\'s `>>` is **arithmetic** and there is no `>>>`, so each shift is\n//     masked to clear the sign extension: `& (2^(64-k) - 1)`, i.e.\n//     `17179869183` for `>> 30`, `137438953471` for `>> 27`, `8589934591`\n//     for `>> 31`. The mask is not optional. Without it, arithmetic shift\n//     commutes with complement (`!(x >> k) == (!x) >> k`) and XOR is\n//     invariant under complementing both operands, so `x ^ (x >> k)` returns\n//     the *same value* for `x` and `!x == -1 - x`. Every later stage is a\n//     function of that output, so the whole finalizer folded 2-to-1 with\n//     `mix64(x) == mix64(-1 - x)` \u{2014} identical hashes, not merely congruent\n//     ones, so each pair shared a bucket at *every* capacity and no resize\n//     could ever separate them. Pinned by `tests/runtime/hash.nova`.\n//\n// NOT SEEDED, and that is a decision rather than an oversight. The\n// per-process seed is XORed into the *input* by the `Int`, `Bool` and `Char`\n// `Hash` impls below, before this function runs, so `mix64` itself stays\n// bit-identical to canonical splitmix64\'s finalizer and the canonical vectors\n// in `tests/runtime/hash.nova` keep testing the same function they always\n// tested.\n//\n// The masks stay load-bearing for exactly the reason given above, because\n// seeding does not rescue an unmasked finalizer. XOR with a constant commutes\n// with complement \u{2014} `(!k) ^ s == !(k ^ s)` \u{2014} so an unmasked stage 1 still maps\n// `k ^ s` and `!(k ^ s)` to one value, and the pair `k`, `!k` still folds\n// together whatever the seed is.\n//\n// Module-private, and it stays that way: ADR 0005 records the privacy as a\n// decision, since this is an implementation detail of the primitive impls\n// rather than a published utility and publishing it would make its exact\n// definition a compatibility surface, and the same ADR reserves the freedom to\n// replace these constants or rounds. So `tests/runtime/hash.nova` cannot call\n// this function at all; it recovers the seed from `(0).hash()` and cancels it,\n// carrying its own inverse of the arithmetic below. If these constants ever\n// change, that inverse changes with them.\nfn mix64(x: Int) -> Int {\n    let a = x ^ ((x >> 30) & 17179869183)\n    let b = a * -4658895280553007687\n    let c = b ^ ((b >> 27) & 137438953471)\n    let d = c * -7723592293110705685\n    d ^ ((d >> 31) & 8589934591)\n}\n\n// The per-process seed goes into `mix64`\'s INPUT, not its output, and that is\n// load-bearing rather than stylistic. `Map` selects buckets with\n// `hash & (cap - 1)`, so post-XOR \u{2014} `mix64(x) ^ int_hash_seed()` \u{2014} would leave\n// the low bits as `(mix64(x) & mask) XOR (seed & mask)`, which *permutes*\n// buckets and leaves every colliding pair still colliding. It would look like\n// seeding and buy nothing.\n//\n// What pre-XOR buys is precomputation resistance: a key set built to collide\n// against one process, or offline, does not collide here. What it does not\n// claim, and how Nova code can recover the seed in one call, is at\n// `int_hash_seed` in the resolver and `nova_rt_int_hash_seed` in the runtime.\n// A consequence worth stating where the reader meets it: an `Int`, `Bool` or\n// `Char` hashes to one value for the whole of a run and can hash to a\n// different one in the next run of the same program.\nimpl Hash for Int {\n    fn hash(self) -> Int { mix64(self ^ int_hash_seed()) }\n}\n\nimpl Hash for Bool {\n    fn hash(self) -> Int {\n        if self { mix64(1 ^ int_hash_seed()) } else { mix64(0 ^ int_hash_seed()) }\n    }\n}\n\n// Hashes the Unicode scalar value, so it agrees with `Hash for Int` on that\n// codepoint. `char_to_int` is a compiler builtin because Nova has no `as`\n// casts and `Char` has no other conversion.\nimpl Hash for Char {\n    fn hash(self) -> Int { mix64(char_to_int(self) ^ int_hash_seed()) }\n}\n\n// Seeded FNV-1a over the bytes then splitmix64\'s finalizer, in the runtime\n// (see the module note above), with its unsigned result reinterpreted as `Int`\n// \u{2014} so it is the impl most obviously able to return a negative hash. See the\n// masking rule on `Hash` above.\n//\n// The seed is drawn once per process, so a given `String` hashes to one value\n// for the whole of a run and can hash to a different one in the next run of the\n// same program \u{2014} not must, since two seeds may agree on one string. What\n// that buys and what it does not is documented at `nova_rt_str_hash` in the\n// runtime. The `Int`, `Bool` and `Char` impls above are seeded too, from a\n// separate draw (`int_hash_seed`), so they are not stable across runs either;\n// what stays unseeded is `mix64`, which those impls XOR the seed in *ahead* of.\nimpl Hash for String {\n    fn hash(self) -> Int { str_hash(self) }\n}\n";
Expand description

std/core/lib.nova.