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

View File

@@ -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<MemberIdent>,

View File

@@ -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<S: ResStage = Unresolved> {
},
If {
cond: S::Var,
body: Vec<UInstrInst<S>>,
body: Vec<InstrID>,
},
Loop {
body: Vec<UInstrInst<S>>,
body: Vec<InstrID>,
},
Break,
Continue,

View File

@@ -20,18 +20,22 @@ pub type GenericID = ID<UGeneric>;
pub type StructID = ID<UStruct>;
pub type DataID = ID<UData>;
pub type ModID = ID<UModule>;
pub type InstrID = ID<UInstrInst>;
pub type VarRes = URes<VarID>;
pub type TypeRes = URes<VarID>;
pub struct UFunc {
pub name: String,
pub origin: Origin,
pub args: Vec<VarID>,
pub gargs: Vec<GenericID>,
pub ret: TypeID,
pub instructions: Vec<UInstrInst>,
pub ret: TypeRes,
pub instructions: Vec<InstrID>,
}
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<VarID>,
pub children: HashMap<String, VarID>,
}
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<T> {
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<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 std::collections::HashMap;
pub struct UProgram {
pub fns: Vec<UFunc>,
@@ -10,8 +9,10 @@ pub struct UProgram {
pub vars: Vec<UVar>,
pub idents: Vec<UIdent>,
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,
}
@@ -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<TypeID> {
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),
}
}

View File

@@ -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<ResE
}
}
for var in &p.vars {
match &p.types[var.ty] {
Type::Real(RType::Infer) => 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,
)),
_ => (),
}
}
}
}

View File

@@ -1,5 +1,110 @@
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 {
pub fn validate(
&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(
dst: &[GenericID],
src: &[TypeID],
@@ -171,4 +193,3 @@ pub fn validate_gargs(
}
Ok(())
}

View File

@@ -10,13 +10,13 @@ pub fn inst_fn_var(
types: &mut Vec<Type>,
) -> 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<Type>,
) -> 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<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
pub fn inst_typedef(def: &TypeDef, gargs: &[TypeID], types: &mut Vec<Type>) -> TypeID {
let gmap = inst_gmap(&def.gargs, &gargs);
@@ -108,32 +75,23 @@ fn inst_type_(
gmap: &HashMap<GenericID, TypeID>,
) -> Option<TypeID> {
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
}

View File

@@ -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<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_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);
let fi = data.res::<UFunc>(*f);
for &a in args {
data.res::<UVar>(a);
}
res |= data.match_types::<UVar, Type>(dst, f.ret, dst);
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 } => {
res |= data.match_types::<UVar, UVar>(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::<Type, UVar>(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::<Type, UVar>(ctx.ret, src, src);
}
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 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;
}

View File

@@ -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<Dst: ResKind, Src: ResKind>(
pub fn match_types(
&mut self,
dst: impl Resolvable<Dst>,
src: impl Resolvable<Src>,
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<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 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<ResolveCtx<'a>>,
changed: bool,
types: &'a mut Vec<Type>,
s: Sources<'a>,
errs: Vec<ResErr>,
errs: &'a mut Vec<ResErr>,
}
impl<'a> ResData<'a> {
pub fn try_res_id<K: ResKind>(&mut self, x: impl Resolvable<K>) -> Result<K::Res, ResolveRes> {
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<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<K: ResKind>(&mut self, i: IdentID) -> Result<K::Res, ResolveRes> {
i.res_as::<K>(&mut self.s, &mut self.types)
}
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)
}
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)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ResolveRes {
Finished,
Unfinished,
@@ -158,28 +112,31 @@ trait Resolvable<K: ResKind> {
s: &mut Sources,
types: &mut Vec<Type>,
errs: &mut Vec<ResErr>,
changed: &mut bool,
) -> Result<K::Res, ResolveRes>;
}
impl<K: ResKind> Resolvable<K> for IdentID {
fn try_res(
impl IdentID {
fn res_as<K: ResKind>(
&self,
s: &mut Sources,
types: &mut Vec<Type>,
errs: &mut Vec<ResErr>,
changed: &mut bool,
) -> Result<K::Res, ResolveRes> {
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<K: ResKind> Resolvable<K> for &IdentID {
s: &mut Sources,
types: &mut Vec<Type>,
errs: &mut Vec<ResErr>,
changed: &mut bool,
) -> 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,
types: &mut Vec<Type>,
errs: &mut Vec<ResErr>,
changed: &mut bool,
) -> Result<<UVar as ResKind>::Res, ResolveRes> {
Ok(*self)
}
@@ -216,7 +171,6 @@ impl Resolvable<Type> for TypeID {
s: &mut Sources,
types: &mut Vec<Type>,
errs: &mut Vec<ResErr>,
changed: &mut bool,
) -> Result<<Type as ResKind>::Res, ResolveRes> {
Ok(*self)
}
@@ -290,7 +244,7 @@ impl ResKind for Type {
_: Origin,
) -> Result<Self::Res, 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,
_ => 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<Type>) {}
}
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 {
fn type_id(&self, s: &Sources) -> TypeID {
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)]
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<TypeID>, 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<TypeID> {
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<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),
},
Type::Error => Err(ResolveRes::Finished),
_ => Ok(id),
}
}