calculations have been made
This commit is contained in:
28
ideas
28
ideas
@@ -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:
|
||||||
|
|
||||||
|
|
||||||
{([<
|
{([<
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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>,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user