uh oh, I need to actually switch to struct subvars and resolve pointer variables

This commit is contained in:
2025-04-26 22:15:36 -04:00
parent 71598a4afa
commit a087af505e
18 changed files with 205 additions and 200 deletions

View File

@@ -38,10 +38,9 @@ impl 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)
pub fn id<K: Kind>(&self, path: &[String], name: &str) -> Option<ID<K>> {
self.get(&path)?.ids[K::INDEX]
.get(name)
.copied()
.map(ID::new)
}
@@ -82,8 +81,8 @@ impl NameMap {
}
path
}
pub fn id<K: Kind>(&self, path: &[String]) -> Option<ID<K>> {
Some(self.tree.id(path)?)
pub fn id<K: Kind>(&self, path: &[String], name: &str) -> Option<ID<K>> {
Some(self.tree.id(path, name)?)
}
pub fn push<K: Kind>(&mut self, path: &[String]) {
let id = self.names[K::INDEX].len();

View File

@@ -1,12 +1,12 @@
use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
use super::{Type, UProgram};
use super::{UProgram, Type};
impl CompilerOutput {
pub fn check_assign(&mut self, p: &UProgram, src: &Type, dest: &Type, span: FileSpan) {
// TODO: spans
if src != dest {
if !src.is_real() || !dest.is_real() {
if !src.is_resolved() || !dest.is_resolved() {
return;
}
self.err(CompilerMsg {

View File

@@ -9,6 +9,7 @@ pub struct VarInst {
pub span: FileSpan,
}
#[derive(Clone)]
pub struct UInstrInst {
pub i: UInstruction,
pub span: FileSpan,

View File

@@ -3,6 +3,7 @@ use std::{collections::HashMap, fmt::Write};
use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, UFunc, UInstrInst};
use crate::{compiler::arch::riscv::Reg, util::Padder};
#[derive(Clone)]
pub enum UInstruction {
Mv {
dest: VarInst,
@@ -51,14 +52,14 @@ pub enum UInstruction {
Continue,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct AsmBlockArg {
pub var: VarInst,
pub reg: Reg,
pub ty: AsmBlockArgType,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum AsmBlockArgType {
In,
Out,

View File

@@ -5,6 +5,7 @@ use crate::{
};
use std::{collections::HashMap, fmt::Debug};
#[derive(Clone)]
pub struct UFunc {
pub args: Vec<VarID>,
pub ret: Type,
@@ -128,7 +129,7 @@ pub type GenericID = ID<UGeneric>;
impl Finish for UFunc {
fn finish(p: &mut UProgram, id: ID<Self>, name: &str) {
let var = p.def_searchable(
name.to_string(),
name,
Some(UVar {
ty: Type::Placeholder,
}),

View File

@@ -12,6 +12,7 @@ pub struct UProgram {
pub names: NameMap,
pub origins: OriginMap,
pub fn_var: FnVarMap,
// utils for creation
pub path: Vec<String>,
pub name_stack: Vec<HashMap<String, Idents>>,
pub temp: usize,
@@ -29,10 +30,14 @@ impl UProgram {
origins: OriginMap::new(),
fn_var: FnVarMap::new(),
path: Vec::new(),
name_stack: vec![HashMap::new()],
name_stack: Vec::new(),
temp: 0,
}
}
pub fn set_module(&mut self, path: Vec<String>) {
self.path = path;
self.name_stack = vec![HashMap::new()];
}
pub fn push(&mut self) {
self.name_stack.push(HashMap::new());
}
@@ -72,12 +77,16 @@ impl UProgram {
self.fns[self.fn_var.fun(id)?.0].as_ref()
}
pub fn temp_var(&mut self, origin: Origin, ty: Type) -> VarInst {
pub fn temp_var(&mut self, origin: Origin, ty: impl Into<Type>) -> VarInst {
self.temp_var_inner(origin, ty)
}
fn temp_var_inner(&mut self, origin: Origin, ty: Type) -> VarInst {
let v = self.def(&format!("temp{}", self.temp), Some(UVar { ty }), origin);
fn temp_var_inner(&mut self, origin: Origin, ty: impl Into<Type>) -> VarInst {
let v = self.def(
&format!("temp{}", self.temp),
Some(UVar { ty: ty.into() }),
origin,
);
self.temp += 1;
VarInst {
id: v,
@@ -110,48 +119,86 @@ impl UProgram {
pub fn def_searchable<K: Kind + Finish>(
&mut self,
name: String,
name: &str,
k: Option<K>,
origin: Origin,
) -> ID<K> {
let id = self.def(&name, k, origin);
self.name_on_stack(id, name);
self.name_on_stack(id, name.to_string());
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> {
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]);
}
pub fn struct_field_type<'a>(&'a self, sty: &'a StructTy, field: &str) -> Option<&'a Type> {
let struc = self.get(sty.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(&sty.args[i]);
}
}
Some(&field.ty)
} else if let Type::Module(path) = sty {
let id = self.names.id::<UVar>(path)?;
}
Some(&field.ty)
}
pub fn field_type<'a>(&'a self, ty: &'a Type, field: &str) -> Option<&'a Type> {
if let Type::Struct(sty) = ty {
self.struct_field_type(sty, field)
} else if let Type::Module(path) = ty {
let id = self.names.id::<UVar>(path, field)?;
Some(&self.get(id)?.ty)
} else {
None
}
}
pub fn follow_ref(&self, m: &FieldRef) -> Option<&Type> {
let parent = self.get(m.parent)?;
self.field_type(self.follow_type(&parent.ty)?, &m.name)
}
pub fn get_type<'a>(&'a self, v: VarID) -> Option<&'a Type> {
self.follow_type(&self.get(v)?.ty)
}
pub fn set_type(&mut self, mut var: VarID, set: Type) -> Option<()> {
let mut path = Vec::new();
while let Type::Field(parent) = &self.get(var)?.ty {
var = parent.parent;
path.push(parent.name.clone());
}
let mut ty = &mut self.vars[var.0].as_mut()?.ty;
'outer: while let Type::Struct(sty) = ty {
let Some(name) = path.pop() else {
break;
};
let struc = &self.structs[sty.id.0].as_ref()?;
let field = struc.fields.get(&name)?;
let Type::Generic { id } = field.ty else {
return None;
};
for (i, g) in struc.generics.iter().enumerate() {
if *g == id {
ty = &mut sty.args[i];
continue 'outer;
}
}
return None;
}
*ty = set;
Some(())
}
pub fn follow_type<'a>(&'a self, ty: &'a Type) -> Option<&'a Type> {
match ty {
Type::Field(m) => {
let parent = self.get(m.parent)?;
self.field_type(self.follow_type(&parent.ty)?, &m.name)
}
ty => Some(ty),
}
}
pub fn type_name(&self, ty: &Type) -> String {
let mut str = String::new();
match ty {
@@ -183,29 +230,29 @@ impl UProgram {
Type::Ref(t) => {
str = str + "&" + &self.type_name(t);
}
Type::Error => str += "{error}",
Type::Infer => str += "{inferred}",
Type::Generic { id } => str += self.names.name(*id),
Type::Bits(size) => str += &format!("b{}", size),
Type::Array(t, len) => str += &format!("[{}; {len}]", self.type_name(t)),
Type::Unit => str += "()",
Type::Slice(t) => str += &format!("&[{}]", self.type_name(t)),
Type::Error => str += "{error}",
Type::Infer => str += "{inferred}",
Type::Placeholder => str += "{placeholder}",
Type::Module(path) => str += &path.join("::"),
Type::Member(m) => {
Type::Field(m) => {
str += &self
.ref_ty(m)
.follow_ref(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_var(&self, path: &NamePath, name: &str) -> Option<VarID> {
self.names.id(path, name)
}
pub fn path_ty(&self, path: &NamePath) -> Option<&Type> {
Some(&self.get(self.path_var(path)?)?.ty)
pub fn path_ty(&self, path: &NamePath, name: &str) -> Option<&Type> {
Some(&self.get(self.path_var(path, name)?)?.ty)
}
fn name_on_stack<K: Kind>(&mut self, id: ID<K>, name: String) {
let idx = self.name_stack.len() - 1;
@@ -230,4 +277,11 @@ impl UProgram {
.enumerate()
.map(|(i, x)| (ID::new(i), x))
}
pub fn cloned_fns(&self) -> impl Iterator<Item = (FnID, UFunc)> + use<'_> {
self.fns
.iter()
.flatten()
.enumerate()
.map(|(i, x)| (ID::new(i), x.clone()))
}
}

View File

@@ -3,7 +3,7 @@ use std::collections::HashMap;
use super::{assoc::NamePath, GenericID, Len, StructID, UInstruction, UProgram, UVar, VarID};
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct MemberRef {
pub struct FieldRef {
pub parent: VarID,
pub name: String,
}
@@ -18,54 +18,55 @@ pub struct StructTy {
pub enum Type {
Bits(u32),
Struct(StructTy),
// is this real? I don't know, it's kind of like infer
Generic { id: GenericID },
Fn { args: Vec<Type>, ret: Box<Type> },
Ref(Box<Type>),
Slice(Box<Type>),
Array(Box<Type>, Len),
Member(MemberRef),
Unit,
// fake types
Field(FieldRef),
Module(NamePath),
Infer,
Error,
Placeholder,
Unit,
}
impl Type {
pub fn is_resolved(&self) -> bool {
!matches!(self, Self::Error | Self::Placeholder | Self::Infer)
}
pub fn rf(self) -> Self {
Self::Ref(Box::new(self))
Type::Ref(Box::new(self))
}
pub fn arr(self, len: Len) -> Self {
Self::Array(Box::new(self), len)
Type::Array(Box::new(self), len)
}
pub fn slice(self) -> Self {
Self::Slice(Box::new(self))
}
pub fn is_real(&self) -> bool {
!matches!(self, Self::Error | Self::Placeholder | Self::Infer)
Type::Slice(Box::new(self))
}
}
impl UProgram {
pub fn resolve_types(&mut self) {
// I LOVE RUST
let mut vars = self.vars.clone();
// set type of vars referring to functions
for (i, f) in self.iter_fns() {
let vi = self.fn_var.var(i);
vars[vi.0].as_mut().expect("bruh").ty = f.ty(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 self.iter_fns() {
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(&mut vars, &i.i).is_none() {
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(&mut vars, &i.i).is_none() {
if self.resolve_instr_types(&i.i).is_none() {
redo_new.push(i);
}
}
@@ -73,19 +74,19 @@ impl UProgram {
redo_new.clear();
}
}
self.vars = vars;
}
pub fn resolve_instr_types(&self, vars: &mut [Option<UVar>], i: &UInstruction) -> Option<()> {
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");
vars[dest.id.0].as_mut().expect("bruh").ty = fun.ret.clone();
self.expect_mut(dest.id).ty = fun.ret.clone();
for (src, &dest) in args.iter().zip(&fun.args) {
let dest_ty = get(vars, dest)?;
let src_ty = get(vars, src.id)?;
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);
}
@@ -166,13 +167,16 @@ impl UProgram {
Some(())
}
pub fn match_types(&self, dest: &Type, src: &Type) -> Option<Type> {
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()),
@@ -223,33 +227,3 @@ impl UProgram {
}
}
}
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 None;
}
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) {
vars[id.0]
.as_mut()
.expect("PARTIAL BORROWING WOULD BE REALLY COOL")
.ty = ty;
}

View File

@@ -1,4 +1,3 @@
// TODO: move this into ir, not parser
use super::{Type, UInstrInst, UInstruction, UProgram};
use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
@@ -33,17 +32,6 @@ impl UProgram {
spans: vec![self.origins.get(id)],
});
}
if let Some(parent) = &var.parent {
let pty = &self.get(parent.var).unwrap().ty;
if let Some(ft) = self.field_type(pty, &parent.field) {
output.check_assign(self, &var.ty, ft, self.origins.get(id));
} else {
output.err(CompilerMsg {
msg: "invalid parent!".to_string(),
spans: vec![self.origins.get(id)],
});
}
}
}
}
@@ -108,6 +96,7 @@ impl UProgram {
UInstruction::AsmBlock { instructions, args } => {
for arg in args {
// TODO: validate size with enabled targets
// maybe should happen in lowering? but I think it could happen here
// if let Some(size) = self.size_of_var(arg.var.id)
// && size != 64
// {
@@ -125,8 +114,8 @@ impl UProgram {
}
UInstruction::Construct { dest, fields } => {
let dest_def = self.expect(dest.id);
let (tyid, args) = match &dest_def.ty {
Type::Struct { id, args } => (*id, args),
let sty = match &dest_def.ty {
Type::Struct(sty) => sty,
_ => {
output.err(CompilerMsg {
msg: format!(
@@ -138,19 +127,19 @@ impl UProgram {
continue;
}
};
let def = self.expect(tyid);
let def = self.expect(sty.id);
for (name, field) in &def.fields {
if let Some(var) = fields.get(name) {
let mut sty = &field.ty;
if let Type::Generic { id } = sty {
for (g, a) in def.generics.iter().zip(args) {
let mut fty = &field.ty;
if let Type::Generic { id } = fty {
for (g, a) in def.generics.iter().zip(&sty.args) {
if *g == *id {
sty = a;
fty = a;
}
}
}
let ety = &self.expect(var.id).ty;
output.check_assign(self, ety, sty, var.span);
output.check_assign(self, ety, fty, var.span);
} else {
output.err(CompilerMsg {
msg: format!("field '{}' missing from struct", name),