diff --git a/compiler/hash-ast-desugaring/src/desugaring.rs b/compiler/hash-ast-desugaring/src/desugaring.rs index 80948911c..a8b3a330b 100644 --- a/compiler/hash-ast-desugaring/src/desugaring.rs +++ b/compiler/hash-ast-desugaring/src/desugaring.rs @@ -355,7 +355,7 @@ impl<'s> AstDesugaring<'s> { /// when an if block returns something from a previous branch, then this /// will fail compilation and it will be reported. /// - /// @@Note: We could just add some flag on the match-case to say that when + /// ##Note: We could just add some flag on the match-case to say that when /// it was lowered from a if-block, it was missing an else case, and /// this would mean we don't always have to add it. However, this might /// complicate things with pattern exhaustiveness because then there diff --git a/compiler/hash-ast/src/ast.rs b/compiler/hash-ast/src/ast.rs index 90c700a38..19aaf2c95 100644 --- a/compiler/hash-ast/src/ast.rs +++ b/compiler/hash-ast/src/ast.rs @@ -470,7 +470,7 @@ define_tree! { /// This is a collection of macro invocations that can occur on a single /// item which are collected into a single node. /// - /// @@Note: the `AstNodeId` of the `MacroInvocations` will be the same as + /// ##Note: the `AstNodeId` of the `MacroInvocations` will be the same as /// the id of the children `invocations` node. The [`MacroInvocations`] /// struct is only to effectively collect logic for handling clumps of such /// invocations under one node. @@ -1098,8 +1098,7 @@ define_tree! { /// A literal pattern e.g. `c` /// - /// @@Note: `tuple`, `map`, and `set` literal cannot appear within this - /// branch + /// ##Note: `tuple` literal cannot appear within this branch. Lit(LitPat), /// An `or` pattern which groups multiple patterns and matches one of the diff --git a/compiler/hash-ast/src/lit.rs b/compiler/hash-ast/src/lit.rs index 7d4e5905e..7364f4bd2 100644 --- a/compiler/hash-ast/src/lit.rs +++ b/compiler/hash-ast/src/lit.rs @@ -21,8 +21,8 @@ use std::num; use hash_reporting::{hash_error_codes::error_codes::HashErrorCode, reporter::Reporter}; use hash_source::{ constant::{ - FloatConstant, FloatTy, IntConstant, IntTy, InternedFloat, InternedInt, NormalisedIntTy, - SIntTy, Size, UIntTy, + BigIntTy, FloatConstant, FloatTy, IntConstant, IntTy, InternedFloat, InternedInt, + NormalisedIntTy, SIntTy, Size, UIntTy, }, SourceMap, }; @@ -68,6 +68,9 @@ pub enum LitParseErrorKind { /// Occurs when a int literal is too large to fit in the /// given type. IntOverflow { base: u32, ty: NormalisedIntTy }, + + /// When a big-int literal is not allowed in the current context. + DisallowedBigLit, } pub fn int_ty_suggestion(lit: &str, base: u32, ty: IntTy) -> IntTy { @@ -77,10 +80,11 @@ pub fn int_ty_suggestion(lit: &str, base: u32, ty: IntTy) -> IntTy { let size = Size::from_bits(bits); match ty { - IntTy::Int(_) if bits > 128 => IntTy::Int(SIntTy::IBig), - IntTy::UInt(_) if bits > 128 => IntTy::UInt(UIntTy::UBig), + IntTy::Int(_) if bits > 128 => IntTy::Big(BigIntTy::IBig), + IntTy::UInt(_) if bits > 128 => IntTy::Big(BigIntTy::UBig), IntTy::Int(_) => IntTy::Int(SIntTy::from_size(size)), IntTy::UInt(_) => IntTy::UInt(UIntTy::from_size(size)), + ty => ty, } } @@ -97,16 +101,12 @@ impl LitParseError { } LitParseErrorKind::IntOverflow { base, ty } => { // Compute additional note about what literal to use, if we overflow. - let suggestion = if ty.original.is_bigint() { - ", use a `ibig` instead".to_string() - } else { - format!( - " whose range is `{}..{}`, use a `{}` instead", - ty.normalised.signed_min(Size::ZERO), - ty.normalised.numeric_max(Size::ZERO), - int_ty_suggestion(self.contents.as_str(), base, ty.normalised) - ) - }; + let suggestion = format!( + " whose range is `{}..{}`, use a `{}` instead", + ty.normalised.signed_min(Size::ZERO), + ty.normalised.numeric_max(Size::ZERO), + int_ty_suggestion(self.contents.as_str(), base, ty.normalised) + ); error .title(format!("literal out of range for type `{}`", ty.original)) @@ -116,6 +116,11 @@ impl LitParseError { self.contents, ty.original, suggestion )); } + LitParseErrorKind::DisallowedBigLit => { + error + .title("big integer literals are not allowed in this context") + .add_labelled_span(self.span.span(), "here"); + } }; } } @@ -147,6 +152,26 @@ impl From for LitParseErrorKind { pub type LitParseResult = Result; +pub enum IntValue { + /// A small constant, i.e. anything less than 128 bits. + Small(InternedInt), + + /// A big constant, i.e. anything greater than 128 bits. + Big(Box), +} + +impl IntValue { + /// Assert that the value is a small constant. This can be used + /// in combination with [`parse_int_const_from_lit()`] when `allow_big` + /// is set to `false`. + pub fn small(self) -> InternedInt { + match self { + Self::Small(value) => value, + Self::Big(_) => panic!("expected small constant"), + } + } +} + /// Parse a integer literal from the given [Hunk]. The integer must be /// in the form of a decimal, binary, octal or hexadecimal literal. /// @@ -156,7 +181,8 @@ pub fn parse_int_const_from_lit( annotation: Option, sources: &SourceMap, ptr_size: Size, -) -> LitParseResult { + allow_big: bool, +) -> LitParseResult { let ty = NormalisedIntTy::new(annotation.unwrap_or_default(), ptr_size); let base: u32 = lit.base.into(); @@ -166,7 +192,17 @@ pub fn parse_int_const_from_lit( macro_rules! parse { (@big) => { - Box::new(BigInt::parse_bytes(hunk.as_bytes(), base).unwrap()).into() + if allow_big { + return Ok(IntValue::Big(Box::new( + BigInt::parse_bytes(hunk.as_bytes(), base).unwrap(), + ))); + } else { + return Err(LitParseError::new( + lit.hunk, + hunk, + LitParseErrorKind::DisallowedBigLit, + )); + } }; ($ty:ty) => { <$ty>::from_str_radix(&hunk, base) @@ -182,7 +218,6 @@ pub fn parse_int_const_from_lit( SIntTy::I32 => parse!(i32), SIntTy::I64 => parse!(i64), SIntTy::I128 => parse!(i128), - SIntTy::IBig => parse!(@big), SIntTy::ISize => unreachable!(), }, IntTy::UInt(ty) => match ty { @@ -191,9 +226,9 @@ pub fn parse_int_const_from_lit( UIntTy::U32 => parse!(u32), UIntTy::U64 => parse!(u64), UIntTy::U128 => parse!(u128), - UIntTy::UBig => parse!(@big), UIntTy::USize => unreachable!(), }, + IntTy::Big(_) => parse!(@big), }; // If the given type is a usize/isize, we need to adjust @@ -202,7 +237,7 @@ pub fn parse_int_const_from_lit( lit.suffix = Some(ty.original.into()); } - Ok(InternedInt::create(lit)) + Ok(IntValue::Small(InternedInt::create(lit))) } /// Parse a float literal from the given [Hunk]. The integer must be diff --git a/compiler/hash-attrs/src/attr.rs b/compiler/hash-attrs/src/attr.rs index f6298362d..8f1a46825 100644 --- a/compiler/hash-attrs/src/attr.rs +++ b/compiler/hash-attrs/src/attr.rs @@ -53,7 +53,7 @@ impl ReprAttr { }; // We reject the type if it is non-sized... - if !ty.is_bounded() { + if !ty.is_big() { return Err(AttrError::InvalidReprIntKind { arg: *arg }); } @@ -181,7 +181,8 @@ impl AttrValueKind { ast::Lit::Str(ast::StrLit { data }) => Ok(Some(Self::Str(*data))), ast::Lit::Char(ast::CharLit { data }) => Ok(Some(Self::Char(*data))), ast::Lit::Int(int_lit) => { - let value = parse_int_const_from_lit(int_lit, None, sources, ptr_size)?; + let value = + parse_int_const_from_lit(int_lit, None, sources, ptr_size, false)?.small(); Ok(Some(Self::Int(value))) } ast::Lit::Float(float_lit) => { diff --git a/compiler/hash-codegen-llvm/src/translation/abi.rs b/compiler/hash-codegen-llvm/src/translation/abi.rs index 6c0958190..2b6ff7b2d 100644 --- a/compiler/hash-codegen-llvm/src/translation/abi.rs +++ b/compiler/hash-codegen-llvm/src/translation/abi.rs @@ -420,7 +420,7 @@ impl<'b, 'm> ExtendedFnAbiMethods<'b, 'm> for FnAbi { if let AbiRepresentation::Scalar(scalar) = abi { if let ScalarKind::Int { .. } = scalar.kind() { - // @@Hack: if the value is boolean, the range metadata would become + // ##Hack: if the value is boolean, the range metadata would become // 0..0 due to the fact that the type of it is `i1`. This would be rejected // by the LLVM IR verifier... so we don't add the range metadata for // boolean types. diff --git a/compiler/hash-codegen-llvm/src/translation/constants.rs b/compiler/hash-codegen-llvm/src/translation/constants.rs index 0518a9800..9a55ca17d 100644 --- a/compiler/hash-codegen-llvm/src/translation/constants.rs +++ b/compiler/hash-codegen-llvm/src/translation/constants.rs @@ -148,14 +148,7 @@ impl<'b, 'm> ConstValueBuilderMethods<'b> for CodeGenCtx<'b, 'm> { // Convert the constant into a u128 and then emit the // correct LLVM constant for it. - const_int - .value - .as_u128() - .map(|value| self.const_uint_big(ty, value)) - .unwrap_or_else(|| { - // @@Todo: deal with bigints... - unimplemented!() - }) + self.const_uint_big(ty, const_int.value.as_u128()) } Const::Float(interned_float) => self.const_float(ty, interned_float.value().as_f64()), Const::Str(str) => self.const_str(str).0, @@ -169,7 +162,7 @@ impl<'b, 'm> ConstValueBuilderMethods<'b> for CodeGenCtx<'b, 'm> { return None; } - // @@Hack: this doesn't properly handle the full range of i128 values, however] + // ##Hack: this doesn't properly handle the full range of i128 values, however] // Inkwell doesn't support arbitrary precision integers, so we can't do much better... // unless we @@PatchInkwell if sign_extend { diff --git a/compiler/hash-codegen/src/lower/locals.rs b/compiler/hash-codegen/src/lower/locals.rs index 5a40fc49b..2ca1417d8 100644 --- a/compiler/hash-codegen/src/lower/locals.rs +++ b/compiler/hash-codegen/src/lower/locals.rs @@ -242,7 +242,7 @@ impl<'ir, 'a, 'b, Builder: BlockBuilderMethods<'a, 'b>> IrVisitorMut<'ir> PlaceContext::Immutable(ImmutablePlaceContext::Projection) }; - // @@Hack: in order to preserve the order of the traversal, we + // ##Hack: in order to preserve the order of the traversal, we // save any locals that come from `Index` projections and then // traverse them after we have traversed the base local. let mut index_locals = vec![]; diff --git a/compiler/hash-driver/src/driver.rs b/compiler/hash-driver/src/driver.rs index 00038614c..3539b1c05 100644 --- a/compiler/hash-driver/src/driver.rs +++ b/compiler/hash-driver/src/driver.rs @@ -301,7 +301,7 @@ impl Driver { ); } - // @@Hack: to prevent the compiler from printing this message when the pipeline + // ##Hack: to prevent the compiler from printing this message when the pipeline // when it was instructed to terminate before all of the stages. For example, if // the compiler is just checking the source, then it will terminate early. if err_count != 0 || warn_count != 0 { diff --git a/compiler/hash-driver/src/lib.rs b/compiler/hash-driver/src/lib.rs index 4a1acddbf..7501b7808 100644 --- a/compiler/hash-driver/src/lib.rs +++ b/compiler/hash-driver/src/lib.rs @@ -109,7 +109,7 @@ pub mod utils { /// be used in contexts where the error type is known to implementing the /// [Into] trait. pub fn emit_on_fatal_error>(f: impl FnOnce() -> Result) -> T { - // @@Hack: we have to create a dummy source map here so that we can use it + // ##Hack: we have to create a dummy source map here so that we can use it // to report errors in the case that the compiler fails to start up. After the // workspace is initiated, it is replaced with the real source map. let source_map = SourceMap::new(); diff --git a/compiler/hash-exhaustiveness/src/constant.rs b/compiler/hash-exhaustiveness/src/constant.rs index 3625595ab..15cda7437 100644 --- a/compiler/hash-exhaustiveness/src/constant.rs +++ b/compiler/hash-exhaustiveness/src/constant.rs @@ -31,7 +31,7 @@ impl Constant { pub fn from_int(constant: InternedInt, ty: TyId) -> Self { // Get the associated bytes with the interned-int so we can convert // into a constant. - let data = constant.value().value.as_u128().unwrap(); + let data = constant.value().value.as_u128(); Constant { data, ty } } diff --git a/compiler/hash-exhaustiveness/src/lower.rs b/compiler/hash-exhaustiveness/src/lower.rs index 3ede21284..81dde9126 100644 --- a/compiler/hash-exhaustiveness/src/lower.rs +++ b/compiler/hash-exhaustiveness/src/lower.rs @@ -370,7 +370,6 @@ impl<'tc> ExhaustivenessChecker<'tc> { // a singleton, and in fact the range will never be constructed from a // `ubig` or `ibig` type. match self.try_use_ty_as_lit_ty(ty).unwrap() { - LitTy::UBig | LitTy::IBig => unreachable!(), ty if ty.is_int() => { let (lo, _) = range.boundaries(); let bias = range.bias; @@ -413,9 +412,7 @@ impl<'tc> ExhaustivenessChecker<'tc> { | LitTy::I64 | LitTy::U64 | LitTy::U128 - | LitTy::I128 - | LitTy::IBig - | LitTy::UBig => { + | LitTy::I128 => { let kind = self.try_use_ty_as_int_ty(ty).unwrap(); let ptr_width = self.target().ptr_size(); diff --git a/compiler/hash-exhaustiveness/src/range.rs b/compiler/hash-exhaustiveness/src/range.rs index 8c4a180e1..97b7ab947 100644 --- a/compiler/hash-exhaustiveness/src/range.rs +++ b/compiler/hash-exhaustiveness/src/range.rs @@ -276,7 +276,7 @@ impl<'tc> ExhaustivenessChecker<'tc> { /// last byte is that identifies the sign. pub(crate) fn signed_bias(&self, ty: TyId) -> u128 { if let Some(ty) = self.try_use_ty_as_int_ty(ty) { - if ty.is_signed() && !ty.is_bigint() { + if ty.is_signed() && !ty.is_big() { let size = ty.size(self.target().ptr_size()); let bits = size.bits() as u128; return 1u128 << (bits - 1); diff --git a/compiler/hash-intrinsics/src/intrinsics.rs b/compiler/hash-intrinsics/src/intrinsics.rs index 09def7fbc..ef51043ac 100644 --- a/compiler/hash-intrinsics/src/intrinsics.rs +++ b/compiler/hash-intrinsics/src/intrinsics.rs @@ -22,7 +22,6 @@ use hash_tir::{ tys::Ty, }; use hash_utils::stream_less_writeln; -use num_bigint::{BigInt, BigUint}; use num_enum::{IntoPrimitive, TryFromPrimitive}; use crate::utils::{LitTy, PrimitiveUtils}; @@ -286,10 +285,6 @@ impl DefinedIntrinsics { LitTy::I32 => handle_integer!(i32), LitTy::I64 => handle_integer!(i64), LitTy::I128 => handle_integer!(i128), - LitTy::IBig => { - let a: BigInt = env.try_use_term_as_integer_lit(a).unwrap(); - Ok(env.create_term_from_integer_lit(operate_integer!(parsed_op, a))) - } LitTy::F32 => { // @@Todo: properly handle f32 let a: f64 = env.try_use_term_as_float_lit(a).unwrap(); @@ -487,8 +482,6 @@ impl DefinedIntrinsics { LitTy::I32 => handle_integer!(i32), LitTy::I64 => handle_integer!(i64), LitTy::I128 => handle_integer!(i128), - LitTy::UBig => handle_integer!(BigUint), - LitTy::IBig => handle_integer!(BigInt), LitTy::F32 => { let lhs: f64 = env.try_use_term_as_float_lit(lhs).unwrap(); let rhs: f64 = env.try_use_term_as_float_lit(rhs).unwrap(); @@ -572,23 +565,6 @@ impl DefinedIntrinsics { ) .map_err(|_| INVALID_OP)?; - // Valid operations on big-ints - macro_rules! operate_bigint { - ($op:expr, $lhs:expr, $rhs:expr) => { - match $op { - EndoBinOp::BitOr => $lhs | $rhs, - EndoBinOp::BitAnd => $lhs & $rhs, - EndoBinOp::BitXor => $lhs ^ $rhs, - EndoBinOp::Add => $lhs + $rhs, - EndoBinOp::Sub => $lhs - $rhs, - EndoBinOp::Mul => $lhs * $rhs, - EndoBinOp::Div => $lhs / $rhs, - EndoBinOp::Mod => $lhs % $rhs, - _ => return Err(INVALID_OP.to_string()), - } - }; - } - // Valid operations on floats macro_rules! operate_float { ($op:expr, $lhs:expr, $rhs:expr) => { @@ -631,14 +607,6 @@ impl DefinedIntrinsics { }}; } - macro_rules! handle_bigint { - ($rust_ty:ty) => {{ - let lhs: $rust_ty = env.try_use_term_as_integer_lit(lhs).unwrap(); - let rhs: $rust_ty = env.try_use_term_as_integer_lit(rhs).unwrap(); - Ok(env.create_term_from_integer_lit(operate_bigint!(parsed_op, lhs, rhs))) - }}; - } - // Handle each `T` parameter: match env.try_use_ty_as_lit_ty(t.as_ty()) { Some(lit_ty) => match lit_ty { @@ -652,8 +620,6 @@ impl DefinedIntrinsics { LitTy::I32 => handle_integer!(i32), LitTy::I64 => handle_integer!(i64), LitTy::I128 => handle_integer!(i128), - LitTy::UBig => handle_bigint!(BigUint), - LitTy::IBig => handle_bigint!(BigInt), LitTy::F32 => { let lhs: f64 = env.try_use_term_as_float_lit(lhs).unwrap(); let rhs: f64 = env.try_use_term_as_float_lit(rhs).unwrap(); diff --git a/compiler/hash-intrinsics/src/utils.rs b/compiler/hash-intrinsics/src/utils.rs index 607df9801..bb851d610 100644 --- a/compiler/hash-intrinsics/src/utils.rs +++ b/compiler/hash-intrinsics/src/utils.rs @@ -4,11 +4,12 @@ use hash_source::constant::{ InternedFloat, InternedInt, SIntTy, UIntTy, }; use hash_storage::store::statics::{SequenceStoreValue, StoreId}; +use hash_target::primitives::BigIntTy; use hash_tir::{ args::{Arg, PatArg}, data::{ArrayCtorInfo, CtorDefId, CtorPat, CtorTerm, DataDefCtors, DataTy, PrimitiveCtorInfo}, environment::env::AccessToEnv, - lits::{CharLit, Lit}, + lits::{CharLit, IntLit, Lit}, node::{Node, NodeOrigin}, pats::{Pat, PatId}, primitives::primitives, @@ -16,7 +17,6 @@ use hash_tir::{ terms::{Term, TermId}, tys::{Ty, TyId}, }; -use num_bigint::BigInt; /// Primitive literal types. /// @@ -34,8 +34,6 @@ pub enum LitTy { U64, U128, I128, - IBig, - UBig, F32, F64, Bool, @@ -57,8 +55,6 @@ impl LitTy { | LitTy::U64 | LitTy::U128 | LitTy::I128 - | LitTy::IBig - | LitTy::UBig ) } } @@ -71,13 +67,11 @@ impl From for IntTy { LitTy::U32 => IntTy::UInt(UIntTy::U32), LitTy::U64 => IntTy::UInt(UIntTy::U64), LitTy::U128 => IntTy::UInt(UIntTy::U128), - LitTy::UBig => IntTy::UInt(UIntTy::UBig), LitTy::I8 => IntTy::Int(SIntTy::I8), LitTy::I16 => IntTy::Int(SIntTy::I16), LitTy::I32 => IntTy::Int(SIntTy::I32), LitTy::I64 => IntTy::Int(SIntTy::I64), LitTy::I128 => IntTy::Int(SIntTy::I128), - LitTy::IBig => IntTy::Int(SIntTy::IBig), _ => unreachable!(), } } @@ -167,8 +161,8 @@ pub trait PrimitiveUtils: AccessToEnv { d if d == primitives().u64() => Some(IntTy::UInt(UIntTy::U64)), d if d == primitives().i128() => Some(IntTy::Int(SIntTy::I128)), d if d == primitives().u128() => Some(IntTy::UInt(UIntTy::U128)), - d if d == primitives().ibig() => Some(IntTy::Int(SIntTy::IBig)), - d if d == primitives().ubig() => Some(IntTy::UInt(UIntTy::UBig)), + d if d == primitives().ibig() => Some(IntTy::Big(BigIntTy::IBig)), + d if d == primitives().ubig() => Some(IntTy::Big(BigIntTy::UBig)), d if d == primitives().isize() => Some(IntTy::Int(SIntTy::ISize)), d if d == primitives().usize() => Some(IntTy::UInt(UIntTy::USize)), _ => None, @@ -214,8 +208,6 @@ pub trait PrimitiveUtils: AccessToEnv { d if d == primitives().u64() => Some(LitTy::U64), d if d == primitives().u128() => Some(LitTy::U128), d if d == primitives().i128() => Some(LitTy::I128), - d if d == primitives().ibig() => Some(LitTy::IBig), - d if d == primitives().ubig() => Some(LitTy::UBig), d if d == primitives().f32() => Some(LitTy::F32), d if d == primitives().f64() => Some(LitTy::F64), d if d == primitives().bool() => Some(LitTy::Bool), @@ -258,7 +250,13 @@ pub trait PrimitiveUtils: AccessToEnv { } } - /// Get the given term as a float literal if possible. + /// Create a term from the given usize integer literal. + fn create_term_from_usize_lit(&self, lit: usize) -> TermId { + let lit: IntLit = InternedInt::create_usize(lit, self.target().ptr_size()).into(); + Node::create_gen(Term::Lit(Node::create_gen(Lit::Int(lit)))) + } + + /// Create a term from the given integer literal. fn create_term_from_integer_lit>(&self, lit: L) -> TermId { let lit = Lit::Int(InternedInt::create(IntConstant::new(lit.into(), None)).into()); // @@MissingOrigin @@ -284,10 +282,13 @@ pub trait PrimitiveUtils: AccessToEnv { } /// Get the given term as an integer literal if possible. - fn try_use_term_as_integer_lit>(&self, term: TermId) -> Option { + fn try_use_term_as_integer_lit TryFrom<&'a IntConstant>>( + &self, + term: TermId, + ) -> Option { match *term.value() { Term::Lit(lit) => match *lit.value() { - Lit::Int(i) => i.value().try_into().ok(), + Lit::Int(i) => (&i.value()).try_into().ok(), _ => None, }, Term::Var(sym) => self @@ -317,7 +318,6 @@ pub trait PrimitiveUtils: AccessToEnv { fn numeric_max_val_of_lit(&self, ty: TyId) -> Option { match self.try_use_ty_as_lit_ty(ty)? { // There is no maximum value for big integers. - LitTy::UBig | LitTy::IBig => None, ty if ty.is_int() => { let int_ty: IntTy = ty.into(); Some(int_ty.numeric_max(self.target().ptr_size())) @@ -333,7 +333,6 @@ pub trait PrimitiveUtils: AccessToEnv { fn numeric_min_val_of_lit(&self, ty: TyId) -> Option { match self.try_use_ty_as_lit_ty(ty)? { // There is no minimum value for big integers. - LitTy::UBig | LitTy::IBig => None, ty if ty.is_int() => { let int_ty: IntTy = ty.into(); Some(int_ty.numeric_min(self.target().ptr_size())) diff --git a/compiler/hash-ir/src/ty.rs b/compiler/hash-ir/src/ty.rs index aa8bec2ef..805760ccf 100644 --- a/compiler/hash-ir/src/ty.rs +++ b/compiler/hash-ir/src/ty.rs @@ -30,6 +30,7 @@ use hash_storage::{ use hash_target::{ abi::{self, Abi, Integer, ScalarKind}, data_layout::HasDataLayout, + primitives::BigIntTy, size::Size, }; use hash_utils::{ @@ -463,15 +464,6 @@ impl IrTy { } } -impl From for IrTy { - fn from(value: IntTy) -> Self { - match value { - IntTy::Int(ty) => Self::Int(ty), - IntTy::UInt(ty) => Self::UInt(ty), - } - } -} - impl From for IntTy { fn from(ty: IrTy) -> Self { match ty { @@ -531,6 +523,12 @@ macro_rules! create_common_ty_table { /// A void pointer, i.e. `&()`. pub void_ptr: IrTyId, + + /// The big unsigned integer type. + pub ubig: IrTyId, + + /// The big signed integer type. + pub ibig: IrTyId, } impl CommonIrTys { @@ -542,6 +540,8 @@ macro_rules! create_common_ty_table { raw_ptr: IrTyId::from_index_unchecked(0), void_ptr: IrTyId::from_index_unchecked(0), str: IrTyId::from_index_unchecked(0), + ubig: IrTyId::from_index_unchecked(0), + ibig: IrTyId::from_index_unchecked(0), }; // Create a `unit` type in order to reserve the first index of @@ -557,12 +557,17 @@ macro_rules! create_common_ty_table { let void_ptr = IrTy::create(IrTy::Ref(table.unit, Mutability::Immutable, RefKind::Raw)); let str = IrTy::create(IrTy::Ref(table.unsized_str, Mutability::Immutable, RefKind::Normal)); + let ubig = IrTy::create(IrTy::Slice(table.u64)); + let ibig = IrTy::tuple(&[table.bool, table.ubig]); + CommonIrTys { byte_slice, ptr, raw_ptr, void_ptr, str, + ubig, + ibig, ..table } } @@ -577,32 +582,50 @@ macro_rules! create_common_ty_table { } create_common_ty_table!( + // ------------------------------------------ // Primitive types + // ------------------------------------------ bool: IrTy::Bool, char: IrTy::Char, never: IrTy::Never, + + // ------------------------------------------ // Unsized string refers to the inner type of a `str`. // // @@Temporary This is only temporary until str/[T] type semantics and rules are decided and // implemented. + // ------------------------------------------ unsized_str: IrTy::Str, + + // ------------------------------------------ // Floating point types + // ------------------------------------------ f32: IrTy::Float(FloatTy::F32), f64: IrTy::Float(FloatTy::F64), + + // ------------------------------------------ // Signed integer types + // ------------------------------------------ i8: IrTy::Int(SIntTy::I8), i16: IrTy::Int(SIntTy::I16), i32: IrTy::Int(SIntTy::I32), i64: IrTy::Int(SIntTy::I64), i128: IrTy::Int(SIntTy::I128), isize: IrTy::Int(SIntTy::ISize), + + // ------------------------------------------ // Unsigned integer types + // ------------------------------------------ u8: IrTy::UInt(UIntTy::U8), u16: IrTy::UInt(UIntTy::U16), u32: IrTy::UInt(UIntTy::U32), u64: IrTy::UInt(UIntTy::U64), u128: IrTy::UInt(UIntTy::U128), - usize: IrTy::UInt(UIntTy::USize), // Unit types, and unit ptr types + + // ------------------------------------------ + // Unit types, and unit ptr types + // ------------------------------------------ + usize: IrTy::UInt(UIntTy::USize), unit: IrTy::Adt(AdtId::UNIT), ); @@ -784,7 +807,6 @@ impl ToIrTy for IntTy { SIntTy::I64 => COMMON_IR_TYS.i64, SIntTy::I128 => COMMON_IR_TYS.i128, SIntTy::ISize => COMMON_IR_TYS.isize, - _ => unimplemented!(), }, IntTy::UInt(ty) => match ty { UIntTy::U8 => COMMON_IR_TYS.u8, @@ -793,7 +815,10 @@ impl ToIrTy for IntTy { UIntTy::U64 => COMMON_IR_TYS.u64, UIntTy::U128 => COMMON_IR_TYS.u128, UIntTy::USize => COMMON_IR_TYS.usize, - _ => unimplemented!(), + }, + IntTy::Big(ty) => match ty { + BigIntTy::IBig => COMMON_IR_TYS.ibig, + BigIntTy::UBig => COMMON_IR_TYS.ubig, }, } } diff --git a/compiler/hash-layout/src/compute.rs b/compiler/hash-layout/src/compute.rs index f4650ee8a..156363c0e 100644 --- a/compiler/hash-layout/src/compute.rs +++ b/compiler/hash-layout/src/compute.rs @@ -169,11 +169,6 @@ impl<'l> LayoutComputer<'l> { SIntTy::I64 => Ok(self.common_layouts().i64), SIntTy::I128 => Ok(self.common_layouts().i128), SIntTy::ISize => Ok(self.common_layouts().isize), - - // @@Layout: for bigints, we will probably use a ScalarPair - // to represent a pointer to the digit array, and then a - // length of the digits. - SIntTy::IBig => Err(LayoutError::Unknown(ty_id)), }, IrTy::UInt(ty) => match ty { UIntTy::U8 => Ok(self.common_layouts().u8), @@ -182,7 +177,6 @@ impl<'l> LayoutComputer<'l> { UIntTy::U64 => Ok(self.common_layouts().u64), UIntTy::U128 => Ok(self.common_layouts().u128), UIntTy::USize => Ok(self.common_layouts().usize), - UIntTy::UBig => Err(LayoutError::Unknown(ty_id)), }, IrTy::Float(ty) => Ok(match ty { FloatTy::F32 => self.common_layouts().f32, diff --git a/compiler/hash-lexer/src/lib.rs b/compiler/hash-lexer/src/lib.rs index d6cf70a18..489f3511b 100644 --- a/compiler/hash-lexer/src/lib.rs +++ b/compiler/hash-lexer/src/lib.rs @@ -209,7 +209,7 @@ impl<'a> Lexer<'a> { let offset = self.offset.get(); - // @@Hack: since we already compare if the first item is a slash, we'll just + // ##Hack: since we already compare if the first item is a slash, we'll just // return here the slash and advance it by one. return Some(Token::new( TokenKind::Slash, @@ -359,8 +359,6 @@ impl<'a> Lexer<'a> { debug_assert!(is_id_start(first)); let start = self.offset.get() - first.len_utf8(); - // @@Hack: instead of using an iterator to collect, we want to eat the chars and - // then take a slice at the end self.eat_while_and_discard(is_id_continue); let name = &self.contents.0[start..self.offset.get()]; diff --git a/compiler/hash-lower/src/build/constant.rs b/compiler/hash-lower/src/build/constant.rs index b17bbb7ce..84bb58627 100644 --- a/compiler/hash-lower/src/build/constant.rs +++ b/compiler/hash-lower/src/build/constant.rs @@ -53,8 +53,6 @@ impl<'tcx> BodyBuilder<'tcx> { /// them. If the operation is not possible, then the function will /// return [None]. pub(crate) fn try_fold_const_op(&mut self, op: BinOp, lhs: Const, rhs: Const) -> Option { - // @@Todo: for now we only handle `small` values of integer types, in the - // future we should also be able to perform folds on `ibig` and `ubig` values. if let Const::Int(interned_lhs) = lhs && let Const::Int(interned_rhs) = rhs { let lhs_const = interned_lhs.value(); diff --git a/compiler/hash-lower/src/build/into.rs b/compiler/hash-lower/src/build/into.rs index 2d05531e8..2bc63c072 100644 --- a/compiler/hash-lower/src/build/into.rs +++ b/compiler/hash-lower/src/build/into.rs @@ -114,7 +114,7 @@ impl<'tcx> BodyBuilder<'tcx> { let ty = self.ty_id_from_tir_term(term); if ty == COMMON_IR_TYS.bool { - // @@Hack: check which constructor is being called to determine whether + // ##Hack: check which constructor is being called to determine whether // it is a `true` or `false` value. let constant = if ctor.ctor.1 == 0 { Const::Bool(true) } else { Const::Bool(false) }; diff --git a/compiler/hash-lower/src/build/matches/mod.rs b/compiler/hash-lower/src/build/matches/mod.rs index 87d1f5ac3..efd5d5e35 100644 --- a/compiler/hash-lower/src/build/matches/mod.rs +++ b/compiler/hash-lower/src/build/matches/mod.rs @@ -48,7 +48,7 @@ impl<'tcx> BodyBuilder<'tcx> { arms: MatchCasesId, match_origin: ast::MatchOrigin, ) -> BlockAnd<()> { - // @@Hack: if the match-origin is an `if`-chain, then we don't bother + // ##Hack: if the match-origin is an `if`-chain, then we don't bother // lowering the place since we always know that the branches are // always matching, and it's only guards that are being tested. Therefore, // we use the `subject_place` as the `return_place` in this instance. diff --git a/compiler/hash-lower/src/build/ty.rs b/compiler/hash-lower/src/build/ty.rs index 6ad62160d..950913528 100644 --- a/compiler/hash-lower/src/build/ty.rs +++ b/compiler/hash-lower/src/build/ty.rs @@ -165,7 +165,7 @@ impl<'tcx> BodyBuilder<'tcx> { match *(*pat).value() { Lit::Int(lit) => { let value = lit.interned_value(); - value.map(|constant| (Const::Int(value), constant.value.as_u128().unwrap())) + value.map(|constant| (Const::Int(value), constant.value.as_u128())) } Lit::Char(lit) => { let value = lit.value(); diff --git a/compiler/hash-lower/src/lower_ty.rs b/compiler/hash-lower/src/lower_ty.rs index e0648f44b..4d1809fda 100644 --- a/compiler/hash-lower/src/lower_ty.rs +++ b/compiler/hash-lower/src/lower_ty.rs @@ -373,7 +373,13 @@ impl<'ir> BuilderCtx<'ir> { } } } - _ => unimplemented!(), // We don't implement big-ints yet + NumericCtorBits::Unbounded => { + if is_signed { + COMMON_IR_TYS.ibig + } else { + COMMON_IR_TYS.ubig + } + } } } } diff --git a/compiler/hash-parser/src/parser/expr.rs b/compiler/hash-parser/src/parser/expr.rs index 5e9370499..2904b360f 100644 --- a/compiler/hash-parser/src/parser/expr.rs +++ b/compiler/hash-parser/src/parser/expr.rs @@ -189,7 +189,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } // Body block. TokenKind::Tree(Delimiter::Brace, _) => { - // @@Hack: we need to backtrack a single token so that `parse_block` can be + // ##Hack: we need to backtrack a single token so that `parse_block` can be // used. self.offset.set(self.offset.get() - 1); diff --git a/compiler/hash-parser/src/parser/macros.rs b/compiler/hash-parser/src/parser/macros.rs index ec756b6a3..0e335e616 100644 --- a/compiler/hash-parser/src/parser/macros.rs +++ b/compiler/hash-parser/src/parser/macros.rs @@ -149,7 +149,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } } - // @@Hack: avoid making another id and allocating another span for + // ##Hack: avoid making another id and allocating another span for // just a wrapper for the children. Ideally, this problem could be // fixed if we had `OptionalChildren!` in tree-def. Ok(self.make_macro_invocations(self.nodes_with_joined_span(invocations, start))) diff --git a/compiler/hash-parser/src/parser/pat.rs b/compiler/hash-parser/src/parser/pat.rs index 5cb84c204..c22201071 100644 --- a/compiler/hash-parser/src/parser/pat.rs +++ b/compiler/hash-parser/src/parser/pat.rs @@ -406,7 +406,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } } - // @@Hack: here it might actually be a nested pattern in parentheses. So we + // ##Hack: here it might actually be a nested pattern in parentheses. So we // perform a slight transformation if the number of parsed patterns is // only one. So essentially we handle the case where a pattern is // wrapped in parentheses and so we just unwrap it. diff --git a/compiler/hash-parser/src/parser/ty.rs b/compiler/hash-parser/src/parser/ty.rs index 104091fb5..60c85a60a 100644 --- a/compiler/hash-parser/src/parser/ty.rs +++ b/compiler/hash-parser/src/parser/ty.rs @@ -209,7 +209,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { name: None, default: None, ty: Some(self.node_with_joined_span(ty, span)), - // @@Note: this will always be none since the above function + // ##Note: this will always be none since the above function // will parse the args and then apply it to us as the subject. // // So if `#foo U -> T` is present, we parse as `TyMacroInvocation { subject: U -> T, macros: #foo }` diff --git a/compiler/hash-source/src/attributes.rs b/compiler/hash-source/src/attributes.rs deleted file mode 100644 index baf161d87..000000000 --- a/compiler/hash-source/src/attributes.rs +++ /dev/null @@ -1,94 +0,0 @@ -//! This defines the [ItemAttributes] structure which is used to store -//! arbitrary attributes on an item that are specified on the item in -//! the source. Item attributes are used to provide additional information -//! about any item, including labelling internal language items, calling -//! conventions, representations, etc. - -use std::sync::LazyLock; - -use hash_utils::{fxhash::FxHashMap, lazy_static::lazy_static, thin_vec::ThinVec}; - -use crate::identifier::{Identifier, IDENTS}; - -/// The [Attribute] structure represents a single attribute on an item. -/// Attributes are specified on items in the source code, and are used -/// to provide additional information about the item. These attributes -/// are computed from the parsed AST for items. -#[derive(Default, Debug, Clone)] -pub struct ItemAttributes { - /// The inner attributes of the item. - attributes: ThinVec, -} - -impl ItemAttributes { - /// Create a new [ItemAttributes] structure. - pub fn new() -> Self { - Self { attributes: ThinVec::new() } - } - - /// Add an attribute to the item. - pub fn add(&mut self, attribute: Attribute) { - self.attributes.push(attribute); - } - - /// Check if an attribute exists on the item. - pub fn contains(&self, name: Identifier) -> bool { - self.attributes.iter().any(|a| a.name == name) - } - - /// Get the attributes of the item. - pub fn attributes(&self) -> &[Attribute] { - &self.attributes - } - - /// Get the attributes of the item. - pub fn attributes_mut(&mut self) -> &mut [Attribute] { - &mut self.attributes - } -} - -/// A singular attribute with a name and an optional -/// value that is associated with the attribute. -#[derive(Debug, Clone)] -pub struct Attribute { - /// The name of the attribute. - name: Identifier, - - /// The value of the attribute. This is used to validate - /// the specified attributes in the source. - pub kind: AttributeKind, -} - -impl Attribute { - /// Create a new word [Attribute]. - pub fn word(name: Identifier) -> Self { - Self { name, kind: AttributeKind::Word } - } -} - -/// Defines the kind of attribute that is being used. -/// -/// @@Incomplete: This is currently incomplete, and will be -/// extended as the attribute system is extended. -#[derive(Debug, Clone)] -pub enum AttributeKind { - /// Just the attribute itself - Word, -} - -lazy_static! { - pub static ref BUILTIN_ATTRIBUTES: [Attribute; 1] = - [Attribute { name: IDENTS.no_mangle, kind: AttributeKind::Word }]; -} - -pub static BUILTIN_ATTRIBUTE_MAP: LazyLock> = - LazyLock::new(|| { - let mut map = FxHashMap::default(); - for attr in BUILTIN_ATTRIBUTES.iter() { - if map.insert(attr.name, attr).is_some() { - panic!("duplicate builtin attribute `{}`", attr.name); - } - } - - map - }); diff --git a/compiler/hash-source/src/constant.rs b/compiler/hash-source/src/constant.rs index c741cf713..c910dd0ca 100644 --- a/compiler/hash-source/src/constant.rs +++ b/compiler/hash-source/src/constant.rs @@ -23,7 +23,7 @@ use hash_utils::{ lazy_static::lazy_static, parking_lot::RwLock, }; -use num_bigint::{BigInt, BigUint, Sign}; +use num_bigint::{BigInt, Sign}; use FloatConstantValue::*; use IntConstantValue::*; @@ -38,7 +38,6 @@ impl From for Identifier { UIntTy::U64 => IDENTS.u64, UIntTy::U128 => IDENTS.u128, UIntTy::USize => IDENTS.usize, - UIntTy::UBig => IDENTS.ubig, } } } @@ -52,7 +51,15 @@ impl From for Identifier { SIntTy::I64 => IDENTS.i64, SIntTy::I128 => IDENTS.i128, SIntTy::ISize => IDENTS.isize, - SIntTy::IBig => IDENTS.ibig, + } + } +} + +impl From for Identifier { + fn from(value: BigIntTy) -> Self { + match value { + BigIntTy::IBig => IDENTS.ibig, + BigIntTy::UBig => IDENTS.ubig, } } } @@ -62,6 +69,7 @@ impl From for Identifier { match value { IntTy::Int(ty) => ty.into(), IntTy::UInt(ty) => ty.into(), + IntTy::Big(ty) => ty.into(), } } } @@ -77,14 +85,14 @@ impl TryFrom for IntTy { i if i == IDENTS.i64 => Ok(IntTy::Int(SIntTy::I64)), i if i == IDENTS.i128 => Ok(IntTy::Int(SIntTy::I128)), i if i == IDENTS.isize => Ok(IntTy::Int(SIntTy::ISize)), - i if i == IDENTS.ibig => Ok(IntTy::Int(SIntTy::IBig)), i if i == IDENTS.u8 => Ok(IntTy::UInt(UIntTy::U8)), i if i == IDENTS.u16 => Ok(IntTy::UInt(UIntTy::U16)), i if i == IDENTS.u32 => Ok(IntTy::UInt(UIntTy::U32)), i if i == IDENTS.u64 => Ok(IntTy::UInt(UIntTy::U64)), i if i == IDENTS.u128 => Ok(IntTy::UInt(UIntTy::U128)), i if i == IDENTS.usize => Ok(IntTy::UInt(UIntTy::USize)), - i if i == IDENTS.ubig => Ok(IntTy::UInt(UIntTy::UBig)), + i if i == IDENTS.ibig => Ok(IntTy::Big(BigIntTy::IBig)), + i if i == IDENTS.ubig => Ok(IntTy::Big(BigIntTy::UBig)), _ => Err(()), } } @@ -303,14 +311,9 @@ impl fmt::Display for InternedFloat { // -------------------- Integers -------------------- -/// Value of the [IntConstant], this kind be either the `inlined` -/// variant where we just fallback to using `u64` for small sized -/// integer constants, and then in the unlikely scenario of needing -/// more than a [u128] to represent the constant, we will then -/// fallback to [BigInt]. -/// -/// N.B: Values are always stored and accessed in **Big Endian** format. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +/// Value of the [IntConstant], stores between an `u8` to `u128` value, +/// including signed variants. +#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)] pub enum IntConstantValue { I8(i8), I16(i16), @@ -322,51 +325,45 @@ pub enum IntConstantValue { U32(u32), U64(u64), U128(u128), - - /// For bigger values, we just store a pointer to the `BigInt` - Big(Box), } impl IntConstantValue { - /// Attempt to convert the given value into a [u128] provided that the - /// value itself is not [`IntConstantValue::Big`]. If the value is a - /// big integer, then [`None`] is returned. - pub fn as_u128(&self) -> Option { + /// Convert the given value into a [u128] provided. + pub fn as_u128(&self) -> u128 { match self { Self::I8(inner) => { let inner = inner.to_be_bytes(); let mut bytes = [0; 16]; bytes[15] = inner[0]; - Some(u128::from_be_bytes(bytes)) + u128::from_be_bytes(bytes) } Self::I16(inner) => { let inner = inner.to_be_bytes(); let mut bytes = [0; 16]; bytes[14..].copy_from_slice(&inner); - Some(u128::from_be_bytes(bytes)) + u128::from_be_bytes(bytes) } Self::I32(inner) => { let inner = inner.to_be_bytes(); let mut bytes = [0; 16]; bytes[12..].copy_from_slice(&inner); - Some(u128::from_be_bytes(bytes)) + u128::from_be_bytes(bytes) } Self::I64(inner) => { let inner = inner.to_be_bytes(); let mut bytes = [0; 16]; bytes[8..].copy_from_slice(&inner); - Some(u128::from_be_bytes(bytes)) + u128::from_be_bytes(bytes) } - Self::I128(inner) => Some(u128::from_be_bytes(inner.to_be_bytes())), + Self::I128(inner) => u128::from_be_bytes(inner.to_be_bytes()), // For unsigned values, its fine to just cast them since we're // zero extending them anyways... - Self::U8(inner) => Some(*inner as u128), - Self::U16(inner) => Some(*inner as u128), - Self::U32(inner) => Some(*inner as u128), - Self::U64(inner) => Some(*inner as u128), - Self::U128(inner) => Some(*inner), - Self::Big(_) => None, + Self::U8(inner) => *inner as u128, + Self::U16(inner) => *inner as u128, + Self::U32(inner) => *inner as u128, + Self::U64(inner) => *inner as u128, + Self::U128(inner) => *inner, } } @@ -401,11 +398,7 @@ impl IntConstantValue { arr.copy_from_slice(bytes); Self::I128(i128::from_le_bytes(arr)) } - - _ => { - assert!(bytes.len() >= 16, "bigints must be at least 16 bytes"); - Self::Big(Box::new(BigInt::from_signed_bytes_le(bytes))) - } + _ => unreachable!("primitive constant can't store values larger than 16 bytes"), } } @@ -474,7 +467,6 @@ impl fmt::Display for IntConstantValue { U32(value) => write!(f, "{value}"), U64(value) => write!(f, "{value}"), U128(value) => write!(f, "{value}"), - Big(value) => write!(f, "{value}"), } } } @@ -484,10 +476,7 @@ impl fmt::Display for IntConstantValue { /// defined literal value to some ascribed type. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct IntConstant { - /// Raw value of the integer. This is stored as either a `u128` which can be - /// directly stored as the value which happens in `99%` of cases, if the - /// constant is not big enough to store this integer, then we resort to - /// using [IntConstant + /// Raw value of the integer. pub value: IntConstantValue, /// If the constant contains a type ascription, as specified @@ -513,7 +502,6 @@ impl IntConstant { UIntTy::U32 => IntConstantValue::U32(value as u32), UIntTy::U64 => IntConstantValue::U64(value as u64), UIntTy::U128 => IntConstantValue::U128(value), - UIntTy::UBig => IntConstantValue::Big(Box::new(BigInt::from(value))), _ => unreachable!("un-normalised integer type"), }; @@ -531,7 +519,6 @@ impl IntConstant { SIntTy::I32 => IntConstantValue::I32(value as i32), SIntTy::I64 => IntConstantValue::I64(value as i64), SIntTy::I128 => IntConstantValue::I128(value), - SIntTy::IBig => IntConstantValue::Big(Box::new(BigInt::from(value))), _ => unreachable!("un-normalised integer type"), }; @@ -553,6 +540,7 @@ impl IntConstant { let value = match ty { IntTy::Int(_) => IntConstantValue::from_be_bytes(&mut value[index..], true), IntTy::UInt(_) => IntConstantValue::from_be_bytes(&mut value[index..], false), + _ => unreachable!(), }; Self { value, suffix: None } @@ -575,13 +563,6 @@ impl IntConstant { U32(_) => IntTy::UInt(UIntTy::U32), U64(_) => IntTy::UInt(UIntTy::U64), U128(_) => IntTy::UInt(UIntTy::U128), - Big(value) => { - if value.sign() == Sign::NoSign { - IntTy::UInt(UIntTy::UBig) - } else { - IntTy::Int(SIntTy::IBig) - } - } } } @@ -609,12 +590,7 @@ impl IntConstant { /// and therefore this follows the same assumption. pub fn is_signed(&self) -> bool { use IntConstantValue::*; - - match self.value { - I8(_) | I16(_) | I32(_) | I64(_) | I128(_) => true, - Big(ref t) if t.sign() != Sign::NoSign => true, - _ => false, - } + matches!(self.value, I8(_) | I16(_) | I32(_) | I64(_) | I128(_)) } } @@ -628,7 +604,6 @@ impl Neg for IntConstant { I32(t) => I32(-t), I64(t) => I64(-t), I128(t) => I128(-t), - Big(box t) => Big(Box::new(-t)), _ => unreachable!(), }; @@ -653,40 +628,14 @@ impl PartialOrd for IntConstant { (U32(left), U32(right)) => Some(left.cmp(right)), (U64(left), U64(right)) => Some(left.cmp(right)), (U128(left), U128(right)) => Some(left.cmp(right)), - (Big(left), Big(right)) => Some(left.cmp(right)), _ => None, } } } -impl From for IntConstant { - fn from(value: BigInt) -> Self { - let (sign, mut bytes) = value.to_bytes_be(); - let value = IntConstantValue::from_be_bytes(&mut bytes, sign == Sign::NoSign); - - Self { value, suffix: None } - } -} - impl fmt::Display for IntConstant { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.value)?; - - // We want to snip the value from the `total` value since we don't care about - // the rest... - match &self.value { - I8(_) => write!(f, "_i8"), - I16(_) => write!(f, "_i16"), - I32(_) => write!(f, "_i32"), - I64(_) => write!(f, "_i64"), - I128(_) => write!(f, "_i128"), - U8(_) => write!(f, "_u8"), - U16(_) => write!(f, "_u16"), - U32(_) => write!(f, "_u32"), - U64(_) => write!(f, "_u64"), - U128(_) => write!(f, "_u128"), - _ => Ok(()), - } + write!(f, "{}_{}", self.value, self.to_int_ty()) } } @@ -710,18 +659,6 @@ macro_rules! int_const_impl_from { } } )* - - impl From for IntConstantValue { - fn from(value: BigInt) -> Self { - Self::Big(Box::new(value)) - } - } - - impl From for IntConstantValue { - fn from(value: BigUint) -> Self { - Self::Big(Box::new(BigInt::from(value))) - } - } }; } @@ -736,7 +673,6 @@ int_const_impl_from!( u32: U32, u64: U64, u128: U128, - Box: Big, ); // /// Provide implementations for converting [IntConstant]s into primitive @@ -746,13 +682,11 @@ int_const_impl_from!( macro_rules! int_const_impl_into { ($($ty:ident),* $(,)?) => { $( - impl TryFrom<&IntConstant> for $ty { + impl TryFrom for $ty { type Error = (); - fn try_from(constant: &IntConstant) -> Result { - use IntConstantValue::*; - - match constant.value { + fn try_from(constant: IntConstantValue) -> Result { + match constant { I8(value) => value.try_into().map_err(|_| ()), I16(value) => value.try_into().map_err(|_| ()), I32(value) => value.try_into().map_err(|_| ()), @@ -763,15 +697,22 @@ macro_rules! int_const_impl_into { U32(value) => value.try_into().map_err(|_| ()), U64(value) => value.try_into().map_err(|_| ()), U128(value) => value.try_into().map_err(|_| ()), - Big(box ref value) => value.clone().try_into().map_err(|_| ()), } } } + + impl TryFrom<&IntConstant> for $ty { + type Error = (); + + fn try_from(constant: &IntConstant) -> Result { + constant.value.try_into() + } + } )* }; } -int_const_impl_into!(i8, i16, i32, i64, isize, i128, u8, u16, u32, u64, usize, u128, BigInt); +int_const_impl_into!(i8, i16, i32, i64, isize, i128, u8, u16, u32, u64, usize, u128); define_index_type! { /// Index for [InternedInt] which is used to index into the [ConstantMap]. @@ -796,7 +737,24 @@ impl InternedInt { /// Create a new usize value with the specified `value` and the /// current target pointer size. pub fn create_usize(value: usize, ptr_width: Size) -> Self { - IntConstant::from_uint(value as u128, UIntTy::USize.normalise(ptr_width)).into() + let mut constant = + IntConstant::from_uint(value as u128, UIntTy::USize.normalise(ptr_width)); + constant.suffix = Some(IDENTS.usize); // ##Hack: set the suffix to ensure the `ty` is usize. + constant.into() + } + + /// Check if the integer is negative, if the int is unsigned, we + /// return false. + pub fn is_negative(self) -> bool { + self.map( + |constant| { + if constant.is_signed() { + (constant.value.as_u128() as i128) < 0 + } else { + false + } + }, + ) } /// Get the value of the integer. @@ -805,31 +763,23 @@ impl InternedInt { store[self].clone() } + /// Get the big-int representation of the value, this is as a + /// convience method. + /// + /// @@Future: remove this! + pub fn big_value(&self) -> BigInt { + let value = self.value(); + + let sign = if value.is_signed() { Sign::Minus } else { Sign::Plus }; + BigInt::from_bytes_be(sign, &value.value.as_u128().to_be_bytes()) + } + /// Map a [InternedInt] to a value. pub fn map(self, f: impl FnOnce(&IntConstant) -> T) -> T { let store = CONSTS.ints.read(); f(&store[self]) } - /// Get the [BigInt] representation of the value. - pub fn as_big(&self) -> BigInt { - use IntConstantValue::*; - - match self.value().value { - I8(inner) => BigInt::from(inner), - I16(inner) => BigInt::from(inner), - I32(inner) => BigInt::from(inner), - I64(inner) => BigInt::from(inner), - I128(inner) => BigInt::from(inner), - U8(inner) => BigInt::from(inner), - U16(inner) => BigInt::from(inner), - U32(inner) => BigInt::from(inner), - U64(inner) => BigInt::from(inner), - U128(inner) => BigInt::from(inner), - Big(inner) => *inner, - } - } - /// Flip the sign of the underlying constant. pub fn negate(self) { let mut store = CONSTS.ints.write(); diff --git a/compiler/hash-source/src/entry_point.rs b/compiler/hash-source/src/entry_point.rs index f6c1edd15..2f30e286d 100644 --- a/compiler/hash-source/src/entry_point.rs +++ b/compiler/hash-source/src/entry_point.rs @@ -24,8 +24,6 @@ pub enum EntryPointKind { pub struct EntryPointState { /// This refers to the entry point of the program, the term points /// to the function definition within the entry point module. - /// - /// @@NewTc: this could just be switched out to an `FnDefId` item: Cell>, } diff --git a/compiler/hash-source/src/lit.rs b/compiler/hash-source/src/lit.rs new file mode 100644 index 000000000..7364f4bd2 --- /dev/null +++ b/compiler/hash-source/src/lit.rs @@ -0,0 +1,270 @@ +//! This file contains utility functions for parsing Hash source +//! integer and float literals. This code is located here because +//! it could be used by various parts of the compiler, and it is +//! not specific to the parser. The reason why this is, is because +//! float and integer literal parsing is **delayed** until the type +//! of the literal is known. Since the parser does not know the type +//! of the literal, it can only attempt to parse it as a default float +//! or integer literal. Only during typechecking is the type of the +//! literal fully known (from annotation on the type itself or from +//! some other context). +//! +//! In the situation that the type is not known, such as during attribute +//! resolution/expansion, a default type is assumed (i.e. `i32` for integers +//! and `f64` for floats). This is fine because the only accepted types +//! for attributes are `i32`, `f64`, `bool`, `str` and `char`. In the +//! worst case, the interned value can always be adjusted using +//! [`InternedInt::adjust()`] and [`InternedFloat::adjust()`]. + +use std::num; + +use hash_reporting::{hash_error_codes::error_codes::HashErrorCode, reporter::Reporter}; +use hash_source::{ + constant::{ + BigIntTy, FloatConstant, FloatTy, IntConstant, IntTy, InternedFloat, InternedInt, + NormalisedIntTy, SIntTy, Size, UIntTy, + }, + SourceMap, +}; +pub use hash_token::{FloatLitKind, IntLitKind}; +use num_bigint::BigInt; + +use crate::ast::{AstNodeId, FloatLit, IntLit}; + +/// An error that occurred when parsing a literal. +#[derive(Debug, Clone)] +pub struct LitParseError { + /// The location of the literal, i.e. the [Hunk]. + span: AstNodeId, + + /// The kind of error that occurred when parsing the + /// literal. + kind: LitParseErrorKind, + + /// The contents that were parsed, used for more detailed + /// error reporting. + contents: String, +} + +impl LitParseError { + /// Create a new [LitParseError] from the given [Hunk] and + /// [LitParsingErrorKind]. + pub fn new(span: AstNodeId, contents: String, kind: LitParseErrorKind) -> Self { + Self { span, kind, contents } + } +} + +/// The kind of error that ocurred. +#[derive(Clone, Copy, Debug)] +pub enum LitParseErrorKind { + /// Occurs when a float literal doesn't follow the language + /// specification, or is too large. + MalformedFloatLit, + + /// Occurs when a int literal doesn't follow the language + /// specification, or is too large. + MalformedIntLit, + + /// Occurs when a int literal is too large to fit in the + /// given type. + IntOverflow { base: u32, ty: NormalisedIntTy }, + + /// When a big-int literal is not allowed in the current context. + DisallowedBigLit, +} + +pub fn int_ty_suggestion(lit: &str, base: u32, ty: IntTy) -> IntTy { + // Get the `bigint` representation of the lit and then compute + // the number of bits that it uses to rerpresent the type. + let bits = BigInt::parse_bytes(lit.as_bytes(), base).unwrap().bits(); + let size = Size::from_bits(bits); + + match ty { + IntTy::Int(_) if bits > 128 => IntTy::Big(BigIntTy::IBig), + IntTy::UInt(_) if bits > 128 => IntTy::Big(BigIntTy::UBig), + IntTy::Int(_) => IntTy::Int(SIntTy::from_size(size)), + IntTy::UInt(_) => IntTy::UInt(UIntTy::from_size(size)), + ty => ty, + } +} + +impl LitParseError { + pub fn add_to_reporter(&self, reporter: &mut Reporter) { + let error = reporter.error().code(HashErrorCode::InvalidLiteral); + + match self.kind { + LitParseErrorKind::MalformedFloatLit => { + error.title("malformed float literal").add_labelled_span(self.span.span(), "here"); + } + LitParseErrorKind::MalformedIntLit => { + error.title("malformed float literal").add_labelled_span(self.span.span(), "here"); + } + LitParseErrorKind::IntOverflow { base, ty } => { + // Compute additional note about what literal to use, if we overflow. + let suggestion = format!( + " whose range is `{}..{}`, use a `{}` instead", + ty.normalised.signed_min(Size::ZERO), + ty.normalised.numeric_max(Size::ZERO), + int_ty_suggestion(self.contents.as_str(), base, ty.normalised) + ); + + error + .title(format!("literal out of range for type `{}`", ty.original)) + .add_labelled_span(self.span.span(), "here") + .add_note(format!( + "the literal `{}` does not fit into the type `{}`{}", + self.contents, ty.original, suggestion + )); + } + LitParseErrorKind::DisallowedBigLit => { + error + .title("big integer literals are not allowed in this context") + .add_labelled_span(self.span.span(), "here"); + } + }; + } +} + +impl From for LitParseErrorKind { + fn from(_: num::ParseFloatError) -> Self { + // @@Dumbness: we can't match on what the error was + // for some reason??? - It can either be empty or + // invalid. Since the lexer would prevent an empty + // float from being passed, we can assume that it + // is "invalid". + LitParseErrorKind::MalformedFloatLit + } +} + +/// Wrapper type to convert a [num::ParseIntError] into a +/// [LitParsingErrorKind]. +struct IntError(NormalisedIntTy, u32, num::ParseIntError); + +impl From for LitParseErrorKind { + fn from(IntError(ty, base, value): IntError) -> Self { + match value.kind() { + num::IntErrorKind::InvalidDigit => Self::MalformedIntLit, + num::IntErrorKind::PosOverflow => Self::IntOverflow { base, ty }, + _ => unreachable!(), + } + } +} + +pub type LitParseResult = Result; + +pub enum IntValue { + /// A small constant, i.e. anything less than 128 bits. + Small(InternedInt), + + /// A big constant, i.e. anything greater than 128 bits. + Big(Box), +} + +impl IntValue { + /// Assert that the value is a small constant. This can be used + /// in combination with [`parse_int_const_from_lit()`] when `allow_big` + /// is set to `false`. + pub fn small(self) -> InternedInt { + match self { + Self::Small(value) => value, + Self::Big(_) => panic!("expected small constant"), + } + } +} + +/// Parse a integer literal from the given [Hunk]. The integer must be +/// in the form of a decimal, binary, octal or hexadecimal literal. +/// +/// @@Investigate: should we rely on stdlib for parsing integers? +pub fn parse_int_const_from_lit( + lit: &IntLit, + annotation: Option, + sources: &SourceMap, + ptr_size: Size, + allow_big: bool, +) -> LitParseResult { + let ty = NormalisedIntTy::new(annotation.unwrap_or_default(), ptr_size); + let base: u32 = lit.base.into(); + + // We have to cleanup the hunk, remove any underscores + let mut hunk = sources.hunk(lit.hunk.span()).to_string(); + hunk.retain(|c| c != '_'); + + macro_rules! parse { + (@big) => { + if allow_big { + return Ok(IntValue::Big(Box::new( + BigInt::parse_bytes(hunk.as_bytes(), base).unwrap(), + ))); + } else { + return Err(LitParseError::new( + lit.hunk, + hunk, + LitParseErrorKind::DisallowedBigLit, + )); + } + }; + ($ty:ty) => { + <$ty>::from_str_radix(&hunk, base) + .map_err(|err| LitParseError::new(lit.hunk, hunk, IntError(ty, base, err).into()))? + .into() + }; + } + + let mut lit: IntConstant = match ty.normalised { + IntTy::Int(ty) => match ty { + SIntTy::I8 => parse!(i8), + SIntTy::I16 => parse!(i16), + SIntTy::I32 => parse!(i32), + SIntTy::I64 => parse!(i64), + SIntTy::I128 => parse!(i128), + SIntTy::ISize => unreachable!(), + }, + IntTy::UInt(ty) => match ty { + UIntTy::U8 => parse!(u8), + UIntTy::U16 => parse!(u16), + UIntTy::U32 => parse!(u32), + UIntTy::U64 => parse!(u64), + UIntTy::U128 => parse!(u128), + UIntTy::USize => unreachable!(), + }, + IntTy::Big(_) => parse!(@big), + }; + + // If the given type is a usize/isize, we need to adjust + // the type on the constant to reflect that. + if ty.original.is_platform_dependent() { + lit.suffix = Some(ty.original.into()); + } + + Ok(IntValue::Small(InternedInt::create(lit))) +} + +/// Parse a float literal from the given [Hunk]. The integer must be +/// in the form of a decimal, binary, octal or hexadecimal literal. +/// +/// @@Investigate: should we rely on stdlib for parsing integers? +pub fn parse_float_const_from_lit( + lit: &FloatLit, + annotation: Option, + sources: &SourceMap, +) -> LitParseResult { + let ty = annotation.unwrap_or_default(); + + // We have to cleanup the hunk, remove any underscores + let mut hunk = sources.hunk(lit.hunk.span()).to_string(); + hunk.retain(|c| c != '_'); + + macro_rules! parse { + ($ty:ty) => { + hunk.parse::<$ty>().map_err(|err| LitParseError::new(lit.hunk, hunk, err.into()))? + }; + } + + let lit = match ty { + FloatTy::F32 => FloatConstant::from(parse!(f32)), + FloatTy::F64 => FloatConstant::from(parse!(f64)), + }; + + Ok(InternedFloat::create(lit)) +} diff --git a/compiler/hash-target/src/abi.rs b/compiler/hash-target/src/abi.rs index 2d58096ea..94d76577f 100644 --- a/compiler/hash-target/src/abi.rs +++ b/compiler/hash-target/src/abi.rs @@ -117,7 +117,6 @@ impl Integer { UIntTy::U64 => Integer::I64, UIntTy::U128 => Integer::I128, UIntTy::USize => ctx.data_layout().ptr_sized_integer(), - UIntTy::UBig => unreachable!("`ubig` cannot be converted into a scalar"), } } @@ -130,7 +129,6 @@ impl Integer { SIntTy::I64 => Integer::I64, SIntTy::I128 => Integer::I128, SIntTy::ISize => ctx.data_layout().ptr_sized_integer(), - SIntTy::IBig => unreachable!("`ibig` cannot be converted into a scalar"), } } @@ -139,6 +137,7 @@ impl Integer { match ty { IntTy::UInt(ty) => Self::from_unsigned_int_ty(ty, ctx), IntTy::Int(ty) => Self::from_signed_int_ty(ty, ctx), + _ => unreachable!(), } } } diff --git a/compiler/hash-target/src/primitives.rs b/compiler/hash-target/src/primitives.rs index 19a894ca2..70fb7ad7c 100644 --- a/compiler/hash-target/src/primitives.rs +++ b/compiler/hash-target/src/primitives.rs @@ -60,7 +60,6 @@ pub enum UIntTy { U64, U128, USize, - UBig, } impl UIntTy { @@ -74,7 +73,6 @@ impl UIntTy { UIntTy::U64 => Size::from_bytes(8), UIntTy::USize => ptr_size, UIntTy::U128 => Size::from_bytes(16), - UIntTy::UBig => panic!("ubig has no defined size"), } } @@ -116,7 +114,6 @@ impl UIntTy { UIntTy::U64 => "u64", UIntTy::U128 => "u128", UIntTy::USize => "usize", - UIntTy::UBig => "ubig", } } @@ -139,7 +136,6 @@ impl From for UIntTy { SIntTy::I64 => UIntTy::U64, SIntTy::I128 => UIntTy::U128, SIntTy::ISize => UIntTy::USize, - SIntTy::IBig => UIntTy::UBig, } } } @@ -177,7 +173,6 @@ pub enum SIntTy { I64, I128, ISize, - IBig, } impl SIntTy { @@ -191,7 +186,6 @@ impl SIntTy { SIntTy::I64 => Size::from_bytes(8), SIntTy::ISize => ptr_width, SIntTy::I128 => Size::from_bytes(16), - SIntTy::IBig => panic!("Cannot get size of IBig"), } } @@ -225,7 +219,7 @@ impl SIntTy { self.size(ptr_size).signed_int_min() } - /// Convert the [IntTy] into a primitive type name + /// Convert the [SIntTy] into a primitive type name. pub fn to_name(&self) -> &'static str { match self { SIntTy::I8 => "i8", @@ -234,7 +228,6 @@ impl SIntTy { SIntTy::I64 => "i64", SIntTy::I128 => "i128", SIntTy::ISize => "isize", - SIntTy::IBig => "ibig", } } @@ -257,7 +250,6 @@ impl From for SIntTy { UIntTy::U64 => SIntTy::I64, UIntTy::U128 => SIntTy::I128, UIntTy::USize => SIntTy::ISize, - UIntTy::UBig => SIntTy::IBig, } } } @@ -286,13 +278,32 @@ impl fmt::Display for SIntTy { } } +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +pub enum BigIntTy { + IBig, + UBig, +} + +impl BigIntTy { + pub fn to_name(&self) -> &'static str { + match self { + BigIntTy::IBig => "ibig", + BigIntTy::UBig => "ubig", + } + } +} + /// The representation of an integer type. #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub enum IntTy { /// Signed integer variant. Int(SIntTy), + /// Unsigned integer variant. UInt(UIntTy), + + /// The big int type variants. + Big(BigIntTy), } impl Default for IntTy { @@ -302,11 +313,6 @@ impl Default for IntTy { } impl IntTy { - /// Check if the type is is bounded, i.e. not a `ubig` or `ibig` type. - pub fn is_bounded(&self) -> bool { - !matches!(self, IntTy::Int(SIntTy::IBig) | IntTy::UInt(UIntTy::UBig)) - } - /// Convert a [Integer] with signed-ness into a [IntTy] pub fn from_integer(integer: Integer, signed: bool) -> Self { if signed { @@ -321,6 +327,7 @@ impl IntTy { match self { IntTy::Int(ty) => ty.to_name(), IntTy::UInt(ty) => ty.to_name(), + IntTy::Big(ty) => ty.to_name(), } } @@ -335,6 +342,7 @@ impl IntTy { match self { IntTy::Int(_) => size.truncate(size.signed_int_min() as u128), IntTy::UInt(_) => 0, + _ => unreachable!(), } } @@ -348,6 +356,7 @@ impl IntTy { match self { IntTy::Int(_) => size.signed_int_min(), IntTy::UInt(_) => 0, + _ => unreachable!(), } } @@ -360,6 +369,7 @@ impl IntTy { match self { IntTy::Int(val) => val.max(ptr_size) as u128, IntTy::UInt(_) => self.size(ptr_size).unsigned_int_max(), + _ => unreachable!(), } } @@ -368,6 +378,7 @@ impl IntTy { match self { IntTy::Int(ty) => ty.size(ptr_width), IntTy::UInt(ty) => ty.size(ptr_width), + _ => unreachable!(), } } @@ -387,8 +398,8 @@ impl IntTy { } /// Check if the type is a [BigInt] variant, i.e. `ibig` or `ubig`. - pub fn is_bigint(self) -> bool { - matches!(self, IntTy::Int(SIntTy::IBig) | IntTy::UInt(UIntTy::UBig)) + pub fn is_big(self) -> bool { + matches!(self, IntTy::Big(_)) } /// Normalise an [IntTy] by removing "usize" and "isize" variants into @@ -397,6 +408,7 @@ impl IntTy { match self { IntTy::Int(ty) => IntTy::Int(ty.normalise(ptr_width)), IntTy::UInt(ty) => IntTy::UInt(ty.normalise(ptr_width)), + _ => self, } } @@ -405,6 +417,7 @@ impl IntTy { match self { IntTy::Int(ty) => ty.into(), IntTy::UInt(ty) => ty, + _ => unreachable!(), } } @@ -413,6 +426,7 @@ impl IntTy { match self { IntTy::Int(ty) => ty, IntTy::UInt(ty) => ty.into(), + _ => unreachable!(), } } } diff --git a/compiler/hash-target/src/targets/windows_msvc_base.rs b/compiler/hash-target/src/targets/windows_msvc_base.rs index 0207e2fa2..54dcdd7ed 100644 --- a/compiler/hash-target/src/targets/windows_msvc_base.rs +++ b/compiler/hash-target/src/targets/windows_msvc_base.rs @@ -15,7 +15,7 @@ pub fn options() -> Target { let mut late_link_args = LinkageArgs::new(); late_link_args.add_str_args( LinkerFlavour::Msvc(Lld::No), - // @@Hack: without `defaultlib:oldnames` we get a linker error: + // ##Hack: without `defaultlib:oldnames` we get a linker error: // specifally for symbols like `write`, unsure why this is needed. &["/ENTRY:mainCRTStartup", "-defaultlib:libcmt", "-defaultlib:oldnames"], ); diff --git a/compiler/hash-tir/src/lits.rs b/compiler/hash-tir/src/lits.rs index 354fcbd04..34f1add7f 100644 --- a/compiler/hash-tir/src/lits.rs +++ b/compiler/hash-tir/src/lits.rs @@ -4,17 +4,16 @@ use std::{fmt::Display, ops::Deref}; use hash_ast::{ ast, lit::{ - parse_float_const_from_lit, parse_int_const_from_lit, FloatLitKind, IntLitKind, + parse_float_const_from_lit, parse_int_const_from_lit, FloatLitKind, IntLitKind, IntValue, LitParseResult, }, }; -use hash_source::constant::{InternedFloat, InternedInt, InternedStr}; +use hash_source::constant::{IntConstant, InternedFloat, InternedInt, InternedStr}; use hash_storage::store::statics::StoreId; use hash_target::{ primitives::{FloatTy, IntTy}, size::Size, }; -use num_bigint::BigInt; use crate::{ environment::{ @@ -54,8 +53,8 @@ impl IntLit { } /// Return the value of the integer literal. - pub fn value(&self) -> BigInt { - self.value.value().as_big() + pub fn value(&self) -> IntConstant { + self.value.value().value() } /// Check whether that value is negative. @@ -64,7 +63,7 @@ impl IntLit { pub fn is_negative(&self, env: &Env<'_>) -> bool { match self.value { LitValue::Raw(lit) => env.source_map().hunk(lit.hunk.span()).starts_with('-'), - LitValue::Value(value) => value.as_big() < 0.into(), + LitValue::Value(value) => value.is_negative(), } } @@ -93,6 +92,10 @@ impl IntLit { /// /// This function does not do anyttihng if the literal has already been /// baked. + /// + /// @@Future: we shouldn't change the literal inplace, we should return a + /// new literal value, or we should return a new term which is the bigint + /// term. pub fn bake(&mut self, env: &Env<'_>, int_ty: IntTy) -> LitParseResult<()> { if let LitValue::Raw(lit) = self.value { let value = parse_int_const_from_lit( @@ -100,9 +103,18 @@ impl IntLit { Some(int_ty), env.source_map(), env.target().ptr_size(), + true, )?; - self.value = LitValue::Value(value); + match value { + IntValue::Small(value) => { + self.value = LitValue::Value(value); + } + IntValue::Big(_) => { + // @@AddBigIntsToPrelude + unimplemented!() + } + } } Ok(()) @@ -315,19 +327,15 @@ impl Display for LitPat { let value = lit.value.value(); let kind = value.map(|constant| constant.ty()); - if !kind.is_bigint() { - // @@Hack: we don't use size since it is never invoked because of - // integer constant don't store usize values. - let dummy_size = Size::ZERO; - let value = value.map(|constant| constant.value.as_u128().unwrap()); - - if kind.numeric_min(dummy_size) == value { - write!(f, "{kind}::MIN") - } else if kind.numeric_max(dummy_size) == value { - write!(f, "{kind}::MAX") - } else { - write!(f, "{lit}") - } + // ##Hack: we don't use size since it is never invoked because of + // integer constant don't store usize values. + let dummy_size = Size::ZERO; + let value = value.map(|constant| constant.value.as_u128()); + + if kind.numeric_min(dummy_size) == value { + write!(f, "{kind}::MIN") + } else if kind.numeric_max(dummy_size) == value { + write!(f, "{kind}::MAX") } else { write!(f, "{lit}") } diff --git a/compiler/hash-typecheck/src/inference.rs b/compiler/hash-typecheck/src/inference.rs index bc20eeb4e..96e90309c 100644 --- a/compiler/hash-typecheck/src/inference.rs +++ b/compiler/hash-typecheck/src/inference.rs @@ -7,7 +7,7 @@ use hash_exhaustiveness::ExhaustivenessChecker; use hash_intrinsics::utils::PrimitiveUtils; use hash_reporting::diagnostic::{Diagnostics, ErrorState}; use hash_source::{ - constant::{FloatTy, IntTy, SIntTy, UIntTy}, + constant::{BigIntTy, FloatTy, IntTy, SIntTy, UIntTy}, entry_point::EntryPointKind, identifier::IDENTS, ModuleKind, @@ -494,7 +494,6 @@ impl InferenceOps<'_, T> { SIntTy::I64 => primitives().i64(), SIntTy::I128 => primitives().i128(), SIntTy::ISize => primitives().isize(), - SIntTy::IBig => primitives().ibig(), }, IntTy::UInt(u_int_ty) => match u_int_ty { UIntTy::U8 => primitives().u8(), @@ -503,7 +502,10 @@ impl InferenceOps<'_, T> { UIntTy::U64 => primitives().u64(), UIntTy::U128 => primitives().u128(), UIntTy::USize => primitives().usize(), - UIntTy::UBig => primitives().ubig(), + }, + IntTy::Big(big_int_ty) => match big_int_ty { + BigIntTy::IBig => primitives().ibig(), + BigIntTy::UBig => primitives().ubig(), }, }, None => { @@ -651,8 +653,8 @@ impl InferenceOps<'_, T> { // Ensure the array lengths match if given if let Some(len) = list_len { - let inferred_len_term = - self.create_term_from_integer_lit(array_term.elements.len() as u64); + let inferred_len_term = self.create_term_from_usize_lit(array_term.elements.len()); + if !self.uni_ops().terms_are_equal(len, inferred_len_term) { return Err(TcError::MismatchingArrayLengths { expected_len: len, diff --git a/compiler/hash-untyped-semantics/src/visitor.rs b/compiler/hash-untyped-semantics/src/visitor.rs index 95820fbaa..c74dcc03d 100644 --- a/compiler/hash-untyped-semantics/src/visitor.rs +++ b/compiler/hash-untyped-semantics/src/visitor.rs @@ -287,7 +287,7 @@ impl AstVisitorMutSelf for SemanticAnalyser<'_> { &mut self, node: hash_ast::ast::AstNodeRef, ) -> Result { - // @@Note: We probably don't have to walk this?? + // ##Note: We probably don't have to walk this?? let _ = walk_mut_self::walk_merge_declaration(self, node); Ok(()) } diff --git a/compiler/hash-utils/src/range_map.rs b/compiler/hash-utils/src/range_map.rs index d0a752a73..3589de955 100644 --- a/compiler/hash-utils/src/range_map.rs +++ b/compiler/hash-utils/src/range_map.rs @@ -272,14 +272,14 @@ mod test_super { // Insert a 10-14 range with 'b' // - // @@Note: this should panic since the map disallows overlapping ranges. + // ##Note: this should panic since the map disallows overlapping ranges. map.insert(10..=14, 'd'); } #[test] #[should_panic] fn test_invalid_range_map() { - // @@Note: this should panic since the provided ranges overlap. + // ##Note: this should panic since the provided ranges overlap. RangeMap::populated(vec![(0..=10, 'a'), (10..=14, 'd'), (15..=20, 'c'), (21..=30, 'd')]); } } diff --git a/tests/cases/typecheck/primitives/integers.hash b/tests/cases/typecheck/primitives/integers.hash index ba24687b4..38ce051c6 100644 --- a/tests/cases/typecheck/primitives/integers.hash +++ b/tests/cases/typecheck/primitives/integers.hash @@ -18,7 +18,8 @@ main := () => { ensure(1isize); ensure(1usize); - ensure(1ibig); - ensure(1ubig); + // @@AddBigIntsToPrelude + // ensure(1ibig); + // ensure(1ubig); };