calculations have been made

This commit is contained in:
2025-05-09 15:16:54 -04:00
parent 4586361000
commit 11ab9285f1
13 changed files with 410 additions and 423 deletions

28
ideas
View File

@@ -1,5 +1,28 @@
move names into separate vec with origins resolution overview
make struct fields a vec, resolve into index loop {
resolve idents
resolve + type check / match instructions
URes.resolve(errs) can return: failed, ok(id), waiting
each instruction keeps track of progress
eg. fns: match each arg
updates to whether it's waiting or finished: ok or err
only finish if no sub tasks are waiting
finished = "macro ready"
run macros / code modification on "macro ready" (fns, structs)
eg. insert instructions
hygienic; only take in from scope
add inserted instructions to unresolved list
finished = "analysis ready"
analysis on "analysis ready" fns
eg. does this return in all code paths
finished + all correct = "ready to lower"
lower "ready to lower" fns
run lowered const fns / var expressions
}
move names into separate vec with origins?
make struct fields a vec, resolve to index?
inner values that auto generate map function: inner values that auto generate map function:
enum Thing<inner T> { enum Thing<inner T> {
@@ -10,6 +33,7 @@ inner values that auto generate map function:
or or
#[derive(Map(T))] #[derive(Map(T))]
enum Thing<T> { ... } enum Thing<T> { ... }
// scoping here is bad :woozy:
{([< {([<

View File

@@ -428,7 +428,7 @@ impl LFunctionBuilderData<'_> {
Type::Generic(id) => return None, Type::Generic(id) => return None,
// function references are resolved at compile time into direct calls, // function references are resolved at compile time into direct calls,
// so they don't have any size as arguments // so they don't have any size as arguments
Type::FnRef(fi) => 0, Type::FnInst(fi) => 0,
Type::Ref(_) => self.addr_size(), Type::Ref(_) => self.addr_size(),
Type::Array(ty, len) => self.size_of_type(p, ty)? * len, Type::Array(ty, len) => self.size_of_type(p, ty)? * len,
Type::Slice(_) => self.addr_size() * 2, Type::Slice(_) => self.addr_size() * 2,

View File

@@ -12,6 +12,10 @@ pub struct UIdent {
pub enum IdentStatus { pub enum IdentStatus {
Res(Res), Res(Res),
// lets you do things like import and then specialize in multiple places
// eg. import SomeStruct ...... f() -> SomeStruct // type ....... SomeStruct {} // struct
// and then have correct errors like "expected struct, found type Bla"
Ref(IdentID),
Unres { Unres {
base: ResBase, base: ResBase,
path: Vec<MemberIdent>, path: Vec<MemberIdent>,

View File

@@ -12,10 +12,10 @@ pub trait ResStage {
pub struct Unresolved; pub struct Unresolved;
impl ResStage for Unresolved { impl ResStage for Unresolved {
type Var = IdentID; type Var = VarRes;
type Func = IdentID; type Func = IdentID;
type Struct = IdentID; type Struct = IdentID;
type Type = IdentID; type Type = TypeRes;
} }
pub struct Resolved; pub struct Resolved;
@@ -66,10 +66,10 @@ pub enum UInstruction<S: ResStage = Unresolved> {
}, },
If { If {
cond: S::Var, cond: S::Var,
body: Vec<UInstrInst<S>>, body: Vec<InstrID>,
}, },
Loop { Loop {
body: Vec<UInstrInst<S>>, body: Vec<InstrID>,
}, },
Break, Break,
Continue, Continue,

View File

@@ -20,18 +20,22 @@ pub type GenericID = ID<UGeneric>;
pub type StructID = ID<UStruct>; pub type StructID = ID<UStruct>;
pub type DataID = ID<UData>; pub type DataID = ID<UData>;
pub type ModID = ID<UModule>; pub type ModID = ID<UModule>;
pub type InstrID = ID<UInstrInst>;
pub type VarRes = URes<VarID>;
pub type TypeRes = URes<VarID>;
pub struct UFunc { pub struct UFunc {
pub name: String, pub name: String,
pub origin: Origin, pub origin: Origin,
pub args: Vec<VarID>, pub args: Vec<VarID>,
pub gargs: Vec<GenericID>, pub gargs: Vec<GenericID>,
pub ret: TypeID, pub ret: TypeRes,
pub instructions: Vec<UInstrInst>, pub instructions: Vec<InstrID>,
} }
pub struct StructField { pub struct StructField {
pub ty: TypeID, pub ty: TypeRes,
pub origin: Origin, pub origin: Origin,
// pub vis: Visibility // pub vis: Visibility
} }
@@ -51,11 +55,16 @@ pub struct UGeneric {
pub struct UVar { pub struct UVar {
pub name: String, pub name: String,
pub origin: Origin, pub origin: Origin,
pub ty: TypeID, pub ty: TypeRes,
pub parent: Option<VarID>, pub parent: Option<VarID>,
pub children: HashMap<String, VarID>, pub children: HashMap<String, VarID>,
} }
pub enum VarTy {
Ident(IdentID),
Res(TypeID),
}
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
pub struct VarOffset { pub struct VarOffset {
pub id: VarID, pub id: VarID,
@@ -120,6 +129,11 @@ impl MemberID {
} }
} }
pub enum URes<T> {
Res(T),
Unres(IdentID),
}
pub type Origin = FileSpan; pub type Origin = FileSpan;
// "effective" (externally visible) kinds // "effective" (externally visible) kinds
@@ -145,37 +159,3 @@ impl Display for KindTy {
}) })
} }
} }
impl UFunc {
pub fn flat_iter(&self) -> impl Iterator<Item = &UInstrInst> {
InstrIter::new(self.instructions.iter())
}
}
pub struct InstrIter<'a> {
iters: Vec<core::slice::Iter<'a, UInstrInst>>,
}
impl<'a> InstrIter<'a> {
pub fn new(iter: core::slice::Iter<'a, UInstrInst>) -> Self {
Self { iters: vec![iter] }
}
}
impl<'a> Iterator for InstrIter<'a> {
type Item = &'a UInstrInst;
fn next(&mut self) -> Option<Self::Item> {
let iter = self.iters.last_mut()?;
let Some(next) = iter.next() else {
self.iters.pop();
return self.next();
};
match &next.i {
UInstruction::Loop { body } => self.iters.push(body.iter()),
UInstruction::If { cond: _, body } => self.iters.push(body.iter()),
_ => (),
}
Some(next)
}
}

View File

@@ -1,5 +1,4 @@
use super::*; use super::*;
use std::collections::HashMap;
pub struct UProgram { pub struct UProgram {
pub fns: Vec<UFunc>, pub fns: Vec<UFunc>,
@@ -10,8 +9,10 @@ pub struct UProgram {
pub vars: Vec<UVar>, pub vars: Vec<UVar>,
pub idents: Vec<UIdent>, pub idents: Vec<UIdent>,
pub types: Vec<Type>, pub types: Vec<Type>,
pub instrs: Vec<UInstrInst>,
pub vfmap: HashMap<VarID, FnID>, pub unres_idents: Vec<IdentID>,
pub unres_instrs: Vec<(FnID, InstrID)>,
pub tc: TypeCache, pub tc: TypeCache,
} }
@@ -24,7 +25,7 @@ impl UProgram {
pub fn new() -> Self { pub fn new() -> Self {
let mut types = Vec::new(); let mut types = Vec::new();
let tc = TypeCache { let tc = TypeCache {
unit: push_id(&mut types, Type::Real(RType::Unit)), unit: push_id(&mut types, Type::Unit),
error: push_id(&mut types, Type::Error), error: push_id(&mut types, Type::Error),
}; };
Self { Self {
@@ -36,13 +37,15 @@ impl UProgram {
generics: Vec::new(), generics: Vec::new(),
data: Vec::new(), data: Vec::new(),
modules: Vec::new(), modules: Vec::new(),
vfmap: HashMap::new(), instrs: Vec::new(),
unres_idents: Vec::new(),
unres_instrs: Vec::new(),
tc, tc,
} }
} }
pub fn infer(&mut self) -> TypeID { pub fn infer(&mut self) -> TypeID {
self.def_ty(RType::Infer.ty()) self.def_ty(Type::Infer)
} }
pub fn def_var(&mut self, v: UVar) -> VarID { pub fn def_var(&mut self, v: UVar) -> VarID {
@@ -58,7 +61,11 @@ impl UProgram {
} }
pub fn def_ident(&mut self, i: UIdent) -> IdentID { pub fn def_ident(&mut self, i: UIdent) -> IdentID {
push_id(&mut self.idents, i) let id = push_id(&mut self.idents, i);
if let IdentStatus::Unres { .. } = self.idents[id].status {
self.unres_idents.push(id);
}
id
} }
pub fn def_generic(&mut self, g: UGeneric) -> GenericID { pub fn def_generic(&mut self, g: UGeneric) -> GenericID {
@@ -77,17 +84,20 @@ impl UProgram {
push_id(&mut self.modules, m) push_id(&mut self.modules, m)
} }
pub fn res_ty(&self, i: IdentID) -> Option<TypeID> {
self.idents[i].status;
}
pub fn type_name(&self, ty: impl Typed) -> String { pub fn type_name(&self, ty: impl Typed) -> String {
match ty.ty(self) { match ty.ty(self) {
Type::Real(rty) => match rty { Type::Struct(ty) => {
RType::Struct(ty) => {
format!( format!(
"{}{}", "{}{}",
self.structs[ty.id].name, self.structs[ty.id].name,
self.gparams_str(&ty.gargs) self.gparams_str(&ty.gargs)
) )
} }
RType::FnRef(ty) => { Type::FnInst(ty) => {
format!( format!(
"fn{}({}) -> {}", "fn{}({}) -> {}",
&self.gparams_str(&ty.gargs), &self.gparams_str(&ty.gargs),
@@ -95,17 +105,15 @@ impl UProgram {
&self.type_name(self.fns[ty.id].ret) &self.type_name(self.fns[ty.id].ret)
) )
} }
RType::Ref(t) => format!("{}&", self.type_name(t)), Type::Ref(t) => format!("{}&", self.type_name(t)),
RType::Deref(t) => format!("{}^", self.type_name(t)), Type::Bits(size) => format!("b{}", size),
RType::Bits(size) => format!("b{}", size), Type::Array(t, len) => format!("[{}; {len}]", self.type_name(t)),
RType::Array(t, len) => format!("[{}; {len}]", self.type_name(t)), Type::Unit => "()".to_string(),
RType::Unit => "()".to_string(), Type::Slice(t) => format!("&[{}]", self.type_name(t)),
RType::Slice(t) => format!("&[{}]", self.type_name(t)), Type::Infer => "{inferred}".to_string(),
RType::Infer => "{inferred}".to_string(),
},
Type::Error => "{error}".to_string(),
Type::Unres(_) => "{unresolved}".to_string(),
Type::Generic(id) => self.generics[id].name.clone(), Type::Generic(id) => self.generics[id].name.clone(),
Type::Deref(t) => format!("{}^", self.type_name(t)),
Type::Error => "{error}".to_string(),
Type::Ptr(id) => self.type_name(id), Type::Ptr(id) => self.type_name(id),
} }
} }

View File

@@ -1,7 +1,4 @@
use crate::{ use crate::common::{CompilerMsg, CompilerOutput};
common::{CompilerMsg, CompilerOutput},
ir::RType,
};
use super::{ use super::{
IdentStatus, KindTy, MemberTy, Origin, Res, ResBase, StructID, Type, TypeID, UProgram, IdentStatus, KindTy, MemberTy, Origin, Res, ResBase, StructID, Type, TypeID, UProgram,
@@ -119,8 +116,9 @@ pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, mut errs: Vec<ResE
} }
} }
for var in &p.vars { for var in &p.vars {
match &p.types[var.ty] { if let Some(ty) = var.ty() {
Type::Real(RType::Infer) => output.err(CompilerMsg::new( match &p.types[ty] {
Type::Infer => output.err(CompilerMsg::new(
format!("Type of {:?} cannot be inferred", var.name), format!("Type of {:?} cannot be inferred", var.name),
var.origin, var.origin,
)), )),
@@ -128,6 +126,7 @@ pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, mut errs: Vec<ResE
} }
} }
} }
}
#[derive(Clone)] #[derive(Clone)]
pub enum ResErr { pub enum ResErr {

View File

@@ -1,5 +1,110 @@
use super::*; use super::*;
impl UProgram {
pub fn resolve_idents(&mut self, errs: &mut Vec<ResErr>) -> ResolveRes {
let mut resolve_res = ResolveRes::Finished;
'main: for i in std::mem::take(&mut self.unres_idents) {
let mut j = i;
// take from ref if possible
while let IdentStatus::Ref(other) = &self.idents[j].status {
match &self.idents[other].status {
IdentStatus::Res(res) => self.idents[i].status = IdentStatus::Res(res.clone()),
&IdentStatus::Ref(id) => j = id,
IdentStatus::Unres { .. } => {
self.unres_idents.push(i);
continue 'main;
}
IdentStatus::Failed(..) => self.idents[i].status = IdentStatus::Cooked,
IdentStatus::Cooked => self.idents[i].status = IdentStatus::Cooked,
}
}
let status = &mut self.idents[i].status;
// TOOD: there are some clones here that shouldn't be needed
let IdentStatus::Unres { path, base } = status else {
continue;
};
while let Some(mem) = path.pop() {
let res = match base {
ResBase::Unvalidated(u) => {
match u.validate(
&self.fns,
&self.structs,
&self.generics,
&mut self.types,
errs,
) {
Ok(res) => res,
Err(err) => {
*status = IdentStatus::Failed(err);
continue 'main;
}
}
}
ResBase::Validated(res) => res.clone(),
};
*base = match (res, mem.ty) {
(Res::Module(id), MemberTy::Member) => {
let Some(m) = self.modules[id].members.get(&mem.name) else {
self.unres_idents.push(i);
continue 'main;
};
ResBase::Unvalidated(MemRes {
mem: m.clone(),
origin: mem.origin,
gargs: mem.gargs,
})
}
(Res::Var(id), MemberTy::Field) => {
// trait resolution here
let Some(&child) = self.vars[id].children.get(&mem.name) else {
self.unres_idents.push(i);
continue 'main;
};
ResBase::Unvalidated(MemRes {
mem: Member {
id: MemberID::Var(child),
},
origin: mem.origin,
gargs: mem.gargs,
})
}
_ => {
*status = IdentStatus::Failed(Some(ResErr::UnknownMember {
origin: mem.origin,
ty: mem.ty,
name: mem.name.clone(),
parent: base.clone(),
}));
continue 'main;
}
};
}
let res = match base {
ResBase::Unvalidated(u) => {
match u.validate(
&self.fns,
&self.structs,
&self.generics,
&mut self.types,
errs,
) {
Ok(res) => res,
Err(err) => {
*status = IdentStatus::Failed(err);
continue 'main;
}
}
}
ResBase::Validated(res) => res.clone(),
};
*status = IdentStatus::Res(res);
resolve_res = ResolveRes::Unfinished;
}
resolve_res
}
}
impl MemRes { impl MemRes {
pub fn validate( pub fn validate(
&self, &self,
@@ -66,89 +171,6 @@ impl MemRes {
} }
} }
impl IdentID {
pub fn resolve(
self,
s: &mut Sources,
types: &mut Vec<Type>,
changed: &mut bool,
errs: &mut Vec<ResErr>,
) -> Result<Res, ResolveRes> {
let status = &mut s.idents[self].status;
// TOOD: there are some clones here that shouldn't be needed
Ok(match status {
IdentStatus::Res(r) => r.clone(),
IdentStatus::Unres { path, base } => {
while let Some(mem) = path.pop() {
let res = match base {
ResBase::Unvalidated(u) => {
match u.validate(s.fns, s.structs, s.generics, types, errs) {
Ok(res) => res,
Err(err) => {
*status = IdentStatus::Failed(err);
return Err(ResolveRes::Finished);
}
}
}
ResBase::Validated(res) => res.clone(),
};
*base = match (res, mem.ty) {
(Res::Module(id), MemberTy::Member) => {
let Some(m) = s.modules[id].members.get(&mem.name) else {
return Err(ResolveRes::Unfinished);
};
ResBase::Unvalidated(MemRes {
mem: m.clone(),
origin: mem.origin,
gargs: mem.gargs,
})
}
(Res::Var(id), MemberTy::Field) => {
// trait resolution here
let Some(&child) = s.vars[id].children.get(&mem.name) else {
return Err(ResolveRes::Unfinished);
};
ResBase::Unvalidated(MemRes {
mem: Member {
id: MemberID::Var(child),
},
origin: mem.origin,
gargs: mem.gargs,
})
}
_ => {
*status = IdentStatus::Failed(Some(ResErr::UnknownMember {
origin: mem.origin,
ty: mem.ty,
name: mem.name.clone(),
parent: base.clone(),
}));
return Err(ResolveRes::Finished);
}
};
}
let res = match base {
ResBase::Unvalidated(u) => {
match u.validate(s.fns, s.structs, s.generics, types, errs) {
Ok(res) => res,
Err(err) => {
*status = IdentStatus::Failed(err);
return Err(ResolveRes::Finished);
}
}
}
ResBase::Validated(res) => res.clone(),
};
*status = IdentStatus::Res(res.clone());
*changed = true;
res
}
IdentStatus::Cooked => return Err(ResolveRes::Finished),
IdentStatus::Failed(_) => return Err(ResolveRes::Finished),
})
}
}
pub fn validate_gargs( pub fn validate_gargs(
dst: &[GenericID], dst: &[GenericID],
src: &[TypeID], src: &[TypeID],
@@ -171,4 +193,3 @@ pub fn validate_gargs(
} }
Ok(()) Ok(())
} }

View File

@@ -10,13 +10,13 @@ pub fn inst_fn_var(
types: &mut Vec<Type>, types: &mut Vec<Type>,
) -> VarID { ) -> VarID {
let name = fns[fi.id].name.clone(); let name = fns[fi.id].name.clone();
let ty = push_id(types, RType::FnRef(fi).ty()); let ty = push_id(types, Type::FnInst(fi));
push_id( push_id(
vars, vars,
UVar { UVar {
name, name,
origin, origin,
ty, ty: VarTy::Res(ty),
parent: None, parent: None,
children: HashMap::new(), children: HashMap::new(),
}, },
@@ -31,53 +31,20 @@ pub fn inst_struct_var(
types: &mut Vec<Type>, types: &mut Vec<Type>,
) -> VarID { ) -> VarID {
let name = structs[si.id].name.clone(); let name = structs[si.id].name.clone();
let ty = push_id(types, RType::Struct(si).ty()); let ty = push_id(types, Type::Struct(si));
let id = push_id( let id = push_id(
vars, vars,
UVar { UVar {
name, name,
origin, origin,
ty, ty: VarTy::Res(ty),
parent: None, parent: None,
children: HashMap::new(), children: HashMap::new(),
}, },
); );
inst_var(vars, structs, id, types);
id id
} }
pub fn inst_var(vars: &mut Vec<UVar>, structs: &[UStruct], id: VarID, types: &mut Vec<Type>) {
match real_type(types, vars[id].ty) {
RType::Struct(si) => {
let fields = &structs[si.id].fields;
let s_gargs = &structs[si.id].gargs;
let gmap = inst_gmap(s_gargs, &si.gargs);
let children = fields
.iter()
.map(|(name, f)| {
(name.clone(), {
let ty = inst_type(f.ty, types, &gmap);
let fid = push_id(
vars,
UVar {
name: name.clone(),
origin: f.origin,
ty,
parent: Some(id),
children: HashMap::new(),
},
);
inst_var(vars, structs, fid, types);
fid
})
})
.collect();
vars[id].children = children;
}
_ => (),
}
}
/// gargs assumed to be valid /// gargs assumed to be valid
pub fn inst_typedef(def: &TypeDef, gargs: &[TypeID], types: &mut Vec<Type>) -> TypeID { pub fn inst_typedef(def: &TypeDef, gargs: &[TypeID], types: &mut Vec<Type>) -> TypeID {
let gmap = inst_gmap(&def.gargs, &gargs); let gmap = inst_gmap(&def.gargs, &gargs);
@@ -108,32 +75,23 @@ fn inst_type_(
gmap: &HashMap<GenericID, TypeID>, gmap: &HashMap<GenericID, TypeID>,
) -> Option<TypeID> { ) -> Option<TypeID> {
let ty = match types[id].clone() { let ty = match types[id].clone() {
Type::Real(rty) => match rty { Type::Bits(_) => return None,
RType::Bits(_) => return None, Type::Struct(struct_ty) => Type::Struct(StructInst {
RType::Struct(struct_ty) => RType::Struct(StructInst {
id: struct_ty.id, id: struct_ty.id,
gargs: inst_all(&struct_ty.gargs, types, gmap)?, gargs: inst_all(&struct_ty.gargs, types, gmap)?,
}), }),
RType::FnRef(fn_ty) => RType::FnRef(FnInst { Type::FnInst(fn_ty) => Type::FnInst(FnInst {
id: fn_ty.id, id: fn_ty.id,
gargs: inst_all(&fn_ty.gargs, types, gmap)?, gargs: inst_all(&fn_ty.gargs, types, gmap)?,
}), }),
RType::Ref(id) => RType::Ref(inst_type_(id, types, gmap)?), Type::Ref(id) => Type::Ref(inst_type_(id, types, gmap)?),
RType::Slice(id) => RType::Slice(inst_type_(id, types, gmap)?), Type::Slice(id) => Type::Slice(inst_type_(id, types, gmap)?),
RType::Array(id, len) => RType::Array(inst_type_(id, types, gmap)?, len), Type::Array(id, len) => Type::Array(inst_type_(id, types, gmap)?, len),
RType::Unit => return None, Type::Unit => return None,
RType::Generic(gid) => { Type::Generic(gid) => return gmap.get(&gid).map(|id| Some(*id)).unwrap_or_else(|| None),
return gmap Type::Infer => Type::Infer,
.get(&gid)
.map(|id| Some(*id))
.unwrap_or_else(|| None)
}
RType::Infer => RType::Infer,
}
.ty(),
Type::Deref(id) => Type::Deref(inst_type_(id, types, gmap)?), Type::Deref(id) => Type::Deref(inst_type_(id, types, gmap)?),
Type::Ptr(id) => Type::Ptr(inst_type_(id, types, gmap)?), Type::Ptr(id) => Type::Ptr(inst_type_(id, types, gmap)?),
Type::Unres(mod_path) => Type::Unres(mod_path.clone()),
Type::Error => return None, Type::Error => return None,
}; };
Some(push_id(types, ty)) Some(push_id(types, ty))
@@ -155,4 +113,3 @@ fn inst_all(
} }
vec vec
} }

View File

@@ -2,30 +2,79 @@ use std::collections::HashSet;
use super::*; use super::*;
pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<()> { pub enum UResEvent {
let mut res = ResolveRes::Finished; VarUse(VarID),
match &ctx.i.i {
UInstruction::Call { dst, f, args } => {
let fi = data.res_id::<UFunc>(f, ctx)?;
let f = &data.s.fns[fi.id];
for (src, &dest) in args.iter().zip(&f.args) {
res |= data.match_types::<UVar, UVar>(dest, src, src);
} }
res |= data.match_types::<UVar, Type>(dst, f.ret, dst);
impl UProgram {
pub fn resolve_instrs(&mut self, errs: &mut Vec<ResErr>) -> ResolveRes {
let mut data = ResData {
changed: false,
types: &mut self.types,
s: Sources {
idents: &mut self.idents,
vars: &mut self.vars,
fns: &self.fns,
structs: &self.structs,
generics: &self.generics,
data: &self.data,
modules: &self.modules,
},
errs,
};
for ids in std::mem::take(&mut self.unres_instrs) {
if let ResolveRes::Unfinished = resolve_instr(ids, &mut self.instrs, &mut data) {
self.unres_instrs.push(ids);
};
}
ResolveRes::Finished
}
}
#[derive(Clone, Copy)]
struct ResolveCtx {
ret: IdentID,
breakable: bool,
i: InstrID,
}
pub fn resolve_instr<'a>(
(fi, ii): (FnID, InstrID),
instrs: &mut Vec<UInstrInst>,
data: &mut ResData<'a>,
) -> ResolveRes {
let instr = &mut instrs[ii];
match &mut instr.i {
UInstruction::Call { dst, f, args } => {
let fi = data.res::<UFunc>(*f);
for &a in args {
data.res::<UVar>(a);
}
data.res::<UVar>(dst);
match fi {
Ok(fi) => {
let f = &data.s.fns[fi.id];
for (&src, &dst) in args.iter().zip(&f.args) {
data.s.constraints.push(UResEvent::AssignVVI { dst, src });
}
}
Err(r) => return r,
}
ResolveRes::Finished
} }
UInstruction::Mv { dst, src } => { UInstruction::Mv { dst, src } => {
res |= data.match_types::<UVar, UVar>(dst, src, src); res |= data.match_types::<UVar, UVar>(dst, src, src);
} }
UInstruction::Ref { dst, src } => { UInstruction::Ref { dst, src } => {
let dstty = data.res_var_ty(dst, ctx)?.0; let dstty = &data.types[data.res_var_ty(dst)?];
let &RType::Ref(dest_ty) = dstty else { let &Type::Ref(dest_ty) = dstty else {
compiler_error() compiler_error()
}; };
res |= data.match_types::<Type, UVar>(dest_ty, src, src); res |= data.match_types::<Type, UVar>(dest_ty, src, src);
} }
UInstruction::Deref { dst, src } => { UInstruction::Deref { dst, src } => {
let (srcty, srcid) = data.res_var_ty(src, ctx)?; let srcid = data.res_var_ty(src)?;
let &RType::Ref(src_ty) = srcty else { let &Type::Ref(src_ty) = data.types[srcid] else {
let origin = src.origin(data); let origin = src.origin(data);
data.errs.push(ResErr::CannotDeref { origin, ty: srcid }); data.errs.push(ResErr::CannotDeref { origin, ty: srcid });
return None; return None;
@@ -38,11 +87,11 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
} }
UInstruction::LoadSlice { dst, src } => { UInstruction::LoadSlice { dst, src } => {
let (dstty, dstid) = data.res_var_ty(dst, ctx)?; let (dstty, dstid) = data.res_var_ty(dst, ctx)?;
let &RType::Slice(dstty) = dstty else { let &Type::Slice(dstty) = dstty else {
compiler_error() compiler_error()
}; };
let srcid = src.type_id(&data.s); let srcid = src.type_id(&data.s);
let Type::Real(RType::Array(srcty, _)) = data.types[srcid] else { let Type::Array(srcty, _) = data.types[srcid] else {
compiler_error() compiler_error()
}; };
res |= data.match_types(dstty, srcty, dst); res |= data.match_types(dstty, srcty, dst);
@@ -54,7 +103,7 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
res |= data.match_types::<Type, UVar>(ctx.ret, src, src); res |= data.match_types::<Type, UVar>(ctx.ret, src, src);
} }
UInstruction::Construct { dst, struc, fields } => { UInstruction::Construct { dst, struc, fields } => {
let si = data.res_id::<UStruct>(dst, ctx)?; let si = data.res::<UStruct>(dst, ctx)?;
let sid = si.id; let sid = si.id;
let st = &data.s.structs[sid]; let st = &data.s.structs[sid];
let mut used = HashSet::new(); let mut used = HashSet::new();
@@ -130,9 +179,4 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
} }
} }
} }
match res {
ResolveRes::Finished => (),
ResolveRes::Unfinished => data.unfinished.push(ctx),
}
return None;
} }

View File

@@ -1,31 +1,33 @@
use super::*; use super::*;
pub fn match_types(data: &mut ResData, dst: impl TypeIDed, src: impl TypeIDed) -> MatchRes { pub fn match_types(data: &mut ResData, dst: TypeID, src: TypeID) -> MatchRes {
let dstid = dst.type_id(&data.s); let Some(dst) = clean_type(data.types, dst) else {
let srcid = src.type_id(&data.s); return MatchRes::Finished;
let dstty = data.real_ty(&dst)?.clone();
let srcty = data.real_ty(&src)?.clone();
let error = || {
MatchRes::Error(vec![TypeMismatch {
dst: dstid,
src: srcid,
}])
}; };
match (dstty, srcty) { let Some(src) = clean_type(data.types, src) else {
return MatchRes::Finished;
};
// prevents this from blowing up I think:
// let mut x, y;
// x = y;
// y = x;
if dst == src {
return MatchRes::Finished;
}
let error = || MatchRes::Error(vec![TypeMismatch { dst, src }]);
match (data.types[dst].clone(), data.types[src].clone()) {
// prefer changing dst over src // prefer changing dst over src
(RType::Infer, _) => { (Type::Infer, _) => {
data.changed = true; data.changed = true;
data.types[dstid] = Type::Ptr(srcid); data.types[dst] = Type::Ptr(src);
dst.finish(&mut data.s, data.types);
MatchRes::Finished MatchRes::Finished
} }
(_, RType::Infer) => { (_, Type::Infer) => {
data.changed = true; data.changed = true;
data.types[srcid] = Type::Ptr(dstid); data.types[src] = Type::Ptr(dst);
src.finish(&mut data.s, data.types);
MatchRes::Finished MatchRes::Finished
} }
(RType::Struct(dest), RType::Struct(src)) => { (Type::Struct(dest), Type::Struct(src)) => {
if dest.id != src.id { if dest.id != src.id {
return error(); return error();
} }
@@ -45,9 +47,9 @@ pub fn match_types(data: &mut ResData, dst: impl TypeIDed, src: impl TypeIDed) -
// let src = src_args.into_iter().chain(once(src_ret)); // let src = src_args.into_iter().chain(once(src_ret));
// match_all(data, dst, src) // match_all(data, dst, src)
// } // }
(RType::Ref(dest), RType::Ref(src)) => match_types(data, dest, src), (Type::Ref(dest), Type::Ref(src)) => match_types(data, dest, src),
(RType::Slice(dest), RType::Slice(src)) => match_types(data, dest, src), (Type::Slice(dest), Type::Slice(src)) => match_types(data, dest, src),
(RType::Array(dest, dlen), RType::Array(src, slen)) => { (Type::Array(dest, dlen), Type::Array(src, slen)) => {
if dlen == slen { if dlen == slen {
match_types(data, dest, src) match_types(data, dest, src)
} else { } else {
@@ -84,22 +86,14 @@ fn match_all(
} }
impl<'a> ResData<'a> { impl<'a> ResData<'a> {
pub fn match_types<Dst: ResKind, Src: ResKind>( pub fn match_types(
&mut self, &mut self,
dst: impl Resolvable<Dst>, dst: impl MaybeTypeID,
src: impl Resolvable<Src>, src: impl MaybeTypeID,
origin: impl HasOrigin, origin: impl HasOrigin,
) -> ResolveRes ) -> ResolveRes {
where let dst = dst.type_id(&self.s)?;
Dst::Res: TypeIDed, let src = src.type_id(&self.s)?;
Src::Res: TypeIDed,
{
let dst = dst
.try_res(&mut self.s, self.types, &mut self.errs, &mut self.changed)?
.type_id(&self.s);
let src = src
.try_res(&mut self.s, self.types, &mut self.errs, &mut self.changed)?
.type_id(&self.s);
let res = match_types(self, dst, src); let res = match_types(self, dst, src);
match res { match res {
MatchRes::Unfinished => ResolveRes::Unfinished, MatchRes::Unfinished => ResolveRes::Unfinished,
@@ -115,12 +109,6 @@ impl<'a> ResData<'a> {
} }
} }
} }
pub fn real_ty(&mut self, x: &impl TypeIDed) -> Result<&RType, MatchRes> {
real_type(self.types, x.type_id(&self.s)).map_err(|res| match res {
ResolveRes::Finished => MatchRes::Finished,
ResolveRes::Unfinished => MatchRes::Unfinished,
})
}
} }
pub enum MatchRes { pub enum MatchRes {
@@ -137,3 +125,22 @@ impl FromResidual<Result<Infallible, MatchRes>> for MatchRes {
} }
} }
} }
pub trait MaybeTypeID {
fn type_id(&self, s: &Sources) -> Result<TypeID, ResolveRes>;
}
impl<T: TypeIDed> MaybeTypeID for T {
fn type_id(&self, s: &Sources) -> Result<TypeID, ResolveRes> {
Ok(self.type_id(s))
}
}
impl MaybeTypeID for VarID {
fn type_id(&self, s: &Sources) -> Result<TypeID, ResolveRes> {
match s.vars[self].ty {
VarTy::Ident(id) => todo!(),
VarTy::Res(id) => Ok(id),
}
}
}

View File

@@ -9,73 +9,40 @@ use std::{
}; };
mod error; mod error;
mod instr;
mod matc;
mod ident; mod ident;
mod instantiate; mod instantiate;
mod instr;
mod matc;
pub use error::*; pub use error::*;
use instr::*;
use instantiate::*; use instantiate::*;
impl UProgram { impl UProgram {
pub fn resolve(&mut self, output: &mut CompilerOutput) { pub fn resolve(&mut self, output: &mut CompilerOutput) {
let mut unfinished = Vec::new(); self.unres_instrs = (0..self.instrs.len()).map(|i| InstrID::from(i)).collect();
let mut data = ResData { let mut res = ResolveRes::Unfinished;
unfinished: Vec::new(), let mut errs = Vec::new();
changed: false, while res == ResolveRes::Unfinished {
types: &mut self.types, res = ResolveRes::Finished;
s: Sources { res |= self.resolve_idents(&mut errs);
idents: &mut self.idents, res |= self.resolve_instrs(&mut errs);
vars: &mut self.vars,
fns: &self.fns,
structs: &self.structs,
generics: &self.generics,
data: &self.data,
modules: &self.modules,
},
errs: Vec::new(),
};
for (fid, f) in self.fns.iter().enumerate() {
for i in &f.instructions {
resolve_instr(
&mut data,
ResolveCtx {
ret: f.ret,
breakable: false,
i,
},
);
} }
for (fid, f) in self.fns.iter().enumerate() {
// this currently works bc expressions create temporary variables // this currently works bc expressions create temporary variables
// although you can't do things like loop {return 3} (need to analyze control flow) // although you can't do things like loop {return 3} (need to analyze control flow)
if data.types[f.ret] != RType::Unit.ty() if let Some(ty) = self.res_ty(f.ret)
&& self.types[ty] != Type::Unit
&& f.instructions && f.instructions
.last() .last()
.is_none_or(|i| !matches!(i.i, UInstruction::Ret { .. })) .is_none_or(|i| !matches!(self.instrs[i].i, UInstruction::Ret { .. }))
{ {
data.errs.push(ResErr::NoReturn { fid }); errs.push(ResErr::NoReturn { fid });
} }
} }
while !data.unfinished.is_empty() && data.changed {
data.changed = false;
std::mem::swap(&mut data.unfinished, &mut unfinished);
for ctx in unfinished.drain(..) {
resolve_instr(&mut data, ctx);
}
}
let errs = data.errs;
report_errs(self, output, errs); report_errs(self, output, errs);
} }
} }
#[derive(Clone, Copy)]
struct ResolveCtx<'a> {
ret: TypeID,
breakable: bool,
i: &'a UInstrInst,
}
fn compiler_error() -> ! { fn compiler_error() -> ! {
// TODO: this is probably a compiler error / should never happen // TODO: this is probably a compiler error / should never happen
panic!("how could this happen to me (you)"); panic!("how could this happen to me (you)");
@@ -92,46 +59,33 @@ struct Sources<'a> {
} }
struct ResData<'a> { struct ResData<'a> {
unfinished: Vec<ResolveCtx<'a>>,
changed: bool, changed: bool,
types: &'a mut Vec<Type>, types: &'a mut Vec<Type>,
s: Sources<'a>, s: Sources<'a>,
errs: Vec<ResErr>, errs: &'a mut Vec<ResErr>,
} }
impl<'a> ResData<'a> { impl<'a> ResData<'a> {
pub fn try_res_id<K: ResKind>(&mut self, x: impl Resolvable<K>) -> Result<K::Res, ResolveRes> { pub fn res<K: ResKind>(&mut self, i: IdentID) -> Result<K::Res, ResolveRes> {
x.try_res( i.res_as::<K>(&mut self.s, &mut self.types)
&mut self.s,
&mut self.types,
&mut self.errs,
&mut self.changed,
)
}
pub fn res_var_ty<'b: 'a>(
&mut self,
x: impl Resolvable<UVar>,
ctx: ResolveCtx<'b>,
) -> Option<(&RType, TypeID)> {
let id = self.res_id::<UVar>(x, ctx).map(|i| i.type_id(&self.s))?;
real_type(self.types, id).ok().map(|ty| (ty, id))
}
pub fn res_id<'b: 'a, K: ResKind>(
&mut self,
x: impl Resolvable<K>,
ctx: ResolveCtx<'b>,
) -> Option<K::Res> {
match self.try_res_id(x) {
Ok(id) => return Some(id),
Err(ResolveRes::Unfinished) => self.unfinished.push(ctx),
Err(ResolveRes::Finished) => (),
}
None
} }
pub fn res_ty(&mut self, x: impl Resolvable<Type>) -> Result<TypeID, ResolveRes> {
let id = Resolvable::<Type>::try_res(&x, &mut self.s, self.types, self.errs)?;
resolved_type(self.types, id)
} }
#[derive(Debug, Clone, Copy)] pub fn res_var_ty(&mut self, i: IdentID) -> Result<TypeID, ResolveRes> {
let id = self.res::<UVar>(i)?;
let id = match self.s.vars[id].ty {
VarTy::Res(t) => Ok(t),
VarTy::Ident(i) => i.res_as::<Type>(&mut self.s, self.types),
}?;
resolved_type(self.types, id)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ResolveRes { pub enum ResolveRes {
Finished, Finished,
Unfinished, Unfinished,
@@ -158,28 +112,31 @@ trait Resolvable<K: ResKind> {
s: &mut Sources, s: &mut Sources,
types: &mut Vec<Type>, types: &mut Vec<Type>,
errs: &mut Vec<ResErr>, errs: &mut Vec<ResErr>,
changed: &mut bool,
) -> Result<K::Res, ResolveRes>; ) -> Result<K::Res, ResolveRes>;
} }
impl<K: ResKind> Resolvable<K> for IdentID { impl IdentID {
fn try_res( fn res_as<K: ResKind>(
&self, &self,
s: &mut Sources, s: &mut Sources,
types: &mut Vec<Type>, types: &mut Vec<Type>,
errs: &mut Vec<ResErr>,
changed: &mut bool,
) -> Result<K::Res, ResolveRes> { ) -> Result<K::Res, ResolveRes> {
let origin = s.idents[self].origin; let origin = s.idents[self].origin;
let res = self.resolve(s, types, changed, errs)?; let res = match &s.idents[self].status {
IdentStatus::Res(res) => res.clone(),
IdentStatus::Ref { .. } => return Err(ResolveRes::Unfinished),
IdentStatus::Unres { .. } => return Err(ResolveRes::Unfinished),
IdentStatus::Failed(..) => return Err(ResolveRes::Finished),
IdentStatus::Cooked => return Err(ResolveRes::Finished),
};
match K::from_res(res, types, s, origin) { match K::from_res(res, types, s, origin) {
Ok(res) => Ok(res), Ok(res) => Ok(res),
Err(res) => { Err(res) => {
errs.push(ResErr::KindMismatch { s.idents[self].status = IdentStatus::Failed(Some(ResErr::KindMismatch {
origin, origin,
expected: K::ty(), expected: K::ty(),
found: res, found: res,
}); }));
Err(ResolveRes::Finished) Err(ResolveRes::Finished)
} }
} }
@@ -192,9 +149,8 @@ impl<K: ResKind> Resolvable<K> for &IdentID {
s: &mut Sources, s: &mut Sources,
types: &mut Vec<Type>, types: &mut Vec<Type>,
errs: &mut Vec<ResErr>, errs: &mut Vec<ResErr>,
changed: &mut bool,
) -> Result<K::Res, ResolveRes> { ) -> Result<K::Res, ResolveRes> {
Resolvable::<K>::try_res(*self, s, types, errs, changed) Resolvable::<K>::try_res(*self, s, types, errs)
} }
} }
@@ -204,7 +160,6 @@ impl Resolvable<UVar> for VarID {
s: &mut Sources, s: &mut Sources,
types: &mut Vec<Type>, types: &mut Vec<Type>,
errs: &mut Vec<ResErr>, errs: &mut Vec<ResErr>,
changed: &mut bool,
) -> Result<<UVar as ResKind>::Res, ResolveRes> { ) -> Result<<UVar as ResKind>::Res, ResolveRes> {
Ok(*self) Ok(*self)
} }
@@ -216,7 +171,6 @@ impl Resolvable<Type> for TypeID {
s: &mut Sources, s: &mut Sources,
types: &mut Vec<Type>, types: &mut Vec<Type>,
errs: &mut Vec<ResErr>, errs: &mut Vec<ResErr>,
changed: &mut bool,
) -> Result<<Type as ResKind>::Res, ResolveRes> { ) -> Result<<Type as ResKind>::Res, ResolveRes> {
Ok(*self) Ok(*self)
} }
@@ -290,7 +244,7 @@ impl ResKind for Type {
_: Origin, _: Origin,
) -> Result<Self::Res, Res> { ) -> Result<Self::Res, Res> {
Ok(match res { Ok(match res {
Res::Struct(si) => push_id(types, RType::Struct(si).ty()), Res::Struct(si) => push_id(types, Type::Struct(si)),
Res::Type(id) => id, Res::Type(id) => id,
_ => return Err(res), _ => return Err(res),
}) })
@@ -299,7 +253,6 @@ impl ResKind for Type {
pub trait TypeIDed { pub trait TypeIDed {
fn type_id(&self, s: &Sources) -> TypeID; fn type_id(&self, s: &Sources) -> TypeID;
fn finish(&self, s: &mut Sources, types: &mut Vec<Type>) {}
} }
impl TypeIDed for TypeID { impl TypeIDed for TypeID {
@@ -308,15 +261,6 @@ impl TypeIDed for TypeID {
} }
} }
impl TypeIDed for VarID {
fn type_id(&self, s: &Sources) -> TypeID {
s.vars[self].ty
}
fn finish(&self, s: &mut Sources, types: &mut Vec<Type>) {
inst_var(s.vars, s.structs, *self, types);
}
}
impl TypeIDed for DataID { impl TypeIDed for DataID {
fn type_id(&self, s: &Sources) -> TypeID { fn type_id(&self, s: &Sources) -> TypeID {
s.data[self].ty s.data[self].ty

View File

@@ -1,4 +1,4 @@
use super::{FnID, GenericID, IdentID, Len, ResolveRes, StructID, TypeID, UProgram, VarID}; use super::{FnID, GenericID, Len, ResolveRes, StructID, TypeID, UProgram, VarID};
#[derive(Debug, Clone, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct FieldRef { pub struct FieldRef {
@@ -22,34 +22,21 @@ pub struct FnInst {
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum Type { pub enum Type {
Real(RType),
Deref(TypeID),
Ptr(TypeID),
Unres(IdentID),
Error,
}
/// "real" types
#[derive(Clone, PartialEq)]
pub enum RType {
Bits(u32), Bits(u32),
Struct(StructInst), Struct(StructInst),
// this can be added for constraints later (F: fn(...) -> ...) // this can be added for constraints later (F: fn(...) -> ...)
// Fn { args: Vec<TypeID>, ret: TypeID }, // Fn { args: Vec<TypeID>, ret: TypeID },
// "fake" types // "fake" types
FnRef(FnInst), FnInst(FnInst),
Ref(TypeID), Ref(TypeID),
Slice(TypeID), Slice(TypeID),
Array(TypeID, Len), Array(TypeID, Len),
Unit, Unit,
Infer, Infer,
Generic(GenericID), Generic(GenericID),
} Deref(TypeID),
Ptr(TypeID),
impl RType { Error,
pub const fn ty(self) -> Type {
Type::Real(self)
}
} }
impl Type { impl Type {
@@ -69,16 +56,16 @@ impl Type {
impl TypeID { impl TypeID {
pub fn rf(self) -> Type { pub fn rf(self) -> Type {
RType::Ref(self).ty() Type::Ref(self)
} }
pub fn derf(self) -> Type { pub fn derf(self) -> Type {
Type::Deref(self) Type::Deref(self)
} }
pub fn arr(self, len: Len) -> Type { pub fn arr(self, len: Len) -> Type {
RType::Array(self, len).ty() Type::Array(self, len)
} }
pub fn slice(self) -> Type { pub fn slice(self) -> Type {
RType::Slice(self).ty() Type::Slice(self)
} }
} }
@@ -88,15 +75,27 @@ impl Type {
} }
} }
pub fn real_type(types: &[Type], id: TypeID) -> Result<&RType, ResolveRes> { pub fn clean_type(types: &[Type], id: TypeID) -> Option<TypeID> {
match &types[id] { match &types[id] {
Type::Real(rtype) => Ok(rtype), &Type::Ptr(id) => clean_type(types, id),
&Type::Ptr(id) => real_type(types, id), &Type::Deref(did) => match &types[clean_type(types, did)?] {
&Type::Deref(id) => match real_type(types, id)? { &Type::Ref(id) => clean_type(types, id),
&RType::Ref(id) => real_type(types, id), _ => Some(id),
},
Type::Error => None,
_ => Some(id),
}
}
pub fn resolved_type(types: &[Type], id: TypeID) -> Result<TypeID, ResolveRes> {
match &types[id] {
&Type::Ptr(id) => resolved_type(types, id),
&Type::Deref(id) => match &types[resolved_type(types, id)?] {
&Type::Ref(id) => resolved_type(types, id),
Type::Infer => Err(ResolveRes::Unfinished),
_ => Err(ResolveRes::Finished), _ => Err(ResolveRes::Finished),
}, },
Type::Unres(_) => Err(ResolveRes::Unfinished),
Type::Error => Err(ResolveRes::Finished), Type::Error => Err(ResolveRes::Finished),
_ => Ok(id),
} }
} }