Skip to content

Commit

Permalink
Merge pull request #939 from hash-org/fix-938
Browse files Browse the repository at this point in the history
fix 938
  • Loading branch information
feds01 authored Sep 4, 2023
2 parents 7c3f6fc + 7286598 commit 462316f
Show file tree
Hide file tree
Showing 38 changed files with 554 additions and 395 deletions.
2 changes: 1 addition & 1 deletion compiler/hash-ast-desugaring/src/desugaring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 2 additions & 3 deletions compiler/hash-ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
73 changes: 54 additions & 19 deletions compiler/hash-ast/src/lit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
}
}

Expand All @@ -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))
Expand All @@ -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");
}
};
}
}
Expand Down Expand Up @@ -147,6 +152,26 @@ impl From<IntError> for LitParseErrorKind {

pub type LitParseResult<T> = Result<T, LitParseError>;

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<BigInt>),
}

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.
///
Expand All @@ -156,7 +181,8 @@ pub fn parse_int_const_from_lit(
annotation: Option<IntTy>,
sources: &SourceMap,
ptr_size: Size,
) -> LitParseResult<InternedInt> {
allow_big: bool,
) -> LitParseResult<IntValue> {
let ty = NormalisedIntTy::new(annotation.unwrap_or_default(), ptr_size);
let base: u32 = lit.base.into();

Expand All @@ -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)
Expand All @@ -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 {
Expand All @@ -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
Expand All @@ -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
Expand Down
5 changes: 3 additions & 2 deletions compiler/hash-attrs/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
}

Expand Down Expand Up @@ -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) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/hash-codegen-llvm/src/translation/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 2 additions & 9 deletions compiler/hash-codegen-llvm/src/translation/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion compiler/hash-codegen/src/lower/locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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![];
Expand Down
2 changes: 1 addition & 1 deletion compiler/hash-driver/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ impl<I: CompilerInterface> Driver<I> {
);
}

// @@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 {
Expand Down
2 changes: 1 addition & 1 deletion compiler/hash-driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ pub mod utils {
/// be used in contexts where the error type is known to implementing the
/// [Into<Report>] trait.
pub fn emit_on_fatal_error<T, E: Into<Report>>(f: impl FnOnce() -> Result<T, E>) -> 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();
Expand Down
2 changes: 1 addition & 1 deletion compiler/hash-exhaustiveness/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}

Expand Down
5 changes: 1 addition & 4 deletions compiler/hash-exhaustiveness/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Expand Down
2 changes: 1 addition & 1 deletion compiler/hash-exhaustiveness/src/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
34 changes: 0 additions & 34 deletions compiler/hash-intrinsics/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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 {
Expand All @@ -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();
Expand Down
Loading

0 comments on commit 462316f

Please sign in to comment.