diff --git a/ideas b/ideas index 6b99cb7..86979fc 100644 --- a/ideas +++ b/ideas @@ -1,5 +1,28 @@ -move names into separate vec with origins -make struct fields a vec, resolve into index +resolution overview + 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: enum Thing { @@ -10,6 +33,7 @@ inner values that auto generate map function: or #[derive(Map(T))] enum Thing { ... } + // scoping here is bad :woozy: {([< diff --git a/src/ir/lower/program.rs b/src/ir/lower/program.rs index 632b4d8..7919c05 100644 --- a/src/ir/lower/program.rs +++ b/src/ir/lower/program.rs @@ -428,7 +428,7 @@ impl LFunctionBuilderData<'_> { Type::Generic(id) => return None, // function references are resolved at compile time into direct calls, // so they don't have any size as arguments - Type::FnRef(fi) => 0, + Type::FnInst(fi) => 0, Type::Ref(_) => self.addr_size(), Type::Array(ty, len) => self.size_of_type(p, ty)? * len, Type::Slice(_) => self.addr_size() * 2, diff --git a/src/ir/upper/ident.rs b/src/ir/upper/ident.rs index cecfe04..6ba5e91 100644 --- a/src/ir/upper/ident.rs +++ b/src/ir/upper/ident.rs @@ -12,6 +12,10 @@ pub struct UIdent { pub enum IdentStatus { 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 { base: ResBase, path: Vec, diff --git a/src/ir/upper/instr.rs b/src/ir/upper/instr.rs index e00bab5..b9ed0ea 100644 --- a/src/ir/upper/instr.rs +++ b/src/ir/upper/instr.rs @@ -12,10 +12,10 @@ pub trait ResStage { pub struct Unresolved; impl ResStage for Unresolved { - type Var = IdentID; + type Var = VarRes; type Func = IdentID; type Struct = IdentID; - type Type = IdentID; + type Type = TypeRes; } pub struct Resolved; @@ -66,10 +66,10 @@ pub enum UInstruction { }, If { cond: S::Var, - body: Vec>, + body: Vec, }, Loop { - body: Vec>, + body: Vec, }, Break, Continue, diff --git a/src/ir/upper/kind.rs b/src/ir/upper/kind.rs index 072285d..247d8b0 100644 --- a/src/ir/upper/kind.rs +++ b/src/ir/upper/kind.rs @@ -20,18 +20,22 @@ pub type GenericID = ID; pub type StructID = ID; pub type DataID = ID; pub type ModID = ID; +pub type InstrID = ID; + +pub type VarRes = URes; +pub type TypeRes = URes; pub struct UFunc { pub name: String, pub origin: Origin, pub args: Vec, pub gargs: Vec, - pub ret: TypeID, - pub instructions: Vec, + pub ret: TypeRes, + pub instructions: Vec, } pub struct StructField { - pub ty: TypeID, + pub ty: TypeRes, pub origin: Origin, // pub vis: Visibility } @@ -51,11 +55,16 @@ pub struct UGeneric { pub struct UVar { pub name: String, pub origin: Origin, - pub ty: TypeID, + pub ty: TypeRes, pub parent: Option, pub children: HashMap, } +pub enum VarTy { + Ident(IdentID), + Res(TypeID), +} + #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] pub struct VarOffset { pub id: VarID, @@ -120,6 +129,11 @@ impl MemberID { } } +pub enum URes { + Res(T), + Unres(IdentID), +} + pub type Origin = FileSpan; // "effective" (externally visible) kinds @@ -145,37 +159,3 @@ impl Display for KindTy { }) } } - -impl UFunc { - pub fn flat_iter(&self) -> impl Iterator { - InstrIter::new(self.instructions.iter()) - } -} - -pub struct InstrIter<'a> { - iters: Vec>, -} - -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 { - 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) - } -} diff --git a/src/ir/upper/program.rs b/src/ir/upper/program.rs index d43d0a2..0ed6b30 100644 --- a/src/ir/upper/program.rs +++ b/src/ir/upper/program.rs @@ -1,5 +1,4 @@ use super::*; -use std::collections::HashMap; pub struct UProgram { pub fns: Vec, @@ -10,8 +9,10 @@ pub struct UProgram { pub vars: Vec, pub idents: Vec, pub types: Vec, + pub instrs: Vec, - pub vfmap: HashMap, + pub unres_idents: Vec, + pub unres_instrs: Vec<(FnID, InstrID)>, pub tc: TypeCache, } @@ -24,7 +25,7 @@ impl UProgram { pub fn new() -> Self { let mut types = Vec::new(); 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), }; Self { @@ -36,13 +37,15 @@ impl UProgram { generics: Vec::new(), data: Vec::new(), modules: Vec::new(), - vfmap: HashMap::new(), + instrs: Vec::new(), + unres_idents: Vec::new(), + unres_instrs: Vec::new(), tc, } } 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 { @@ -58,7 +61,11 @@ impl UProgram { } 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 { @@ -77,35 +84,36 @@ impl UProgram { push_id(&mut self.modules, m) } + pub fn res_ty(&self, i: IdentID) -> Option { + self.idents[i].status; + } + pub fn type_name(&self, ty: impl Typed) -> String { match ty.ty(self) { - Type::Real(rty) => match rty { - RType::Struct(ty) => { - format!( - "{}{}", - self.structs[ty.id].name, - self.gparams_str(&ty.gargs) - ) - } - RType::FnRef(ty) => { - format!( - "fn{}({}) -> {}", - &self.gparams_str(&ty.gargs), - &self.type_list_str(self.fns[ty.id].args.iter().map(|v| self.vars[v].ty)), - &self.type_name(self.fns[ty.id].ret) - ) - } - RType::Ref(t) => format!("{}&", self.type_name(t)), - RType::Deref(t) => format!("{}^", self.type_name(t)), - RType::Bits(size) => format!("b{}", size), - RType::Array(t, len) => format!("[{}; {len}]", self.type_name(t)), - RType::Unit => "()".to_string(), - RType::Slice(t) => format!("&[{}]", self.type_name(t)), - RType::Infer => "{inferred}".to_string(), - }, - Type::Error => "{error}".to_string(), - Type::Unres(_) => "{unresolved}".to_string(), + Type::Struct(ty) => { + format!( + "{}{}", + self.structs[ty.id].name, + self.gparams_str(&ty.gargs) + ) + } + Type::FnInst(ty) => { + format!( + "fn{}({}) -> {}", + &self.gparams_str(&ty.gargs), + &self.type_list_str(self.fns[ty.id].args.iter().map(|v| self.vars[v].ty)), + &self.type_name(self.fns[ty.id].ret) + ) + } + Type::Ref(t) => format!("{}&", self.type_name(t)), + Type::Bits(size) => format!("b{}", size), + Type::Array(t, len) => format!("[{}; {len}]", self.type_name(t)), + Type::Unit => "()".to_string(), + Type::Slice(t) => format!("&[{}]", self.type_name(t)), + Type::Infer => "{inferred}".to_string(), 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), } } diff --git a/src/ir/upper/resolve/error.rs b/src/ir/upper/resolve/error.rs index 56bb2d6..8fa919c 100644 --- a/src/ir/upper/resolve/error.rs +++ b/src/ir/upper/resolve/error.rs @@ -1,7 +1,4 @@ -use crate::{ - common::{CompilerMsg, CompilerOutput}, - ir::RType, -}; +use crate::common::{CompilerMsg, CompilerOutput}; use super::{ IdentStatus, KindTy, MemberTy, Origin, Res, ResBase, StructID, Type, TypeID, UProgram, @@ -119,12 +116,14 @@ pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, mut errs: Vec output.err(CompilerMsg::new( - format!("Type of {:?} cannot be inferred", var.name), - var.origin, - )), - _ => (), + if let Some(ty) = var.ty() { + match &p.types[ty] { + Type::Infer => output.err(CompilerMsg::new( + format!("Type of {:?} cannot be inferred", var.name), + var.origin, + )), + _ => (), + } } } } diff --git a/src/ir/upper/resolve/ident.rs b/src/ir/upper/resolve/ident.rs index 8af4b78..f35f939 100644 --- a/src/ir/upper/resolve/ident.rs +++ b/src/ir/upper/resolve/ident.rs @@ -1,5 +1,110 @@ use super::*; +impl UProgram { + pub fn resolve_idents(&mut self, errs: &mut Vec) -> 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 { pub fn validate( &self, @@ -66,89 +171,6 @@ impl MemRes { } } -impl IdentID { - pub fn resolve( - self, - s: &mut Sources, - types: &mut Vec, - changed: &mut bool, - errs: &mut Vec, - ) -> Result { - 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( dst: &[GenericID], src: &[TypeID], @@ -171,4 +193,3 @@ pub fn validate_gargs( } Ok(()) } - diff --git a/src/ir/upper/resolve/instantiate.rs b/src/ir/upper/resolve/instantiate.rs index 0f9e11d..767395f 100644 --- a/src/ir/upper/resolve/instantiate.rs +++ b/src/ir/upper/resolve/instantiate.rs @@ -10,13 +10,13 @@ pub fn inst_fn_var( types: &mut Vec, ) -> VarID { 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( vars, UVar { name, origin, - ty, + ty: VarTy::Res(ty), parent: None, children: HashMap::new(), }, @@ -31,53 +31,20 @@ pub fn inst_struct_var( types: &mut Vec, ) -> VarID { 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( vars, UVar { name, origin, - ty, + ty: VarTy::Res(ty), parent: None, children: HashMap::new(), }, ); - inst_var(vars, structs, id, types); id } -pub fn inst_var(vars: &mut Vec, structs: &[UStruct], id: VarID, types: &mut Vec) { - 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 pub fn inst_typedef(def: &TypeDef, gargs: &[TypeID], types: &mut Vec) -> TypeID { let gmap = inst_gmap(&def.gargs, &gargs); @@ -108,32 +75,23 @@ fn inst_type_( gmap: &HashMap, ) -> Option { let ty = match types[id].clone() { - Type::Real(rty) => match rty { - RType::Bits(_) => return None, - RType::Struct(struct_ty) => RType::Struct(StructInst { - id: struct_ty.id, - gargs: inst_all(&struct_ty.gargs, types, gmap)?, - }), - RType::FnRef(fn_ty) => RType::FnRef(FnInst { - id: fn_ty.id, - gargs: inst_all(&fn_ty.gargs, types, gmap)?, - }), - RType::Ref(id) => RType::Ref(inst_type_(id, types, gmap)?), - RType::Slice(id) => RType::Slice(inst_type_(id, types, gmap)?), - RType::Array(id, len) => RType::Array(inst_type_(id, types, gmap)?, len), - RType::Unit => return None, - RType::Generic(gid) => { - return gmap - .get(&gid) - .map(|id| Some(*id)) - .unwrap_or_else(|| None) - } - RType::Infer => RType::Infer, - } - .ty(), + Type::Bits(_) => return None, + Type::Struct(struct_ty) => Type::Struct(StructInst { + id: struct_ty.id, + gargs: inst_all(&struct_ty.gargs, types, gmap)?, + }), + Type::FnInst(fn_ty) => Type::FnInst(FnInst { + id: fn_ty.id, + gargs: inst_all(&fn_ty.gargs, types, gmap)?, + }), + Type::Ref(id) => Type::Ref(inst_type_(id, types, gmap)?), + Type::Slice(id) => Type::Slice(inst_type_(id, types, gmap)?), + Type::Array(id, len) => Type::Array(inst_type_(id, types, gmap)?, len), + Type::Unit => return None, + Type::Generic(gid) => return gmap.get(&gid).map(|id| Some(*id)).unwrap_or_else(|| None), + Type::Infer => Type::Infer, Type::Deref(id) => Type::Deref(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, }; Some(push_id(types, ty)) @@ -155,4 +113,3 @@ fn inst_all( } vec } - diff --git a/src/ir/upper/resolve/instr.rs b/src/ir/upper/resolve/instr.rs index 813b3a8..b57c961 100644 --- a/src/ir/upper/resolve/instr.rs +++ b/src/ir/upper/resolve/instr.rs @@ -2,30 +2,79 @@ use std::collections::HashSet; use super::*; -pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<()> { - let mut res = ResolveRes::Finished; - match &ctx.i.i { +pub enum UResEvent { + VarUse(VarID), +} + +impl UProgram { + pub fn resolve_instrs(&mut self, errs: &mut Vec) -> 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, + data: &mut ResData<'a>, +) -> ResolveRes { + let instr = &mut instrs[ii]; + match &mut instr.i { UInstruction::Call { dst, f, args } => { - let fi = data.res_id::(f, ctx)?; - let f = &data.s.fns[fi.id]; - for (src, &dest) in args.iter().zip(&f.args) { - res |= data.match_types::(dest, src, src); + let fi = data.res::(*f); + for &a in args { + data.res::(a); } - res |= data.match_types::(dst, f.ret, dst); + data.res::(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 } => { res |= data.match_types::(dst, src, src); } UInstruction::Ref { dst, src } => { - let dstty = data.res_var_ty(dst, ctx)?.0; - let &RType::Ref(dest_ty) = dstty else { + let dstty = &data.types[data.res_var_ty(dst)?]; + let &Type::Ref(dest_ty) = dstty else { compiler_error() }; res |= data.match_types::(dest_ty, src, src); } UInstruction::Deref { dst, src } => { - let (srcty, srcid) = data.res_var_ty(src, ctx)?; - let &RType::Ref(src_ty) = srcty else { + let srcid = data.res_var_ty(src)?; + let &Type::Ref(src_ty) = data.types[srcid] else { let origin = src.origin(data); data.errs.push(ResErr::CannotDeref { origin, ty: srcid }); return None; @@ -38,11 +87,11 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option< } UInstruction::LoadSlice { dst, src } => { let (dstty, dstid) = data.res_var_ty(dst, ctx)?; - let &RType::Slice(dstty) = dstty else { + let &Type::Slice(dstty) = dstty else { compiler_error() }; 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() }; 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::(ctx.ret, src, src); } UInstruction::Construct { dst, struc, fields } => { - let si = data.res_id::(dst, ctx)?; + let si = data.res::(dst, ctx)?; let sid = si.id; let st = &data.s.structs[sid]; 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; } diff --git a/src/ir/upper/resolve/matc.rs b/src/ir/upper/resolve/matc.rs index b5c1256..d3a474b 100644 --- a/src/ir/upper/resolve/matc.rs +++ b/src/ir/upper/resolve/matc.rs @@ -1,31 +1,33 @@ use super::*; -pub fn match_types(data: &mut ResData, dst: impl TypeIDed, src: impl TypeIDed) -> MatchRes { - let dstid = dst.type_id(&data.s); - let srcid = src.type_id(&data.s); - let dstty = data.real_ty(&dst)?.clone(); - let srcty = data.real_ty(&src)?.clone(); - let error = || { - MatchRes::Error(vec![TypeMismatch { - dst: dstid, - src: srcid, - }]) +pub fn match_types(data: &mut ResData, dst: TypeID, src: TypeID) -> MatchRes { + let Some(dst) = clean_type(data.types, dst) else { + return MatchRes::Finished; }; - 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 - (RType::Infer, _) => { + (Type::Infer, _) => { data.changed = true; - data.types[dstid] = Type::Ptr(srcid); - dst.finish(&mut data.s, data.types); + data.types[dst] = Type::Ptr(src); MatchRes::Finished } - (_, RType::Infer) => { + (_, Type::Infer) => { data.changed = true; - data.types[srcid] = Type::Ptr(dstid); - src.finish(&mut data.s, data.types); + data.types[src] = Type::Ptr(dst); MatchRes::Finished } - (RType::Struct(dest), RType::Struct(src)) => { + (Type::Struct(dest), Type::Struct(src)) => { if dest.id != src.id { 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)); // match_all(data, dst, src) // } - (RType::Ref(dest), RType::Ref(src)) => match_types(data, dest, src), - (RType::Slice(dest), RType::Slice(src)) => match_types(data, dest, src), - (RType::Array(dest, dlen), RType::Array(src, slen)) => { + (Type::Ref(dest), Type::Ref(src)) => match_types(data, dest, src), + (Type::Slice(dest), Type::Slice(src)) => match_types(data, dest, src), + (Type::Array(dest, dlen), Type::Array(src, slen)) => { if dlen == slen { match_types(data, dest, src) } else { @@ -84,22 +86,14 @@ fn match_all( } impl<'a> ResData<'a> { - pub fn match_types( + pub fn match_types( &mut self, - dst: impl Resolvable, - src: impl Resolvable, + dst: impl MaybeTypeID, + src: impl MaybeTypeID, origin: impl HasOrigin, - ) -> ResolveRes - where - Dst::Res: TypeIDed, - 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); + ) -> ResolveRes { + let dst = dst.type_id(&self.s)?; + let src = src.type_id(&self.s)?; let res = match_types(self, dst, src); match res { 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 { @@ -137,3 +125,22 @@ impl FromResidual> for MatchRes { } } } + +pub trait MaybeTypeID { + fn type_id(&self, s: &Sources) -> Result; +} + +impl MaybeTypeID for T { + fn type_id(&self, s: &Sources) -> Result { + Ok(self.type_id(s)) + } +} + +impl MaybeTypeID for VarID { + fn type_id(&self, s: &Sources) -> Result { + match s.vars[self].ty { + VarTy::Ident(id) => todo!(), + VarTy::Res(id) => Ok(id), + } + } +} diff --git a/src/ir/upper/resolve/mod.rs b/src/ir/upper/resolve/mod.rs index 852dc31..9115a25 100644 --- a/src/ir/upper/resolve/mod.rs +++ b/src/ir/upper/resolve/mod.rs @@ -9,73 +9,40 @@ use std::{ }; mod error; -mod instr; -mod matc; mod ident; mod instantiate; +mod instr; +mod matc; pub use error::*; -use instr::*; use instantiate::*; impl UProgram { pub fn resolve(&mut self, output: &mut CompilerOutput) { - let mut unfinished = Vec::new(); - let mut data = ResData { - unfinished: Vec::new(), - 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: Vec::new(), - }; + self.unres_instrs = (0..self.instrs.len()).map(|i| InstrID::from(i)).collect(); + let mut res = ResolveRes::Unfinished; + let mut errs = Vec::new(); + while res == ResolveRes::Unfinished { + res = ResolveRes::Finished; + res |= self.resolve_idents(&mut errs); + res |= self.resolve_instrs(&mut errs); + } for (fid, f) in self.fns.iter().enumerate() { - for i in &f.instructions { - resolve_instr( - &mut data, - ResolveCtx { - ret: f.ret, - breakable: false, - i, - }, - ); - } // this currently works bc expressions create temporary variables // 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 .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); } } -#[derive(Clone, Copy)] -struct ResolveCtx<'a> { - ret: TypeID, - breakable: bool, - i: &'a UInstrInst, -} - fn compiler_error() -> ! { // TODO: this is probably a compiler error / should never happen panic!("how could this happen to me (you)"); @@ -92,46 +59,33 @@ struct Sources<'a> { } struct ResData<'a> { - unfinished: Vec>, changed: bool, types: &'a mut Vec, s: Sources<'a>, - errs: Vec, + errs: &'a mut Vec, } impl<'a> ResData<'a> { - pub fn try_res_id(&mut self, x: impl Resolvable) -> Result { - x.try_res( - &mut self.s, - &mut self.types, - &mut self.errs, - &mut self.changed, - ) - } - pub fn res_var_ty<'b: 'a>( - &mut self, - x: impl Resolvable, - ctx: ResolveCtx<'b>, - ) -> Option<(&RType, TypeID)> { - let id = self.res_id::(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, - ctx: ResolveCtx<'b>, - ) -> Option { - 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(&mut self, i: IdentID) -> Result { + i.res_as::(&mut self.s, &mut self.types) } + pub fn res_ty(&mut self, x: impl Resolvable) -> Result { + let id = Resolvable::::try_res(&x, &mut self.s, self.types, self.errs)?; + resolved_type(self.types, id) + } + + pub fn res_var_ty(&mut self, i: IdentID) -> Result { + let id = self.res::(i)?; + let id = match self.s.vars[id].ty { + VarTy::Res(t) => Ok(t), + VarTy::Ident(i) => i.res_as::(&mut self.s, self.types), + }?; + resolved_type(self.types, id) + } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum ResolveRes { Finished, Unfinished, @@ -158,28 +112,31 @@ trait Resolvable { s: &mut Sources, types: &mut Vec, errs: &mut Vec, - changed: &mut bool, ) -> Result; } -impl Resolvable for IdentID { - fn try_res( +impl IdentID { + fn res_as( &self, s: &mut Sources, types: &mut Vec, - errs: &mut Vec, - changed: &mut bool, ) -> Result { 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) { Ok(res) => Ok(res), Err(res) => { - errs.push(ResErr::KindMismatch { + s.idents[self].status = IdentStatus::Failed(Some(ResErr::KindMismatch { origin, expected: K::ty(), found: res, - }); + })); Err(ResolveRes::Finished) } } @@ -192,9 +149,8 @@ impl Resolvable for &IdentID { s: &mut Sources, types: &mut Vec, errs: &mut Vec, - changed: &mut bool, ) -> Result { - Resolvable::::try_res(*self, s, types, errs, changed) + Resolvable::::try_res(*self, s, types, errs) } } @@ -204,7 +160,6 @@ impl Resolvable for VarID { s: &mut Sources, types: &mut Vec, errs: &mut Vec, - changed: &mut bool, ) -> Result<::Res, ResolveRes> { Ok(*self) } @@ -216,7 +171,6 @@ impl Resolvable for TypeID { s: &mut Sources, types: &mut Vec, errs: &mut Vec, - changed: &mut bool, ) -> Result<::Res, ResolveRes> { Ok(*self) } @@ -290,7 +244,7 @@ impl ResKind for Type { _: Origin, ) -> Result { 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, _ => return Err(res), }) @@ -299,7 +253,6 @@ impl ResKind for Type { pub trait TypeIDed { fn type_id(&self, s: &Sources) -> TypeID; - fn finish(&self, s: &mut Sources, types: &mut Vec) {} } 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) { - inst_var(s.vars, s.structs, *self, types); - } -} - impl TypeIDed for DataID { fn type_id(&self, s: &Sources) -> TypeID { s.data[self].ty diff --git a/src/ir/upper/ty.rs b/src/ir/upper/ty.rs index 4b782fd..c1a5d57 100644 --- a/src/ir/upper/ty.rs +++ b/src/ir/upper/ty.rs @@ -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)] pub struct FieldRef { @@ -22,34 +22,21 @@ pub struct FnInst { #[derive(Clone, PartialEq)] pub enum Type { - Real(RType), - Deref(TypeID), - Ptr(TypeID), - Unres(IdentID), - Error, -} - -/// "real" types -#[derive(Clone, PartialEq)] -pub enum RType { Bits(u32), Struct(StructInst), // this can be added for constraints later (F: fn(...) -> ...) // Fn { args: Vec, ret: TypeID }, // "fake" types - FnRef(FnInst), + FnInst(FnInst), Ref(TypeID), Slice(TypeID), Array(TypeID, Len), Unit, Infer, Generic(GenericID), -} - -impl RType { - pub const fn ty(self) -> Type { - Type::Real(self) - } + Deref(TypeID), + Ptr(TypeID), + Error, } impl Type { @@ -69,16 +56,16 @@ impl Type { impl TypeID { pub fn rf(self) -> Type { - RType::Ref(self).ty() + Type::Ref(self) } pub fn derf(self) -> Type { Type::Deref(self) } pub fn arr(self, len: Len) -> Type { - RType::Array(self, len).ty() + Type::Array(self, len) } 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 { match &types[id] { - Type::Real(rtype) => Ok(rtype), - &Type::Ptr(id) => real_type(types, id), - &Type::Deref(id) => match real_type(types, id)? { - &RType::Ref(id) => real_type(types, id), - _ => Err(ResolveRes::Finished), + &Type::Ptr(id) => clean_type(types, id), + &Type::Deref(did) => match &types[clean_type(types, did)?] { + &Type::Ref(id) => clean_type(types, id), + _ => Some(id), }, - Type::Unres(_) => Err(ResolveRes::Unfinished), - Type::Error => Err(ResolveRes::Finished), + Type::Error => None, + _ => Some(id), + } +} + +pub fn resolved_type(types: &[Type], id: TypeID) -> Result { + 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), + }, + Type::Error => Err(ResolveRes::Finished), + _ => Ok(id), } }