Skip to content

Commit

Permalink
misc: literal out of range errors
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra committed Apr 19, 2020
1 parent 21150d5 commit f8b47db
Show file tree
Hide file tree
Showing 19 changed files with 254 additions and 160 deletions.
6 changes: 3 additions & 3 deletions crates/mun_codegen/src/ir/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use inkwell::{
};
use std::{collections::HashMap, sync::Arc};

use crate::ir::ty::ResolveBitness;
use hir::ResolveBitness;
use inkwell::basic_block::BasicBlock;
use inkwell::values::{AggregateValueEnum, GlobalValue, PointerValue};

Expand Down Expand Up @@ -275,7 +275,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {

let context = self.db.context();
let has_sign = ty.signedness == hir::Signedness::Signed;
let ir_ty = match ty.resolve(&self.db.target_data()).bitness {
let ir_ty = match ty.resolve(&self.db.target_data_layout()).bitness {
hir::IntBitness::X8 => context.i8_type().const_int(v.value as u64, has_sign),
hir::IntBitness::X16 => context.i16_type().const_int(v.value as u64, has_sign),
hir::IntBitness::X32 => context.i32_type().const_int(v.value as u64, has_sign),
Expand All @@ -299,7 +299,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
};

let context = self.db.context();
let ir_ty = match ty.resolve(&self.db.target_data()).bitness {
let ir_ty = match ty.bitness.resolve(&self.db.target_data_layout()) {
hir::FloatBitness::X32 => context.f32_type().const_float(v.value),
hir::FloatBitness::X64 => context.f64_type().const_float(v.value),
_ => unreachable!("unresolved bitness in code generation"),
Expand Down
58 changes: 13 additions & 45 deletions crates/mun_codegen/src/ir/ty.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use super::try_convert_any_to_basic;
use crate::type_info::TypeSize;
use crate::{
type_info::TypeSize,
type_info::{TypeGroup, TypeInfo},
CodeGenParams, IrDatabase,
};
use hir::{ApplicationTy, CallableDef, FloatBitness, FloatTy, IntBitness, IntTy, Ty, TypeCtor};
use inkwell::targets::TargetData;
use inkwell::types::{AnyTypeEnum, BasicType, BasicTypeEnum, FloatType, IntType, StructType};
use inkwell::AddressSpace;
use hir::{
ApplicationTy, CallableDef, FloatBitness, FloatTy, IntBitness, IntTy, ResolveBitness, Ty,
TypeCtor,
};
use inkwell::{
types::{AnyTypeEnum, BasicType, BasicTypeEnum, FloatType, IntType, StructType},
AddressSpace,
};

/// Given a mun type, construct an LLVM IR type
#[rustfmt::skip]
Expand Down Expand Up @@ -57,7 +61,7 @@ pub(crate) fn ir_query(db: &impl IrDatabase, ty: Ty, params: CodeGenParams) -> A
/// Returns the LLVM IR type of the specified float type
fn float_ty_query(db: &impl IrDatabase, fty: FloatTy) -> FloatType {
let context = db.context();
match fty.resolve(&db.target_data()).bitness {
match fty.bitness.resolve(&db.target_data_layout()) {
FloatBitness::X64 => context.f64_type(),
FloatBitness::X32 => context.f32_type(),
_ => unreachable!(),
Expand All @@ -67,7 +71,7 @@ fn float_ty_query(db: &impl IrDatabase, fty: FloatTy) -> FloatType {
/// Returns the LLVM IR type of the specified int type
fn int_ty_query(db: &impl IrDatabase, ity: IntTy) -> IntType {
let context = db.context();
match ity.resolve(&db.target_data()).bitness {
match ity.bitness.resolve(&db.target_data_layout()) {
IntBitness::X128 => context.i128_type(),
IntBitness::X64 => context.i64_type(),
IntBitness::X32 => context.i32_type(),
Expand Down Expand Up @@ -102,7 +106,7 @@ pub fn type_info_query(db: &impl IrDatabase, ty: Ty) -> TypeInfo {
let ir_ty = float_ty_query(db, ty);
let type_size = TypeSize::from_ir_type(&ir_ty, target.as_ref());
TypeInfo::new(
format!("core::{}", ty.resolve(&db.target_data())),
format!("core::{}", ty.resolve(&db.target_data_layout())),
TypeGroup::FundamentalTypes,
type_size,
)
Expand All @@ -111,7 +115,7 @@ pub fn type_info_query(db: &impl IrDatabase, ty: Ty) -> TypeInfo {
let ir_ty = int_ty_query(db, ty);
let type_size = TypeSize::from_ir_type(&ir_ty, target.as_ref());
TypeInfo::new(
format!("core::{}", ty.resolve(&db.target_data())),
format!("core::{}", ty.resolve(&db.target_data_layout())),
TypeGroup::FundamentalTypes,
type_size,
)
Expand All @@ -131,39 +135,3 @@ pub fn type_info_query(db: &impl IrDatabase, ty: Ty) -> TypeInfo {
_ => unreachable!("{:?} unhandled", ty),
}
}

pub(crate) trait ResolveBitness {
fn resolve(&self, target: &TargetData) -> Self;
}

impl ResolveBitness for FloatTy {
fn resolve(&self, _target: &TargetData) -> Self {
let bitness = match self.bitness {
FloatBitness::Undefined => FloatBitness::X64,
bitness => bitness,
};
FloatTy { bitness }
}
}

impl ResolveBitness for IntTy {
fn resolve(&self, target: &TargetData) -> Self {
let ptr_bit_size = target.ptr_sized_int_type(None).get_bit_width();
let bitness = match ptr_bit_size {
16 => IntBitness::X16,
32 => IntBitness::X32,
64 => IntBitness::X64,
128 => IntBitness::X128,
_ => unreachable!("unsupported bit size for pointers"),
};
let bitness = match self.bitness {
IntBitness::Undefined => IntBitness::X64,
IntBitness::Xsize => bitness,
bitness => bitness,
};
IntTy {
bitness,
signedness: self.signedness,
}
}
}
59 changes: 0 additions & 59 deletions crates/mun_codegen/src/snapshots/test__literal_types_file_ir.snap

This file was deleted.

This file was deleted.

4 changes: 2 additions & 2 deletions crates/mun_hir/src/code_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,8 @@ impl Function {
body.add_diagnostics(db, self.into(), sink);
let infer = self.infer(db);
infer.add_diagnostics(db, self, sink);
let mut validator = ExprValidator::new(self, db, sink);
validator.validate_body();
let validator = ExprValidator::new(self, db);
validator.validate_body(sink);
}
}

Expand Down
5 changes: 3 additions & 2 deletions crates/mun_hir/src/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::adt::StructKind;
use crate::in_file::InFile;
use crate::{FileId, HirDatabase, Name, Ty};
use crate::{FileId, HirDatabase, IntTy, Name, Ty};
use mun_syntax::{ast, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange};
use std::{any::Any, fmt};

Expand Down Expand Up @@ -581,11 +581,12 @@ impl Diagnostic for IntLiteralTooLarge {
#[derive(Debug)]
pub struct LiteralOutOfRange {
pub literal: InFile<AstPtr<ast::Literal>>,
pub int_ty: IntTy,
}

impl Diagnostic for LiteralOutOfRange {
fn message(&self) -> String {
"literal out of range".to_owned()
format!("literal out of range for `{}`", self.int_ty.ty_to_string())
}

fn source(&self) -> InFile<SyntaxNodePtr> {
Expand Down
2 changes: 1 addition & 1 deletion crates/mun_hir/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1005,7 +1005,7 @@ fn integer_lit(str: &str, suffix: Option<&str>) -> (Literal, Vec<LiteralError>)
if from_lexer {
(0, Some(LiteralError::LexerError))
} else {
(u128::max_value(), Some(LiteralError::IntTooLarge))
(0, Some(LiteralError::IntTooLarge))
}
}
};
Expand Down
25 changes: 13 additions & 12 deletions crates/mun_hir/src/expr/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,47 @@ use crate::{diagnostics::DiagnosticSink, Body, Expr, Function, HirDatabase, Infe
use mun_syntax::{AstNode, SyntaxNodePtr};
use std::sync::Arc;

mod literal_out_of_range;
mod uninitialized_access;

#[cfg(test)]
mod tests;

pub struct ExprValidator<'a, 'b: 'a, 'd, DB: HirDatabase> {
pub struct ExprValidator<'d, DB: HirDatabase> {
func: Function,
infer: Arc<InferenceResult>,
body: Arc<Body>,
body_source_map: Arc<BodySourceMap>,
sink: &'a mut DiagnosticSink<'b>,
db: &'d DB,
}

impl<'a, 'b, 'd, DB: HirDatabase> ExprValidator<'a, 'b, 'd, DB> {
pub fn new(func: Function, db: &'d DB, sink: &'a mut DiagnosticSink<'b>) -> Self {
impl<'d, DB: HirDatabase> ExprValidator<'d, DB> {
pub fn new(func: Function, db: &'d DB) -> Self {
let (body, body_source_map) = db.body_with_source_map(func.into());
ExprValidator {
func,
sink,
db,
infer: db.infer(func.into()),
body,
body_source_map,
}
}

pub fn validate_body(&mut self) {
self.validate_uninitialized_access();
self.validate_extern();
pub fn validate_body(&self, sink: &mut DiagnosticSink) {
self.validate_literal_ranges(sink);
self.validate_uninitialized_access(sink);
self.validate_extern(sink);
}
pub fn validate_extern(&mut self) {

pub fn validate_extern(&self, sink: &mut DiagnosticSink) {
if !self.func.is_extern(self.db) {
return;
}

// Validate that there is no body
match self.body[self.func.body(self.db).body_expr] {
Expr::Missing => {}
_ => self.sink.push(ExternCannotHaveBody {
_ => sink.push(ExternCannotHaveBody {
func: self
.func
.source(self.db)
Expand All @@ -62,7 +63,7 @@ impl<'a, 'b, 'd, DB: HirDatabase> ExprValidator<'a, 'b, 'd, DB> {
.type_ref_syntax(*ty_ref)
.map(|ptr| ptr.syntax_node_ptr())
.unwrap();
self.sink.push(ExternNonPrimitiveParam {
sink.push(ExternNonPrimitiveParam {
param: InFile::new(self.func.source(self.db).file_id, arg_ptr),
})
}
Expand All @@ -75,7 +76,7 @@ impl<'a, 'b, 'd, DB: HirDatabase> ExprValidator<'a, 'b, 'd, DB> {
.type_ref_syntax(*fn_data.ret_type())
.map(|ptr| ptr.syntax_node_ptr())
.unwrap();
self.sink.push(ExternNonPrimitiveParam {
sink.push(ExternNonPrimitiveParam {
param: InFile::new(self.func.source(self.db).file_id, arg_ptr),
})
}
Expand Down
43 changes: 43 additions & 0 deletions crates/mun_hir/src/expr/validator/literal_out_of_range.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use super::ExprValidator;
use crate::diagnostics::{DiagnosticSink, LiteralOutOfRange};
use crate::ty::ResolveBitness;
use crate::{ty_app, TypeCtor};
use crate::{Expr, HirDatabase, HirDisplay, Literal};

impl<'d, D: HirDatabase> ExprValidator<'d, D> {
/// Iterates over all expressions to determine if one of the literals has a value that is out of
/// range of its type.
pub fn validate_literal_ranges(&self, sink: &mut DiagnosticSink) {
self.body[self.body.body_expr].walk_child_exprs(move |expr_id| {
let expr = &self.body[expr_id];
if let Expr::Literal(Literal::Int(lit)) = &expr {
let ty = &self.infer[expr_id];
match ty {
ty_app!(TypeCtor::Int(int_ty)) => {
if lit.value > int_ty.resolve(&self.db.target_data_layout()).max() {
let literal = self
.body_source_map
.expr_syntax(expr_id)
.expect("could not retrieve expr from source map")
.map(|expr_src| {
expr_src
.left()
.expect("could not retrieve expr from ExprSource")
.cast()
.expect("could not cast expression to literal")
});
sink.push(LiteralOutOfRange {
literal,
int_ty: *int_ty,
})
}
}
_ => panic!(
"expected int literal to have int ty while instead it is `{}`",
ty.display(self.db)
),
}
}
})
}
}
2 changes: 1 addition & 1 deletion crates/mun_hir/src/expr/validator/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ fn diagnostics(content: &str) -> String {
let fun = Function {
id: ctx.to_def(&def),
};
ExprValidator::new(fun, &db, &mut diag_sink).validate_body();
ExprValidator::new(fun, &db).validate_body(&mut diag_sink);
}
}
drop(diag_sink);
Expand Down
Loading

0 comments on commit f8b47db

Please sign in to comment.