I can see the light

This commit is contained in:
2025-05-02 18:18:13 -04:00
parent d7222cc7a4
commit 57c46b653e
35 changed files with 1247 additions and 1000 deletions
+60 -189
View File
@@ -1,6 +1,4 @@
use std::collections::HashMap;
use super::{assoc::NamePath, Len, StructID, TypeID, UInstruction, UProgram, VarID};
use super::{FnID, GenericID, Len, ModPath, StructID, TypeID, UVar, VarID, VarInst};
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct FieldRef {
@@ -8,211 +6,84 @@ pub struct FieldRef {
pub name: String,
}
#[derive(Clone, Eq, PartialEq)]
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct StructTy {
pub id: StructID,
pub fields: HashMap<String, VarID>,
pub args: Vec<TypeID>,
}
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone)]
pub enum Type {
Bits(u32),
Struct(StructTy),
Fn { args: Vec<TypeID>, ret: TypeID },
Fn(FnID),
Ref(TypeID),
Deref(TypeID),
Slice(TypeID),
Array(TypeID, Len),
Unit,
// fake types
Field(FieldRef),
Module(NamePath),
// "fake" types
Unres(ModPath),
Generic(GenericID),
Infer,
Error,
Placeholder,
}
impl TypeID {
pub fn rf(self) -> Type {
Type::Ref(self)
}
pub fn derf(self) -> Type {
Type::Deref(self)
}
pub fn arr(self, len: Len) -> Type {
Type::Array(self, len)
}
pub fn slice(self) -> Type {
Type::Slice(self)
}
}
impl Type {
pub fn is_resolved(&self) -> bool {
!matches!(self, Self::Error | Self::Placeholder | Self::Infer)
}
}
impl UProgram {
pub fn resolve_types(&mut self) {
// PARTIAL BORROWING :SOB:
let fns: Vec<_> = self.cloned_fns().collect();
for (i, f) in &fns {
let vi = self.fn_var.var(*i);
self.expect_mut(vi).ty = f.ty(self);
}
for (i, f) in &fns {
let mut redo_iter = Vec::new();
let mut redo_new = Vec::new();
for i in f.flat_iter() {
if self.resolve_instr_types(&i.i).is_none() {
redo_iter.push(i);
}
}
while !redo_iter.is_empty() {
for &i in &redo_iter {
if self.resolve_instr_types(&i.i).is_none() {
redo_new.push(i);
}
}
std::mem::swap(&mut redo_iter, &mut redo_new);
redo_new.clear();
}
}
}
pub fn resolve_instr_types(&mut self, i: &UInstruction) -> Option<()> {
'outer: {
match &i {
UInstruction::Call { dest, f, args } => {
let fun = self.get_fn_var(f.id).expect("bruh");
self.expect_mut(dest.id).ty = fun.ret.clone();
for (src, &dest) in args.iter().zip(&fun.args) {
let dest_ty = self.get_type(dest)?;
let src_ty = self.get_type(src.id)?;
if let Some(ty) = self.match_types(dest_ty, src_ty) {
self.expect_mut(dest).ty = ty.clone();
set(vars, dest, ty.clone());
set(vars, src.id, ty);
}
}
}
UInstruction::Mv { dest, src } => {
let dest_ty = get(vars, dest.id)?;
let src_ty = get(vars, src.id)?;
if let Some(ty) = self.match_types(dest_ty, src_ty) {
set(vars, dest.id, ty.clone());
set(vars, src.id, ty);
}
}
UInstruction::Ref { dest, src } => {
let dest_ty = get(vars, dest.id)?;
let src_ty = get(vars, src.id)?;
let Type::Ref(dest_ty) = dest_ty else {
break 'outer;
};
if let Some(ty) = self.match_types(dest_ty, src_ty) {
set(vars, dest.id, ty.clone().rf());
set(vars, src.id, ty);
}
}
UInstruction::LoadData { dest, src } => {
// TODO
}
UInstruction::LoadSlice { dest, src } => {
// TODO
}
UInstruction::LoadFn { dest, src } => {
// TODO
}
UInstruction::AsmBlock { instructions, args } => {
// TODO
}
UInstruction::Ret { .. } => {}
UInstruction::Construct { dest, fields } => {
let dest_ty = get(vars, dest.id)?;
let Type::Struct(sty) = dest_ty else {
break 'outer;
};
let id = sty.id;
let Some(struc) = self.get(id) else {
break 'outer;
};
let mut new = HashMap::new();
for (name, field) in &struc.fields {
let Some(src) = fields.get(name) else {
continue;
};
let src_ty = get(vars, src.id)?;
if let Some(ty) = self.match_types(&field.ty, src_ty) {
if let Type::Generic { id } = field.ty {
new.insert(id, ty.clone());
}
set(vars, src.id, ty);
}
}
let mut args: Vec<_> = struc
.generics
.iter()
.map(|&id| Type::Generic { id })
.collect();
for (i, g) in struc.generics.iter().enumerate() {
if let Some(ty) = new.remove(g) {
args[i] = ty;
}
}
set(vars, dest.id, Type::Struct(StructTy { id, args }));
}
UInstruction::If { cond, body: _ } => {}
UInstruction::Loop { body: _ } => {}
UInstruction::Break => {}
UInstruction::Continue => {}
}
}
Some(())
}
pub fn match_types<'a>(&'a self, mut dest: &'a Type, mut src: &'a Type) -> Option<Type> {
dest = self.follow_type(dest)?;
src = self.follow_type(src)?;
if dest == src {
return None;
}
match (dest, src) {
(Type::Error, _) | (_, Type::Error) => None,
(Type::Placeholder, _) | (_, Type::Placeholder) => None,
(Type::Infer, Type::Infer) => 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 bx(self) -> Box<Self> {
Box::new(self)
}
}
pub trait TypeIDed {
fn type_id(&self, vars: &[UVar]) -> TypeID;
}
impl TypeIDed for TypeID {
fn type_id(&self, _: &[UVar]) -> TypeID {
*self
}
}
impl TypeIDed for &TypeID {
fn type_id(&self, _: &[UVar]) -> TypeID {
**self
}
}
impl TypeIDed for VarID {
fn type_id(&self, vars: &[UVar]) -> TypeID {
vars[self].ty
}
}
impl TypeIDed for VarInst {
fn type_id(&self, vars: &[UVar]) -> TypeID {
self.id.type_id(vars)
}
}
impl TypeIDed for &VarInst {
fn type_id(&self, vars: &[UVar]) -> TypeID {
self.id.type_id(vars)
}
}