Improve deref parsing
This commit is contained in:
parent
cc367a38e7
commit
676554b6a0
@ -12,4 +12,4 @@ fn main() -> u32 {
|
||||
fn mutate(value: &mut [u32; 3]) {
|
||||
// Dereference the borrow to mutate it
|
||||
*value[1] = 17;
|
||||
}
|
||||
}
|
||||
|
@ -80,8 +80,8 @@ pub struct Expression(pub ExpressionKind, pub TokenRange);
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ExpressionKind {
|
||||
VariableName(String),
|
||||
Borrow(String, bool),
|
||||
Deref(String),
|
||||
Borrow(Box<Expression>, bool),
|
||||
Deref(Box<Expression>),
|
||||
Literal(Literal),
|
||||
Array(Vec<Expression>),
|
||||
ArrayShort(Box<Expression>, u64),
|
||||
|
@ -179,6 +179,36 @@ impl Parse for AssociatedFunctionCall {
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_inner<T>(expr: PrimaryExpression, fun: T) -> Expression
|
||||
where
|
||||
T: FnOnce(PrimaryExpression) -> Expression,
|
||||
{
|
||||
match &expr.0 .0 {
|
||||
ExpressionKind::Indexed(value_expr, index_expr) => Expression(
|
||||
ExpressionKind::Indexed(
|
||||
Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)),
|
||||
index_expr.clone(),
|
||||
),
|
||||
expr.0 .1,
|
||||
),
|
||||
ExpressionKind::Accessed(value_expr, index_name) => Expression(
|
||||
ExpressionKind::Accessed(
|
||||
Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)),
|
||||
index_name.clone(),
|
||||
),
|
||||
expr.0 .1,
|
||||
),
|
||||
ExpressionKind::AccessCall(value_expr, fn_call) => Expression(
|
||||
ExpressionKind::AccessCall(
|
||||
Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)),
|
||||
fn_call.clone(),
|
||||
),
|
||||
expr.0 .1,
|
||||
),
|
||||
_ => fun(expr),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PrimaryExpression(Expression);
|
||||
|
||||
@ -195,18 +225,21 @@ impl Parse for PrimaryExpression {
|
||||
} else if let (Some(Token::Et), Some(Token::MutKeyword)) = (stream.peek(), stream.peek2()) {
|
||||
stream.next(); // Consume Et
|
||||
stream.next(); // Consume mut
|
||||
let Some(Token::Identifier(name)) = stream.next() else {
|
||||
return Err(stream.expected_err("identifier")?);
|
||||
};
|
||||
Expression(Kind::Borrow(name, true), stream.get_range().unwrap())
|
||||
} else if let (Some(Token::Et), Some(Token::Identifier(name))) = (stream.peek(), stream.peek2()) {
|
||||
Expression(
|
||||
Kind::Borrow(Box::new(stream.parse()?), true),
|
||||
stream.get_range().unwrap(),
|
||||
)
|
||||
} else if let Some(Token::Et) = stream.peek() {
|
||||
stream.next(); // Consume Et
|
||||
stream.next(); // Consume identifier
|
||||
Expression(Kind::Borrow(name, false), stream.get_range().unwrap())
|
||||
} else if let (Some(Token::Star), Some(Token::Identifier(name))) = (stream.peek(), stream.peek2()) {
|
||||
Expression(
|
||||
Kind::Borrow(Box::new(stream.parse()?), false),
|
||||
stream.get_range().unwrap(),
|
||||
)
|
||||
} else if let Some(Token::Star) = stream.peek() {
|
||||
stream.next(); // Consume Et
|
||||
stream.next(); // Consume identifier
|
||||
Expression(Kind::Deref(name), stream.get_range().unwrap())
|
||||
apply_inner(stream.parse()?, |e| {
|
||||
Expression(Kind::Deref(Box::new(e.0)), stream.get_range().unwrap())
|
||||
})
|
||||
} else if let Ok(unary) = stream.parse() {
|
||||
Expression(
|
||||
Kind::UnaryOperation(unary, Box::new(stream.parse()?)),
|
||||
|
@ -361,19 +361,10 @@ impl ast::Expression {
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
name.clone(),
|
||||
),
|
||||
ast::ExpressionKind::Borrow(name, mutable) => mir::ExprKind::Borrow(
|
||||
NamedVariableRef(
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
name.clone(),
|
||||
self.1.as_meta(module_id),
|
||||
),
|
||||
*mutable,
|
||||
),
|
||||
ast::ExpressionKind::Deref(name) => mir::ExprKind::Deref(NamedVariableRef(
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
name.clone(),
|
||||
self.1.as_meta(module_id),
|
||||
)),
|
||||
ast::ExpressionKind::Borrow(expr, mutable) => {
|
||||
mir::ExprKind::Borrow(Box::new(expr.process(module_id)), *mutable)
|
||||
}
|
||||
ast::ExpressionKind::Deref(expr) => mir::ExprKind::Deref(Box::new(expr.process(module_id))),
|
||||
ast::ExpressionKind::UnaryOperation(unary_operator, expr) => match unary_operator {
|
||||
ast::UnaryOperator::Plus => mir::ExprKind::BinOp(
|
||||
mir::BinaryOperator::Add,
|
||||
|
@ -1144,12 +1144,8 @@ impl mir::Expression {
|
||||
TypeKind::CustomType(type_key),
|
||||
))
|
||||
}
|
||||
mir::ExprKind::Borrow(varref, mutable) => {
|
||||
varref.0.known().expect("variable type unknown");
|
||||
let v = scope
|
||||
.stack_values
|
||||
.get(&varref.1)
|
||||
.expect("Variable reference not found?!");
|
||||
mir::ExprKind::Borrow(expr, mutable) => {
|
||||
let v = expr.codegen(scope, &state.load(false))?.unwrap();
|
||||
|
||||
let TypeKind::CodegenPtr(ptr_inner) = &v.1 else {
|
||||
panic!();
|
||||
@ -1160,12 +1156,8 @@ impl mir::Expression {
|
||||
TypeKind::Borrow(Box::new(*ptr_inner.clone()), *mutable),
|
||||
))
|
||||
}
|
||||
mir::ExprKind::Deref(varref) => {
|
||||
varref.0.known().expect("variable type unknown");
|
||||
let v = scope
|
||||
.stack_values
|
||||
.get(&varref.1)
|
||||
.expect("Variable reference not found?!");
|
||||
mir::ExprKind::Deref(expr) => {
|
||||
let v = expr.codegen(scope, &state.load(false))?.unwrap();
|
||||
|
||||
let TypeKind::CodegenPtr(ptr_inner) = &v.1 else {
|
||||
panic!();
|
||||
@ -1174,7 +1166,7 @@ impl mir::Expression {
|
||||
let var_ptr_instr = scope
|
||||
.block
|
||||
.build_named(
|
||||
format!("{}.deref", varref.1),
|
||||
format!("{}.deref", expr.backing_var().unwrap().1),
|
||||
Instr::Load(v.0.instr(), ptr_inner.get_type(scope.type_values)),
|
||||
)
|
||||
.unwrap();
|
||||
@ -1187,7 +1179,7 @@ impl mir::Expression {
|
||||
scope
|
||||
.block
|
||||
.build_named(
|
||||
format!("{}.deref.inner", varref.1),
|
||||
format!("{}.deref.inner", expr.backing_var().unwrap().1),
|
||||
Instr::Load(var_ptr_instr, inner.get_type(scope.type_values)),
|
||||
)
|
||||
.unwrap(),
|
||||
|
@ -425,15 +425,15 @@ impl Expression {
|
||||
ReturnKind::Soft,
|
||||
TypeKind::CustomType(CustomTypeKey(name.clone(), mod_id)),
|
||||
)),
|
||||
Borrow(var, mutable) => {
|
||||
let ret_type = var.return_type()?;
|
||||
Borrow(expr, mutable) => {
|
||||
let ret_type = expr.return_type(refs, mod_id)?;
|
||||
Ok((ret_type.0, TypeKind::Borrow(Box::new(ret_type.1), *mutable)))
|
||||
}
|
||||
Deref(var) => {
|
||||
let (kind, ret_type) = var.return_type()?;
|
||||
Deref(expr) => {
|
||||
let (kind, ret_type) = expr.return_type(refs, mod_id)?;
|
||||
match ret_type.resolve_weak(refs) {
|
||||
TypeKind::Borrow(type_kind, _) => Ok((kind, *type_kind)),
|
||||
_ => Err(ReturnTypeOther::DerefNonBorrow(var.2)),
|
||||
_ => Err(ReturnTypeOther::DerefNonBorrow(expr.1)),
|
||||
}
|
||||
}
|
||||
CastTo(expr, type_kind) => match expr.return_type(refs, mod_id) {
|
||||
@ -452,8 +452,8 @@ impl Expression {
|
||||
ExprKind::Variable(var_ref) => Some(var_ref),
|
||||
ExprKind::Indexed(lhs, _, _) => lhs.backing_var(),
|
||||
ExprKind::Accessed(lhs, _, _) => lhs.backing_var(),
|
||||
ExprKind::Borrow(var, _) => Some(var),
|
||||
ExprKind::Deref(var) => Some(var),
|
||||
ExprKind::Borrow(expr, _) => expr.backing_var(),
|
||||
ExprKind::Deref(expr) => expr.backing_var(),
|
||||
ExprKind::Block(block) => block.backing_var(),
|
||||
ExprKind::Array(_) => None,
|
||||
ExprKind::Struct(_, _) => None,
|
||||
|
@ -401,12 +401,8 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
}
|
||||
super::ExprKind::BinOp(.., type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id),
|
||||
|
||||
super::ExprKind::Borrow(var_ref, _) => {
|
||||
var_ref.0 = var_ref.0.update_imported(extern_types, mod_id);
|
||||
}
|
||||
super::ExprKind::Deref(var_ref) => {
|
||||
var_ref.0 = var_ref.0.update_imported(extern_types, mod_id);
|
||||
}
|
||||
super::ExprKind::Borrow(expr, _) => {}
|
||||
super::ExprKind::Deref(expr) => {}
|
||||
super::ExprKind::CastTo(_, type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id),
|
||||
_ => {}
|
||||
}
|
||||
|
@ -261,8 +261,8 @@ pub enum ExprKind {
|
||||
AssociatedFunctionCall(TypeKind, FunctionCall),
|
||||
If(IfExpression),
|
||||
Block(Block),
|
||||
Borrow(NamedVariableRef, bool),
|
||||
Deref(NamedVariableRef),
|
||||
Borrow(Box<Expression>, bool),
|
||||
Deref(Box<Expression>),
|
||||
CastTo(Box<Expression>, TypeKind),
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,9 @@ pub enum ErrorKind {
|
||||
#[error("This type of expression can not be used for assignment")]
|
||||
InvalidSetExpression,
|
||||
#[error("Can not deref {0}, as it is not a borrow")]
|
||||
AttemptedDerefNonBorrow(String),
|
||||
AttemptedDerefNonBorrow(TypeKind),
|
||||
#[error("Can not borrow this kind of expression")]
|
||||
ImpossibleBorrow,
|
||||
#[error("Types {0} and {1} differ in mutability")]
|
||||
TypesDifferMutability(TypeKind, TypeKind),
|
||||
#[error("Cannot mutably borrow variable {0}, which is not declared as mutable")]
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! This module contains code relevant to doing a type checking pass on the MIR.
|
||||
//! During typechecking relevant types are also coerced if possible.
|
||||
use std::{collections::HashSet, convert::Infallible, iter};
|
||||
use std::{collections::HashSet, convert::Infallible, hint, iter};
|
||||
|
||||
use crate::{mir::*, util::try_all};
|
||||
use VagueType as Vague;
|
||||
@ -668,60 +668,49 @@ impl Expression {
|
||||
|
||||
Ok(TypeKind::CustomType(type_key))
|
||||
}
|
||||
ExprKind::Borrow(var_ref, mutable) => {
|
||||
let scope_var = state.scope.variables.get(&var_ref.1).cloned();
|
||||
|
||||
let existing = state
|
||||
.or_else(
|
||||
scope_var
|
||||
.clone()
|
||||
.map(|var| var.ty)
|
||||
.ok_or(ErrorKind::VariableNotDefined(var_ref.1.clone())),
|
||||
TypeKind::Vague(Vague::Unknown),
|
||||
var_ref.2,
|
||||
)
|
||||
.resolve_ref(typerefs);
|
||||
|
||||
if let Some(scope_var) = scope_var {
|
||||
if !scope_var.mutable && *mutable {
|
||||
return Err(ErrorKind::ImpossibleMutableBorrow(var_ref.1.clone()));
|
||||
ExprKind::Borrow(expr, mutable) => {
|
||||
let hint_t = if let HintKind::Coerce(hint_t) = hint_t {
|
||||
if let TypeKind::Borrow(inner, _) = hint_t {
|
||||
HintKind::Coerce(*inner)
|
||||
} else {
|
||||
return Err(ErrorKind::TypesIncompatible(
|
||||
hint_t,
|
||||
TypeKind::Borrow(Box::new(TypeKind::Vague(VagueType::Unknown)), *mutable),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Update typing to be more accurate
|
||||
var_ref.0 = state.or_else(
|
||||
var_ref.0.resolve_ref(typerefs).narrow_into(&existing),
|
||||
TypeKind::Vague(Vague::Unknown),
|
||||
var_ref.2,
|
||||
);
|
||||
|
||||
Ok(TypeKind::Borrow(Box::new(var_ref.0.clone()), *mutable))
|
||||
}
|
||||
ExprKind::Deref(var_ref) => {
|
||||
let existing = state
|
||||
.or_else(
|
||||
state
|
||||
.scope
|
||||
.variables
|
||||
.get(&var_ref.1)
|
||||
.map(|var| &var.ty)
|
||||
.cloned()
|
||||
.ok_or(ErrorKind::VariableNotDefined(var_ref.1.clone())),
|
||||
TypeKind::Vague(Vague::Unknown),
|
||||
var_ref.2,
|
||||
)
|
||||
.resolve_ref(typerefs);
|
||||
|
||||
// Update typing to be more accurate
|
||||
let TypeKind::Borrow(inner, mutable) = state.or_else(
|
||||
var_ref.0.resolve_ref(typerefs).narrow_into(&existing),
|
||||
TypeKind::Vague(Vague::Unknown),
|
||||
var_ref.2,
|
||||
) else {
|
||||
return Err(ErrorKind::AttemptedDerefNonBorrow(var_ref.1.clone()));
|
||||
} else {
|
||||
hint_t
|
||||
};
|
||||
|
||||
var_ref.0 = TypeKind::Borrow(inner.clone(), mutable);
|
||||
let expr_ty = expr.typecheck(state, typerefs, hint_t)?.resolve_ref(typerefs);
|
||||
|
||||
if let Some(backing_var) = expr.backing_var() {
|
||||
if let Some(scope_var) = state.scope.variables.get(&backing_var.1) {
|
||||
if !scope_var.mutable && *mutable {
|
||||
return Err(ErrorKind::ImpossibleMutableBorrow(backing_var.1.clone()));
|
||||
}
|
||||
} else {
|
||||
return Err(ErrorKind::VariableNotDefined(backing_var.1.clone()));
|
||||
}
|
||||
} else {
|
||||
return Err(ErrorKind::ImpossibleBorrow);
|
||||
}
|
||||
|
||||
Ok(TypeKind::Borrow(Box::new(expr_ty.clone()), *mutable))
|
||||
}
|
||||
ExprKind::Deref(expr) => {
|
||||
let hint_t = if let HintKind::Coerce(hint_t) = hint_t {
|
||||
HintKind::Coerce(TypeKind::Borrow(Box::new(hint_t), false))
|
||||
} else {
|
||||
hint_t
|
||||
};
|
||||
|
||||
let expr_ty = expr.typecheck(state, typerefs, hint_t)?.resolve_ref(typerefs);
|
||||
|
||||
// Update typing to be more accurate
|
||||
let TypeKind::Borrow(inner, _) = expr_ty else {
|
||||
return Err(ErrorKind::AttemptedDerefNonBorrow(expr_ty.clone()));
|
||||
};
|
||||
|
||||
Ok(*inner)
|
||||
}
|
||||
|
@ -557,37 +557,23 @@ impl Expression {
|
||||
}
|
||||
Ok(type_refs.from_type(&TypeKind::CustomType(type_key.clone())).unwrap())
|
||||
}
|
||||
ExprKind::Borrow(var, mutable) => {
|
||||
ExprKind::Borrow(expr, mutable) => {
|
||||
// Find variable type
|
||||
let type_ref = type_refs
|
||||
.find_var(&var.1)
|
||||
.map(|(_, hint)| hint)
|
||||
.ok_or(ErrorKind::VariableNotDefined(var.1.clone()));
|
||||
|
||||
// Update MIR type to TypeRef if found
|
||||
if let Ok(hint) = &type_ref {
|
||||
var.0 = hint.as_type();
|
||||
}
|
||||
let type_ref = expr.infer_types(state, type_refs)?;
|
||||
|
||||
Ok(type_refs
|
||||
.from_type(&TypeKind::Borrow(Box::new(var.0.clone()), *mutable))
|
||||
.from_type(&TypeKind::Borrow(Box::new(type_ref.as_type()), *mutable))
|
||||
.unwrap())
|
||||
}
|
||||
ExprKind::Deref(var) => {
|
||||
ExprKind::Deref(expr) => {
|
||||
// Find variable type
|
||||
let type_ref = type_refs
|
||||
.find_var(&var.1)
|
||||
.map(|(_, hint)| hint)
|
||||
.ok_or(ErrorKind::VariableNotDefined(var.1.clone()));
|
||||
let type_ref = expr.infer_types(state, type_refs)?;
|
||||
|
||||
// Update MIR type to TypeRef if found
|
||||
if let Ok(hint) = &type_ref {
|
||||
var.0 = hint.as_type();
|
||||
}
|
||||
// Update typing to be more accurate
|
||||
|
||||
match &var.0.resolve_weak(type_refs.types) {
|
||||
Borrow(type_kind, _) => Ok(type_refs.from_type(&type_kind).unwrap()),
|
||||
_ => Err(ErrorKind::AttemptedDerefNonBorrow(var.1.clone())),
|
||||
match type_ref.resolve_weak().unwrap() {
|
||||
Borrow(inner, _) => Ok(type_refs.from_type(&inner).unwrap()),
|
||||
_ => Err(ErrorKind::AttemptedDerefNonBorrow(type_ref.resolve_deep().unwrap())),
|
||||
}
|
||||
}
|
||||
ExprKind::CastTo(expression, type_kind) => {
|
||||
|
@ -27,6 +27,10 @@ impl<'scope> TypeRef<'scope> {
|
||||
let resolved_elem_ty = self.1.from_type(&elem_ty).unwrap().resolve_weak()?;
|
||||
Some(TypeKind::Array(Box::new(resolved_elem_ty), len))
|
||||
}
|
||||
TypeKind::Borrow(inner_ty, mutable) => {
|
||||
let resolved_elem_ty = self.1.from_type(&inner_ty).unwrap().resolve_weak()?;
|
||||
Some(TypeKind::Borrow(Box::new(resolved_elem_ty), mutable))
|
||||
}
|
||||
_ => Some(resolved),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user