something is wrong, but typechecking
This commit is contained in:
parent
70644ede3e
commit
e9335d3fc5
|
@ -241,7 +241,7 @@ impl IntegralType {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, Hash)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum Type {
|
||||
Any,
|
||||
Void,
|
||||
|
@ -289,8 +289,8 @@ impl core::fmt::Display for Type {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Type {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
impl Type {
|
||||
pub fn is_compatible_with(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::ComptimeNumber, Self::Integer(_)) => true,
|
||||
(Self::Integer(_), Self::ComptimeNumber) => true,
|
||||
|
@ -319,9 +319,6 @@ impl PartialEq for Type {
|
|||
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn as_primitive_type(&self) -> Option<PrimitiveType> {
|
||||
match self {
|
||||
Type::Void => Some(PrimitiveType::Void),
|
||||
|
|
|
@ -2009,6 +2009,20 @@ impl From<(u128, IntegralType)> for ComptimeNumber {
|
|||
}
|
||||
|
||||
impl ComptimeNumber {
|
||||
pub fn bit_count(&self) -> u16 {
|
||||
match self {
|
||||
ComptimeNumber::Integral(i) => match i {
|
||||
ComptimeInt::Native { ty, .. } => ty.bits,
|
||||
ComptimeInt::BigInt { ty, .. } => ty.bits,
|
||||
ComptimeInt::Comptime(i) => i.bits() as u16,
|
||||
},
|
||||
ComptimeNumber::Bool(_) => 1,
|
||||
ComptimeNumber::Floating(f) => match f {
|
||||
ComptimeFloat::Binary32(_) => 32,
|
||||
ComptimeFloat::Binary64(_) => 64,
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn add(self, other: Self) -> Result<Self> {
|
||||
match (self, other) {
|
||||
(ComptimeNumber::Integral(a), ComptimeNumber::Integral(b)) => {
|
||||
|
|
|
@ -1305,16 +1305,12 @@ pub mod liveness {
|
|||
interval.map(|max| (node, max))
|
||||
});
|
||||
|
||||
eprintln!("intervals: [");
|
||||
|
||||
let mut edges = HashSet::<(u32, u32)>::new();
|
||||
for (from, to) in intervals {
|
||||
eprint!("({from}..{to}), ");
|
||||
for &(other, _) in references.range(from.exclusive_start()..to.inclusive_end()) {
|
||||
edges.insert((from.0, other.0));
|
||||
}
|
||||
}
|
||||
eprintln!("]");
|
||||
|
||||
let inference_graph = petgraph::graph::UnGraph::<(), ()>::from_edges(edges.into_iter());
|
||||
|
||||
|
|
170
src/parser.rs
170
src/parser.rs
|
@ -12,6 +12,7 @@ use crate::{
|
|||
string_table::{ImmOrIndex, Index, StringTable},
|
||||
symbol_table::{SymbolKind, SymbolTable},
|
||||
tokens::Token,
|
||||
variant,
|
||||
};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
|
@ -1498,7 +1499,7 @@ impl Tree {
|
|||
writeln_indented!(
|
||||
indent,
|
||||
writer,
|
||||
"%{} = store(dst: %{}, val: %{})",
|
||||
"%{} = store (dst: %{}, val: %{})",
|
||||
node.get(),
|
||||
lhs.get(),
|
||||
rhs.get()
|
||||
|
@ -1560,6 +1561,28 @@ impl Tree {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn peer_type_of_nodes(&self, lhs: Node, rhs: Node) -> Option<Type> {
|
||||
let lty = self.type_of_node(lhs);
|
||||
let rty = self.type_of_node(rhs);
|
||||
|
||||
let peer = lty.equal_type(&rty)?;
|
||||
|
||||
if lty == Type::ComptimeNumber {
|
||||
let value = self.value_of_comptime_node(lhs)?;
|
||||
if value.bit_count() > rty.bit_width() {
|
||||
panic!("comptime number is incompatible with type {rty}!");
|
||||
}
|
||||
}
|
||||
if rty == Type::ComptimeNumber {
|
||||
let value = self.value_of_comptime_node(rhs)?;
|
||||
if value.bit_count() > lty.bit_width() {
|
||||
panic!("comptime number is incompatible with type {lty}!");
|
||||
}
|
||||
}
|
||||
|
||||
Some(peer)
|
||||
}
|
||||
|
||||
pub fn type_of_node(&self, node: Node) -> crate::ast::Type {
|
||||
match self.nodes.get_node(node) {
|
||||
Tag::FunctionDecl { proto, .. } => self.type_of_node(*proto),
|
||||
|
@ -1600,36 +1623,44 @@ impl Tree {
|
|||
Tag::Block { trailing_expr, .. } => trailing_expr
|
||||
.map(|n| self.type_of_node(n))
|
||||
.unwrap_or(Type::void()),
|
||||
Tag::VarDecl {
|
||||
explicit_type,
|
||||
assignment, // this is a Tag::Assign
|
||||
..
|
||||
} => {
|
||||
let lhs = explicit_type.map(|n| self.type_of_node(n));
|
||||
let rhs = assignment.map(|n| match self.nodes.get_node(n) {
|
||||
Tag::Assign { rhs, .. } => self.type_of_node(*rhs),
|
||||
_ => unreachable!(),
|
||||
});
|
||||
if lhs.as_ref().zip(rhs.as_ref()).map(|(l, r)| l != r) == Some(true) {
|
||||
eprintln!("vardecl: incompatible types {lhs:?} and {rhs:?}.");
|
||||
}
|
||||
lhs.or(rhs)
|
||||
.expect("Type could not be automatically deduced.")
|
||||
}
|
||||
Tag::GlobalDecl {
|
||||
explicit_type,
|
||||
assignment, // this is a Tag::Assign
|
||||
..
|
||||
} => {
|
||||
let lhs = explicit_type.map(|n| self.type_of_node(n));
|
||||
let rhs = match self.nodes.get_node(*assignment) {
|
||||
Tag::Assign { rhs, .. } => self.type_of_node(*rhs),
|
||||
_ => unreachable!(),
|
||||
variant!(self.nodes.get_node(*assignment) => Tag::Assign { rhs ,..});
|
||||
let ty = match (explicit_type.as_ref(), rhs) {
|
||||
(None, b) => self.type_of_node(*b),
|
||||
(Some(a), b) => self.peer_type_of_nodes(*a, *b).expect({
|
||||
let at = self.type_of_node(*a);
|
||||
let bt = self.type_of_node(*b);
|
||||
&format!("incompatible types for %{a}({at}) and %{b}({bt})")
|
||||
}),
|
||||
};
|
||||
if lhs.as_ref().zip(Some(&rhs)).map(|(l, r)| l != r) == Some(true) {
|
||||
eprintln!("vardecl: incompatible types {lhs:?} and {rhs:?}.");
|
||||
|
||||
ty
|
||||
}
|
||||
lhs.unwrap_or(rhs)
|
||||
Tag::VarDecl {
|
||||
explicit_type,
|
||||
assignment, // this is a Tag::Assign
|
||||
..
|
||||
} => {
|
||||
let rhs = assignment.map(|n| {
|
||||
variant!(self.nodes.get_node(n) => Tag::Assign { rhs ,..});
|
||||
*rhs
|
||||
});
|
||||
let ty = match (explicit_type.as_ref(), rhs.as_ref()) {
|
||||
(None, None) => panic!("%{node}: no type specified?"),
|
||||
(None, Some(b)) => self.type_of_node(*b),
|
||||
(Some(a), None) => self.type_of_node(*a),
|
||||
(Some(a), Some(b)) => self.peer_type_of_nodes(*a, *b).expect({
|
||||
let at = self.type_of_node(*a);
|
||||
let bt = self.type_of_node(*b);
|
||||
&format!("incompatible types for %{a}({at}) and %{b}({bt})")
|
||||
}),
|
||||
};
|
||||
|
||||
ty
|
||||
}
|
||||
Tag::CallExpr { lhs, .. } => self.type_of_node(*lhs),
|
||||
Tag::ExplicitCast { typename, .. } => self.type_of_node(*typename),
|
||||
|
@ -1637,18 +1668,23 @@ impl Tree {
|
|||
Tag::Ref { lhs } => self.type_of_node(*lhs).into_ptr(),
|
||||
Tag::Not { lhs } => self.type_of_node(*lhs),
|
||||
Tag::Negate { lhs } => self.type_of_node(*lhs),
|
||||
Tag::Or { lhs, .. } => self.type_of_node(*lhs),
|
||||
Tag::And { lhs, .. } => self.type_of_node(*lhs),
|
||||
Tag::BitOr { lhs, .. } => self.type_of_node(*lhs),
|
||||
Tag::BitAnd { lhs, .. } => self.type_of_node(*lhs),
|
||||
Tag::BitXOr { lhs, .. } => self.type_of_node(*lhs),
|
||||
Tag::Assign { lhs, rhs }
|
||||
| Tag::Add { lhs, rhs }
|
||||
| Tag::Sub { lhs, rhs }
|
||||
| Tag::Mul { lhs, rhs }
|
||||
| Tag::Rem { lhs, rhs }
|
||||
| Tag::Div { lhs, rhs }
|
||||
| Tag::Or { lhs, rhs }
|
||||
| Tag::And { lhs, rhs }
|
||||
| Tag::BitOr { lhs, rhs }
|
||||
| Tag::BitAnd { lhs, rhs }
|
||||
| Tag::BitXOr { lhs, rhs } => self.peer_type_of_nodes(*lhs, *rhs).expect({
|
||||
let at = self.type_of_node(*lhs);
|
||||
let bt = self.type_of_node(*rhs);
|
||||
&format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
|
||||
}),
|
||||
Tag::Shl { lhs, .. } => self.type_of_node(*lhs),
|
||||
Tag::Shr { lhs, .. } => self.type_of_node(*lhs),
|
||||
Tag::Add { lhs, .. } => self.type_of_node(*lhs),
|
||||
Tag::Sub { lhs, .. } => self.type_of_node(*lhs),
|
||||
Tag::Mul { lhs, .. } => self.type_of_node(*lhs),
|
||||
Tag::Rem { lhs, .. } => self.type_of_node(*lhs),
|
||||
Tag::Div { lhs, .. } => self.type_of_node(*lhs),
|
||||
Tag::Eq { .. } => Type::bool(),
|
||||
Tag::NEq { .. } => Type::bool(),
|
||||
Tag::Lt { .. } => Type::bool(),
|
||||
|
@ -1736,6 +1772,72 @@ impl Tree {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn value_of_comptime_node(&self, node: Node) -> Option<ComptimeNumber> {
|
||||
match self.nodes.get_node(node) {
|
||||
Tag::Constant { bytes, ty } => {
|
||||
let bytes = match bytes {
|
||||
ImmOrIndex::U64(v) => &v.to_le_bytes()[..],
|
||||
|
||||
ImmOrIndex::U32(v) => &v.to_le_bytes()[..],
|
||||
ImmOrIndex::Index(idx) => self.strings.get_bytes(*idx),
|
||||
};
|
||||
|
||||
let number: ComptimeNumber = match ty {
|
||||
Type::Bool => (bytes[0] != 0).into(),
|
||||
Type::ComptimeNumber => {
|
||||
BigInt::from_bytes_le(num_bigint::Sign::Plus, bytes).into()
|
||||
}
|
||||
Type::Integer(ty) => {
|
||||
if bytes.len() > core::mem::size_of::<u128>() {
|
||||
let bits = BigInt::from_bytes_le(num_bigint::Sign::Plus, bytes);
|
||||
(bits, *ty).into()
|
||||
} else {
|
||||
let mut buf = [0u8; core::mem::size_of::<u128>()];
|
||||
buf[..bytes.len()].copy_from_slice(bytes);
|
||||
let bits = u128::from_le_bytes(buf);
|
||||
(bits, *ty).into()
|
||||
}
|
||||
}
|
||||
Type::Floating(ty) => match ty {
|
||||
FloatingType::Binary32 => {
|
||||
(f32::from_le_bytes((&bytes[..4]).try_into().unwrap())).into()
|
||||
}
|
||||
FloatingType::Binary64 => {
|
||||
(f64::from_le_bytes((&bytes[..8]).try_into().unwrap())).into()
|
||||
}
|
||||
},
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
Some(number)
|
||||
}
|
||||
Tag::Block { .. } => todo!(),
|
||||
&Tag::DeclRef(lhs) => {
|
||||
let start = lhs;
|
||||
let end = node;
|
||||
let mut last_value = None;
|
||||
|
||||
ast::tree_visitor::Visitor::new_seek(
|
||||
self,start,
|
||||
|_: &Tree, _| {
|
||||
},
|
||||
|tree: &Tree, node| match tree.nodes.get_node(node) {
|
||||
&Tag::Assign { lhs, rhs } => {
|
||||
if lhs == start || matches!(tree.nodes.get_node(lhs), &Tag::DeclRef(decl) if decl == start) {
|
||||
last_value = Some(rhs);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
)
|
||||
.until_after(end)
|
||||
.visit(self);
|
||||
|
||||
self.value_of_comptime_node(last_value?)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_comptime_with_visitor(&mut self, decl: Node) {
|
||||
ast::tree_visitor::Visitor::new(
|
||||
decl,
|
||||
|
|
|
@ -260,6 +260,35 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn peer_type_of_nodes(&self, lhs: AstNode, rhs: AstNode) -> Option<Type> {
|
||||
let lty = self.tree.type_of_node(lhs);
|
||||
let rty = self.tree.type_of_node(rhs);
|
||||
|
||||
let peer = lty
|
||||
.equal_type(&rty)
|
||||
.expect(&format!("types {lty} and {rty} are incompatible!"));
|
||||
|
||||
if lty == Type::ComptimeNumber {
|
||||
eprintln!(
|
||||
"%{lhs} is comptime number: {:?}",
|
||||
self.tree.nodes.get_node(lhs)
|
||||
);
|
||||
let value = self.tree.value_of_comptime_node(lhs)?;
|
||||
if value.bit_count() > rty.bit_width() {
|
||||
panic!("comptime number is incompatible with type {rty}!");
|
||||
}
|
||||
}
|
||||
if rty == Type::ComptimeNumber {
|
||||
eprintln!("%{rhs} is comptime number");
|
||||
let value = self.tree.value_of_comptime_node(rhs)?;
|
||||
if value.bit_count() > lty.bit_width() {
|
||||
panic!("comptime number is incompatible with type {lty}!");
|
||||
}
|
||||
}
|
||||
|
||||
Some(peer)
|
||||
}
|
||||
|
||||
fn visit(&mut self, node: AstNode) -> Node {
|
||||
match &self.tree.nodes[node].clone() {
|
||||
Tag::FunctionDecl { proto, body } => {
|
||||
|
@ -353,7 +382,7 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
|||
self.ir.push(Inst::Load(ty.into()), Some(Data::lhs(lhs)))
|
||||
}
|
||||
Tag::Assign { lhs, rhs } => {
|
||||
let ty = self.tree.type_of_node(*rhs);
|
||||
let ty = self.tree.type_of_node(node);
|
||||
let dest = self.visit(*lhs);
|
||||
let source = self.visit(*rhs);
|
||||
|
||||
|
@ -361,40 +390,61 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
|||
.push(Inst::Store(ty.into()), Some(Data::new(source, dest)))
|
||||
}
|
||||
Tag::Add { lhs, rhs } => {
|
||||
let ty = self.tree.type_of_node(*lhs);
|
||||
let ty = self.tree.type_of_node(node);
|
||||
let lhs = self.visit(*lhs);
|
||||
let rhs = self.visit(*rhs);
|
||||
self.ir
|
||||
.push(Inst::Add(ty.into()), Some(Data::new(lhs, rhs)))
|
||||
}
|
||||
Tag::Sub { lhs, rhs } => {
|
||||
let ty = self.tree.type_of_node(*lhs);
|
||||
let ty = self.tree.type_of_node(node);
|
||||
let lhs = self.visit(*lhs);
|
||||
let rhs = self.visit(*rhs);
|
||||
self.ir
|
||||
.push(Inst::Sub(ty.into()), Some(Data::new(lhs, rhs)))
|
||||
}
|
||||
Tag::BitAnd { lhs, rhs } => {
|
||||
let ty = self.tree.type_of_node(node);
|
||||
let lhs = self.visit(*lhs);
|
||||
let rhs = self.visit(*rhs);
|
||||
self.ir
|
||||
.push(Inst::BitAnd(ty.into()), Some(Data::new(lhs, rhs)))
|
||||
}
|
||||
Tag::BitOr { lhs, rhs } => {
|
||||
let ty = self.tree.type_of_node(node);
|
||||
let lhs = self.visit(*lhs);
|
||||
let rhs = self.visit(*rhs);
|
||||
self.ir
|
||||
.push(Inst::BitOr(ty.into()), Some(Data::new(lhs, rhs)))
|
||||
}
|
||||
Tag::BitXOr { lhs, rhs } => {
|
||||
let ty = self.tree.type_of_node(node);
|
||||
let lhs = self.visit(*lhs);
|
||||
let rhs = self.visit(*rhs);
|
||||
self.ir
|
||||
.push(Inst::BitXOr(ty.into()), Some(Data::new(lhs, rhs)))
|
||||
}
|
||||
Tag::Mul { lhs, rhs } => {
|
||||
let ty = self.tree.type_of_node(*lhs);
|
||||
let ty = self.tree.type_of_node(node);
|
||||
let lhs = self.visit(*lhs);
|
||||
let rhs = self.visit(*rhs);
|
||||
self.ir
|
||||
.push(Inst::Mul(ty.into()), Some(Data::new(lhs, rhs)))
|
||||
}
|
||||
Tag::Negate { lhs } => {
|
||||
let ty = self.tree.type_of_node(*lhs);
|
||||
let ty = self.tree.type_of_node(node);
|
||||
let lhs = self.visit(*lhs);
|
||||
self.ir.push(Inst::Negate(ty.into()), Some(Data::lhs(lhs)))
|
||||
}
|
||||
Tag::Shl { lhs, rhs } => {
|
||||
let ty = self.tree.type_of_node(*lhs);
|
||||
let ty = self.tree.type_of_node(node);
|
||||
let lhs = self.visit(*lhs);
|
||||
let rhs = self.visit(*rhs);
|
||||
self.ir
|
||||
.push(Inst::ShiftLeft(ty.into()), Some(Data::new(lhs, rhs)))
|
||||
}
|
||||
Tag::Shr { lhs, rhs } => {
|
||||
let ty = self.tree.type_of_node(*lhs);
|
||||
let ty = self.tree.type_of_node(node);
|
||||
let lhs = self.visit(*lhs);
|
||||
let rhs = self.visit(*rhs);
|
||||
self.ir
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
fn inverse_sqrt(n: f32) -> f32 {
|
||||
let x = n;
|
||||
var i = *(&x as *i32);
|
||||
i = 0x5f3759dfi32 - (i >> 1);
|
||||
i = 0x5f3759df - (i >> 1);
|
||||
let y = *(&i as *f32);
|
||||
y * (1.5f32 - (x * 0.5f32 * y * y))
|
||||
}
|
Loading…
Reference in a new issue