Compare commits
3 commits
aeab786fe3
...
d124ae2b59
Author | SHA1 | Date | |
---|---|---|---|
|
d124ae2b59 | ||
|
adfc2c27f8 | ||
|
bbaa9cb671 |
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "compiler"
|
name = "compiler"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ansi_term = "0.12.1"
|
ansi_term = "0.12.1"
|
||||||
|
@ -16,3 +16,5 @@ paste = "1.0.15"
|
||||||
petgraph = "0.6.5"
|
petgraph = "0.6.5"
|
||||||
thiserror = "1.0.63"
|
thiserror = "1.0.63"
|
||||||
unicode-xid = "0.2.4"
|
unicode-xid = "0.2.4"
|
||||||
|
|
||||||
|
werkzeug = { path = "../../rust/werkzeug" }
|
96
flake.lock
Normal file
96
flake.lock
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1753939845,
|
||||||
|
"narHash": "sha256-K2ViRJfdVGE8tpJejs8Qpvvejks1+A4GQej/lBk5y7I=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "94def634a20494ee057c76998843c015909d6311",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1744536153,
|
||||||
|
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"rust-overlays": "rust-overlays"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlays": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1754102567,
|
||||||
|
"narHash": "sha256-d6nZ+1e4VDqW6VAwfx9EAUDJdPxSwqwGiuli32FEgoE=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "08ff39bf869cadca3102b39824f4c7025186b7dc",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
31
flake.nix
Normal file
31
flake.nix
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
description = "A nix flake for nightly rust";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
rust-overlays.url = "github:oxalica/rust-overlay";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, flake-utils, rust-overlays, ...}:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system: let
|
||||||
|
overlays = [
|
||||||
|
(import rust-overlays)
|
||||||
|
];
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system overlays;
|
||||||
|
};
|
||||||
|
rust = pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.default.override {
|
||||||
|
extensions = ["rust-src" "rust-analyzer"];
|
||||||
|
targets = [ "x86_64-unknown-linux-gnu" ];
|
||||||
|
});
|
||||||
|
in with pkgs; {
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
pkg-config
|
||||||
|
git
|
||||||
|
rust
|
||||||
|
];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
88
src/ast2/biunification.rs
Normal file
88
src/ast2/biunification.rs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
//! Type checking for the AST.
|
||||||
|
//! This module implements a bi-unification type-checking algorithm to infer
|
||||||
|
//! types for each node in the AST.
|
||||||
|
|
||||||
|
// Visitor pattern has lots of unused arguments
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::{Ast, Index, intern, visitor::AstVisitorTrait};
|
||||||
|
|
||||||
|
type Id = u32;
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
Reified(intern::Index),
|
||||||
|
Variable(Id),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Variance of a type parameter or constraint.
|
||||||
|
/// A function of type `A -> B` is covariant in `B` and contravariant in `A`.
|
||||||
|
/// This means that a type `T` may be substituted for `A` if `T` is a subtype of `A`, but
|
||||||
|
/// a type `T` may only be substituted for `B` if `T` is a supertype of `B`.
|
||||||
|
///
|
||||||
|
/// Namely, in a type system with `int` and `nat <: int`, for a function `f: int
|
||||||
|
/// -> int` in the expression `let u: int = 3; let t: nat = f(u);`, `u` may
|
||||||
|
/// safely be used as an argument to `f` because `nat <: int`, but `f(u`)` may
|
||||||
|
/// not be assigned to `t` because `int <: nat` is not true.
|
||||||
|
enum Variance {
|
||||||
|
#[doc(alias = "Positive")]
|
||||||
|
Covariant,
|
||||||
|
#[doc(alias = "Negative")]
|
||||||
|
Contravariant,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Value(Id);
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Use(Id);
|
||||||
|
|
||||||
|
/// Typechecking error.
|
||||||
|
#[derive(Debug, Clone, thiserror::Error)]
|
||||||
|
enum Error {
|
||||||
|
#[error("Unimplemented feature")]
|
||||||
|
Unimplemented,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
struct Bindings {
|
||||||
|
inner: HashMap<super::Index, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TypeChecker<'a> {
|
||||||
|
pool: &'a mut intern::InternPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Core
|
||||||
|
impl TypeChecker<'_> {
|
||||||
|
pub fn new(pool: &mut intern::InternPool) -> TypeChecker {
|
||||||
|
TypeChecker { pool }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn var(&mut self) -> (Value, Use) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frontend
|
||||||
|
|
||||||
|
impl<'a> AstVisitorTrait<&'a Ast> for TypeChecker<'_> {
|
||||||
|
type Error = Error;
|
||||||
|
type Value = Value;
|
||||||
|
|
||||||
|
const UNIMPL: Self::Error = Error::Unimplemented;
|
||||||
|
|
||||||
|
fn visit_constant_impl(
|
||||||
|
&mut self,
|
||||||
|
ast: &'a Ast,
|
||||||
|
idx: Index,
|
||||||
|
ty: Index,
|
||||||
|
value: intern::Index,
|
||||||
|
) -> std::result::Result<Self::Value, Self::Error> {
|
||||||
|
// constants may be of type `comptime_int`, which is a special type that
|
||||||
|
// cannot exist at runtime.
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,12 @@ pub enum SimpleType {
|
||||||
USize,
|
USize,
|
||||||
ISize,
|
ISize,
|
||||||
ComptimeInt,
|
ComptimeInt,
|
||||||
|
/// Top type: this is the supertype of all types, and any value can coerce into it.
|
||||||
|
/// Although Rust's `()` is not a top type, it can be thought of as a top type in some contexts.
|
||||||
|
Top,
|
||||||
|
/// Bottom type: this is the subtype of all types, and it can coerce into a value of any type.
|
||||||
|
/// Akin to Rust's `!`.
|
||||||
|
Bottom,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u8> for SimpleType {
|
impl From<u8> for SimpleType {
|
||||||
|
@ -52,6 +58,8 @@ impl Display for SimpleType {
|
||||||
SimpleType::USize => "usize",
|
SimpleType::USize => "usize",
|
||||||
SimpleType::ISize => "isize",
|
SimpleType::ISize => "isize",
|
||||||
SimpleType::ComptimeInt => "comptime_int",
|
SimpleType::ComptimeInt => "comptime_int",
|
||||||
|
SimpleType::Top => "⊤",
|
||||||
|
SimpleType::Bottom => "⊥",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -527,6 +535,8 @@ macro_rules! static_keys {
|
||||||
}
|
}
|
||||||
|
|
||||||
static_keys!(
|
static_keys!(
|
||||||
|
TOP => Key::SimpleType {ty: SimpleType::Top,},
|
||||||
|
BOTTOM => Key::SimpleType {ty: SimpleType::Bottom,},
|
||||||
BOOL => Key::SimpleType {ty: SimpleType::Bool,},
|
BOOL => Key::SimpleType {ty: SimpleType::Bool,},
|
||||||
F32 => Key::SimpleType {ty: SimpleType::F32,},
|
F32 => Key::SimpleType {ty: SimpleType::F32,},
|
||||||
F64 => Key::SimpleType {ty: SimpleType::F64,},
|
F64 => Key::SimpleType {ty: SimpleType::F64,},
|
||||||
|
@ -632,6 +642,18 @@ impl InternPool {
|
||||||
pub fn get_i64_type(&self) -> Index {
|
pub fn get_i64_type(&self) -> Index {
|
||||||
self.get_assume_present(&Key::SIntType { bit_width: 64 })
|
self.get_assume_present(&Key::SIntType { bit_width: 64 })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_top_type(&self) -> Index {
|
||||||
|
self.get_assume_present(&Key::SimpleType {
|
||||||
|
ty: SimpleType::Top,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_bottom_type(&self) -> Index {
|
||||||
|
self.get_assume_present(&Key::SimpleType {
|
||||||
|
ty: SimpleType::Bottom,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -740,8 +762,8 @@ impl InternPool {
|
||||||
todo!("void can't be turned into a mir type")
|
todo!("void can't be turned into a mir type")
|
||||||
}
|
}
|
||||||
SimpleType::ISize | SimpleType::USize => Type::QWord,
|
SimpleType::ISize | SimpleType::USize => Type::QWord,
|
||||||
SimpleType::ComptimeInt => {
|
SimpleType::Top | SimpleType::Bottom | SimpleType::ComptimeInt => {
|
||||||
panic!("comptime int can't be turned into a mir type")
|
panic!("{ty} can't be turned into a mir type")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Key::ArrayType { .. } => {
|
Key::ArrayType { .. } => {
|
||||||
|
@ -816,6 +838,9 @@ impl InternPool {
|
||||||
},
|
},
|
||||||
SimpleType::USize => ptr_size,
|
SimpleType::USize => ptr_size,
|
||||||
SimpleType::ISize => ptr_size,
|
SimpleType::ISize => ptr_size,
|
||||||
|
SimpleType::Top | SimpleType::Bottom => {
|
||||||
|
panic!("top and bottom types are not sized")
|
||||||
|
}
|
||||||
SimpleType::ComptimeInt => panic!("comptime int is unsized"),
|
SimpleType::ComptimeInt => panic!("comptime int is unsized"),
|
||||||
},
|
},
|
||||||
Key::PointerType { .. } => ptr_size,
|
Key::PointerType { .. } => ptr_size,
|
||||||
|
@ -953,6 +978,9 @@ impl InternPool {
|
||||||
SimpleType::USize => Type::Integer(IntegralType::new(false, pointer_bits)),
|
SimpleType::USize => Type::Integer(IntegralType::new(false, pointer_bits)),
|
||||||
SimpleType::ISize => Type::Integer(IntegralType::new(true, pointer_bits)),
|
SimpleType::ISize => Type::Integer(IntegralType::new(true, pointer_bits)),
|
||||||
SimpleType::ComptimeInt => Type::comptime_number(),
|
SimpleType::ComptimeInt => Type::comptime_number(),
|
||||||
|
SimpleType::Top | SimpleType::Bottom => {
|
||||||
|
panic!("top and bottom types cannot be converted to ast1 types")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Key::PointerType { pointee, flags } => Type::Pointer {
|
Key::PointerType { pointee, flags } => Type::Pointer {
|
||||||
constness: flags.is_const,
|
constness: flags.is_const,
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
|
#![allow(unused_variables)]
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast2::{
|
ast2::{
|
||||||
intern::{self, AMD64_POINTER_TYPE_INFO},
|
|
||||||
Index,
|
Index,
|
||||||
|
intern::{self, AMD64_POINTER_TYPE_INFO},
|
||||||
},
|
},
|
||||||
triples::{self, Inst, IR},
|
triples::{self, IR, Inst},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
@ -15,9 +16,9 @@ enum Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
Ast, Data, PlaceOrValue, Tag, TypeCache,
|
||||||
intern::InternPoolWrapper as InternPool,
|
intern::InternPoolWrapper as InternPool,
|
||||||
visitor::{AstExt, AstVisitorTrait},
|
visitor::{AstExt, AstVisitorTrait},
|
||||||
Ast, Data, PlaceOrValue, Tag, TypeCache,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IrBuilder {
|
struct IrBuilder {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
};
|
};
|
||||||
|
|
||||||
use intern::{InternPoolWrapper as InternPool, PointerFlags, StructFlags, AMD64_POINTER_TYPE_INFO};
|
use intern::{AMD64_POINTER_TYPE_INFO, InternPoolWrapper as InternPool, PointerFlags, StructFlags};
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -13,6 +13,7 @@ use crate::{
|
||||||
symbol_table::syms2::DeclKind, tokens::Token,
|
symbol_table::syms2::DeclKind, tokens::Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub mod biunification;
|
||||||
pub mod debug;
|
pub mod debug;
|
||||||
pub mod intern;
|
pub mod intern;
|
||||||
pub mod ir;
|
pub mod ir;
|
||||||
|
@ -586,6 +587,7 @@ mod index {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Index tyoe for the AST.
|
||||||
/// Index type that has 28 bits of index and 4 bits of kind.
|
/// Index type that has 28 bits of index and 4 bits of kind.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
@ -2251,6 +2253,9 @@ where
|
||||||
};
|
};
|
||||||
ComptimeNumber::Integral(ComptimeInt::Comptime(bigint))
|
ComptimeNumber::Integral(ComptimeInt::Comptime(bigint))
|
||||||
}
|
}
|
||||||
|
intern::SimpleType::Top | intern::SimpleType::Bottom => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
|
// Visitor pattern has lots of unused arguments
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
use crate::variant;
|
use crate::variant;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
Ast, Data, Index, Tag,
|
||||||
intern::{self},
|
intern::{self},
|
||||||
tag::{AstNode, AstNodeExt},
|
tag::{AstNode, AstNodeExt},
|
||||||
visitor::{AstExt, AstVisitorTrait},
|
visitor::{AstExt, AstVisitorTrait},
|
||||||
Ast, Data, Index, Tag,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
|
424
src/comptime.rs
424
src/comptime.rs
|
@ -12,10 +12,7 @@ pub mod bigint {
|
||||||
pub struct BigInt(Vec<u32>);
|
pub struct BigInt(Vec<u32>);
|
||||||
|
|
||||||
impl BigInt {
|
impl BigInt {
|
||||||
pub fn parse_digits<C: IntoIterator<Item = char>>(
|
pub fn parse_digits<C: IntoIterator<Item = char>>(text: C, radix: Radix) -> BigInt {
|
||||||
text: C,
|
|
||||||
radix: Radix,
|
|
||||||
) -> BigInt {
|
|
||||||
Self(parse_bigint(text.into_iter(), radix))
|
Self(parse_bigint(text.into_iter(), radix))
|
||||||
}
|
}
|
||||||
pub fn from_u32(v: u32) -> BigInt {
|
pub fn from_u32(v: u32) -> BigInt {
|
||||||
|
@ -240,13 +237,9 @@ pub mod bigint {
|
||||||
|
|
||||||
fn sub(mut self, rhs: Self) -> Self::Output {
|
fn sub(mut self, rhs: Self) -> Self::Output {
|
||||||
if self.0.len() < rhs.0.len() {
|
if self.0.len() < rhs.0.len() {
|
||||||
println!(
|
println!("extending self by {} zeroes", rhs.0.len() - self.0.len());
|
||||||
"extending self by {} zeroes",
|
self.0
|
||||||
rhs.0.len() - self.0.len()
|
.extend(core::iter::repeat(0).take(rhs.0.len() - self.0.len()));
|
||||||
);
|
|
||||||
self.0.extend(
|
|
||||||
core::iter::repeat(0).take(rhs.0.len() - self.0.len()),
|
|
||||||
);
|
|
||||||
println!("self: {self:?}");
|
println!("self: {self:?}");
|
||||||
}
|
}
|
||||||
sub_bigint(&mut self.0, &rhs.0);
|
sub_bigint(&mut self.0, &rhs.0);
|
||||||
|
@ -504,10 +497,7 @@ pub mod bigint {
|
||||||
_ => {
|
_ => {
|
||||||
if scalar.is_power_of_two() {
|
if scalar.is_power_of_two() {
|
||||||
lhs.push(0);
|
lhs.push(0);
|
||||||
shl_bitint(
|
shl_bitint(lhs.as_mut_slice(), scalar.trailing_zeros() as usize);
|
||||||
lhs.as_mut_slice(),
|
|
||||||
scalar.trailing_zeros() as usize,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
let mut carry = 0;
|
let mut carry = 0;
|
||||||
for a in lhs.iter_mut() {
|
for a in lhs.iter_mut() {
|
||||||
|
@ -580,7 +570,7 @@ pub mod bigint {
|
||||||
fn trailing_zeros(lhs: &[u32]) -> usize {
|
fn trailing_zeros(lhs: &[u32]) -> usize {
|
||||||
lhs.iter()
|
lhs.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, &c)| c != 0)
|
.find(|&(_, &c)| c != 0)
|
||||||
.map(|(i, &c)| i * u32::BITS as usize + c.trailing_zeros() as usize)
|
.map(|(i, &c)| i * u32::BITS as usize + c.trailing_zeros() as usize)
|
||||||
.unwrap_or(0)
|
.unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
@ -593,10 +583,7 @@ pub mod bigint {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
/// divident must be at least as wide as divisor
|
/// divident must be at least as wide as divisor
|
||||||
/// returns (quotient, remainder)
|
/// returns (quotient, remainder)
|
||||||
pub fn div_rem_bigint_ref(
|
pub fn div_rem_bigint_ref(divident: &BigInt, divisor: &BigInt) -> (BigInt, BigInt) {
|
||||||
divident: &BigInt,
|
|
||||||
divisor: &BigInt,
|
|
||||||
) -> (BigInt, BigInt) {
|
|
||||||
if bigint_is_zero(&divisor.0) {
|
if bigint_is_zero(&divisor.0) {
|
||||||
panic!("divide by zero!");
|
panic!("divide by zero!");
|
||||||
}
|
}
|
||||||
|
@ -614,8 +601,7 @@ pub mod bigint {
|
||||||
|
|
||||||
if divisor.is_power_of_two() {
|
if divisor.is_power_of_two() {
|
||||||
let exp = divisor.trailing_zeros();
|
let exp = divisor.trailing_zeros();
|
||||||
let (div, rem) =
|
let (div, rem) = divident.0.split_at(exp.div_floor(u32::BITS as usize));
|
||||||
divident.0.split_at(exp.div_floor(u32::BITS as usize));
|
|
||||||
let (mut div, mut rem) = (div.to_vec(), rem.to_vec());
|
let (mut div, mut rem) = (div.to_vec(), rem.to_vec());
|
||||||
|
|
||||||
shr_bitint(&mut div, exp % u32::BITS as usize);
|
shr_bitint(&mut div, exp % u32::BITS as usize);
|
||||||
|
@ -641,10 +627,7 @@ pub mod bigint {
|
||||||
if shift == 0 {
|
if shift == 0 {
|
||||||
div_rem_core(divident.clone(), &divisor.0)
|
div_rem_core(divident.clone(), &divisor.0)
|
||||||
} else {
|
} else {
|
||||||
let (q, r) = div_rem_core(
|
let (q, r) = div_rem_core(divident.clone() << shift, &(divisor.clone() << shift).0);
|
||||||
divident.clone() << shift,
|
|
||||||
&(divisor.clone() << shift).0,
|
|
||||||
);
|
|
||||||
|
|
||||||
(q, r >> shift)
|
(q, r >> shift)
|
||||||
}
|
}
|
||||||
|
@ -653,10 +636,7 @@ pub mod bigint {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
/// divident must be at least as wide as divisor
|
/// divident must be at least as wide as divisor
|
||||||
/// returns (quotient, remainder)
|
/// returns (quotient, remainder)
|
||||||
pub fn div_rem_bigint(
|
pub fn div_rem_bigint(divident: BigInt, divisor: BigInt) -> (BigInt, BigInt) {
|
||||||
divident: BigInt,
|
|
||||||
divisor: BigInt,
|
|
||||||
) -> (BigInt, BigInt) {
|
|
||||||
let divident = divident.normalised();
|
let divident = divident.normalised();
|
||||||
let mut divisor = divisor.normalised();
|
let mut divisor = divisor.normalised();
|
||||||
|
|
||||||
|
@ -677,8 +657,7 @@ pub mod bigint {
|
||||||
|
|
||||||
if divisor.is_power_of_two() {
|
if divisor.is_power_of_two() {
|
||||||
let exp = divisor.trailing_zeros();
|
let exp = divisor.trailing_zeros();
|
||||||
let (div, rem) =
|
let (div, rem) = divident.0.split_at(exp.div_floor(u32::BITS as usize));
|
||||||
divident.0.split_at(exp.div_floor(u32::BITS as usize));
|
|
||||||
let (mut div, mut rem) = (div.to_vec(), rem.to_vec());
|
let (mut div, mut rem) = (div.to_vec(), rem.to_vec());
|
||||||
|
|
||||||
shr_bitint(&mut div, exp % u32::BITS as usize);
|
shr_bitint(&mut div, exp % u32::BITS as usize);
|
||||||
|
@ -810,9 +789,7 @@ pub mod bigint {
|
||||||
// q0 is too large if:
|
// q0 is too large if:
|
||||||
// [a2,a1,a0] < q0 * [b1,b0]
|
// [a2,a1,a0] < q0 * [b1,b0]
|
||||||
// (r << BITS) + a2 < q0 * b1
|
// (r << BITS) + a2 < q0 * b1
|
||||||
while r <= u32::MAX as u64
|
while r <= u32::MAX as u64 && from_lo_hi_dwords(r as u32, a2) < q0 as u64 * b1 as u64 {
|
||||||
&& from_lo_hi_dwords(r as u32, a2) < q0 as u64 * b1 as u64
|
|
||||||
{
|
|
||||||
q0 -= 1;
|
q0 -= 1;
|
||||||
r += b0 as u64;
|
r += b0 as u64;
|
||||||
}
|
}
|
||||||
|
@ -1041,10 +1018,7 @@ pub mod bigint {
|
||||||
carry
|
carry
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_bigint(
|
pub fn parse_bigint(text: impl Iterator<Item = char>, radix: Radix) -> Vec<u32> {
|
||||||
text: impl Iterator<Item = char>,
|
|
||||||
radix: Radix,
|
|
||||||
) -> Vec<u32> {
|
|
||||||
let digits = text
|
let digits = text
|
||||||
.filter_map(|c| match c {
|
.filter_map(|c| match c {
|
||||||
'_' => None,
|
'_' => None,
|
||||||
|
@ -1112,20 +1086,14 @@ pub mod bigint {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse() {
|
fn parse() {
|
||||||
let bigint = BigInt::parse_digits(
|
let bigint = BigInt::parse_digits("2_cafe_babe_dead_beef".chars(), Radix::Hex);
|
||||||
"2_cafe_babe_dead_beef".chars(),
|
|
||||||
Radix::Hex,
|
|
||||||
);
|
|
||||||
println!("{:#x?}", bigint);
|
println!("{:#x?}", bigint);
|
||||||
let bigint = BigInt::parse_digits("f".chars(), Radix::Hex);
|
let bigint = BigInt::parse_digits("f".chars(), Radix::Hex);
|
||||||
println!("{:#x?}", bigint);
|
println!("{:#x?}", bigint);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn add() {
|
fn add() {
|
||||||
let a = BigInt::parse_digits(
|
let a = BigInt::parse_digits("2_0000_0000_0000_0000".chars(), Radix::Hex);
|
||||||
"2_0000_0000_0000_0000".chars(),
|
|
||||||
Radix::Hex,
|
|
||||||
);
|
|
||||||
println!("{:#x?}", a);
|
println!("{:#x?}", a);
|
||||||
let b = BigInt::parse_digits("cafebabe".chars(), Radix::Hex);
|
let b = BigInt::parse_digits("cafebabe".chars(), Radix::Hex);
|
||||||
println!("{:#x?}", b);
|
println!("{:#x?}", b);
|
||||||
|
@ -1143,10 +1111,7 @@ pub mod bigint {
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn overflowing_sub() {
|
fn overflowing_sub() {
|
||||||
let a = BigInt::parse_digits(
|
let a = BigInt::parse_digits("2_0000_0000_0000_0000".chars(), Radix::Hex);
|
||||||
"2_0000_0000_0000_0000".chars(),
|
|
||||||
Radix::Hex,
|
|
||||||
);
|
|
||||||
println!("{:#x?}", a);
|
println!("{:#x?}", a);
|
||||||
let b = BigInt::parse_digits("ffff_ffff".chars(), Radix::Hex);
|
let b = BigInt::parse_digits("ffff_ffff".chars(), Radix::Hex);
|
||||||
println!("{:#x?}", b);
|
println!("{:#x?}", b);
|
||||||
|
@ -1155,8 +1120,7 @@ pub mod bigint {
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn shr() {
|
fn shr() {
|
||||||
let mut a =
|
let mut a = BigInt::parse_digits("cafe_babe_0000".chars(), Radix::Hex);
|
||||||
BigInt::parse_digits("cafe_babe_0000".chars(), Radix::Hex);
|
|
||||||
print!("{:0>8x?} >> 32 ", a);
|
print!("{:0>8x?} >> 32 ", a);
|
||||||
shr_bitint(&mut a.0, 32);
|
shr_bitint(&mut a.0, 32);
|
||||||
println!("{:0>8x?}", a);
|
println!("{:0>8x?}", a);
|
||||||
|
@ -1188,9 +1152,7 @@ pub mod bigint {
|
||||||
pub mod bigsint {
|
pub mod bigsint {
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
ops::{
|
ops::{Add, AddAssign, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub, SubAssign},
|
||||||
Add, AddAssign, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub, SubAssign,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::bigint::{self, *};
|
use super::bigint::{self, *};
|
||||||
|
@ -1333,13 +1295,11 @@ pub mod bigsint {
|
||||||
match (self.sign, rhs.sign) {
|
match (self.sign, rhs.sign) {
|
||||||
(_, Sign::None) => self,
|
(_, Sign::None) => self,
|
||||||
(Sign::None, _) => rhs,
|
(Sign::None, _) => rhs,
|
||||||
(Sign::Positive, Sign::Positive)
|
(Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => Self {
|
||||||
| (Sign::Negative, Sign::Negative) => Self {
|
|
||||||
sign: self.sign,
|
sign: self.sign,
|
||||||
bigint: self.bigint + rhs.bigint,
|
bigint: self.bigint + rhs.bigint,
|
||||||
},
|
},
|
||||||
(Sign::Positive, Sign::Negative)
|
(Sign::Positive, Sign::Negative) | (Sign::Negative, Sign::Positive) => {
|
||||||
| (Sign::Negative, Sign::Positive) => {
|
|
||||||
match self.bigint.cmp(&rhs.bigint) {
|
match self.bigint.cmp(&rhs.bigint) {
|
||||||
Ordering::Less => Self {
|
Ordering::Less => Self {
|
||||||
sign: rhs.sign,
|
sign: rhs.sign,
|
||||||
|
@ -1361,13 +1321,11 @@ pub mod bigsint {
|
||||||
|
|
||||||
fn add(self, rhs: u32) -> Self::Output {
|
fn add(self, rhs: u32) -> Self::Output {
|
||||||
match self.sign {
|
match self.sign {
|
||||||
Sign::Negative => {
|
Sign::Negative => match self.bigint.partial_cmp(&rhs).unwrap() {
|
||||||
match self.bigint.partial_cmp(&rhs).unwrap() {
|
Ordering::Less => Self::positive(rhs - self.bigint),
|
||||||
Ordering::Less => Self::positive(rhs - self.bigint),
|
Ordering::Equal => Self::zero(),
|
||||||
Ordering::Equal => Self::zero(),
|
Ordering::Greater => -Self::positive(self.bigint - rhs),
|
||||||
Ordering::Greater => -Self::positive(self.bigint - rhs),
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
Sign::None => Self::from_u32(rhs),
|
Sign::None => Self::from_u32(rhs),
|
||||||
Sign::Positive => Self::positive(self.bigint + rhs),
|
Sign::Positive => Self::positive(self.bigint + rhs),
|
||||||
}
|
}
|
||||||
|
@ -1379,13 +1337,11 @@ pub mod bigsint {
|
||||||
|
|
||||||
fn add(self, rhs: u64) -> Self::Output {
|
fn add(self, rhs: u64) -> Self::Output {
|
||||||
match self.sign {
|
match self.sign {
|
||||||
Sign::Negative => {
|
Sign::Negative => match self.bigint.partial_cmp(&rhs).unwrap() {
|
||||||
match self.bigint.partial_cmp(&rhs).unwrap() {
|
Ordering::Less => Self::positive(rhs - self.bigint),
|
||||||
Ordering::Less => Self::positive(rhs - self.bigint),
|
Ordering::Equal => Self::zero(),
|
||||||
Ordering::Equal => Self::zero(),
|
Ordering::Greater => -Self::positive(self.bigint - rhs),
|
||||||
Ordering::Greater => -Self::positive(self.bigint - rhs),
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
Sign::None => Self::from_u64(rhs),
|
Sign::None => Self::from_u64(rhs),
|
||||||
Sign::Positive => Self::positive(self.bigint + rhs),
|
Sign::Positive => Self::positive(self.bigint + rhs),
|
||||||
}
|
}
|
||||||
|
@ -1406,13 +1362,11 @@ pub mod bigsint {
|
||||||
match (self.sign, rhs.sign) {
|
match (self.sign, rhs.sign) {
|
||||||
(_, Sign::None) => self,
|
(_, Sign::None) => self,
|
||||||
(Sign::None, _) => -rhs,
|
(Sign::None, _) => -rhs,
|
||||||
(Sign::Positive, Sign::Negative)
|
(Sign::Positive, Sign::Negative) | (Sign::Negative, Sign::Positive) => Self {
|
||||||
| (Sign::Negative, Sign::Positive) => Self {
|
|
||||||
sign: self.sign,
|
sign: self.sign,
|
||||||
bigint: self.bigint + rhs.bigint,
|
bigint: self.bigint + rhs.bigint,
|
||||||
},
|
},
|
||||||
(Sign::Positive, Sign::Positive)
|
(Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
|
||||||
| (Sign::Negative, Sign::Negative) => {
|
|
||||||
match self.bigint.cmp(&rhs.bigint) {
|
match self.bigint.cmp(&rhs.bigint) {
|
||||||
Ordering::Less => Self {
|
Ordering::Less => Self {
|
||||||
sign: -self.sign,
|
sign: -self.sign,
|
||||||
|
@ -1516,11 +1470,7 @@ pub mod bigsint {
|
||||||
bigint: r,
|
bigint: r,
|
||||||
};
|
};
|
||||||
|
|
||||||
if rhs.is_negative() {
|
if rhs.is_negative() { (-q, r) } else { (q, r) }
|
||||||
(-q, r)
|
|
||||||
} else {
|
|
||||||
(q, r)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shr_rounding(lhs: &BigSInt, shift: usize) -> bool {
|
fn shr_rounding(lhs: &BigSInt, shift: usize) -> bool {
|
||||||
|
@ -1548,7 +1498,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use num_bigint::{BigInt, BigUint, Sign};
|
use num_bigint::{BigInt, BigUint, Sign};
|
||||||
use num_traits::{cast::ToPrimitive, ToBytes};
|
use num_traits::{ToBytes, cast::ToPrimitive};
|
||||||
|
|
||||||
use crate::ast::{FloatingType, IntegralType, Type};
|
use crate::ast::{FloatingType, IntegralType, Type};
|
||||||
|
|
||||||
|
@ -1585,20 +1535,14 @@ impl ComptimeInt {
|
||||||
pub fn add(self, other: Self) -> Result<Self> {
|
pub fn add(self, other: Self) -> Result<Self> {
|
||||||
let (a, b) = self.coalesce(other)?;
|
let (a, b) = self.coalesce(other)?;
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(
|
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
|
||||||
ComptimeInt::Native { bits: a, ty },
|
|
||||||
ComptimeInt::Native { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let bits = a.checked_add(b).ok_or(Error::IntegerOverflow)?;
|
let bits = a.checked_add(b).ok_or(Error::IntegerOverflow)?;
|
||||||
if bits & !ty.u128_bitmask() != 0 {
|
if bits & !ty.u128_bitmask() != 0 {
|
||||||
return Err(Error::IntegerOverflow);
|
return Err(Error::IntegerOverflow);
|
||||||
}
|
}
|
||||||
Ok(Self::Native { bits, ty })
|
Ok(Self::Native { bits, ty })
|
||||||
}
|
}
|
||||||
(
|
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
|
||||||
ComptimeInt::BigInt { bits: a, ty },
|
|
||||||
ComptimeInt::BigInt { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let width = ty.bits - ty.signed as u16;
|
let width = ty.bits - ty.signed as u16;
|
||||||
let bits = a + b;
|
let bits = a + b;
|
||||||
if bits.bits() > width as u64 {
|
if bits.bits() > width as u64 {
|
||||||
|
@ -1607,9 +1551,7 @@ impl ComptimeInt {
|
||||||
Ok(Self::BigInt { bits, ty })
|
Ok(Self::BigInt { bits, ty })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
|
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a + b)),
|
||||||
Ok(Self::Comptime(a + b))
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -1619,20 +1561,14 @@ impl ComptimeInt {
|
||||||
pub fn sub(self, other: Self) -> Result<Self> {
|
pub fn sub(self, other: Self) -> Result<Self> {
|
||||||
let (a, b) = self.coalesce(other)?;
|
let (a, b) = self.coalesce(other)?;
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(
|
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
|
||||||
ComptimeInt::Native { bits: a, ty },
|
|
||||||
ComptimeInt::Native { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let bits = a.checked_sub(b).ok_or(Error::IntegerOverflow)?;
|
let bits = a.checked_sub(b).ok_or(Error::IntegerOverflow)?;
|
||||||
if bits & !ty.u128_bitmask() != 0 {
|
if bits & !ty.u128_bitmask() != 0 {
|
||||||
return Err(Error::IntegerOverflow);
|
return Err(Error::IntegerOverflow);
|
||||||
}
|
}
|
||||||
Ok(Self::Native { bits, ty })
|
Ok(Self::Native { bits, ty })
|
||||||
}
|
}
|
||||||
(
|
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
|
||||||
ComptimeInt::BigInt { bits: a, ty },
|
|
||||||
ComptimeInt::BigInt { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let width = ty.bits - ty.signed as u16;
|
let width = ty.bits - ty.signed as u16;
|
||||||
let bits = a - b;
|
let bits = a - b;
|
||||||
if bits.bits() > width as u64 {
|
if bits.bits() > width as u64 {
|
||||||
|
@ -1641,9 +1577,7 @@ impl ComptimeInt {
|
||||||
Ok(Self::BigInt { bits, ty })
|
Ok(Self::BigInt { bits, ty })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
|
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a - b)),
|
||||||
Ok(Self::Comptime(a - b))
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -1653,20 +1587,14 @@ impl ComptimeInt {
|
||||||
pub fn mul(self, other: Self) -> Result<Self> {
|
pub fn mul(self, other: Self) -> Result<Self> {
|
||||||
let (a, b) = self.coalesce(other)?;
|
let (a, b) = self.coalesce(other)?;
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(
|
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
|
||||||
ComptimeInt::Native { bits: a, ty },
|
|
||||||
ComptimeInt::Native { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let bits = a.checked_mul(b).ok_or(Error::IntegerOverflow)?;
|
let bits = a.checked_mul(b).ok_or(Error::IntegerOverflow)?;
|
||||||
if bits & !ty.u128_bitmask() != 0 {
|
if bits & !ty.u128_bitmask() != 0 {
|
||||||
return Err(Error::IntegerOverflow);
|
return Err(Error::IntegerOverflow);
|
||||||
}
|
}
|
||||||
Ok(Self::Native { bits, ty })
|
Ok(Self::Native { bits, ty })
|
||||||
}
|
}
|
||||||
(
|
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
|
||||||
ComptimeInt::BigInt { bits: a, ty },
|
|
||||||
ComptimeInt::BigInt { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let width = ty.bits - ty.signed as u16;
|
let width = ty.bits - ty.signed as u16;
|
||||||
let bits = a * b;
|
let bits = a * b;
|
||||||
if bits.bits() > width as u64 {
|
if bits.bits() > width as u64 {
|
||||||
|
@ -1675,9 +1603,7 @@ impl ComptimeInt {
|
||||||
Ok(Self::BigInt { bits, ty })
|
Ok(Self::BigInt { bits, ty })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
|
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a * b)),
|
||||||
Ok(Self::Comptime(a * b))
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -1687,20 +1613,14 @@ impl ComptimeInt {
|
||||||
pub fn div(self, other: Self) -> Result<Self> {
|
pub fn div(self, other: Self) -> Result<Self> {
|
||||||
let (a, b) = self.coalesce(other)?;
|
let (a, b) = self.coalesce(other)?;
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(
|
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
|
||||||
ComptimeInt::Native { bits: a, ty },
|
|
||||||
ComptimeInt::Native { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let bits = a.checked_div(b).ok_or(Error::IntegerOverflow)?;
|
let bits = a.checked_div(b).ok_or(Error::IntegerOverflow)?;
|
||||||
if bits & !ty.u128_bitmask() != 0 {
|
if bits & !ty.u128_bitmask() != 0 {
|
||||||
return Err(Error::IntegerOverflow);
|
return Err(Error::IntegerOverflow);
|
||||||
}
|
}
|
||||||
Ok(Self::Native { bits, ty })
|
Ok(Self::Native { bits, ty })
|
||||||
}
|
}
|
||||||
(
|
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
|
||||||
ComptimeInt::BigInt { bits: a, ty },
|
|
||||||
ComptimeInt::BigInt { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let width = ty.bits - ty.signed as u16;
|
let width = ty.bits - ty.signed as u16;
|
||||||
let bits = a / b;
|
let bits = a / b;
|
||||||
if bits.bits() > width as u64 {
|
if bits.bits() > width as u64 {
|
||||||
|
@ -1709,9 +1629,7 @@ impl ComptimeInt {
|
||||||
Ok(Self::BigInt { bits, ty })
|
Ok(Self::BigInt { bits, ty })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
|
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a / b)),
|
||||||
Ok(Self::Comptime(a / b))
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -1721,20 +1639,14 @@ impl ComptimeInt {
|
||||||
pub fn rem(self, other: Self) -> Result<Self> {
|
pub fn rem(self, other: Self) -> Result<Self> {
|
||||||
let (a, b) = self.coalesce(other)?;
|
let (a, b) = self.coalesce(other)?;
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(
|
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
|
||||||
ComptimeInt::Native { bits: a, ty },
|
|
||||||
ComptimeInt::Native { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let bits = a.checked_rem(b).ok_or(Error::IntegerOverflow)?;
|
let bits = a.checked_rem(b).ok_or(Error::IntegerOverflow)?;
|
||||||
if bits & !ty.u128_bitmask() != 0 {
|
if bits & !ty.u128_bitmask() != 0 {
|
||||||
return Err(Error::IntegerOverflow);
|
return Err(Error::IntegerOverflow);
|
||||||
}
|
}
|
||||||
Ok(Self::Native { bits, ty })
|
Ok(Self::Native { bits, ty })
|
||||||
}
|
}
|
||||||
(
|
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
|
||||||
ComptimeInt::BigInt { bits: a, ty },
|
|
||||||
ComptimeInt::BigInt { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let width = ty.bits - ty.signed as u16;
|
let width = ty.bits - ty.signed as u16;
|
||||||
let bits = a % b;
|
let bits = a % b;
|
||||||
if bits.bits() > width as u64 {
|
if bits.bits() > width as u64 {
|
||||||
|
@ -1743,9 +1655,7 @@ impl ComptimeInt {
|
||||||
Ok(Self::BigInt { bits, ty })
|
Ok(Self::BigInt { bits, ty })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
|
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a % b)),
|
||||||
Ok(Self::Comptime(a % b))
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -1755,23 +1665,15 @@ impl ComptimeInt {
|
||||||
pub fn bitand(self, other: Self) -> Result<Self> {
|
pub fn bitand(self, other: Self) -> Result<Self> {
|
||||||
let (a, b) = self.coalesce(other)?;
|
let (a, b) = self.coalesce(other)?;
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(
|
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
|
||||||
ComptimeInt::Native { bits: a, ty },
|
|
||||||
ComptimeInt::Native { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let bits = a.bitand(b);
|
let bits = a.bitand(b);
|
||||||
Ok(Self::Native { bits, ty })
|
Ok(Self::Native { bits, ty })
|
||||||
}
|
}
|
||||||
(
|
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
|
||||||
ComptimeInt::BigInt { bits: a, ty },
|
|
||||||
ComptimeInt::BigInt { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let bits = a & b;
|
let bits = a & b;
|
||||||
Ok(Self::BigInt { bits, ty })
|
Ok(Self::BigInt { bits, ty })
|
||||||
}
|
}
|
||||||
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
|
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a & b)),
|
||||||
Ok(Self::Comptime(a & b))
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -1781,23 +1683,15 @@ impl ComptimeInt {
|
||||||
pub fn bitor(self, other: Self) -> Result<Self> {
|
pub fn bitor(self, other: Self) -> Result<Self> {
|
||||||
let (a, b) = self.coalesce(other)?;
|
let (a, b) = self.coalesce(other)?;
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(
|
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
|
||||||
ComptimeInt::Native { bits: a, ty },
|
|
||||||
ComptimeInt::Native { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let bits = a.bitor(b);
|
let bits = a.bitor(b);
|
||||||
Ok(Self::Native { bits, ty })
|
Ok(Self::Native { bits, ty })
|
||||||
}
|
}
|
||||||
(
|
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
|
||||||
ComptimeInt::BigInt { bits: a, ty },
|
|
||||||
ComptimeInt::BigInt { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let bits = a | b;
|
let bits = a | b;
|
||||||
Ok(Self::BigInt { bits, ty })
|
Ok(Self::BigInt { bits, ty })
|
||||||
}
|
}
|
||||||
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
|
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a | b)),
|
||||||
Ok(Self::Comptime(a | b))
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -1807,23 +1701,15 @@ impl ComptimeInt {
|
||||||
pub fn bitxor(self, other: Self) -> Result<Self> {
|
pub fn bitxor(self, other: Self) -> Result<Self> {
|
||||||
let (a, b) = self.coalesce(other)?;
|
let (a, b) = self.coalesce(other)?;
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(
|
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
|
||||||
ComptimeInt::Native { bits: a, ty },
|
|
||||||
ComptimeInt::Native { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let bits = a.bitxor(b);
|
let bits = a.bitxor(b);
|
||||||
Ok(Self::Native { bits, ty })
|
Ok(Self::Native { bits, ty })
|
||||||
}
|
}
|
||||||
(
|
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
|
||||||
ComptimeInt::BigInt { bits: a, ty },
|
|
||||||
ComptimeInt::BigInt { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let bits = a ^ b;
|
let bits = a ^ b;
|
||||||
Ok(Self::BigInt { bits, ty })
|
Ok(Self::BigInt { bits, ty })
|
||||||
}
|
}
|
||||||
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
|
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a ^ b)),
|
||||||
Ok(Self::Comptime(a ^ b))
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -1832,14 +1718,8 @@ impl ComptimeInt {
|
||||||
pub fn cmp(self, other: Self) -> Result<Ordering> {
|
pub fn cmp(self, other: Self) -> Result<Ordering> {
|
||||||
let (a, b) = self.coalesce(other)?;
|
let (a, b) = self.coalesce(other)?;
|
||||||
let ord = match (a, b) {
|
let ord = match (a, b) {
|
||||||
(
|
(ComptimeInt::Native { bits: a, .. }, ComptimeInt::Native { bits: b, .. }) => a.cmp(&b),
|
||||||
ComptimeInt::Native { bits: a, .. },
|
(ComptimeInt::BigInt { bits: a, .. }, ComptimeInt::BigInt { bits: b, .. }) => a.cmp(&b),
|
||||||
ComptimeInt::Native { bits: b, .. },
|
|
||||||
) => a.cmp(&b),
|
|
||||||
(
|
|
||||||
ComptimeInt::BigInt { bits: a, .. },
|
|
||||||
ComptimeInt::BigInt { bits: b, .. },
|
|
||||||
) => a.cmp(&b),
|
|
||||||
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => a.cmp(&b),
|
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => a.cmp(&b),
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -1857,13 +1737,11 @@ impl ComptimeInt {
|
||||||
let bits = if ty.signed {
|
let bits = if ty.signed {
|
||||||
(bits as i128)
|
(bits as i128)
|
||||||
.checked_shl(shift)
|
.checked_shl(shift)
|
||||||
.ok_or(Error::IntegerOverflow)?
|
.ok_or(Error::IntegerOverflow)? as u128
|
||||||
as u128
|
|
||||||
} else {
|
} else {
|
||||||
(bits as u128)
|
(bits as u128)
|
||||||
.checked_shl(shift)
|
.checked_shl(shift)
|
||||||
.ok_or(Error::IntegerOverflow)?
|
.ok_or(Error::IntegerOverflow)? as u128
|
||||||
as u128
|
|
||||||
} & ty.u128_bitmask();
|
} & ty.u128_bitmask();
|
||||||
|
|
||||||
Ok(Self::Native { bits, ty })
|
Ok(Self::Native { bits, ty })
|
||||||
|
@ -1888,13 +1766,11 @@ impl ComptimeInt {
|
||||||
let bits = if ty.signed {
|
let bits = if ty.signed {
|
||||||
(bits as i128)
|
(bits as i128)
|
||||||
.checked_shr(shift)
|
.checked_shr(shift)
|
||||||
.ok_or(Error::IntegerOverflow)?
|
.ok_or(Error::IntegerOverflow)? as u128
|
||||||
as u128
|
|
||||||
} else {
|
} else {
|
||||||
(bits as u128)
|
(bits as u128)
|
||||||
.checked_shr(shift)
|
.checked_shr(shift)
|
||||||
.ok_or(Error::IntegerOverflow)?
|
.ok_or(Error::IntegerOverflow)? as u128
|
||||||
as u128
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self::Native { bits, ty })
|
Ok(Self::Native { bits, ty })
|
||||||
|
@ -1913,9 +1789,7 @@ impl ComptimeInt {
|
||||||
if ty.signed {
|
if ty.signed {
|
||||||
return Err(Error::UnsignedNegation);
|
return Err(Error::UnsignedNegation);
|
||||||
}
|
}
|
||||||
let bits =
|
let bits = (a as i128).checked_neg().ok_or(Error::IntegerOverflow)? as u128;
|
||||||
(a as i128).checked_neg().ok_or(Error::IntegerOverflow)?
|
|
||||||
as u128;
|
|
||||||
|
|
||||||
if bits & !ty.u128_bitmask() != 0 {
|
if bits & !ty.u128_bitmask() != 0 {
|
||||||
return Err(Error::IntegerOverflow);
|
return Err(Error::IntegerOverflow);
|
||||||
|
@ -1933,9 +1807,7 @@ impl ComptimeInt {
|
||||||
bits: !bits | ty.u128_bitmask(),
|
bits: !bits | ty.u128_bitmask(),
|
||||||
ty,
|
ty,
|
||||||
}),
|
}),
|
||||||
ComptimeInt::BigInt { bits, ty } => {
|
ComptimeInt::BigInt { bits, ty } => Ok(Self::BigInt { bits: !bits, ty }),
|
||||||
Ok(Self::BigInt { bits: !bits, ty })
|
|
||||||
}
|
|
||||||
ComptimeInt::Comptime(bigint) => Ok(Self::Comptime(!bigint)),
|
ComptimeInt::Comptime(bigint) => Ok(Self::Comptime(!bigint)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1951,14 +1823,8 @@ impl ComptimeInt {
|
||||||
|
|
||||||
fn coalesce(self, other: Self) -> Result<(ComptimeInt, ComptimeInt)> {
|
fn coalesce(self, other: Self) -> Result<(ComptimeInt, ComptimeInt)> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(
|
(lhs @ ComptimeInt::Native { ty: a_ty, .. }, ComptimeInt::Comptime(b))
|
||||||
lhs @ ComptimeInt::Native { ty: a_ty, .. },
|
| (lhs @ ComptimeInt::Native { ty: a_ty, .. }, ComptimeInt::BigInt { bits: b, .. }) => {
|
||||||
ComptimeInt::Comptime(b),
|
|
||||||
)
|
|
||||||
| (
|
|
||||||
lhs @ ComptimeInt::Native { ty: a_ty, .. },
|
|
||||||
ComptimeInt::BigInt { bits: b, .. },
|
|
||||||
) => {
|
|
||||||
let b_signed = b.sign() == Sign::Minus;
|
let b_signed = b.sign() == Sign::Minus;
|
||||||
if !a_ty.signed && b_signed {
|
if !a_ty.signed && b_signed {
|
||||||
return Err(Error::IncompatibleTypes);
|
return Err(Error::IncompatibleTypes);
|
||||||
|
@ -1975,14 +1841,8 @@ impl ComptimeInt {
|
||||||
};
|
};
|
||||||
Ok((lhs, Self::Native { bits: b, ty: a_ty }))
|
Ok((lhs, Self::Native { bits: b, ty: a_ty }))
|
||||||
}
|
}
|
||||||
(
|
(ComptimeInt::Comptime(b), rhs @ ComptimeInt::Native { ty: a_ty, .. })
|
||||||
ComptimeInt::Comptime(b),
|
| (ComptimeInt::BigInt { bits: b, .. }, rhs @ ComptimeInt::Native { ty: a_ty, .. }) => {
|
||||||
rhs @ ComptimeInt::Native { ty: a_ty, .. },
|
|
||||||
)
|
|
||||||
| (
|
|
||||||
ComptimeInt::BigInt { bits: b, .. },
|
|
||||||
rhs @ ComptimeInt::Native { ty: a_ty, .. },
|
|
||||||
) => {
|
|
||||||
let b_signed = b.sign() == Sign::Minus;
|
let b_signed = b.sign() == Sign::Minus;
|
||||||
if !a_ty.signed && b_signed {
|
if !a_ty.signed && b_signed {
|
||||||
return Err(Error::IncompatibleTypes);
|
return Err(Error::IncompatibleTypes);
|
||||||
|
@ -1999,10 +1859,7 @@ impl ComptimeInt {
|
||||||
};
|
};
|
||||||
Ok((Self::Native { bits: b, ty: a_ty }, rhs))
|
Ok((Self::Native { bits: b, ty: a_ty }, rhs))
|
||||||
}
|
}
|
||||||
(
|
(lhs @ ComptimeInt::BigInt { ty, .. }, ComptimeInt::Comptime(b)) => {
|
||||||
lhs @ ComptimeInt::BigInt { ty, .. },
|
|
||||||
ComptimeInt::Comptime(b),
|
|
||||||
) => {
|
|
||||||
let b_signed = b.sign() == Sign::Minus;
|
let b_signed = b.sign() == Sign::Minus;
|
||||||
if !ty.signed && b_signed {
|
if !ty.signed && b_signed {
|
||||||
return Err(Error::IncompatibleTypes);
|
return Err(Error::IncompatibleTypes);
|
||||||
|
@ -2014,10 +1871,7 @@ impl ComptimeInt {
|
||||||
}
|
}
|
||||||
Ok((lhs, Self::BigInt { bits: b, ty }))
|
Ok((lhs, Self::BigInt { bits: b, ty }))
|
||||||
}
|
}
|
||||||
(
|
(ComptimeInt::Comptime(b), rhs @ ComptimeInt::BigInt { ty, .. }) => {
|
||||||
ComptimeInt::Comptime(b),
|
|
||||||
rhs @ ComptimeInt::BigInt { ty, .. },
|
|
||||||
) => {
|
|
||||||
let b_signed = b.sign() == Sign::Minus;
|
let b_signed = b.sign() == Sign::Minus;
|
||||||
if !ty.signed && b_signed {
|
if !ty.signed && b_signed {
|
||||||
return Err(Error::IncompatibleTypes);
|
return Err(Error::IncompatibleTypes);
|
||||||
|
@ -2029,20 +1883,14 @@ impl ComptimeInt {
|
||||||
}
|
}
|
||||||
Ok((Self::BigInt { bits: b, ty }, rhs))
|
Ok((Self::BigInt { bits: b, ty }, rhs))
|
||||||
}
|
}
|
||||||
(
|
(lhs @ ComptimeInt::Native { ty: a, .. }, rhs @ ComptimeInt::Native { ty: b, .. }) => {
|
||||||
lhs @ ComptimeInt::Native { ty: a, .. },
|
|
||||||
rhs @ ComptimeInt::Native { ty: b, .. },
|
|
||||||
) => {
|
|
||||||
if a == b {
|
if a == b {
|
||||||
Ok((lhs, rhs))
|
Ok((lhs, rhs))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::IncompatibleTypes)
|
Err(Error::IncompatibleTypes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(
|
(lhs @ ComptimeInt::BigInt { ty: a, .. }, rhs @ ComptimeInt::BigInt { ty: b, .. }) => {
|
||||||
lhs @ ComptimeInt::BigInt { ty: a, .. },
|
|
||||||
rhs @ ComptimeInt::BigInt { ty: b, .. },
|
|
||||||
) => {
|
|
||||||
if a == b {
|
if a == b {
|
||||||
Ok((lhs, rhs))
|
Ok((lhs, rhs))
|
||||||
} else {
|
} else {
|
||||||
|
@ -2063,56 +1911,36 @@ pub enum ComptimeFloat {
|
||||||
impl ComptimeFloat {
|
impl ComptimeFloat {
|
||||||
pub fn add(self, other: Self) -> Result<ComptimeFloat> {
|
pub fn add(self, other: Self) -> Result<ComptimeFloat> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => {
|
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => Ok(Self::Binary32(a + b)),
|
||||||
Ok(Self::Binary32(a + b))
|
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => Ok(Self::Binary64(a + b)),
|
||||||
}
|
|
||||||
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => {
|
|
||||||
Ok(Self::Binary64(a + b))
|
|
||||||
}
|
|
||||||
_ => Err(Error::IncompatibleTypes),
|
_ => Err(Error::IncompatibleTypes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn sub(self, other: Self) -> Result<ComptimeFloat> {
|
pub fn sub(self, other: Self) -> Result<ComptimeFloat> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => {
|
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => Ok(Self::Binary32(a - b)),
|
||||||
Ok(Self::Binary32(a - b))
|
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => Ok(Self::Binary64(a - b)),
|
||||||
}
|
|
||||||
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => {
|
|
||||||
Ok(Self::Binary64(a - b))
|
|
||||||
}
|
|
||||||
_ => Err(Error::IncompatibleTypes),
|
_ => Err(Error::IncompatibleTypes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn mul(self, other: Self) -> Result<ComptimeFloat> {
|
pub fn mul(self, other: Self) -> Result<ComptimeFloat> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => {
|
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => Ok(Self::Binary32(a * b)),
|
||||||
Ok(Self::Binary32(a * b))
|
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => Ok(Self::Binary64(a * b)),
|
||||||
}
|
|
||||||
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => {
|
|
||||||
Ok(Self::Binary64(a * b))
|
|
||||||
}
|
|
||||||
_ => Err(Error::IncompatibleTypes),
|
_ => Err(Error::IncompatibleTypes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn div(self, other: Self) -> Result<ComptimeFloat> {
|
pub fn div(self, other: Self) -> Result<ComptimeFloat> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => {
|
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => Ok(Self::Binary32(a / b)),
|
||||||
Ok(Self::Binary32(a / b))
|
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => Ok(Self::Binary64(a / b)),
|
||||||
}
|
|
||||||
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => {
|
|
||||||
Ok(Self::Binary64(a / b))
|
|
||||||
}
|
|
||||||
_ => Err(Error::IncompatibleTypes),
|
_ => Err(Error::IncompatibleTypes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn rem(self, other: Self) -> Result<ComptimeFloat> {
|
pub fn rem(self, other: Self) -> Result<ComptimeFloat> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => {
|
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => Ok(Self::Binary32(a % b)),
|
||||||
Ok(Self::Binary32(a % b))
|
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => Ok(Self::Binary64(a % b)),
|
||||||
}
|
|
||||||
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => {
|
|
||||||
Ok(Self::Binary64(a % b))
|
|
||||||
}
|
|
||||||
_ => Err(Error::IncompatibleTypes),
|
_ => Err(Error::IncompatibleTypes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2124,12 +1952,8 @@ impl ComptimeFloat {
|
||||||
}
|
}
|
||||||
pub fn cmp(self, other: Self) -> Result<Ordering> {
|
pub fn cmp(self, other: Self) -> Result<Ordering> {
|
||||||
let ord = match (self, other) {
|
let ord = match (self, other) {
|
||||||
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => {
|
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => a.partial_cmp(&b),
|
||||||
a.partial_cmp(&b)
|
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => a.partial_cmp(&b),
|
||||||
}
|
|
||||||
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => {
|
|
||||||
a.partial_cmp(&b)
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::IncompatibleTypes);
|
return Err(Error::IncompatibleTypes);
|
||||||
}
|
}
|
||||||
|
@ -2281,9 +2105,7 @@ impl ComptimeNumber {
|
||||||
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
|
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
|
||||||
// Ok(Self::Floating(a.sub(b)?))
|
// Ok(Self::Floating(a.sub(b)?))
|
||||||
// }
|
// }
|
||||||
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => {
|
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => Ok(Self::Bool(a.bitand(b))),
|
||||||
Ok(Self::Bool(a.bitand(b)))
|
|
||||||
}
|
|
||||||
_ => Err(Error::IncompatibleTypes),
|
_ => Err(Error::IncompatibleTypes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2295,9 +2117,7 @@ impl ComptimeNumber {
|
||||||
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
|
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
|
||||||
// Ok(Self::Floating(a.bitor(b)?))
|
// Ok(Self::Floating(a.bitor(b)?))
|
||||||
// }
|
// }
|
||||||
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => {
|
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => Ok(Self::Bool(a.bitor(b))),
|
||||||
Ok(Self::Bool(a.bitor(b)))
|
|
||||||
}
|
|
||||||
_ => Err(Error::IncompatibleTypes),
|
_ => Err(Error::IncompatibleTypes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2309,9 +2129,7 @@ impl ComptimeNumber {
|
||||||
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
|
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
|
||||||
// Ok(Self::Floating(a.bitxor(b)?))
|
// Ok(Self::Floating(a.bitxor(b)?))
|
||||||
// }
|
// }
|
||||||
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => {
|
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => Ok(Self::Bool(a.bitxor(b))),
|
||||||
Ok(Self::Bool(a.bitxor(b)))
|
|
||||||
}
|
|
||||||
_ => Err(Error::IncompatibleTypes),
|
_ => Err(Error::IncompatibleTypes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2347,9 +2165,7 @@ impl ComptimeNumber {
|
||||||
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
|
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
|
||||||
// Ok(Self::Floating(a.bitxor(b)?))
|
// Ok(Self::Floating(a.bitxor(b)?))
|
||||||
// }
|
// }
|
||||||
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => {
|
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => Ok(Self::Bool(a || b)),
|
||||||
Ok(Self::Bool(a || b))
|
|
||||||
}
|
|
||||||
_ => Err(Error::IncompatibleTypes),
|
_ => Err(Error::IncompatibleTypes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2361,35 +2177,23 @@ impl ComptimeNumber {
|
||||||
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
|
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
|
||||||
// Ok(Self::Floating(a.bitxor(b)?))
|
// Ok(Self::Floating(a.bitxor(b)?))
|
||||||
// }
|
// }
|
||||||
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => {
|
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => Ok(Self::Bool(a && b)),
|
||||||
Ok(Self::Bool(a && b))
|
|
||||||
}
|
|
||||||
_ => Err(Error::IncompatibleTypes),
|
_ => Err(Error::IncompatibleTypes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn eq(self, other: Self) -> Result<Self> {
|
pub fn eq(self, other: Self) -> Result<Self> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ComptimeNumber::Integral(a), ComptimeNumber::Integral(b)) => {
|
(ComptimeNumber::Integral(a), ComptimeNumber::Integral(b)) => Ok(Self::Bool(a == b)),
|
||||||
Ok(Self::Bool(a == b))
|
(ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => Ok(Self::Bool(a == b)),
|
||||||
}
|
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => Ok(Self::Bool(a == b)),
|
||||||
(ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
|
|
||||||
Ok(Self::Bool(a == b))
|
|
||||||
}
|
|
||||||
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => {
|
|
||||||
Ok(Self::Bool(a == b))
|
|
||||||
}
|
|
||||||
_ => Err(Error::IncompatibleTypes),
|
_ => Err(Error::IncompatibleTypes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cmp(self, other: Self) -> Result<Ordering> {
|
pub fn cmp(self, other: Self) -> Result<Ordering> {
|
||||||
let ord = match (self, other) {
|
let ord = match (self, other) {
|
||||||
(ComptimeNumber::Integral(a), ComptimeNumber::Integral(b)) => {
|
(ComptimeNumber::Integral(a), ComptimeNumber::Integral(b)) => a.cmp(b)?,
|
||||||
a.cmp(b)?
|
(ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => a.cmp(b)?,
|
||||||
}
|
|
||||||
(ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
|
|
||||||
a.cmp(b)?
|
|
||||||
}
|
|
||||||
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => a.cmp(&b),
|
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => a.cmp(&b),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::IncompatibleTypes);
|
return Err(Error::IncompatibleTypes);
|
||||||
|
@ -2429,17 +2233,12 @@ impl ComptimeNumber {
|
||||||
match self {
|
match self {
|
||||||
ComptimeNumber::Integral(i) => match i {
|
ComptimeNumber::Integral(i) => match i {
|
||||||
ComptimeInt::Native { bits, .. } => Ok((bits != 0).into()),
|
ComptimeInt::Native { bits, .. } => Ok((bits != 0).into()),
|
||||||
ComptimeInt::Comptime(bits)
|
ComptimeInt::Comptime(bits) | ComptimeInt::BigInt { bits, .. } => {
|
||||||
| ComptimeInt::BigInt { bits, .. } => {
|
|
||||||
Ok((bits.sign() != Sign::NoSign).into())
|
Ok((bits.sign() != Sign::NoSign).into())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ComptimeNumber::Floating(ComptimeFloat::Binary32(f)) => {
|
ComptimeNumber::Floating(ComptimeFloat::Binary32(f)) => Ok((f != 0.0).into()),
|
||||||
Ok((f != 0.0).into())
|
ComptimeNumber::Floating(ComptimeFloat::Binary64(f)) => Ok((f != 0.0).into()),
|
||||||
}
|
|
||||||
ComptimeNumber::Floating(ComptimeFloat::Binary64(f)) => {
|
|
||||||
Ok((f != 0.0).into())
|
|
||||||
}
|
|
||||||
a => Ok(a),
|
a => Ok(a),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2447,29 +2246,19 @@ impl ComptimeNumber {
|
||||||
pub fn into_int(self, ty: IntegralType) -> Result<Self> {
|
pub fn into_int(self, ty: IntegralType) -> Result<Self> {
|
||||||
match self {
|
match self {
|
||||||
ComptimeNumber::Integral(i) => match i {
|
ComptimeNumber::Integral(i) => match i {
|
||||||
ComptimeInt::Native { bits, .. } => {
|
ComptimeInt::Native { bits, .. } => Ok((bits & ty.u128_bitmask(), ty).into()),
|
||||||
Ok((bits & ty.u128_bitmask(), ty).into())
|
ComptimeInt::Comptime(bits) | ComptimeInt::BigInt { bits, .. } => {
|
||||||
}
|
let max = BigUint::from(2u32).pow((ty.bits - ty.signed as u16) as u32);
|
||||||
ComptimeInt::Comptime(bits)
|
|
||||||
| ComptimeInt::BigInt { bits, .. } => {
|
|
||||||
let max = BigUint::from(2u32)
|
|
||||||
.pow((ty.bits - ty.signed as u16) as u32);
|
|
||||||
let (sign, data) = bits.into_parts();
|
let (sign, data) = bits.into_parts();
|
||||||
let data = data.clamp(BigUint::ZERO, max);
|
let data = data.clamp(BigUint::ZERO, max);
|
||||||
|
|
||||||
Ok((BigInt::from_biguint(sign, data), ty).into())
|
Ok((BigInt::from_biguint(sign, data), ty).into())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ComptimeNumber::Bool(b) => {
|
ComptimeNumber::Bool(b) => Ok((b as u128 & ty.u128_bitmask(), ty).into()),
|
||||||
Ok((b as u128 & ty.u128_bitmask(), ty).into())
|
|
||||||
}
|
|
||||||
ComptimeNumber::Floating(f) => match f {
|
ComptimeNumber::Floating(f) => match f {
|
||||||
ComptimeFloat::Binary32(f) => {
|
ComptimeFloat::Binary32(f) => Ok((f as u128 & ty.u128_bitmask(), ty).into()),
|
||||||
Ok((f as u128 & ty.u128_bitmask(), ty).into())
|
ComptimeFloat::Binary64(f) => Ok((f as u128 & ty.u128_bitmask(), ty).into()),
|
||||||
}
|
|
||||||
ComptimeFloat::Binary64(f) => {
|
|
||||||
Ok((f as u128 & ty.u128_bitmask(), ty).into())
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
ComptimeNumber::Void => {
|
ComptimeNumber::Void => {
|
||||||
return Err(Error::VoidConversion);
|
return Err(Error::VoidConversion);
|
||||||
|
@ -2480,8 +2269,7 @@ impl ComptimeNumber {
|
||||||
let f = match self {
|
let f = match self {
|
||||||
ComptimeNumber::Integral(i) => match i {
|
ComptimeNumber::Integral(i) => match i {
|
||||||
ComptimeInt::Native { bits, .. } => bits as f64,
|
ComptimeInt::Native { bits, .. } => bits as f64,
|
||||||
ComptimeInt::Comptime(bits)
|
ComptimeInt::Comptime(bits) | ComptimeInt::BigInt { bits, .. } => {
|
||||||
| ComptimeInt::BigInt { bits, .. } => {
|
|
||||||
bits.to_f64().unwrap_or(f64::NAN)
|
bits.to_f64().unwrap_or(f64::NAN)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,9 +8,10 @@
|
||||||
int_roundings,
|
int_roundings,
|
||||||
if_let_guard,
|
if_let_guard,
|
||||||
debug_closure_helpers,
|
debug_closure_helpers,
|
||||||
|
box_vec_non_null,
|
||||||
macro_metavar_expr
|
macro_metavar_expr
|
||||||
)]
|
)]
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros, unsafe_op_in_unsafe_fn)]
|
||||||
|
|
||||||
pub mod asm;
|
pub mod asm;
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
|
|
|
@ -2,6 +2,7 @@ use itertools::Itertools;
|
||||||
use num_bigint::{BigInt, BigUint};
|
use num_bigint::{BigInt, BigUint};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
BitSize,
|
||||||
ast::{self, FloatingType, IntegralType, LetOrVar, Node, Tag, Type},
|
ast::{self, FloatingType, IntegralType, LetOrVar, Node, Tag, Type},
|
||||||
ast2::intern::{self, AMD64_POINTER_BITS},
|
ast2::intern::{self, AMD64_POINTER_BITS},
|
||||||
common::NextIf,
|
common::NextIf,
|
||||||
|
@ -9,8 +10,7 @@ use crate::{
|
||||||
error::{AnalysisError, AnalysisErrorTag},
|
error::{AnalysisError, AnalysisErrorTag},
|
||||||
lexer::{Radix, TokenIterator},
|
lexer::{Radix, TokenIterator},
|
||||||
symbol_table::{SymbolKind, SymbolTable},
|
symbol_table::{SymbolKind, SymbolTable},
|
||||||
tokens::{Token, PRECEDENCE_MAP},
|
tokens::{PRECEDENCE_MAP, Token},
|
||||||
BitSize,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
@ -1767,10 +1767,10 @@ impl Tree {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peer_type_of_nodes_unwrap(&self, lhs: Node, rhs: Node) -> Type {
|
pub fn peer_type_of_nodes_unwrap(&self, lhs: Node, rhs: Node) -> Type {
|
||||||
self.peer_type_of_nodes(lhs, rhs).expect({
|
self.peer_type_of_nodes(lhs, rhs).expect(&{
|
||||||
let at = self.type_of_node(lhs);
|
let at = self.type_of_node(lhs);
|
||||||
let bt = self.type_of_node(rhs);
|
let bt = self.type_of_node(rhs);
|
||||||
&format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
|
format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1844,10 +1844,10 @@ impl Tree {
|
||||||
} => {
|
} => {
|
||||||
let ty = match (explicit_type.as_ref(), assignment) {
|
let ty = match (explicit_type.as_ref(), assignment) {
|
||||||
(None, b) => self.type_of_node(*b),
|
(None, b) => self.type_of_node(*b),
|
||||||
(Some(a), b) => self.peer_type_of_nodes(*a, *b).expect({
|
(Some(a), b) => self.peer_type_of_nodes(*a, *b).expect(&{
|
||||||
let at = self.type_of_node(*a);
|
let at = self.type_of_node(*a);
|
||||||
let bt = self.type_of_node(*b);
|
let bt = self.type_of_node(*b);
|
||||||
&format!("incompatible types for %{a}({at}) and %{b}({bt})")
|
format!("incompatible types for %{a}({at}) and %{b}({bt})")
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1863,10 +1863,10 @@ impl Tree {
|
||||||
(None, None) => panic!("%{node}: no type specified?"),
|
(None, None) => panic!("%{node}: no type specified?"),
|
||||||
(None, Some(b)) => self.type_of_node(*b),
|
(None, Some(b)) => self.type_of_node(*b),
|
||||||
(Some(a), None) => self.type_of_node(*a),
|
(Some(a), None) => self.type_of_node(*a),
|
||||||
(Some(a), Some(b)) => self.peer_type_of_nodes(*a, *b).expect({
|
(Some(a), Some(b)) => self.peer_type_of_nodes(*a, *b).expect(&{
|
||||||
let at = self.type_of_node(*a);
|
let at = self.type_of_node(*a);
|
||||||
let bt = self.type_of_node(*b);
|
let bt = self.type_of_node(*b);
|
||||||
&format!("incompatible types for %{a}({at}) and %{b}({bt})")
|
format!("incompatible types for %{a}({at}) and %{b}({bt})")
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1888,10 +1888,10 @@ impl Tree {
|
||||||
| Tag::And { lhs, rhs }
|
| Tag::And { lhs, rhs }
|
||||||
| Tag::BitOr { lhs, rhs }
|
| Tag::BitOr { lhs, rhs }
|
||||||
| Tag::BitAnd { lhs, rhs }
|
| Tag::BitAnd { lhs, rhs }
|
||||||
| Tag::BitXOr { lhs, rhs } => self.peer_type_of_nodes(*lhs, *rhs).expect({
|
| Tag::BitXOr { lhs, rhs } => self.peer_type_of_nodes(*lhs, *rhs).expect(&{
|
||||||
let at = self.type_of_node(*lhs);
|
let at = self.type_of_node(*lhs);
|
||||||
let bt = self.type_of_node(*rhs);
|
let bt = self.type_of_node(*rhs);
|
||||||
&format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
|
format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
|
||||||
}),
|
}),
|
||||||
Tag::Shl { lhs, .. } => self.type_of_node(*lhs),
|
Tag::Shl { lhs, .. } => self.type_of_node(*lhs),
|
||||||
Tag::Shr { lhs, .. } => self.type_of_node(*lhs),
|
Tag::Shr { lhs, .. } => self.type_of_node(*lhs),
|
||||||
|
@ -1906,11 +1906,11 @@ impl Tree {
|
||||||
Tag::IfExpr { .. } => Type::void(),
|
Tag::IfExpr { .. } => Type::void(),
|
||||||
Tag::IfElseExpr {
|
Tag::IfElseExpr {
|
||||||
body, else_expr, ..
|
body, else_expr, ..
|
||||||
} => self.peer_type_of_nodes(*body, *else_expr).expect({
|
} => self.peer_type_of_nodes(*body, *else_expr).expect(&{
|
||||||
let (lhs, rhs) = (body, else_expr);
|
let (lhs, rhs) = (body, else_expr);
|
||||||
let at = self.type_of_node(*lhs);
|
let at = self.type_of_node(*lhs);
|
||||||
let bt = self.type_of_node(*rhs);
|
let bt = self.type_of_node(*rhs);
|
||||||
&format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
|
format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
|
||||||
}),
|
}),
|
||||||
_ => Type::void(),
|
_ => Type::void(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,11 +69,11 @@ impl InnerSymbolTable {
|
||||||
Self::new_with(Self::new_inner)
|
Self::new_with(Self::new_inner)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_with<G>(gen: G) -> NonNull<InnerSymbolTable>
|
fn new_with<G>(r#gen: G) -> NonNull<InnerSymbolTable>
|
||||||
where
|
where
|
||||||
G: FnOnce() -> Self,
|
G: FnOnce() -> Self,
|
||||||
{
|
{
|
||||||
NonNull::new(Box::leak(Box::new(gen())) as *mut _).unwrap()
|
Box::into_non_null(Box::new(r#gen()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_inner() -> InnerSymbolTable {
|
fn new_inner() -> InnerSymbolTable {
|
||||||
|
@ -404,8 +404,8 @@ pub mod syms2 {
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use crate::ast2::intern::Index as InternIndex;
|
|
||||||
use crate::ast2::Index as AstIndex;
|
use crate::ast2::Index as AstIndex;
|
||||||
|
use crate::ast2::intern::Index as InternIndex;
|
||||||
use crate::lexer::SourceLocation;
|
use crate::lexer::SourceLocation;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{Node as AstNode, Tag, Type},
|
ast::{Node as AstNode, Tag, Type},
|
||||||
ast2::intern::{self, InternPool, AMD64_POINTER_BITS, AMD64_POINTER_TYPE_INFO},
|
ast2::intern::{self, AMD64_POINTER_BITS, AMD64_POINTER_TYPE_INFO, InternPool},
|
||||||
parser::Tree,
|
parser::Tree,
|
||||||
variant, write_indented, writeln_indented,
|
variant, write_indented, writeln_indented,
|
||||||
};
|
};
|
||||||
|
@ -608,10 +608,10 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
||||||
let ty = self
|
let ty = self
|
||||||
.tree
|
.tree
|
||||||
.peer_type_of_nodes(*lhs, *rhs)
|
.peer_type_of_nodes(*lhs, *rhs)
|
||||||
.expect({
|
.expect(&{
|
||||||
let at = self.tree.type_of_node(*lhs);
|
let at = self.tree.type_of_node(*lhs);
|
||||||
let bt = self.tree.type_of_node(*rhs);
|
let bt = self.tree.type_of_node(*rhs);
|
||||||
&format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
|
format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
|
||||||
})
|
})
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue