trudging through the snow
This commit is contained in:
@@ -1,11 +1,25 @@
|
||||
use crate::{
|
||||
common::{CompilerMsg, CompilerOutput},
|
||||
ir::ID,
|
||||
use crate::common::{CompilerMsg, CompilerOutput};
|
||||
|
||||
use super::{
|
||||
IdentStatus, KindTy, MemRes, MemberTy, Origin, Res, ResBase, StructID, Type, TypeID, UProgram
|
||||
};
|
||||
|
||||
use super::{KindTy, Origin, Res, StructID, TypeID, UProgram};
|
||||
|
||||
pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, errs: Vec<ResErr>) {
|
||||
pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, mut errs: Vec<ResErr>) {
|
||||
for ident in &p.idents {
|
||||
match &ident.status {
|
||||
IdentStatus::Unres { path, base } => {
|
||||
let mem = path.last().unwrap();
|
||||
errs.push(ResErr::UnknownMember {
|
||||
ty: mem.ty,
|
||||
name: mem.name.clone(),
|
||||
origin: mem.origin,
|
||||
parent: base.clone(),
|
||||
})
|
||||
}
|
||||
IdentStatus::Failed(err) => errs.push(err.clone()),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
for err in errs {
|
||||
match err {
|
||||
ResErr::Type {
|
||||
@@ -56,7 +70,7 @@ pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, errs: Vec<ResErr>)
|
||||
origin,
|
||||
));
|
||||
}
|
||||
ResErr::UnknownField { origin, id, name } => {
|
||||
ResErr::UnknownStructField { origin, id, name } => {
|
||||
output.err(CompilerMsg::new(
|
||||
format!("Unknown field '{name}' in struct '{}'", p.structs[id].name),
|
||||
origin,
|
||||
@@ -83,47 +97,48 @@ pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, errs: Vec<ResErr>)
|
||||
found,
|
||||
expected,
|
||||
} => output.err(CompilerMsg::new(
|
||||
{
|
||||
let name = match &found {
|
||||
Res::Fn(fty) => &p.fns[fty.id].name,
|
||||
Res::Type(id) => &p.type_name(id),
|
||||
Res::Var(id) => &p.vars[id].name,
|
||||
Res::Struct(sty) => &p.structs[sty.id].name,
|
||||
};
|
||||
format!(
|
||||
"Expected {}, found {} '{}'",
|
||||
expected.str(),
|
||||
found.kind_str(),
|
||||
name
|
||||
)
|
||||
},
|
||||
format!("Expected {expected}, found {}", found.display_str(p)),
|
||||
origin,
|
||||
)),
|
||||
ResErr::UnexpectedField { origin } => {
|
||||
output.err(CompilerMsg::new(format!("Unexpected fields here"), origin))
|
||||
}
|
||||
ResErr::UnknownMember {
|
||||
origin,
|
||||
ty,
|
||||
name,
|
||||
parent,
|
||||
} => output.err(CompilerMsg::new(
|
||||
format!("Unknown {ty} {name} of {}", parent.display_str(p)),
|
||||
origin,
|
||||
)),
|
||||
}
|
||||
}
|
||||
for var in &p.vars {
|
||||
match &p.types[var.ty] {
|
||||
Type::Error => output.err(CompilerMsg::new(
|
||||
format!("Var {:?} is error type!", var.name),
|
||||
var.origin,
|
||||
)),
|
||||
Type::Infer => output.err(CompilerMsg::new(
|
||||
format!("Type of {:?} cannot be inferred", var.name),
|
||||
var.origin,
|
||||
)),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub enum ResErr {
|
||||
UnknownModule {
|
||||
origin: Origin,
|
||||
name: String,
|
||||
},
|
||||
UnknownMember {
|
||||
origin: Origin,
|
||||
ty: MemberTy,
|
||||
name: String,
|
||||
parent: ResBase,
|
||||
},
|
||||
KindMismatch {
|
||||
origin: Origin,
|
||||
expected: KindTy,
|
||||
found: Res,
|
||||
},
|
||||
UnexpectedField {
|
||||
origin: Origin,
|
||||
},
|
||||
GenericCount {
|
||||
origin: Origin,
|
||||
expected: usize,
|
||||
@@ -153,7 +168,7 @@ pub enum ResErr {
|
||||
id: StructID,
|
||||
name: String,
|
||||
},
|
||||
UnknownField {
|
||||
UnknownStructField {
|
||||
origin: Origin,
|
||||
id: StructID,
|
||||
name: String,
|
||||
|
||||
@@ -1,153 +1,71 @@
|
||||
use std::{collections::HashMap, fmt::Write};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::{arch::riscv64::RV64Instruction, DataID, FnID, Origin, UFunc, UIdent, IdentID};
|
||||
use crate::{compiler::arch::riscv::Reg, util::Padder};
|
||||
use super::{arch::riscv64::RV64Instruction, DataID, IdentID, Origin, ResStage, Unresolved};
|
||||
use crate::compiler::arch::riscv::Reg;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum UInstruction {
|
||||
pub enum UInstruction<S: ResStage = Unresolved> {
|
||||
Mv {
|
||||
dst: IdentID,
|
||||
src: IdentID,
|
||||
dst: S::Var,
|
||||
src: S::Var,
|
||||
},
|
||||
Ref {
|
||||
dst: IdentID,
|
||||
src: IdentID,
|
||||
dst: S::Var,
|
||||
src: S::Var,
|
||||
},
|
||||
Deref {
|
||||
dst: IdentID,
|
||||
src: IdentID,
|
||||
dst: S::Var,
|
||||
src: S::Var,
|
||||
},
|
||||
LoadData {
|
||||
dst: IdentID,
|
||||
dst: S::Var,
|
||||
src: DataID,
|
||||
},
|
||||
LoadSlice {
|
||||
dst: IdentID,
|
||||
dst: S::Var,
|
||||
src: DataID,
|
||||
},
|
||||
LoadFn {
|
||||
dst: IdentID,
|
||||
src: FnID,
|
||||
},
|
||||
Call {
|
||||
dst: IdentID,
|
||||
f: IdentID,
|
||||
args: Vec<IdentID>,
|
||||
dst: S::Var,
|
||||
f: S::Func,
|
||||
args: Vec<S::Var>,
|
||||
},
|
||||
AsmBlock {
|
||||
instructions: Vec<RV64Instruction>,
|
||||
args: Vec<AsmBlockArg>,
|
||||
instructions: Vec<RV64Instruction<S::Var>>,
|
||||
args: Vec<AsmBlockArg<S::Var>>,
|
||||
},
|
||||
Ret {
|
||||
src: IdentID,
|
||||
src: S::Var,
|
||||
},
|
||||
Construct {
|
||||
dst: IdentID,
|
||||
struc: IdentID,
|
||||
fields: HashMap<String, IdentID>,
|
||||
dst: S::Var,
|
||||
struc: S::Struct,
|
||||
fields: HashMap<String, S::Var>,
|
||||
},
|
||||
If {
|
||||
cond: IdentID,
|
||||
body: Vec<UInstrInst>,
|
||||
cond: S::Var,
|
||||
body: Vec<UInstrInst<S>>,
|
||||
},
|
||||
Loop {
|
||||
body: Vec<UInstrInst>,
|
||||
body: Vec<UInstrInst<S>>,
|
||||
},
|
||||
Break,
|
||||
Continue,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UInstrInst {
|
||||
pub i: UInstruction,
|
||||
pub struct UInstrInst<S: ResStage = Unresolved> {
|
||||
pub i: UInstruction<S>,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for UInstrInst {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.i)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AsmBlockArg {
|
||||
pub var: IdentID,
|
||||
pub struct AsmBlockArg<V = IdentID> {
|
||||
pub var: V,
|
||||
pub reg: Reg,
|
||||
pub ty: AsmBlockArgType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum AsmBlockArgType {
|
||||
In,
|
||||
Out,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for UInstruction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Mv { dst: dest, src } => write!(f, "{dest:?} <- {src:?}")?,
|
||||
Self::Ref { dst: dest, src } => write!(f, "{dest:?} <- {src:?}&")?,
|
||||
Self::Deref { dst: dest, src } => write!(f, "{dest:?} <- {src:?}^")?,
|
||||
Self::LoadData { dst: dest, src } => write!(f, "{dest:?} <- {src:?}")?,
|
||||
Self::LoadFn { dst: dest, src } => write!(f, "{dest:?} <- {src:?}")?,
|
||||
Self::LoadSlice { dst: dest, src } => write!(f, "{dest:?} <- &[{src:?}]")?,
|
||||
Self::Call {
|
||||
dst: dest,
|
||||
f: func,
|
||||
args,
|
||||
} => write!(f, "{dest:?} <- {func:?}({args:?})")?,
|
||||
Self::AsmBlock { args, instructions } => write!(f, "asm {args:?} {instructions:#?}")?,
|
||||
Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish()?,
|
||||
Self::Construct { dst: dest, struc, fields } => write!(f, "{dest:?} <- {struc:?}{fields:?}")?,
|
||||
Self::If { cond, body } => {
|
||||
write!(f, "if {cond:?}:")?;
|
||||
if !body.is_empty() {
|
||||
f.write_str("{\n ")?;
|
||||
let mut padder = Padder::new(f);
|
||||
for i in body {
|
||||
// they don't expose wrap_buf :grief:
|
||||
padder.write_str(&format!("{i:?};\n"))?;
|
||||
}
|
||||
f.write_char('}')?;
|
||||
} else {
|
||||
f.write_str("{}")?;
|
||||
}
|
||||
}
|
||||
Self::Loop { body } => {
|
||||
write!(f, "loop:")?;
|
||||
if !body.is_empty() {
|
||||
f.write_str("{\n ")?;
|
||||
let mut padder = Padder::new(f);
|
||||
for i in body {
|
||||
// they don't expose wrap_buf :grief:
|
||||
padder.write_str(&format!("{i:?};\n"))?;
|
||||
}
|
||||
f.write_char('}')?;
|
||||
} else {
|
||||
f.write_str("{}")?;
|
||||
}
|
||||
}
|
||||
Self::Break => write!(f, "break")?,
|
||||
Self::Continue => write!(f, "continue")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for UFunc {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.args)?;
|
||||
if !self.instructions.is_empty() {
|
||||
f.write_str("{\n ")?;
|
||||
let mut padder = Padder::new(f);
|
||||
for i in &self.instructions {
|
||||
// they don't expose wrap_buf :grief:
|
||||
padder.write_str(&format!("{i:?};\n"))?;
|
||||
}
|
||||
f.write_char('}')?;
|
||||
} else {
|
||||
f.write_str("{}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,37 @@
|
||||
use super::{FnInst, ResErr, StructInst, Type, UInstrInst, UInstruction};
|
||||
//! all main IR Upper data structures stored in UProgram
|
||||
|
||||
use super::{FnInst, ResErr, StructInst, Type, UInstrInst, UInstruction, UProgram};
|
||||
use crate::{
|
||||
common::FileSpan,
|
||||
ir::{Len, ID},
|
||||
};
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::{Debug, Display},
|
||||
};
|
||||
|
||||
pub trait ResStage {
|
||||
type Var;
|
||||
type Func;
|
||||
type Struct;
|
||||
type Type;
|
||||
}
|
||||
|
||||
pub struct Unresolved;
|
||||
impl ResStage for Unresolved {
|
||||
type Var = IdentID;
|
||||
type Func = IdentID;
|
||||
type Struct = IdentID;
|
||||
type Type = IdentID;
|
||||
}
|
||||
|
||||
pub struct Resolved;
|
||||
impl ResStage for Resolved {
|
||||
type Var = VarID;
|
||||
type Func = FnInst;
|
||||
type Struct = StructInst;
|
||||
type Type = TypeID;
|
||||
}
|
||||
|
||||
pub type NamePath = Vec<String>;
|
||||
|
||||
@@ -16,7 +44,6 @@ pub type StructID = ID<UStruct>;
|
||||
pub type DataID = ID<UData>;
|
||||
pub type ModID = ID<UModule>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UFunc {
|
||||
pub name: String,
|
||||
pub origin: Origin,
|
||||
@@ -26,12 +53,12 @@ pub struct UFunc {
|
||||
pub instructions: Vec<UInstrInst>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StructField {
|
||||
pub ty: TypeID,
|
||||
pub origin: Origin,
|
||||
// pub vis: Visibility
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UStruct {
|
||||
pub name: String,
|
||||
pub origin: Origin,
|
||||
@@ -39,13 +66,11 @@ pub struct UStruct {
|
||||
pub gargs: Vec<GenericID>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UGeneric {
|
||||
pub name: String,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UVar {
|
||||
pub name: String,
|
||||
pub origin: Origin,
|
||||
@@ -54,43 +79,53 @@ pub struct UVar {
|
||||
pub children: HashMap<String, VarID>,
|
||||
}
|
||||
|
||||
/// eg. a::b::c::<T,U>.d.e
|
||||
#[derive(Clone, Debug)]
|
||||
/// a generic identifier for all (identifiable) kinds
|
||||
/// eg. a::b::c.d.e
|
||||
/// or a::Result<T,_>
|
||||
pub struct UIdent {
|
||||
pub status: IdentStatus,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum IdentStatus {
|
||||
Var(VarID),
|
||||
Struct(StructInst),
|
||||
Fn(FnInst),
|
||||
Type(TypeID),
|
||||
Res(Res),
|
||||
Unres {
|
||||
path: ModPath,
|
||||
mem: MemberID,
|
||||
gargs: Vec<TypeID>,
|
||||
fields: Vec<MemberID>,
|
||||
base: ResBase,
|
||||
path: Vec<MemberIdent>,
|
||||
},
|
||||
PartialVar {
|
||||
id: VarID,
|
||||
fields: Vec<MemberID>,
|
||||
},
|
||||
Failed(ResErr),
|
||||
Failed(Option<ResErr>),
|
||||
Cooked,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct MemberID {
|
||||
pub struct MemberIdent {
|
||||
pub ty: MemberTy,
|
||||
pub name: String,
|
||||
pub gargs: Vec<TypeID>,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ModPath {
|
||||
pub id: ModID,
|
||||
pub path: Vec<MemberID>,
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum MemberTy {
|
||||
Member,
|
||||
Field,
|
||||
}
|
||||
|
||||
impl MemberTy {
|
||||
pub fn sep(&self) -> &'static str {
|
||||
match self {
|
||||
MemberTy::Member => "::",
|
||||
MemberTy::Field => ".",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MemberTy {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
MemberTy::Member => "member",
|
||||
MemberTy::Field => "field",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||
@@ -110,25 +145,163 @@ pub struct UData {
|
||||
pub struct UModule {
|
||||
pub name: String,
|
||||
pub members: HashMap<String, Member>,
|
||||
pub children: HashMap<String, ModID>,
|
||||
pub parent: Option<ModID>,
|
||||
pub func: FnID,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Member {
|
||||
pub id: MemberTy,
|
||||
pub id: MemberID,
|
||||
// pub visibility: Visibility
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum MemberTy {
|
||||
pub enum MemberID {
|
||||
Fn(FnID),
|
||||
Struct(StructID),
|
||||
Var(VarID),
|
||||
Module(ModID),
|
||||
Type(TypeDef),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TypeDef {
|
||||
pub gargs: Vec<GenericID>,
|
||||
pub ty: TypeID,
|
||||
}
|
||||
|
||||
impl MemberID {
|
||||
pub fn kind(&self) -> KindTy {
|
||||
match self {
|
||||
MemberID::Fn(_) => KindTy::Fn,
|
||||
MemberID::Struct(_) => KindTy::Struct,
|
||||
MemberID::Var(_) => KindTy::Var,
|
||||
MemberID::Module(_) => KindTy::Module,
|
||||
MemberID::Type(_) => KindTy::Type,
|
||||
}
|
||||
}
|
||||
pub fn display_str(&self, p: &UProgram) -> String {
|
||||
let name = match self {
|
||||
MemberID::Var(id) => &p.vars[id].name,
|
||||
MemberID::Fn(id) => &p.fns[id].name,
|
||||
MemberID::Struct(id) => &p.structs[id].name,
|
||||
MemberID::Module(id) => &p.modules[id].name,
|
||||
MemberID::Type(id) => &p.type_name(id),
|
||||
};
|
||||
format!("{} '{}'", self.kind(), name)
|
||||
}
|
||||
}
|
||||
|
||||
pub type Origin = FileSpan;
|
||||
|
||||
// "effective" (externally visible) kinds
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum KindTy {
|
||||
Type,
|
||||
Var,
|
||||
Struct,
|
||||
Fn,
|
||||
Module,
|
||||
Generic,
|
||||
}
|
||||
|
||||
impl Display for KindTy {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
KindTy::Type => "type",
|
||||
KindTy::Var => "variable",
|
||||
KindTy::Fn => "function",
|
||||
KindTy::Struct => "struct",
|
||||
KindTy::Module => "module",
|
||||
KindTy::Generic => "generic",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Res {
|
||||
Var(VarID),
|
||||
Fn(FnInst),
|
||||
Struct(StructInst),
|
||||
Type(TypeID),
|
||||
Generic(GenericID),
|
||||
Module(ModID),
|
||||
}
|
||||
|
||||
impl Res {
|
||||
pub fn kind(&self) -> KindTy {
|
||||
match self {
|
||||
Res::Var(..) => KindTy::Var,
|
||||
Res::Fn(..) => KindTy::Fn,
|
||||
Res::Struct(..) => KindTy::Struct,
|
||||
Res::Type(..) => KindTy::Type,
|
||||
Res::Module(..) => KindTy::Module,
|
||||
Res::Generic(..) => KindTy::Generic,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display_str(&self, p: &UProgram) -> String {
|
||||
let name = match self {
|
||||
Res::Var(id) => &p.vars[id].name,
|
||||
Res::Fn(fi) => &p.fns[fi.id].name,
|
||||
Res::Struct(si) => &p.structs[si.id].name,
|
||||
Res::Type(id) => &p.type_name(id),
|
||||
Res::Generic(id) => &p.generics[id].name,
|
||||
Res::Module(id) => &p.modules[id].name,
|
||||
};
|
||||
format!("{} '{}'", self.kind(), name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ResBase {
|
||||
Unvalidated(MemRes),
|
||||
Validated(Res),
|
||||
}
|
||||
|
||||
impl ResBase {
|
||||
pub fn display_str(&self, p: &UProgram) -> String {
|
||||
match self {
|
||||
ResBase::Unvalidated(uv) => uv.display_str(p),
|
||||
ResBase::Validated(res) => res.display_str(p),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MemRes {
|
||||
pub mem: Member,
|
||||
pub origin: Origin,
|
||||
pub gargs: Vec<TypeID>,
|
||||
}
|
||||
|
||||
impl MemRes {
|
||||
pub fn display_str(&self, p: &UProgram) -> String {
|
||||
self.mem.id.display_str(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl IdentID {
|
||||
pub fn var(&self, p: &UProgram) -> Option<VarID> {
|
||||
match p.idents[self].status {
|
||||
IdentStatus::Res(Res::Var(id)) => Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn fun<'a>(&self, p: &'a UProgram) -> Option<&'a FnInst> {
|
||||
match &p.idents[self].status {
|
||||
IdentStatus::Res(Res::Fn(i)) => Some(&i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn struc<'a>(&self, p: &'a UProgram) -> Option<&'a StructInst> {
|
||||
match &p.idents[self].status {
|
||||
IdentStatus::Res(Res::Struct(i)) => Some(&i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UFunc {
|
||||
pub fn flat_iter(&self) -> impl Iterator<Item = &UInstrInst> {
|
||||
InstrIter::new(self.instructions.iter())
|
||||
@@ -162,4 +335,3 @@ impl<'a> Iterator for InstrIter<'a> {
|
||||
Some(next)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
use super::*;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct UProgram {
|
||||
pub fns: Vec<UFunc>,
|
||||
@@ -23,12 +20,6 @@ pub struct TypeCache {
|
||||
pub error: TypeID,
|
||||
}
|
||||
|
||||
pub struct UModuleBuilder<'a> {
|
||||
pub p: &'a mut UProgram,
|
||||
pub module: ModID,
|
||||
pub temp: usize,
|
||||
}
|
||||
|
||||
impl UProgram {
|
||||
pub fn new() -> Self {
|
||||
let mut types = Vec::new();
|
||||
@@ -66,7 +57,7 @@ impl UProgram {
|
||||
push_id(&mut self.types, t)
|
||||
}
|
||||
|
||||
pub fn def_var_inst(&mut self, i: UIdent) -> IdentID {
|
||||
pub fn def_ident(&mut self, i: UIdent) -> IdentID {
|
||||
push_id(&mut self.idents, i)
|
||||
}
|
||||
|
||||
@@ -82,10 +73,18 @@ impl UProgram {
|
||||
push_id(&mut self.structs, s)
|
||||
}
|
||||
|
||||
pub fn def_module(&mut self, m: UModule) -> ModID {
|
||||
push_id(&mut self.modules, m)
|
||||
}
|
||||
|
||||
pub fn type_name(&self, ty: impl Typed) -> String {
|
||||
match ty.ty(self) {
|
||||
Type::Struct(ty) => {
|
||||
format!("{}{}", self.structs[ty.id].name, self.gparams_str(&ty.gargs))
|
||||
format!(
|
||||
"{}{}",
|
||||
self.structs[ty.id].name,
|
||||
self.gparams_str(&ty.gargs)
|
||||
)
|
||||
}
|
||||
Type::FnRef(ty) => {
|
||||
format!(
|
||||
@@ -97,13 +96,13 @@ impl UProgram {
|
||||
}
|
||||
Type::Ref(t) => format!("{}&", self.type_name(t)),
|
||||
Type::Deref(t) => format!("{}^", self.type_name(t)),
|
||||
Type::Unres(_) => "{unresolved}".to_string(),
|
||||
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::Error => "{error}".to_string(),
|
||||
Type::Infer => "{inferred}".to_string(),
|
||||
Type::Unres(_) => "{unresolved}".to_string(),
|
||||
Type::Generic(id) => self.generics[id].name.clone(),
|
||||
}
|
||||
}
|
||||
@@ -138,34 +137,6 @@ pub fn push_id<T>(v: &mut Vec<T>, t: T) -> ID<T> {
|
||||
id
|
||||
}
|
||||
|
||||
impl<'a> UModuleBuilder<'a> {
|
||||
pub fn new(program: &'a mut UProgram, id: ModID) -> Self {
|
||||
Self {
|
||||
p: program,
|
||||
module: id,
|
||||
temp: 0,
|
||||
}
|
||||
}
|
||||
pub fn temp_var(&mut self, origin: Origin, ty: impl Typable) -> IdentID {
|
||||
self.temp_var_inner(origin, ty)
|
||||
}
|
||||
fn temp_var_inner(&mut self, origin: Origin, ty: impl Typable) -> IdentID {
|
||||
let var = UVar {
|
||||
name: format!("temp{}", self.temp),
|
||||
ty: ty.ty(self),
|
||||
origin,
|
||||
parent: None,
|
||||
children: HashMap::new(),
|
||||
};
|
||||
let id = self.p.def_var(var);
|
||||
self.temp += 1;
|
||||
self.def_var_inst(UIdent {
|
||||
status: IdentStatus::Var(id),
|
||||
origin,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// I'm done with names...
|
||||
pub trait Typed {
|
||||
fn ty<'a>(&'a self, p: &'a UProgram) -> &'a Type;
|
||||
@@ -194,33 +165,3 @@ impl Typed for &Box<Type> {
|
||||
&**self
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Typable {
|
||||
fn ty(self, p: &mut UProgram) -> TypeID;
|
||||
}
|
||||
|
||||
impl Typable for Type {
|
||||
fn ty(self, p: &mut UProgram) -> TypeID {
|
||||
p.def_ty(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Typable for TypeID {
|
||||
fn ty(self, p: &mut UProgram) -> TypeID {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for UModuleBuilder<'_> {
|
||||
type Target = UProgram;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.p
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for UModuleBuilder<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.p
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
use super::{
|
||||
inst_fn_ty, inst_struct_ty, report_errs, ControlFlowOp, DataID, FnInst, IdentID, IdentStatus,
|
||||
MemberTy, Origin, ResErr, StructInst, Type, TypeID, TypeMismatch, UData, UFunc, UGeneric,
|
||||
UIdent, UInstrInst, UInstruction, UModule, UProgram, UStruct, UVar, VarID,
|
||||
inst_fn_var, inst_type, inst_typedef, inst_var, push_id, report_errs, resolve_refs, validate_gargs, ControlFlowOp, DataID, FnInst, IdentID, IdentStatus, KindTy, MemberID, MemberTy, Origin, Res, ResBase, ResErr, StructInst, Type, TypeID, TypeMismatch, UData, UFunc, UGeneric, UIdent, UInstrInst, UInstruction, UModule, UProgram, UStruct, UVar, VarID
|
||||
};
|
||||
use crate::{
|
||||
common::{CompilerMsg, CompilerOutput},
|
||||
ir::{inst_fn_var, ID},
|
||||
common::CompilerOutput,
|
||||
ir::{MemRes, Member},
|
||||
};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
@@ -14,6 +12,7 @@ use std::{
|
||||
};
|
||||
|
||||
// dawg this file is way too long
|
||||
// this is the omega file tho that's super cool
|
||||
|
||||
impl UProgram {
|
||||
pub fn resolve(&mut self, output: &mut CompilerOutput) {
|
||||
@@ -61,41 +60,8 @@ impl UProgram {
|
||||
resolve_instr(&mut data, ctx);
|
||||
}
|
||||
}
|
||||
let mut errs = data.errs;
|
||||
for ident in &self.idents {
|
||||
match &ident.status {
|
||||
IdentStatus::Unres {
|
||||
path,
|
||||
mem,
|
||||
gargs,
|
||||
fields,
|
||||
} => errs.push(ResErr::UnknownModule {
|
||||
origin: path.path[0].origin,
|
||||
name: path.path[0].name.clone(),
|
||||
}),
|
||||
IdentStatus::PartialVar { id, fields } => todo!(),
|
||||
IdentStatus::Failed(err) => errs.push(err.clone()),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
let errs = data.errs;
|
||||
report_errs(self, output, errs);
|
||||
for var in &self.vars {
|
||||
match &self.types[var.ty] {
|
||||
Type::Error => output.err(CompilerMsg::new(
|
||||
format!("Var {:?} is error type!", var.name),
|
||||
var.origin,
|
||||
)),
|
||||
Type::Infer => output.err(CompilerMsg::new(
|
||||
format!("Type of {:?} cannot be inferred", var.name),
|
||||
var.origin,
|
||||
)),
|
||||
Type::Unres(_) => output.err(CompilerMsg::new(
|
||||
format!("Var {:?} type still unresolved!", var.name),
|
||||
var.origin,
|
||||
)),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,36 +78,37 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
|
||||
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(dest, src, src);
|
||||
for (src, &dest) in args.iter().zip(&f.args) {
|
||||
res |= data.match_types::<UVar, UVar>(dest, src, src);
|
||||
}
|
||||
res |= data.match_types(dst, f.ret, dst);
|
||||
res |= data.match_types::<UVar, Type>(dst, f.ret, dst);
|
||||
}
|
||||
UInstruction::Mv { dst, src } => {
|
||||
res |= data.match_types(dst, src, src);
|
||||
res |= data.match_types::<UVar, UVar>(dst, src, src);
|
||||
}
|
||||
UInstruction::Ref { dst, src } => {
|
||||
let dstid = data.res_ty_id::<UVar>(dst, ctx)?;
|
||||
let dstid = data.res_var_ty(dst, ctx)?;
|
||||
let Type::Ref(dest_ty) = data.types[dstid] else {
|
||||
compiler_error()
|
||||
};
|
||||
res |= data.match_types(dest_ty, src, src);
|
||||
res |= data.match_types::<Type, UVar>(dest_ty, src, src);
|
||||
}
|
||||
UInstruction::Deref { dst, src } => {
|
||||
let srcid = data.res_ty_id::<UVar>(src, ctx)?;
|
||||
let srcid = data.res_var_ty(src, ctx)?;
|
||||
let Type::Ref(src_ty) = data.types[srcid] else {
|
||||
let origin = src.origin(data);
|
||||
data.errs.push(ResErr::CannotDeref { origin, ty: srcid });
|
||||
return None;
|
||||
};
|
||||
res |= data.match_types(dst, src_ty, src);
|
||||
res |= data.match_types::<UVar, Type>(dst, src_ty, src);
|
||||
}
|
||||
UInstruction::LoadData { dst, src } => {
|
||||
res |= data.match_types(dst, src, dst);
|
||||
let srcid = src.type_id(&data.s);
|
||||
res |= data.match_types::<UVar, Type>(dst, srcid, dst);
|
||||
}
|
||||
UInstruction::LoadSlice { dst, src } => {
|
||||
let dstid = data.res_id(src, ctx)?;
|
||||
let srcid = data.res_id(src, ctx)?;
|
||||
let dstid = data.res_var_ty(dst, ctx)?;
|
||||
let srcid = src.type_id(&data.s);
|
||||
let Type::Slice(dstty) = data.types[dstid] else {
|
||||
compiler_error()
|
||||
};
|
||||
@@ -150,14 +117,11 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
|
||||
};
|
||||
res |= data.match_types(dstty, srcty, dst);
|
||||
}
|
||||
UInstruction::LoadFn { dst, src } => {
|
||||
// TODO: validate size with enabled targets
|
||||
}
|
||||
UInstruction::AsmBlock { instructions, args } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::Ret { src } => {
|
||||
res |= data.match_types(ctx.ret, src, src);
|
||||
res |= data.match_types::<Type, UVar>(ctx.ret, src, src);
|
||||
}
|
||||
UInstruction::Construct { dst, struc, fields } => {
|
||||
let si = data.res_id::<UStruct>(dst, ctx)?;
|
||||
@@ -167,7 +131,7 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
|
||||
for (name, field) in &st.fields {
|
||||
if let Some(src) = fields.get(name) {
|
||||
used.insert(name);
|
||||
res |= data.match_types(field.ty, src, src);
|
||||
res |= data.match_types::<Type, UVar>(field.ty, src, src);
|
||||
} else {
|
||||
let origin = dst.origin(data);
|
||||
data.errs.push(ResErr::MissingField {
|
||||
@@ -180,7 +144,7 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
|
||||
for (name, _) in fields {
|
||||
if !used.contains(name) {
|
||||
let origin = dst.origin(data);
|
||||
data.errs.push(ResErr::UnknownField {
|
||||
data.errs.push(ResErr::UnknownStructField {
|
||||
origin,
|
||||
id: sid,
|
||||
name: name.clone(),
|
||||
@@ -189,7 +153,7 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option<
|
||||
}
|
||||
}
|
||||
UInstruction::If { cond, body } => {
|
||||
if let Some(id) = data.res_ty_id::<UVar>(cond, ctx) {
|
||||
if let Some(id) = data.res_var_ty(cond, ctx) {
|
||||
if !matches!(data.types[id], Type::Bits(64)) {
|
||||
let origin = cond.origin(data);
|
||||
data.errs.push(ResErr::CondType { origin, ty: id });
|
||||
@@ -247,24 +211,31 @@ fn compiler_error() -> ! {
|
||||
panic!("how could this happen to me (you)");
|
||||
}
|
||||
|
||||
pub fn match_types(data: &mut TypeResData, dst: impl TypeIDed, src: impl TypeIDed) -> MatchRes {
|
||||
let dst = data.res_id(dst);
|
||||
let src = data.res_id(src);
|
||||
if dst == src {
|
||||
pub fn match_types(data: &mut ResData, dst: impl TypeIDed, src: impl TypeIDed) -> MatchRes {
|
||||
let dstid = data.res_ty(&dst)?;
|
||||
let srcid = data.res_ty(&src)?;
|
||||
if dstid == srcid {
|
||||
return MatchRes::Finished;
|
||||
}
|
||||
let error = || MatchRes::Error(vec![TypeMismatch { dst, src }]);
|
||||
match (data.types[dst].clone(), data.types[src].clone()) {
|
||||
let error = || {
|
||||
MatchRes::Error(vec![TypeMismatch {
|
||||
dst: dstid,
|
||||
src: srcid,
|
||||
}])
|
||||
};
|
||||
match (data.types[dstid].clone(), data.types[srcid].clone()) {
|
||||
(Type::Error, _) | (_, Type::Error) => MatchRes::Finished,
|
||||
(Type::Infer, Type::Infer) => MatchRes::Unfinished,
|
||||
(Type::Infer, x) => {
|
||||
*data.changed = true;
|
||||
data.types[dst] = x;
|
||||
data.changed = true;
|
||||
data.types[dstid] = x;
|
||||
dst.finish(&mut data.s, data.types);
|
||||
MatchRes::Finished
|
||||
}
|
||||
(x, Type::Infer) => {
|
||||
*data.changed = true;
|
||||
data.types[src] = x;
|
||||
data.changed = true;
|
||||
data.types[srcid] = x;
|
||||
src.finish(&mut data.s, data.types);
|
||||
MatchRes::Finished
|
||||
}
|
||||
(Type::Struct(dest), Type::Struct(src)) => {
|
||||
@@ -300,18 +271,8 @@ pub fn match_types(data: &mut TypeResData, dst: impl TypeIDed, src: impl TypeIDe
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_refs(types: &[Type], id: TypeID) -> TypeID {
|
||||
if let Type::Deref(rid) = types[id]
|
||||
&& let Type::Ref(nid) = types[rid]
|
||||
{
|
||||
nid
|
||||
} else {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
fn match_all(
|
||||
data: &mut TypeResData,
|
||||
data: &mut ResData,
|
||||
dst: impl Iterator<Item = TypeID>,
|
||||
src: impl Iterator<Item = TypeID>,
|
||||
) -> MatchRes {
|
||||
@@ -353,30 +314,24 @@ struct ResData<'a> {
|
||||
errs: Vec<ResErr>,
|
||||
}
|
||||
|
||||
struct TypeResData<'a> {
|
||||
changed: &'a mut bool,
|
||||
types: &'a mut [Type],
|
||||
sources: &'a Sources<'a>,
|
||||
}
|
||||
|
||||
impl<'a> ResData<'a> {
|
||||
pub fn match_types(
|
||||
pub fn match_types<Dst: ResKind, Src: ResKind>(
|
||||
&mut self,
|
||||
dst: impl Resolvable<Type>,
|
||||
src: impl Resolvable<Type>,
|
||||
dst: impl Resolvable<Dst>,
|
||||
src: impl Resolvable<Src>,
|
||||
origin: impl HasOrigin,
|
||||
) -> InstrRes {
|
||||
let dst = dst.try_res(&mut self.s, self.types, &mut self.errs)?;
|
||||
let src = src.try_res(&mut self.s, self.types, &mut self.errs)?;
|
||||
let res = match_types(
|
||||
&mut TypeResData {
|
||||
changed: &mut self.changed,
|
||||
types: self.types,
|
||||
sources: &self.s,
|
||||
},
|
||||
dst,
|
||||
src,
|
||||
);
|
||||
) -> InstrRes
|
||||
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);
|
||||
let res = match_types(self, dst, src);
|
||||
match res {
|
||||
MatchRes::Unfinished => InstrRes::Unfinished,
|
||||
MatchRes::Finished => InstrRes::Finished,
|
||||
@@ -392,17 +347,19 @@ impl<'a> ResData<'a> {
|
||||
}
|
||||
}
|
||||
pub fn try_res_id<K: ResKind>(&mut self, x: impl Resolvable<K>) -> Result<K::Res, InstrRes> {
|
||||
x.try_res(&mut self.s, &mut self.types, &mut self.errs)
|
||||
x.try_res(
|
||||
&mut self.s,
|
||||
&mut self.types,
|
||||
&mut self.errs,
|
||||
&mut self.changed,
|
||||
)
|
||||
}
|
||||
pub fn res_ty_id<'b: 'a, K: ResKind>(
|
||||
pub fn res_var_ty<'b: 'a>(
|
||||
&mut self,
|
||||
x: impl Resolvable<K>,
|
||||
x: impl Resolvable<UVar>,
|
||||
ctx: ResolveCtx<'b>,
|
||||
) -> Option<TypeID>
|
||||
where
|
||||
K::Res: TypeIDed,
|
||||
{
|
||||
self.res_id::<K>(x, ctx).map(|i| i.type_id(&self.s))
|
||||
) -> Option<TypeID> {
|
||||
self.res_id::<UVar>(x, ctx).map(|i| i.type_id(&self.s))
|
||||
}
|
||||
pub fn res_id<'b: 'a, K: ResKind>(
|
||||
&mut self,
|
||||
@@ -416,11 +373,22 @@ impl<'a> ResData<'a> {
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeResData<'_> {
|
||||
pub fn res_id(&self, x: impl TypeIDed) -> TypeID {
|
||||
resolve_refs(self.types, x.type_id(self.sources))
|
||||
pub fn res_ty(&mut self, x: &impl TypeIDed) -> Result<TypeID, InstrRes> {
|
||||
let id = resolve_refs(self.types, x.type_id(&self.s));
|
||||
Ok(if let Type::Unres(ident) = self.types[id] {
|
||||
match self.try_res_id::<Type>(ident) {
|
||||
Ok(nid) => {
|
||||
// this does NOT feel good lmao
|
||||
self.types[id] = self.types[nid].clone();
|
||||
x.finish(&mut self.s, self.types);
|
||||
nid
|
||||
}
|
||||
Err(res) => return Err(res),
|
||||
}
|
||||
} else {
|
||||
id
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,6 +404,155 @@ pub enum InstrRes {
|
||||
Unfinished,
|
||||
}
|
||||
|
||||
impl MemRes {
|
||||
pub fn validate(
|
||||
&self,
|
||||
fns: &[UFunc],
|
||||
structs: &[UStruct],
|
||||
generics: &[UGeneric],
|
||||
types: &mut Vec<Type>,
|
||||
errs: &mut Vec<ResErr>,
|
||||
) -> Result<Res, Option<ResErr>> {
|
||||
let no_gargs = || {
|
||||
if self.gargs.len() > 0 {
|
||||
Err(ResErr::GenericCount {
|
||||
origin: self.origin,
|
||||
expected: 0,
|
||||
found: self.gargs.len(),
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
Ok(match &self.mem.id {
|
||||
&MemberID::Fn(id) => {
|
||||
validate_gargs(
|
||||
&fns[id].gargs,
|
||||
&self.gargs,
|
||||
generics,
|
||||
types,
|
||||
errs,
|
||||
self.origin,
|
||||
)?;
|
||||
Res::Fn(FnInst {
|
||||
id,
|
||||
gargs: self.gargs.clone(),
|
||||
})
|
||||
}
|
||||
&MemberID::Struct(id) => {
|
||||
validate_gargs(
|
||||
&structs[id].gargs,
|
||||
&self.gargs,
|
||||
generics,
|
||||
types,
|
||||
errs,
|
||||
self.origin,
|
||||
)?;
|
||||
Res::Struct(StructInst {
|
||||
id,
|
||||
gargs: self.gargs.clone(),
|
||||
})
|
||||
}
|
||||
&MemberID::Var(id) => {
|
||||
no_gargs()?;
|
||||
Res::Var(id)
|
||||
}
|
||||
&MemberID::Module(id) => {
|
||||
no_gargs()?;
|
||||
Res::Module(id)
|
||||
}
|
||||
MemberID::Type(def) => {
|
||||
validate_gargs(&def.gargs, &self.gargs, generics, types, errs, self.origin)?;
|
||||
inst_typedef(def, &self.gargs, types);
|
||||
Res::Type(def.ty)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl IdentID {
|
||||
pub fn resolve(
|
||||
self,
|
||||
s: &mut Sources,
|
||||
types: &mut Vec<Type>,
|
||||
changed: &mut bool,
|
||||
errs: &mut Vec<ResErr>,
|
||||
) -> Result<Res, InstrRes> {
|
||||
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(InstrRes::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(InstrRes::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(InstrRes::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(InstrRes::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(InstrRes::Finished);
|
||||
}
|
||||
}
|
||||
}
|
||||
ResBase::Validated(res) => res.clone(),
|
||||
};
|
||||
*status = IdentStatus::Res(res.clone());
|
||||
*changed = true;
|
||||
res
|
||||
}
|
||||
IdentStatus::Cooked => return Err(InstrRes::Finished),
|
||||
IdentStatus::Failed(_) => return Err(InstrRes::Finished),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOrAssign for InstrRes {
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
match rhs {
|
||||
@@ -457,134 +574,23 @@ trait Resolvable<K: ResKind> {
|
||||
s: &mut Sources,
|
||||
types: &mut Vec<Type>,
|
||||
errs: &mut Vec<ResErr>,
|
||||
changed: &mut bool,
|
||||
) -> Result<K::Res, InstrRes>;
|
||||
}
|
||||
|
||||
impl<T: TypeIDed> Resolvable<Type> for T {
|
||||
fn try_res(
|
||||
&self,
|
||||
s: &mut Sources,
|
||||
_: &mut Vec<Type>,
|
||||
errs: &mut Vec<ResErr>,
|
||||
) -> Result<TypeID, InstrRes> {
|
||||
Ok(self.type_id(s))
|
||||
}
|
||||
}
|
||||
|
||||
impl IdentID {
|
||||
pub fn resolve(self, s: &mut Sources) -> Result<Res, InstrRes> {
|
||||
let ident = &mut s.idents[self];
|
||||
Ok(match &mut ident.status {
|
||||
IdentStatus::Var(id) => Res::Var(*id),
|
||||
IdentStatus::Struct(sty) => Res::Struct(sty.clone()),
|
||||
IdentStatus::Fn(fty) => Res::Fn(fty.clone()),
|
||||
IdentStatus::Type(ty) => Res::Type(*ty),
|
||||
IdentStatus::Unres {
|
||||
path,
|
||||
mem,
|
||||
gargs,
|
||||
fields,
|
||||
} => {
|
||||
let mut mid = path.id;
|
||||
let mut count = 0;
|
||||
for mem in &path.path {
|
||||
let Some(&child) = s.modules[mid].children.get(&mem.name) else {
|
||||
break;
|
||||
};
|
||||
count += 1;
|
||||
mid = child;
|
||||
}
|
||||
path.path.drain(0..count);
|
||||
path.id = mid;
|
||||
if path.path.len() != 0 {
|
||||
return Err(InstrRes::Unfinished);
|
||||
}
|
||||
let Some(mem) = s.modules[mid].members.get(&mem.name) else {
|
||||
return Err(InstrRes::Unfinished);
|
||||
};
|
||||
match mem.id {
|
||||
MemberTy::Fn(id) => {
|
||||
if fields.len() > 0 {
|
||||
ident.status = IdentStatus::Failed(ResErr::UnexpectedField {
|
||||
origin: ident.origin,
|
||||
});
|
||||
return Err(InstrRes::Finished);
|
||||
}
|
||||
let fty = FnInst {
|
||||
id,
|
||||
gargs: gargs.clone(),
|
||||
};
|
||||
ident.status = IdentStatus::Fn(fty.clone());
|
||||
Res::Fn(fty)
|
||||
}
|
||||
MemberTy::Struct(id) => {
|
||||
if fields.len() > 0 {
|
||||
ident.status = IdentStatus::Failed(ResErr::UnexpectedField {
|
||||
origin: ident.origin,
|
||||
});
|
||||
return Err(InstrRes::Finished);
|
||||
}
|
||||
let sty = StructInst {
|
||||
id,
|
||||
gargs: gargs.clone(),
|
||||
};
|
||||
ident.status = IdentStatus::Struct(sty.clone());
|
||||
Res::Struct(sty)
|
||||
}
|
||||
MemberTy::Var(id) => {
|
||||
if !gargs.is_empty() {
|
||||
ident.status = IdentStatus::Failed(ResErr::GenericCount {
|
||||
origin: ident.origin,
|
||||
expected: 0,
|
||||
found: gargs.len(),
|
||||
});
|
||||
return Err(InstrRes::Finished);
|
||||
}
|
||||
ident.status = IdentStatus::PartialVar {
|
||||
id,
|
||||
fields: fields.clone(),
|
||||
};
|
||||
return self.resolve(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
IdentStatus::PartialVar { id, fields } => {
|
||||
let mut fiter = fields.iter();
|
||||
let mut next = fiter.next();
|
||||
let mut count = 0;
|
||||
while let Some(mem) = next
|
||||
&& let Some(&cid) = s.vars[*id].children.get(&mem.name)
|
||||
{
|
||||
*id = cid;
|
||||
next = fiter.next();
|
||||
count += 1;
|
||||
}
|
||||
fields.drain(0..count);
|
||||
if fields.len() != 0 {
|
||||
return Err(InstrRes::Unfinished);
|
||||
}
|
||||
let id = *id;
|
||||
ident.status = IdentStatus::Var(id);
|
||||
Res::Var(id)
|
||||
}
|
||||
IdentStatus::Cooked => return Err(InstrRes::Finished),
|
||||
IdentStatus::Failed(_) => return Err(InstrRes::Finished),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: ResKind> Resolvable<K> for IdentID {
|
||||
fn try_res(
|
||||
&self,
|
||||
s: &mut Sources,
|
||||
types: &mut Vec<Type>,
|
||||
errs: &mut Vec<ResErr>,
|
||||
changed: &mut bool,
|
||||
) -> Result<K::Res, InstrRes> {
|
||||
let origin = s.idents[self].origin;
|
||||
let res = self.resolve(s)?;
|
||||
match K::from_res(res.clone(), types, s, origin, errs) {
|
||||
Some(res) => Ok(res),
|
||||
None => {
|
||||
let res = self.resolve(s, types, changed, errs)?;
|
||||
match K::from_res(res, types, s, origin) {
|
||||
Ok(res) => Ok(res),
|
||||
Err(res) => {
|
||||
errs.push(ResErr::KindMismatch {
|
||||
origin,
|
||||
expected: K::ty(),
|
||||
@@ -596,45 +602,39 @@ impl<K: ResKind> Resolvable<K> for IdentID {
|
||||
}
|
||||
}
|
||||
|
||||
// "effective" (externally visible) kinds
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum KindTy {
|
||||
Type,
|
||||
Var,
|
||||
Struct,
|
||||
Fn,
|
||||
}
|
||||
|
||||
impl KindTy {
|
||||
pub fn str(&self) -> &'static str {
|
||||
match self {
|
||||
KindTy::Type => "type",
|
||||
KindTy::Var => "variable",
|
||||
KindTy::Fn => "function",
|
||||
KindTy::Struct => "struct",
|
||||
}
|
||||
impl<K: ResKind> Resolvable<K> for &IdentID {
|
||||
fn try_res(
|
||||
&self,
|
||||
s: &mut Sources,
|
||||
types: &mut Vec<Type>,
|
||||
errs: &mut Vec<ResErr>,
|
||||
changed: &mut bool,
|
||||
) -> Result<K::Res, InstrRes> {
|
||||
Resolvable::<K>::try_res(*self, s, types, errs, changed)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Res {
|
||||
Var(VarID),
|
||||
Fn(FnInst),
|
||||
Struct(StructInst),
|
||||
Type(TypeID),
|
||||
impl Resolvable<UVar> for VarID {
|
||||
fn try_res(
|
||||
&self,
|
||||
s: &mut Sources,
|
||||
types: &mut Vec<Type>,
|
||||
errs: &mut Vec<ResErr>,
|
||||
changed: &mut bool,
|
||||
) -> Result<<UVar as ResKind>::Res, InstrRes> {
|
||||
Ok(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Res {
|
||||
pub fn kind(&self) -> KindTy {
|
||||
match self {
|
||||
Res::Var(..) => KindTy::Var,
|
||||
Res::Fn(..) => KindTy::Fn,
|
||||
Res::Struct(..) => KindTy::Struct,
|
||||
Res::Type(..) => KindTy::Type,
|
||||
}
|
||||
}
|
||||
pub fn kind_str(&self) -> &'static str {
|
||||
self.kind().str()
|
||||
impl Resolvable<Type> for TypeID {
|
||||
fn try_res(
|
||||
&self,
|
||||
s: &mut Sources,
|
||||
types: &mut Vec<Type>,
|
||||
errs: &mut Vec<ResErr>,
|
||||
changed: &mut bool,
|
||||
) -> Result<<Type as ResKind>::Res, InstrRes> {
|
||||
Ok(*self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,8 +646,7 @@ pub trait ResKind {
|
||||
types: &mut Vec<Type>,
|
||||
s: &mut Sources,
|
||||
origin: Origin,
|
||||
errs: &mut Vec<ResErr>,
|
||||
) -> Option<Self::Res>;
|
||||
) -> Result<Self::Res, Res>;
|
||||
}
|
||||
|
||||
impl ResKind for UFunc {
|
||||
@@ -655,16 +654,10 @@ impl ResKind for UFunc {
|
||||
fn ty() -> KindTy {
|
||||
KindTy::Fn
|
||||
}
|
||||
fn from_res(
|
||||
res: Res,
|
||||
_: &mut Vec<Type>,
|
||||
_: &mut Sources,
|
||||
_: Origin,
|
||||
_: &mut Vec<ResErr>,
|
||||
) -> Option<Self::Res> {
|
||||
fn from_res(res: Res, _: &mut Vec<Type>, _: &mut Sources, _: Origin) -> Result<Self::Res, Res> {
|
||||
match res {
|
||||
Res::Fn(fi) => Some(fi),
|
||||
_ => None,
|
||||
Res::Fn(fi) => Ok(fi),
|
||||
_ => Err(res),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -679,13 +672,11 @@ impl ResKind for UVar {
|
||||
types: &mut Vec<Type>,
|
||||
s: &mut Sources,
|
||||
origin: Origin,
|
||||
errs: &mut Vec<ResErr>,
|
||||
) -> Option<Self::Res> {
|
||||
Some(match res {
|
||||
Res::Fn(fty) => inst_fn_var(&fty, s.fns, origin, s.vars, types, s.generics, errs),
|
||||
) -> Result<Self::Res, Res> {
|
||||
Ok(match res {
|
||||
Res::Fn(fty) => inst_fn_var(fty, s.fns, origin, s.vars, types),
|
||||
Res::Var(id) => id,
|
||||
Res::Struct(_) => return None,
|
||||
Res::Type(_) => return None,
|
||||
_ => return Err(res),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -695,16 +686,10 @@ impl ResKind for UStruct {
|
||||
fn ty() -> KindTy {
|
||||
KindTy::Struct
|
||||
}
|
||||
fn from_res(
|
||||
res: Res,
|
||||
_: &mut Vec<Type>,
|
||||
_: &mut Sources,
|
||||
_: Origin,
|
||||
_: &mut Vec<ResErr>,
|
||||
) -> Option<Self::Res> {
|
||||
fn from_res(res: Res, _: &mut Vec<Type>, _: &mut Sources, _: Origin) -> Result<Self::Res, Res> {
|
||||
match res {
|
||||
Res::Struct(si) => Some(si),
|
||||
_ => None,
|
||||
Res::Struct(si) => Ok(si),
|
||||
_ => Err(res),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -719,30 +704,18 @@ impl ResKind for Type {
|
||||
types: &mut Vec<Type>,
|
||||
s: &mut Sources,
|
||||
_: Origin,
|
||||
errs: &mut Vec<ResErr>,
|
||||
) -> Option<Self::Res> {
|
||||
Some(match res {
|
||||
Res::Fn(fty) => inst_fn_ty(&fty, s.fns, types, s.generics, errs),
|
||||
Res::Var(id) => id.type_id(s),
|
||||
Res::Struct(si) => inst_struct_ty(&si, s.structs, types, s.generics, errs),
|
||||
) -> Result<Self::Res, Res> {
|
||||
Ok(match res {
|
||||
Res::Struct(si) => push_id(types, Type::Struct(si)),
|
||||
Res::Type(id) => id,
|
||||
_ => return Err(res),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: ResKind> Resolvable<K> for &IdentID {
|
||||
fn try_res(
|
||||
&self,
|
||||
s: &mut Sources,
|
||||
types: &mut Vec<Type>,
|
||||
errs: &mut Vec<ResErr>,
|
||||
) -> Result<K::Res, InstrRes> {
|
||||
Resolvable::<K>::try_res(*self, s, types, errs)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TypeIDed {
|
||||
fn type_id(&self, s: &Sources) -> TypeID;
|
||||
fn finish(&self, s: &mut Sources, types: &mut Vec<Type>) {}
|
||||
}
|
||||
|
||||
impl TypeIDed for TypeID {
|
||||
@@ -755,6 +728,9 @@ 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 {
|
||||
@@ -769,8 +745,8 @@ impl<T: TypeIDed> TypeIDed for &T {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromResidual<std::result::Result<std::convert::Infallible, InstrRes>> for InstrRes {
|
||||
fn from_residual(residual: std::result::Result<std::convert::Infallible, InstrRes>) -> Self {
|
||||
impl FromResidual<Result<Infallible, InstrRes>> for InstrRes {
|
||||
fn from_residual(residual: Result<Infallible, InstrRes>) -> Self {
|
||||
match residual {
|
||||
Ok(_) => unreachable!(),
|
||||
Err(r) => r,
|
||||
@@ -787,3 +763,11 @@ impl HasOrigin for &IdentID {
|
||||
data.s.idents[*self].origin
|
||||
}
|
||||
}
|
||||
impl FromResidual<Result<Infallible, MatchRes>> for MatchRes {
|
||||
fn from_residual(residual: Result<Infallible, MatchRes>) -> Self {
|
||||
match residual {
|
||||
Ok(_) => unreachable!(),
|
||||
Err(r) => r,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::{
|
||||
push_id, FnID, GenericID, Len, ModPath, Origin, ResErr, StructID, TypeID, UFunc, UGeneric,
|
||||
UProgram, UStruct, UVar, VarID,
|
||||
push_id, FnID, GenericID, IdentID, Len, Origin, ResErr, StructID, TypeDef, TypeID, UFunc,
|
||||
UGeneric, UProgram, UStruct, UVar, VarID,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
@@ -14,12 +14,14 @@ pub struct FieldRef {
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct StructInst {
|
||||
pub id: StructID,
|
||||
/// assumed to be valid
|
||||
pub gargs: Vec<TypeID>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct FnInst {
|
||||
pub id: FnID,
|
||||
/// assumed to be valid
|
||||
pub gargs: Vec<TypeID>,
|
||||
}
|
||||
|
||||
@@ -36,7 +38,7 @@ pub enum Type {
|
||||
Array(TypeID, Len),
|
||||
Unit,
|
||||
// "fake" types
|
||||
Unres(ModPath),
|
||||
Unres(IdentID),
|
||||
Generic(GenericID),
|
||||
Infer,
|
||||
Error,
|
||||
@@ -79,16 +81,14 @@ impl Type {
|
||||
}
|
||||
|
||||
pub fn inst_fn_var(
|
||||
fi: &FnInst,
|
||||
fi: FnInst,
|
||||
fns: &[UFunc],
|
||||
origin: Origin,
|
||||
vars: &mut Vec<UVar>,
|
||||
types: &mut Vec<Type>,
|
||||
generics: &[UGeneric],
|
||||
errs: &mut Vec<ResErr>,
|
||||
) -> VarID {
|
||||
let ty = inst_fn_ty(fi, fns, types, generics, errs);
|
||||
let name = fns[fi.id].name.clone();
|
||||
let ty = push_id(types, Type::FnRef(fi));
|
||||
push_id(
|
||||
vars,
|
||||
UVar {
|
||||
@@ -101,33 +101,16 @@ pub fn inst_fn_var(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn inst_fn_ty(
|
||||
fi: &FnInst,
|
||||
fns: &[UFunc],
|
||||
types: &mut Vec<Type>,
|
||||
generics: &[UGeneric],
|
||||
errs: &mut Vec<ResErr>,
|
||||
) -> TypeID {
|
||||
let f = &fns[fi.id];
|
||||
let ty = Type::FnRef(FnInst {
|
||||
id: fi.id,
|
||||
gargs: inst_generics(&f.gargs, &fi.gargs, types, generics, errs),
|
||||
});
|
||||
push_id(types, ty)
|
||||
}
|
||||
|
||||
pub fn inst_struct_var(
|
||||
si: &StructInst,
|
||||
si: StructInst,
|
||||
structs: &[UStruct],
|
||||
origin: Origin,
|
||||
vars: &mut Vec<UVar>,
|
||||
types: &mut Vec<Type>,
|
||||
generics: &[UGeneric],
|
||||
errs: &mut Vec<ResErr>,
|
||||
) -> VarID {
|
||||
let ty = inst_struct_ty(si, structs, types, generics, errs);
|
||||
let name = structs[si.id].name.clone();
|
||||
push_id(
|
||||
let ty = push_id(types, Type::Struct(si));
|
||||
let id = push_id(
|
||||
vars,
|
||||
UVar {
|
||||
name,
|
||||
@@ -136,68 +119,91 @@ pub fn inst_struct_var(
|
||||
parent: None,
|
||||
children: HashMap::new(),
|
||||
},
|
||||
)
|
||||
);
|
||||
inst_var(vars, structs, id, types);
|
||||
id
|
||||
}
|
||||
|
||||
pub fn inst_struct_ty(
|
||||
si: &StructInst,
|
||||
structs: &[UStruct],
|
||||
types: &mut Vec<Type>,
|
||||
pub fn inst_var(vars: &mut Vec<UVar>, structs: &[UStruct], id: VarID, types: &mut Vec<Type>) {
|
||||
match &types[resolve_refs(types, vars[id].ty)] {
|
||||
Type::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;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_refs(types: &[Type], id: TypeID) -> TypeID {
|
||||
if let Type::Deref(rid) = types[id]
|
||||
&& let Type::Ref(nid) = types[rid]
|
||||
{
|
||||
nid
|
||||
} else {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_gargs(
|
||||
dst: &[GenericID],
|
||||
src: &[TypeID],
|
||||
generics: &[UGeneric],
|
||||
types: &[Type],
|
||||
errs: &mut Vec<ResErr>,
|
||||
) -> TypeID {
|
||||
let s = &structs[si.id];
|
||||
let ty = Type::Struct(StructInst {
|
||||
id: si.id,
|
||||
gargs: inst_generics(&s.gargs, &si.gargs, types, generics, errs),
|
||||
});
|
||||
push_id(types, ty)
|
||||
origin: Origin,
|
||||
) -> Result<(), Option<ResErr>> {
|
||||
if dst.len() != src.len() {
|
||||
return Err(Some(ResErr::GenericCount {
|
||||
origin,
|
||||
expected: dst.len(),
|
||||
found: src.len(),
|
||||
}));
|
||||
}
|
||||
for (dst, src) in dst.iter().zip(src.iter()) {
|
||||
let g = &generics[dst];
|
||||
let t = &types[src];
|
||||
// TODO: validate trait constraints
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn inst_generics(
|
||||
source: &[GenericID],
|
||||
args: &[TypeID],
|
||||
types: &mut Vec<Type>,
|
||||
// will be needed when constraints are added
|
||||
_generics: &[UGeneric],
|
||||
errs: &mut Vec<ResErr>,
|
||||
) -> Vec<TypeID> {
|
||||
if source.len() != args.len() {
|
||||
// don't want unequal lengths to be inferred further
|
||||
return source.iter().map(|_| push_id(types, Type::Error)).collect();
|
||||
}
|
||||
let mut gargs = Vec::new();
|
||||
/// 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);
|
||||
inst_type(def.ty, types, &gmap)
|
||||
}
|
||||
|
||||
pub fn inst_gmap(dst: &[GenericID], src: &[TypeID]) -> HashMap<GenericID, TypeID> {
|
||||
let mut gmap = HashMap::new();
|
||||
for &gid in source {
|
||||
let id = push_id(types, Type::Error);
|
||||
gmap.insert(gid, id);
|
||||
gargs.push(id);
|
||||
for (&gid, &tid) in dst.iter().zip(src) {
|
||||
gmap.insert(gid, tid);
|
||||
}
|
||||
for (gid, &ty) in source.iter().zip(args) {
|
||||
inst_type_ins(
|
||||
|types, ty| {
|
||||
let id = gmap[gid];
|
||||
types[id] = ty;
|
||||
id
|
||||
},
|
||||
ty,
|
||||
types,
|
||||
&gmap,
|
||||
);
|
||||
}
|
||||
gargs
|
||||
gmap
|
||||
}
|
||||
|
||||
pub fn inst_type(id: TypeID, types: &mut Vec<Type>, gmap: &HashMap<GenericID, TypeID>) -> TypeID {
|
||||
inst_type_ins(push_id, id, types, gmap)
|
||||
}
|
||||
|
||||
pub fn inst_type_ins(
|
||||
insert: impl Fn(&mut Vec<Type>, Type) -> TypeID,
|
||||
id: TypeID,
|
||||
types: &mut Vec<Type>,
|
||||
gmap: &HashMap<GenericID, TypeID>,
|
||||
) -> TypeID {
|
||||
let ty = match types[id].clone() {
|
||||
Type::Bits(_) => return id,
|
||||
Type::Struct(struct_ty) => Type::Struct(StructInst {
|
||||
@@ -226,5 +232,7 @@ pub fn inst_type_ins(
|
||||
Type::Infer => Type::Infer,
|
||||
Type::Error => Type::Error,
|
||||
};
|
||||
insert(types, ty)
|
||||
push_id(types, ty)
|
||||
}
|
||||
|
||||
// type Test<T, U> = (&T, &U)
|
||||
|
||||
Reference in New Issue
Block a user