Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions crates/mun_codegen/src/ir/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use inkwell::{
basic_block::BasicBlock,
builder::Builder,
context::Context,
types::BasicTypeEnum,
values::{
AggregateValueEnum, BasicMetadataValueEnum, BasicValueEnum, CallSiteValue, FloatValue,
FunctionValue, GlobalValue, IntValue, PointerValue, StructValue,
Expand Down Expand Up @@ -230,6 +231,35 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
Expr::BinaryOp { lhs, rhs, op } => {
self.gen_binary_op(expr, *lhs, *rhs, op.expect("missing op"))
}
&Expr::Cast { expr, type_ref: _ } => {
let value = self.gen_expr(expr).expect("no value");
let value_ty = &self.infer[expr];
let is_signed = value_ty.signedness().is_signed();

let from_ty = value.get_type();
let to_ty = self
.hir_types
.get_basic_type(&self.infer[expr])
.expect("expected basic type");

Some(match (from_ty, to_ty) {
(BasicTypeEnum::IntType(hg), BasicTypeEnum::IntType(_)) => self
.builder
.build_int_cast_sign_flag(
value.into_int_value(),
to_ty.into_int_type(),
is_signed,
"",
)
.into(),
(BasicTypeEnum::FloatType(_), BasicTypeEnum::FloatType(_)) => {
let src = value_ty.float_width();

todo!()
}
(_, _) => unreachable!("unimplemented cast from {from_ty} to {to_ty}"),
})
}
Expr::UnaryOp { expr, op } => self.gen_unary_op(*expr, *op),
Expr::MethodCall { .. } => {
unimplemented!("Method calls are not yet implemented in the IR generator")
Expand Down
13 changes: 13 additions & 0 deletions crates/mun_hir/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ pub enum Expr {
rhs: ExprId,
op: Option<BinaryOp>,
},
Cast {
expr: ExprId,
type_ref: LocalTypeRefId,
},
Index {
base: ExprId,
index: ExprId,
Expand Down Expand Up @@ -457,6 +461,9 @@ impl Expr {
f(*expr);
}
}
Expr::Cast { expr, type_ref: _ } => {
f(*expr);
}
}
}
}
Expand Down Expand Up @@ -915,6 +922,12 @@ impl<'a> ExprCollector<'a> {
let index = self.collect_expr_opt(e.index());
self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
}
ast::ExprKind::CastExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
let type_ref = self.type_ref_builder.alloc_from_node_opt(e.ty().as_ref());

self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions crates/mun_hir/src/expr/validator/uninitialized_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ impl ExprValidator<'_> {
self.validate_expr_access(sink, initialized_patterns, *lhs, lhs_expr_kind);
self.validate_expr_access(sink, initialized_patterns, *rhs, ExprKind::Normal);
}
Expr::Cast { expr, type_ref: _ } => {
self.validate_expr_access(sink, initialized_patterns, *expr, expr_side)
}
Expr::Block { statements, tail } => {
for statement in statements.iter() {
match statement {
Expand Down
22 changes: 21 additions & 1 deletion crates/mun_hir/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ use smallvec::SmallVec;
use crate::{
display::{HirDisplay, HirFormatter},
ty::{infer::InferTy, lower::fn_sig_for_struct_constructor},
HasVisibility, HirDatabase, Struct, StructMemoryKind, TypeAlias, Visibility,
FloatBitness, HasVisibility, HirDatabase, Signedness, Struct, StructMemoryKind, TypeAlias,
Visibility,
};

#[cfg(test)]
Expand Down Expand Up @@ -130,6 +131,25 @@ impl Ty {
TyKind::Tuple(0, Substitution::empty()).intern()
}

pub fn signedness(&self) -> Signedness {
match self.interned() {
TyKind::Int(ty) => ty.signedness,
_ => unreachable!("expected signedness for int type, got {self:?}"),
}
}

pub fn float_width(&self) -> usize {
match self.interned() {
TyKind::Float(FloatTy {
bitness: FloatBitness::X32,
}) => 32,
TyKind::Float(FloatTy {
bitness: FloatBitness::X64,
}) => 64,
_ => unreachable!("expected float width for float type, got {self:?}"),
}
}

/// Constructs a new struct type
pub fn struct_ty(strukt: Struct) -> Ty {
TyKind::Struct(strukt).intern()
Expand Down
59 changes: 59 additions & 0 deletions crates/mun_hir/src/ty/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@ enum ActiveLoop {
For,
}

#[derive(Clone, Debug)]
pub(super) struct Cast {
expr: ExprId,
source_expr: ExprId,
cast_ty: Ty,
}

/// The inference context contains all information needed during type inference.
struct InferenceResultBuilder<'a> {
db: &'a dyn HirDatabase,
Expand All @@ -180,6 +187,8 @@ struct InferenceResultBuilder<'a> {

/// Stores the resolution of method calls
method_resolution: FxHashMap<ExprId, FunctionId>,

deferred_cast: Vec<Cast>,
}

impl<'a> InferenceResultBuilder<'a> {
Expand All @@ -197,6 +206,7 @@ impl<'a> InferenceResultBuilder<'a> {
resolver,
return_ty: TyKind::Unknown.intern(), // set in collect_fn_signature
method_resolution: FxHashMap::default(),
deferred_cast: Vec::default(),
}
}

Expand Down Expand Up @@ -378,6 +388,18 @@ impl InferenceResultBuilder<'_> {
}
_ => error_type(),
},
Expr::Cast { expr, type_ref } => {
let cast_ty = self.resolve_type(*type_ref);
let _expr_ty = self.infer_expr(*expr, &Expectation::none());

self.deferred_cast.push(Cast {
expr: tgt_expr,
source_expr: *expr,
cast_ty: cast_ty.clone(),
});

cast_ty
}
Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected),
Expr::Call { callee: call, args } => self.infer_call(tgt_expr, *call, args, expected),
Expr::MethodCall {
Expand Down Expand Up @@ -1001,6 +1023,7 @@ impl InferenceResultBuilder<'_> {
fn resolve_all(mut self) -> InferenceResult {
// FIXME resolve obligations as well (use Guidance if necessary)
//let mut tv_stack = Vec::new();

let mut expr_types = std::mem::take(&mut self.type_of_expr);
for (expr, ty) in expr_types.iter_mut() {
let was_unknown = ty.is_unknown();
Expand All @@ -1019,6 +1042,25 @@ impl InferenceResultBuilder<'_> {
}
*ty = resolved;
}

for cast in self.deferred_cast {
let expr_ty = &expr_types[cast.expr];

match (expr_ty.interned(), cast.cast_ty.interned()) {
(_, TyKind::Bool) => {
self.diagnostics.push(InferenceDiagnostic::InvalidCast {
expr: cast.source_expr,
error: diagnostics::CastError::CastToBool,
expr_ty: expr_ty.clone(),
cast_ty: cast.cast_ty,
});
}
(TyKind::Bool, TyKind::Int(_))
| (TyKind::Int(_) | TyKind::Float(_), TyKind::Int(_) | TyKind::Float(_)) => {}
(_, _) => {}
}
}

InferenceResult {
// field_resolutions: self.field_resolutions,
// variant_resolutions: self.variant_resolutions,
Expand Down Expand Up @@ -1265,6 +1307,11 @@ mod diagnostics {
ExprId, Function, HirDatabase, IntTy, Name, Ty,
};

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CastError {
CastToBool,
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub(crate) enum InferenceDiagnostic {
UnresolvedValue {
Expand All @@ -1280,6 +1327,12 @@ mod diagnostics {
id: ExprId,
found: Ty,
},
InvalidCast {
expr: ExprId,
error: CastError,
expr_ty: Ty,
cast_ty: Ty,
},
ParameterCountMismatch {
id: ExprId,
found: usize,
Expand Down Expand Up @@ -1731,6 +1784,12 @@ mod diagnostics {
.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
sink.push(PrivateAccess { file, expr });
}
InferenceDiagnostic::InvalidCast {
expr: _,
error: _,
expr_ty: _,
cast_ty: _,
} => todo!(),
}
}
}
Expand Down
40 changes: 40 additions & 0 deletions crates/mun_syntax/src/ast/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,38 @@ impl CallExpr {
}
}

// CastExpr

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CastExpr {
pub(crate) syntax: SyntaxNode,
}

impl AstNode for CastExpr {
fn can_cast(kind: SyntaxKind) -> bool {
matches!(kind, CAST_EXPR)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(CastExpr { syntax })
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.syntax
}
}
impl CastExpr {
pub fn expr(&self) -> Option<Expr> {
super::child_opt(self)
}

pub fn ty(&self) -> Option<TypeRef> {
super::child_opt(self)
}
}

// Condition

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -362,6 +394,7 @@ impl AstNode for Expr {
| PREFIX_EXPR
| PATH_EXPR
| BIN_EXPR
| CAST_EXPR
| PAREN_EXPR
| CALL_EXPR
| METHOD_CALL_EXPR
Expand Down Expand Up @@ -394,6 +427,7 @@ pub enum ExprKind {
PrefixExpr(PrefixExpr),
PathExpr(PathExpr),
BinExpr(BinExpr),
CastExpr(CastExpr),
ParenExpr(ParenExpr),
CallExpr(CallExpr),
MethodCallExpr(MethodCallExpr),
Expand Down Expand Up @@ -428,6 +462,11 @@ impl From<BinExpr> for Expr {
Expr { syntax: n.syntax }
}
}
impl From<CastExpr> for Expr {
fn from(n: CastExpr) -> Expr {
Expr { syntax: n.syntax }
}
}
impl From<ParenExpr> for Expr {
fn from(n: ParenExpr) -> Expr {
Expr { syntax: n.syntax }
Expand Down Expand Up @@ -501,6 +540,7 @@ impl Expr {
PREFIX_EXPR => ExprKind::PrefixExpr(PrefixExpr::cast(self.syntax.clone()).unwrap()),
PATH_EXPR => ExprKind::PathExpr(PathExpr::cast(self.syntax.clone()).unwrap()),
BIN_EXPR => ExprKind::BinExpr(BinExpr::cast(self.syntax.clone()).unwrap()),
CAST_EXPR => ExprKind::CastExpr(CastExpr::cast(self.syntax.clone()).unwrap()),
PAREN_EXPR => ExprKind::ParenExpr(ParenExpr::cast(self.syntax.clone()).unwrap()),
CALL_EXPR => ExprKind::CallExpr(CallExpr::cast(self.syntax.clone()).unwrap()),
METHOD_CALL_EXPR => {
Expand Down
5 changes: 5 additions & 0 deletions crates/mun_syntax/src/grammar.ron
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ Grammar(
"PREFIX_EXPR",
"LITERAL",
"BIN_EXPR",
"CAST_EXPR",
"PAREN_EXPR",
"CALL_EXPR",
"METHOD_CALL_EXPR",
Expand Down Expand Up @@ -290,6 +291,9 @@ Grammar(
"PathExpr": (options: ["Path"]),
"PrefixExpr": (options: ["Expr"]),
"BinExpr": (),
"CastExpr": (
options: [ ["expr", "Expr"], ["ty", "TypeRef"] ]
),
"Literal": (),
"ParenExpr": (options: ["Expr"]),
"CallExpr": (
Expand Down Expand Up @@ -326,6 +330,7 @@ Grammar(
"PrefixExpr",
"PathExpr",
"BinExpr",
"CastExpr",
"ParenExpr",
"CallExpr",
"MethodCallExpr",
Expand Down
2 changes: 1 addition & 1 deletion crates/mun_syntax/src/parsing/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use super::{
token_set::TokenSet,
SyntaxKind::{
self, ARG_LIST, ARRAY_EXPR, ARRAY_TYPE, BIND_PAT, BIN_EXPR, BLOCK_EXPR, BREAK_EXPR,
CALL_EXPR, CONDITION, EOF, ERROR, EXPR_STMT, EXTERN, FIELD_EXPR, FLOAT_NUMBER,
CALL_EXPR, CAST_EXPR, CONDITION, EOF, ERROR, EXPR_STMT, EXTERN, FIELD_EXPR, FLOAT_NUMBER,
FUNCTION_DEF, GC_KW, IDENT, IF_EXPR, INDEX, INDEX_EXPR, INT_NUMBER, LET_STMT, LITERAL,
LOOP_EXPR, MEMORY_TYPE_SPECIFIER, NAME, NAME_REF, NEVER_TYPE, PARAM, PARAM_LIST,
PAREN_EXPR, PATH, PATH_EXPR, PATH_SEGMENT, PATH_TYPE, PLACEHOLDER_PAT, PREFIX_EXPR,
Expand Down
Loading