going insane (not working yet)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::ir::{AsmBlockArgType, Size, SymbolSpace, UFunc, UInstrInst, VarOffset};
|
||||
use crate::ir::{AsmBlockArgType, Size, StructTy, SymbolSpace, UFunc, UInstrInst, VarOffset};
|
||||
|
||||
use super::{
|
||||
IRLFunction, LInstruction, Len, Symbol, SymbolSpaceBuilder, Type, UInstruction, UProgram, VarID,
|
||||
@@ -17,7 +17,7 @@ impl LProgram {
|
||||
pub fn create(p: &UProgram) -> Result<Self, String> {
|
||||
let start = p
|
||||
.names
|
||||
.id::<UFunc>("crate")
|
||||
.id::<UFunc>(&["crate".to_string()])
|
||||
.ok_or("no start method found")?;
|
||||
let mut ssbuilder = SymbolSpaceBuilder::with_entries(&[start]);
|
||||
let entry = ssbuilder.func(&start);
|
||||
@@ -44,10 +44,20 @@ impl LProgram {
|
||||
|
||||
pub struct StructInst {
|
||||
offsets: Vec<Len>,
|
||||
types: Vec<Type>,
|
||||
order: HashMap<String, usize>,
|
||||
size: Size,
|
||||
}
|
||||
|
||||
impl StructInst {
|
||||
pub fn offset(&self, name: &str) -> Option<Len> {
|
||||
Some(self.offsets[*self.order.get(name)?])
|
||||
}
|
||||
pub fn ty(&self, name: &str) -> Option<&Type> {
|
||||
Some(&self.types[*self.order.get(name)?])
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LFunctionBuilder<'a> {
|
||||
data: LFunctionBuilderData<'a>,
|
||||
program: &'a UProgram,
|
||||
@@ -72,7 +82,7 @@ pub struct LFunctionBuilderData<'a> {
|
||||
instrs: Vec<LInstruction>,
|
||||
stack: HashMap<VarID, Size>,
|
||||
subvar_map: HashMap<VarID, VarOffset>,
|
||||
struct_insts: HashMap<Type, StructInst>,
|
||||
struct_insts: HashMap<StructTy, StructInst>,
|
||||
makes_call: bool,
|
||||
loopp: Option<LoopCtx>,
|
||||
}
|
||||
@@ -258,6 +268,10 @@ impl<'a> LFunctionBuilder<'a> {
|
||||
self.data.instrs.push(LInstruction::Ret { src })
|
||||
}
|
||||
UInstruction::Construct { dest, fields } => {
|
||||
let sty = &self.program.expect(dest.id).ty;
|
||||
let Type::Struct(sty) = sty else {
|
||||
panic!("bruh htis aint' a struct");
|
||||
};
|
||||
self.alloc_stack(dest.id)?;
|
||||
for (field, var) in fields {
|
||||
self.map_subvar(var.id);
|
||||
@@ -266,7 +280,7 @@ impl<'a> LFunctionBuilder<'a> {
|
||||
src: var.id,
|
||||
dest_offset: self
|
||||
.data
|
||||
.field_offset(self.program, dest.id, field)
|
||||
.field_offset(self.program, sty, field)
|
||||
.expect("field offset"),
|
||||
src_offset: 0,
|
||||
};
|
||||
@@ -344,22 +358,25 @@ impl<'a> LFunctionBuilder<'a> {
|
||||
impl LFunctionBuilderData<'_> {
|
||||
pub fn var_offset(&mut self, p: &UProgram, var: VarID) -> Option<VarOffset> {
|
||||
let mut current = VarOffset { id: var, offset: 0 };
|
||||
while let Some(parent) = &p.get(current.id)?.parent {
|
||||
current.id = parent.var;
|
||||
current.offset += self.field_offset(p, parent.var, &parent.field)?;
|
||||
while let Type::Member(parent) = &p.get(current.id)?.ty {
|
||||
current.id = parent.parent;
|
||||
// ... should it be set to 0 if not? what does that even mean??
|
||||
// "the field of this struct is a reference to another variable" ????
|
||||
if let Type::Struct(sty) = &p.get(parent.parent)?.ty {
|
||||
current.offset += self.field_offset(p, sty, &parent.name)?;
|
||||
}
|
||||
}
|
||||
Some(current)
|
||||
}
|
||||
pub fn addr_size(&self) -> Size {
|
||||
64
|
||||
}
|
||||
pub fn struct_inst(&mut self, p: &UProgram, ty: &Type) -> Option<&StructInst> {
|
||||
pub fn struct_inst(&mut self, p: &UProgram, ty: &StructTy) -> &StructInst {
|
||||
// normally I'd let Some(..) here and return, but polonius does not exist :grief:
|
||||
if self.struct_insts.get(ty).is_none() {
|
||||
let Type::Struct { id, args } = ty else {
|
||||
return None;
|
||||
};
|
||||
let struc = p.get(*id)?;
|
||||
let StructTy { id, args } = ty;
|
||||
let struc = p.expect(*id);
|
||||
let mut types = Vec::new();
|
||||
let mut sizes = struc
|
||||
.fields
|
||||
.iter()
|
||||
@@ -374,6 +391,7 @@ impl LFunctionBuilderData<'_> {
|
||||
} else {
|
||||
&f.ty
|
||||
};
|
||||
types.push(ty.clone());
|
||||
(n, self.size_of_type(p, ty).expect("unsized type"))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@@ -392,25 +410,24 @@ impl LFunctionBuilderData<'_> {
|
||||
StructInst {
|
||||
offsets,
|
||||
order,
|
||||
types,
|
||||
size: offset,
|
||||
},
|
||||
);
|
||||
}
|
||||
self.struct_insts.get(ty)
|
||||
self.struct_insts.get(ty).unwrap()
|
||||
}
|
||||
|
||||
pub fn field_offset(&mut self, p: &UProgram, var: VarID, field: &str) -> Option<Len> {
|
||||
let ty = &p.get(var)?.ty;
|
||||
let inst = self.struct_inst(p, ty)?;
|
||||
let i = *inst.order.get(field)?;
|
||||
Some(*inst.offsets.get(i)?)
|
||||
pub fn field_offset(&mut self, p: &UProgram, sty: &StructTy, field: &str) -> Option<Len> {
|
||||
let inst = self.struct_inst(p, sty);
|
||||
Some(inst.offset(field)?)
|
||||
}
|
||||
|
||||
pub fn size_of_type(&mut self, p: &UProgram, ty: &Type) -> Option<Size> {
|
||||
// TODO: target matters
|
||||
Some(match ty {
|
||||
Type::Bits(b) => *b,
|
||||
Type::Struct { id, args } => self.struct_inst(p, ty)?.size,
|
||||
Type::Struct(ty) => self.struct_inst(p, ty).size,
|
||||
Type::Generic { id } => return None,
|
||||
Type::Fn { args, ret } => todo!(),
|
||||
Type::Ref(_) => self.addr_size(),
|
||||
@@ -420,6 +437,18 @@ impl LFunctionBuilderData<'_> {
|
||||
Type::Error => return None,
|
||||
Type::Unit => 0,
|
||||
Type::Placeholder => return None,
|
||||
Type::Module(_) => return None,
|
||||
Type::Member(m) => {
|
||||
let pty = &p.expect(m.parent).ty;
|
||||
let ty = match pty {
|
||||
Type::Struct(ty) => self.struct_inst(p, ty).ty(&m.name)?,
|
||||
Type::Module(path) => p.path_ty(path)?,
|
||||
Type::Member(_) => return self.size_of_type(p, pty),
|
||||
_ => return None,
|
||||
}
|
||||
.clone();
|
||||
self.size_of_type(p, &ty)?
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -20,16 +20,56 @@ impl OriginMap {
|
||||
}
|
||||
}
|
||||
|
||||
pub type NamePath = Vec<String>;
|
||||
|
||||
pub struct NameTree {
|
||||
ids: [HashMap<String, usize>; NAMED_KINDS],
|
||||
children: HashMap<String, NameTree>,
|
||||
}
|
||||
|
||||
impl NameTree {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
ids: core::array::from_fn(|_| HashMap::new()),
|
||||
children: HashMap::new(),
|
||||
}
|
||||
}
|
||||
pub fn get(&self, path: &[String]) -> Option<&NameTree> {
|
||||
let first = path.first()?;
|
||||
self.children.get(first)?.get(&path[1..])
|
||||
}
|
||||
pub fn id<K: Kind>(&self, path: &[String]) -> Option<ID<K>> {
|
||||
let last = path.last()?;
|
||||
self.get(&path[..path.len() - 1])?.ids[K::INDEX]
|
||||
.get(last)
|
||||
.copied()
|
||||
.map(ID::new)
|
||||
}
|
||||
pub fn insert<K: Kind>(&mut self, path: &[String], id: usize) {
|
||||
if let [key] = &path[..] {
|
||||
self.ids[K::INDEX].insert(key.to_string(), id);
|
||||
return;
|
||||
}
|
||||
let Some(key) = path.first() else {
|
||||
return;
|
||||
};
|
||||
self.children
|
||||
.entry(key.to_string())
|
||||
.or_insert_with(|| NameTree::new())
|
||||
.insert::<K>(&path[1..], id);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NameMap {
|
||||
names: [Vec<String>; NAMED_KINDS],
|
||||
inv_names: [HashMap<String, usize>; NAMED_KINDS],
|
||||
tree: NameTree,
|
||||
}
|
||||
|
||||
impl NameMap {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
names: core::array::from_fn(|_| Vec::new()),
|
||||
inv_names: core::array::from_fn(|_| HashMap::new()),
|
||||
tree: NameTree::new(),
|
||||
}
|
||||
}
|
||||
pub fn path<K: Kind>(&self, id: ID<K>) -> &str {
|
||||
@@ -42,11 +82,13 @@ impl NameMap {
|
||||
}
|
||||
path
|
||||
}
|
||||
pub fn id<K: Kind>(&self, name: &str) -> Option<ID<K>> {
|
||||
Some(ID::new(*self.inv_names[K::INDEX].get(name)?))
|
||||
pub fn id<K: Kind>(&self, path: &[String]) -> Option<ID<K>> {
|
||||
Some(self.tree.id(path)?)
|
||||
}
|
||||
pub fn push<K: Kind>(&mut self, name: String) {
|
||||
self.inv_names[K::INDEX].insert(name.clone(), self.names[K::INDEX].len());
|
||||
pub fn push<K: Kind>(&mut self, path: &[String]) {
|
||||
let id = self.names[K::INDEX].len();
|
||||
self.tree.insert::<K>(path, id);
|
||||
let name = path.join("::");
|
||||
self.names[K::INDEX].push(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ pub struct UGeneric {}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UVar {
|
||||
pub parent: Option<FieldRef>,
|
||||
pub ty: Type,
|
||||
}
|
||||
|
||||
@@ -37,12 +36,6 @@ pub struct VarOffset {
|
||||
pub offset: Len,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
pub struct FieldRef {
|
||||
pub var: VarID,
|
||||
pub field: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UData {
|
||||
pub ty: Type,
|
||||
@@ -124,7 +117,7 @@ impl_kind!(UVar, 1, vars, "var");
|
||||
impl_kind!(UStruct, 2, structs, "struct");
|
||||
impl_kind!(UGeneric, 3, types, "type");
|
||||
impl_kind!(UData, 4, data, "data");
|
||||
pub const NAMED_KINDS: usize = 5;
|
||||
pub const NAMED_KINDS: usize = 6;
|
||||
|
||||
pub type FnID = ID<UFunc>;
|
||||
pub type VarID = ID<UVar>;
|
||||
@@ -137,7 +130,6 @@ impl Finish for UFunc {
|
||||
let var = p.def_searchable(
|
||||
name.to_string(),
|
||||
Some(UVar {
|
||||
parent: None,
|
||||
ty: Type::Placeholder,
|
||||
}),
|
||||
p.origins.get(id),
|
||||
|
||||
@@ -71,19 +71,13 @@ impl UProgram {
|
||||
pub fn get_fn_var(&self, id: VarID) -> Option<&UFunc> {
|
||||
self.fns[self.fn_var.fun(id)?.0].as_ref()
|
||||
}
|
||||
pub fn temp_subvar(&mut self, origin: Origin, ty: Type, parent: FieldRef) -> VarInst {
|
||||
self.temp_var_inner(origin, ty, Some(parent))
|
||||
}
|
||||
|
||||
pub fn temp_var(&mut self, origin: Origin, ty: Type) -> VarInst {
|
||||
self.temp_var_inner(origin, ty, None)
|
||||
self.temp_var_inner(origin, ty)
|
||||
}
|
||||
|
||||
fn temp_var_inner(&mut self, origin: Origin, ty: Type, parent: Option<FieldRef>) -> VarInst {
|
||||
let v = self.def(
|
||||
&format!("temp{}", self.temp),
|
||||
Some(UVar { parent, ty }),
|
||||
origin,
|
||||
);
|
||||
fn temp_var_inner(&mut self, origin: Origin, ty: Type) -> VarInst {
|
||||
let v = self.def(&format!("temp{}", self.temp), Some(UVar { ty }), origin);
|
||||
self.temp += 1;
|
||||
VarInst {
|
||||
id: v,
|
||||
@@ -96,7 +90,7 @@ impl UProgram {
|
||||
}
|
||||
|
||||
pub fn def<K: Kind + Finish>(&mut self, name: &str, k: Option<K>, origin: Origin) -> ID<K> {
|
||||
self.names.push::<K>(self.path_for(name));
|
||||
self.names.push::<K>(&self.path_for(name));
|
||||
self.origins.push::<K>(origin);
|
||||
let vec = K::from_program_mut(self);
|
||||
let id = ID::new(vec.len());
|
||||
@@ -105,12 +99,12 @@ impl UProgram {
|
||||
id
|
||||
}
|
||||
|
||||
pub fn path_for(&self, name: &str) -> String {
|
||||
pub fn path_for(&self, name: &str) -> Vec<String> {
|
||||
if self.path.is_empty() {
|
||||
return name.to_string();
|
||||
return vec![name.to_string()];
|
||||
}
|
||||
let mut path = self.path.join("::");
|
||||
path = path + "::" + name;
|
||||
let mut path = self.path.clone();
|
||||
path.push(name.to_string());
|
||||
path
|
||||
}
|
||||
|
||||
@@ -125,27 +119,46 @@ impl UProgram {
|
||||
id
|
||||
}
|
||||
|
||||
pub fn ref_ty<'a>(&'a self, mem: &MemberRef) -> Option<&'a Type> {
|
||||
self.follow_ref(mem).and_then(|r| Some(&self.get(r)?.ty))
|
||||
}
|
||||
|
||||
pub fn follow_ref<'a>(&'a self, mem: &MemberRef) -> Option<VarID> {
|
||||
let parent = self.get(mem.parent)?;
|
||||
if let Type::Member(mem) = &parent.ty {
|
||||
self.follow_ref(mem)
|
||||
} else {
|
||||
Some(mem.parent)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field_type<'a>(&'a self, sty: &'a Type, field: &str) -> Option<&'a Type> {
|
||||
let Type::Struct { id, args } = sty else {
|
||||
return None;
|
||||
};
|
||||
let struc = self.get(*id)?;
|
||||
let field = struc.fields.get(field)?;
|
||||
if let Type::Generic { id } = field.ty {
|
||||
for (i, g) in struc.generics.iter().enumerate() {
|
||||
if *g == id {
|
||||
return Some(&args[i]);
|
||||
if let Type::Struct(st) = sty {
|
||||
let struc = self.get(st.id)?;
|
||||
let field = struc.fields.get(field)?;
|
||||
if let Type::Generic { id } = field.ty {
|
||||
for (i, g) in struc.generics.iter().enumerate() {
|
||||
if *g == id {
|
||||
return Some(&st.args[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(&field.ty)
|
||||
} else if let Type::Module(path) = sty {
|
||||
let id = self.names.id::<UVar>(path)?;
|
||||
Some(&self.get(id)?.ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
Some(&field.ty)
|
||||
}
|
||||
|
||||
pub fn type_name(&self, ty: &Type) -> String {
|
||||
let mut str = String::new();
|
||||
match ty {
|
||||
Type::Struct { id: base, args } => {
|
||||
str += self.names.name(*base);
|
||||
Type::Struct(ty) => {
|
||||
let base = ty.id;
|
||||
let args = &ty.args;
|
||||
str += self.names.name(base);
|
||||
if let Some(arg) = args.first() {
|
||||
str = str + "<" + &self.type_name(arg);
|
||||
}
|
||||
@@ -178,9 +191,22 @@ impl UProgram {
|
||||
Type::Unit => str += "()",
|
||||
Type::Slice(t) => str += &format!("&[{}]", self.type_name(t)),
|
||||
Type::Placeholder => str += "{placeholder}",
|
||||
Type::Module(path) => str += &path.join("::"),
|
||||
Type::Member(m) => {
|
||||
str += &self
|
||||
.ref_ty(m)
|
||||
.map(|t| self.type_name(t))
|
||||
.unwrap_or("{error}".to_string())
|
||||
}
|
||||
}
|
||||
str
|
||||
}
|
||||
pub fn path_var(&self, path: &NamePath) -> Option<VarID> {
|
||||
self.names.id(path)
|
||||
}
|
||||
pub fn path_ty(&self, path: &NamePath) -> Option<&Type> {
|
||||
Some(&self.get(self.path_var(path)?)?.ty)
|
||||
}
|
||||
fn name_on_stack<K: Kind>(&mut self, id: ID<K>, name: String) {
|
||||
let idx = self.name_stack.len() - 1;
|
||||
let last = &mut self.name_stack[idx];
|
||||
|
||||
@@ -1,16 +1,30 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::{GenericID, Len, StructID, UInstruction, UProgram, UVar, VarID};
|
||||
use super::{assoc::NamePath, GenericID, Len, StructID, UInstruction, UProgram, UVar, VarID};
|
||||
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
pub struct MemberRef {
|
||||
pub parent: VarID,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||
pub struct StructTy {
|
||||
pub id: StructID,
|
||||
pub args: Vec<Type>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Type {
|
||||
Bits(u32),
|
||||
Struct { id: StructID, args: Vec<Type> },
|
||||
Struct(StructTy),
|
||||
Generic { id: GenericID },
|
||||
Fn { args: Vec<Type>, ret: Box<Type> },
|
||||
Ref(Box<Type>),
|
||||
Slice(Box<Type>),
|
||||
Array(Box<Type>, Len),
|
||||
Member(MemberRef),
|
||||
Module(NamePath),
|
||||
Infer,
|
||||
Error,
|
||||
Placeholder,
|
||||
@@ -43,37 +57,16 @@ impl UProgram {
|
||||
}
|
||||
for (i, f) in self.iter_fns() {
|
||||
let mut redo_iter = Vec::new();
|
||||
let mut ph_vars = Vec::new();
|
||||
let mut redo_new = Vec::new();
|
||||
for i in f.flat_iter() {
|
||||
if let Err(id) = self.resolve_instr_types(&mut vars, &i.i) {
|
||||
if self.resolve_instr_types(&mut vars, &i.i).is_none() {
|
||||
redo_iter.push(i);
|
||||
ph_vars.push(id);
|
||||
}
|
||||
}
|
||||
while !redo_iter.is_empty() {
|
||||
let mut new_ph = Vec::new();
|
||||
for id in &ph_vars {
|
||||
let i = id.0;
|
||||
let Some(var) = &vars[i] else {
|
||||
continue;
|
||||
};
|
||||
if var.ty == Type::Placeholder
|
||||
&& let Some(parent) = var.parent.as_ref()
|
||||
{
|
||||
let pty = &vars[parent.var.0].as_ref().unwrap().ty;
|
||||
if let Some(ft) = self.field_type(pty, &parent.field) {
|
||||
vars[i].as_mut().unwrap().ty = ft.clone();
|
||||
} else {
|
||||
new_ph.push(parent.var);
|
||||
}
|
||||
}
|
||||
}
|
||||
ph_vars = new_ph;
|
||||
for &i in &redo_iter {
|
||||
if let Err(id) = self.resolve_instr_types(&mut vars, &i.i) {
|
||||
if self.resolve_instr_types(&mut vars, &i.i).is_none() {
|
||||
redo_new.push(i);
|
||||
ph_vars.push(id);
|
||||
}
|
||||
}
|
||||
std::mem::swap(&mut redo_iter, &mut redo_new);
|
||||
@@ -83,11 +76,7 @@ impl UProgram {
|
||||
self.vars = vars;
|
||||
}
|
||||
|
||||
pub fn resolve_instr_types(
|
||||
&self,
|
||||
vars: &mut [Option<UVar>],
|
||||
i: &UInstruction,
|
||||
) -> Result<(), VarID> {
|
||||
pub fn resolve_instr_types(&self, vars: &mut [Option<UVar>], i: &UInstruction) -> Option<()> {
|
||||
'outer: {
|
||||
match &i {
|
||||
UInstruction::Call { dest, f, args } => {
|
||||
@@ -96,7 +85,7 @@ impl UProgram {
|
||||
for (src, &dest) in args.iter().zip(&fun.args) {
|
||||
let dest_ty = get(vars, dest)?;
|
||||
let src_ty = get(vars, src.id)?;
|
||||
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||
if let Some(ty) = self.match_types(dest_ty, src_ty) {
|
||||
set(vars, dest, ty.clone());
|
||||
set(vars, src.id, ty);
|
||||
}
|
||||
@@ -105,7 +94,7 @@ impl UProgram {
|
||||
UInstruction::Mv { dest, src } => {
|
||||
let dest_ty = get(vars, dest.id)?;
|
||||
let src_ty = get(vars, src.id)?;
|
||||
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||
if let Some(ty) = self.match_types(dest_ty, src_ty) {
|
||||
set(vars, dest.id, ty.clone());
|
||||
set(vars, src.id, ty);
|
||||
}
|
||||
@@ -116,7 +105,7 @@ impl UProgram {
|
||||
let Type::Ref(dest_ty) = dest_ty else {
|
||||
break 'outer;
|
||||
};
|
||||
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||
if let Some(ty) = self.match_types(dest_ty, src_ty) {
|
||||
set(vars, dest.id, ty.clone().rf());
|
||||
set(vars, src.id, ty);
|
||||
}
|
||||
@@ -136,10 +125,10 @@ impl UProgram {
|
||||
UInstruction::Ret { .. } => {}
|
||||
UInstruction::Construct { dest, fields } => {
|
||||
let dest_ty = get(vars, dest.id)?;
|
||||
let Type::Struct { id, args } = dest_ty else {
|
||||
let Type::Struct(sty) = dest_ty else {
|
||||
break 'outer;
|
||||
};
|
||||
let id = *id;
|
||||
let id = sty.id;
|
||||
let Some(struc) = self.get(id) else {
|
||||
break 'outer;
|
||||
};
|
||||
@@ -149,7 +138,7 @@ impl UProgram {
|
||||
continue;
|
||||
};
|
||||
let src_ty = get(vars, src.id)?;
|
||||
if let Some(ty) = match_types(&field.ty, src_ty) {
|
||||
if let Some(ty) = self.match_types(&field.ty, src_ty) {
|
||||
if let Type::Generic { id } = field.ty {
|
||||
new.insert(id, ty.clone());
|
||||
}
|
||||
@@ -166,7 +155,7 @@ impl UProgram {
|
||||
args[i] = ty;
|
||||
}
|
||||
}
|
||||
set(vars, dest.id, Type::Struct { id, args });
|
||||
set(vars, dest.id, Type::Struct(StructTy { id, args }));
|
||||
}
|
||||
UInstruction::If { cond, body: _ } => {}
|
||||
UInstruction::Loop { body: _ } => {}
|
||||
@@ -174,18 +163,88 @@ impl UProgram {
|
||||
UInstruction::Continue => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
Some(())
|
||||
}
|
||||
|
||||
pub fn match_types(&self, dest: &Type, src: &Type) -> Option<Type> {
|
||||
if dest == src {
|
||||
return None;
|
||||
}
|
||||
match (dest, src) {
|
||||
(Type::Error, _) | (_, Type::Error) => None,
|
||||
(Type::Placeholder, _) | (_, Type::Placeholder) => None,
|
||||
(Type::Infer, x) | (x, Type::Infer) => Some(x.clone()),
|
||||
// TODO: handle constraints?
|
||||
(Type::Generic { id }, x) | (x, Type::Generic { id }) => Some(x.clone()),
|
||||
(Type::Struct(dest), Type::Struct(src)) => {
|
||||
if dest.id != src.id {
|
||||
return None;
|
||||
}
|
||||
let mut args = Vec::new();
|
||||
let mut changed = false;
|
||||
for (darg, sarg) in dest.args.iter().zip(&src.args) {
|
||||
if let Some(ty) = self.match_types(darg, sarg) {
|
||||
args.push(ty);
|
||||
changed = true;
|
||||
} else if darg != sarg {
|
||||
return None;
|
||||
} else {
|
||||
args.push(darg.clone());
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
Some(Type::Struct(StructTy { id: dest.id, args }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
(
|
||||
Type::Fn {
|
||||
args: dest_args,
|
||||
ret: dest_ret,
|
||||
},
|
||||
Type::Fn {
|
||||
args: src_args,
|
||||
ret: src_ret,
|
||||
},
|
||||
) => {
|
||||
// TODO
|
||||
None
|
||||
}
|
||||
(Type::Ref(dest), Type::Ref(src)) => Some(self.match_types(dest, src)?.rf()),
|
||||
(Type::Slice(dest), Type::Slice(src)) => Some(self.match_types(dest, src)?.slice()),
|
||||
(Type::Array(dest, dlen), Type::Array(src, slen)) => {
|
||||
if dlen != slen {
|
||||
return None;
|
||||
}
|
||||
Some(self.match_types(dest, src)?.arr(*dlen))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(vars: &[Option<UVar>], id: VarID) -> Result<&Type, VarID> {
|
||||
let var = vars[id.0]
|
||||
pub fn get(vars: &[Option<UVar>], id: VarID) -> Option<&Type> {
|
||||
let mut var = vars[id.0]
|
||||
.as_ref()
|
||||
.expect("PARTIAL BORROWING WOULD BE REALLY COOL");
|
||||
if var.ty == Type::Placeholder {
|
||||
return Err(id);
|
||||
return None;
|
||||
}
|
||||
Ok(&var.ty)
|
||||
while let Type::Member(m) = &var.ty {
|
||||
var = vars[m.parent.0].as_ref().expect("xd");
|
||||
}
|
||||
// x.y().z == a.b.c()
|
||||
// 0 ------- member(1, z)
|
||||
// 1 ----- call(2)
|
||||
// 2 --- member(3, y)
|
||||
// 3 - x
|
||||
//
|
||||
// 0 ------- call(1)
|
||||
// 1 ----- member(c, 2)
|
||||
// 2 --- member(b, 3)
|
||||
// 3 - a
|
||||
Some(&var.ty)
|
||||
}
|
||||
|
||||
pub fn set(vars: &mut [Option<UVar>], id: VarID, ty: Type) {
|
||||
@@ -194,69 +253,3 @@ pub fn set(vars: &mut [Option<UVar>], id: VarID, ty: Type) {
|
||||
.expect("PARTIAL BORROWING WOULD BE REALLY COOL")
|
||||
.ty = ty;
|
||||
}
|
||||
|
||||
pub fn match_types(dest: &Type, src: &Type) -> Option<Type> {
|
||||
if dest == src {
|
||||
return None;
|
||||
}
|
||||
match (dest, src) {
|
||||
(Type::Error, _) | (_, Type::Error) => None,
|
||||
(Type::Placeholder, _) | (_, Type::Placeholder) => None,
|
||||
(Type::Infer, x) | (x, Type::Infer) => Some(x.clone()),
|
||||
// TODO: handle constraints?
|
||||
(Type::Generic { id }, x) | (x, Type::Generic { id }) => Some(x.clone()),
|
||||
(
|
||||
Type::Struct {
|
||||
id: dest_id,
|
||||
args: dest_args,
|
||||
},
|
||||
Type::Struct {
|
||||
id: src_id,
|
||||
args: src_args,
|
||||
},
|
||||
) => {
|
||||
if dest_id != src_id {
|
||||
return None;
|
||||
}
|
||||
let mut args = Vec::new();
|
||||
let mut changed = false;
|
||||
for (darg, sarg) in dest_args.iter().zip(src_args) {
|
||||
if let Some(ty) = match_types(darg, sarg) {
|
||||
args.push(ty);
|
||||
changed = true;
|
||||
} else if darg != sarg {
|
||||
return None;
|
||||
} else {
|
||||
args.push(darg.clone());
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
Some(Type::Struct { id: *dest_id, args })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
(
|
||||
Type::Fn {
|
||||
args: dest_args,
|
||||
ret: dest_ret,
|
||||
},
|
||||
Type::Fn {
|
||||
args: src_args,
|
||||
ret: src_ret,
|
||||
},
|
||||
) => {
|
||||
// TODO
|
||||
None
|
||||
}
|
||||
(Type::Ref(dest), Type::Ref(src)) => Some(match_types(dest, src)?.rf()),
|
||||
(Type::Slice(dest), Type::Slice(src)) => Some(match_types(dest, src)?.slice()),
|
||||
(Type::Array(dest, dlen), Type::Array(src, slen)) => {
|
||||
if dlen != slen {
|
||||
return None;
|
||||
}
|
||||
Some(match_types(dest, src)?.arr(*dlen))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,13 @@ use super::{Type, UInstrInst, UInstruction, UProgram};
|
||||
use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
|
||||
|
||||
impl UProgram {
|
||||
pub fn validate(&self) -> CompilerOutput {
|
||||
let mut output = CompilerOutput::new();
|
||||
pub fn validate(&self, output: &mut CompilerOutput) {
|
||||
for (id, f) in self.iter_fns() {
|
||||
self.validate_fn(
|
||||
&f.instructions,
|
||||
self.origins.get(id),
|
||||
&f.ret,
|
||||
&mut output,
|
||||
output,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
@@ -46,7 +45,6 @@ impl UProgram {
|
||||
}
|
||||
}
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
pub fn validate_fn(
|
||||
|
||||
Reference in New Issue
Block a user