INITIAL GENERICS IMPL
This commit is contained in:
@@ -3,9 +3,12 @@ use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
|
||||
use super::{Type, UProgram};
|
||||
|
||||
impl CompilerOutput {
|
||||
pub fn check_assign(&mut self, p: &UProgram, src: &Type, dest: &Type, span: FileSpan) -> bool {
|
||||
pub fn check_assign(&mut self, p: &UProgram, src: &Type, dest: &Type, span: FileSpan) {
|
||||
// TODO: spans
|
||||
if src != dest {
|
||||
if !src.is_real() || !dest.is_real() {
|
||||
return;
|
||||
}
|
||||
self.err(CompilerMsg {
|
||||
msg: format!(
|
||||
"Cannot assign type '{}' to '{}'",
|
||||
@@ -14,9 +17,6 @@ impl CompilerOutput {
|
||||
),
|
||||
spans: vec![span],
|
||||
});
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{collections::HashMap, fmt::Write};
|
||||
|
||||
use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, UInstrInst, UFunc};
|
||||
use crate::{compiler::arch::riscv::Reg, ir::FieldID, util::Padder};
|
||||
use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, UFunc, UInstrInst};
|
||||
use crate::{compiler::arch::riscv::Reg, util::Padder};
|
||||
|
||||
pub enum UInstruction {
|
||||
Mv {
|
||||
@@ -38,7 +38,7 @@ pub enum UInstruction {
|
||||
},
|
||||
Construct {
|
||||
dest: VarInst,
|
||||
fields: HashMap<FieldID, VarInst>,
|
||||
fields: HashMap<String, VarInst>,
|
||||
},
|
||||
If {
|
||||
cond: VarInst,
|
||||
|
||||
@@ -3,11 +3,9 @@ use crate::{
|
||||
ir::{Len, Named, ID},
|
||||
};
|
||||
|
||||
use super::{Type, UInstrInst, UProgram};
|
||||
use super::{Type, UInstrInst, UInstruction, UProgram};
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
pub const NAMED_KINDS: usize = 4;
|
||||
|
||||
pub struct UFunc {
|
||||
pub args: Vec<VarID>,
|
||||
pub ret: Type,
|
||||
@@ -17,17 +15,19 @@ pub struct UFunc {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StructField {
|
||||
pub name: String,
|
||||
pub ty: Type,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UStruct {
|
||||
pub fields: Vec<StructField>,
|
||||
pub field_map: HashMap<String, FieldID>,
|
||||
pub fields: HashMap<String, StructField>,
|
||||
pub generics: Vec<GenericID>,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UGeneric {}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UVar {
|
||||
pub parent: Option<FieldRef>,
|
||||
@@ -41,13 +41,10 @@ pub struct VarOffset {
|
||||
pub offset: Len,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
pub struct FieldRef {
|
||||
pub var: VarID,
|
||||
// this is technically redundant bc you can get it from the var...
|
||||
// but it makes things a lot easier, and you'd have to recheck the fields anyways
|
||||
pub struc: StructID,
|
||||
pub field: FieldID,
|
||||
pub field: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -70,84 +67,68 @@ impl UFunc {
|
||||
ret: Box::new(self.ret.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UStruct {
|
||||
pub fn field(&self, id: FieldID) -> &StructField {
|
||||
&self.fields[id.0]
|
||||
}
|
||||
pub fn get_field(&self, name: &str) -> Option<&StructField> {
|
||||
self.field_map.get(name).map(|id| self.field(*id))
|
||||
}
|
||||
pub fn iter_fields(&self) -> impl Iterator<Item = (FieldID, &StructField)> {
|
||||
self.fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, f)| (FieldID::new(i), f))
|
||||
pub fn flat_iter(&self) -> impl Iterator<Item = &UInstrInst> {
|
||||
InstrIter::new(self.instructions.iter())
|
||||
}
|
||||
}
|
||||
|
||||
pub type StructID = ID<UStruct>;
|
||||
pub type VarID = ID<UVar>;
|
||||
pub type DataID = ID<UData>;
|
||||
pub type FieldID = ID<StructField>;
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_kind {
|
||||
($struc:ty, $idx:expr, $field:ident, $name:expr) => {
|
||||
impl Kind for $struc {
|
||||
const INDEX: usize = $idx;
|
||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||
&mut program.$field
|
||||
}
|
||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||
&program.$field
|
||||
}
|
||||
}
|
||||
impl Named for $struc {
|
||||
const NAME: &str = $name;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_kind!(UFunc, 0, fns, "func");
|
||||
impl_kind!(UVar, 1, vars, "var");
|
||||
impl_kind!(UStruct, 2, structs, "struct");
|
||||
impl_kind!(UGeneric, 3, types, "type");
|
||||
impl_kind!(UData, 4, data, "data");
|
||||
pub const NAMED_KINDS: usize = 5;
|
||||
|
||||
pub type FnID = ID<UFunc>;
|
||||
|
||||
impl Kind for UFunc {
|
||||
const INDEX: usize = 0;
|
||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||
&mut program.fns
|
||||
}
|
||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||
&program.fns
|
||||
}
|
||||
}
|
||||
impl Named for UFunc {
|
||||
const NAME: &str = "func";
|
||||
}
|
||||
|
||||
impl Kind for UVar {
|
||||
const INDEX: usize = 1;
|
||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||
&mut program.vars
|
||||
}
|
||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||
&program.vars
|
||||
}
|
||||
}
|
||||
impl Named for UVar {
|
||||
const NAME: &str = "var";
|
||||
}
|
||||
|
||||
impl Kind for UStruct {
|
||||
const INDEX: usize = 2;
|
||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||
&mut program.structs
|
||||
}
|
||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||
&program.structs
|
||||
}
|
||||
}
|
||||
impl Named for UStruct {
|
||||
const NAME: &str = "struct";
|
||||
}
|
||||
|
||||
impl Kind for UData {
|
||||
const INDEX: usize = 3;
|
||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||
&mut program.data
|
||||
}
|
||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||
&program.data
|
||||
}
|
||||
}
|
||||
impl Named for UData {
|
||||
const NAME: &str = "data";
|
||||
}
|
||||
|
||||
impl Named for StructField {
|
||||
const NAME: &str = "field";
|
||||
}
|
||||
pub type VarID = ID<UVar>;
|
||||
pub type StructID = ID<UStruct>;
|
||||
pub type DataID = ID<UData>;
|
||||
pub type GenericID = ID<UGeneric>;
|
||||
|
||||
pub trait Kind {
|
||||
const INDEX: usize;
|
||||
|
||||
@@ -6,6 +6,7 @@ pub struct UProgram {
|
||||
pub fns: Vec<Option<UFunc>>,
|
||||
pub vars: Vec<Option<UVar>>,
|
||||
pub structs: Vec<Option<UStruct>>,
|
||||
pub types: Vec<Option<UGeneric>>,
|
||||
pub data: Vec<Option<UData>>,
|
||||
pub start: Option<FnID>,
|
||||
pub names: NameMap,
|
||||
@@ -46,6 +47,7 @@ impl UProgram {
|
||||
fns: Vec::new(),
|
||||
vars: Vec::new(),
|
||||
structs: Vec::new(),
|
||||
types: Vec::new(),
|
||||
data: Vec::new(),
|
||||
start: None,
|
||||
names: NameMap::new(),
|
||||
@@ -87,27 +89,6 @@ impl UProgram {
|
||||
pub fn get_fn_var(&self, id: VarID) -> Option<&UFunc> {
|
||||
self.fns[self.fn_map.get(&id)?.0].as_ref()
|
||||
}
|
||||
pub fn size_of_type(&self, ty: &Type) -> Option<Size> {
|
||||
// TODO: target matters
|
||||
Some(match ty {
|
||||
Type::Bits(b) => *b,
|
||||
Type::Struct { id, args } => self.structs[id.0]
|
||||
.as_ref()?
|
||||
.fields
|
||||
.iter()
|
||||
.try_fold(0, |sum, f| Some(sum + self.size_of_type(&f.ty)?))?,
|
||||
Type::Fn { args, ret } => todo!(),
|
||||
Type::Ref(_) => 64,
|
||||
Type::Array(ty, len) => self.size_of_type(ty)? * len,
|
||||
Type::Slice(_) => 128,
|
||||
Type::Infer => return None,
|
||||
Type::Error => return None,
|
||||
Type::Unit => 0,
|
||||
})
|
||||
}
|
||||
pub fn size_of_var(&self, var: VarID) -> Option<Size> {
|
||||
self.size_of_type(&self.get(var)?.ty)
|
||||
}
|
||||
pub fn temp_subvar(&mut self, origin: Origin, ty: Type, parent: FieldRef) -> VarInst {
|
||||
self.temp_var_inner(origin, ty, Some(parent))
|
||||
}
|
||||
@@ -145,6 +126,22 @@ impl UProgram {
|
||||
id
|
||||
}
|
||||
|
||||
pub fn field_type<'a>(&'a self, sty: &'a Type, field: &str) -> Option<&'a Type> {
|
||||
let Type::Struct { id, args } = sty else {
|
||||
return None;
|
||||
};
|
||||
let struc = self.get(*id)?;
|
||||
let field = struc.fields.get(field)?;
|
||||
if let Type::Generic { id } = field.ty {
|
||||
for (i, g) in struc.generics.iter().enumerate() {
|
||||
if *g == id {
|
||||
return Some(&args[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(&field.ty)
|
||||
}
|
||||
|
||||
pub fn type_name(&self, ty: &Type) -> String {
|
||||
let mut str = String::new();
|
||||
match ty {
|
||||
@@ -176,10 +173,12 @@ impl UProgram {
|
||||
}
|
||||
Type::Error => str += "{error}",
|
||||
Type::Infer => str += "{inferred}",
|
||||
Type::Generic { id } => str += self.names.get(*id),
|
||||
Type::Bits(size) => str += &format!("b{}", size),
|
||||
Type::Array(t, len) => str += &format!("[{}; {len}]", self.type_name(t)),
|
||||
Type::Unit => str += "()",
|
||||
Type::Slice(t) => str += &format!("&[{}]", self.type_name(t)),
|
||||
Type::Placeholder => str += "{placeholder}",
|
||||
}
|
||||
str
|
||||
}
|
||||
@@ -192,22 +191,6 @@ impl UProgram {
|
||||
last.insert(name, Idents::new(id.into()));
|
||||
}
|
||||
}
|
||||
pub fn var_offset(&self, var: VarID) -> Option<VarOffset> {
|
||||
let mut current = VarOffset { id: var, offset: 0 };
|
||||
while let Some(parent) = self.get(current.id)?.parent {
|
||||
current.id = parent.var;
|
||||
current.offset += self.field_offset(parent.struc, parent.field)?;
|
||||
}
|
||||
Some(current)
|
||||
}
|
||||
pub fn field_offset(&self, struct_id: StructID, field: FieldID) -> Option<Len> {
|
||||
let struc = self.get(struct_id)?;
|
||||
let mut offset = 0;
|
||||
for i in 0..field.0 {
|
||||
offset += self.size_of_type(&struc.fields[i].ty)?;
|
||||
}
|
||||
Some(offset)
|
||||
}
|
||||
pub fn iter_vars(&self) -> impl Iterator<Item = (VarID, &UVar)> {
|
||||
self.vars
|
||||
.iter()
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
use super::{Len, StructID, UInstruction, UProgram, UVar, VarID};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
use super::{GenericID, Len, StructID, UInstruction, UProgram, UVar, VarID};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Type {
|
||||
Bits(u32),
|
||||
Struct { id: StructID, args: Vec<Type> },
|
||||
Generic { id: GenericID },
|
||||
Fn { args: Vec<Type>, ret: Box<Type> },
|
||||
Ref(Box<Type>),
|
||||
Slice(Box<Type>),
|
||||
Array(Box<Type>, Len),
|
||||
Infer,
|
||||
Error,
|
||||
Placeholder,
|
||||
Unit,
|
||||
}
|
||||
|
||||
@@ -23,81 +27,163 @@ impl Type {
|
||||
pub fn slice(self) -> Self {
|
||||
Self::Slice(Box::new(self))
|
||||
}
|
||||
pub fn is_real(&self) -> bool {
|
||||
!matches!(self, Self::Error | Self::Placeholder | Self::Infer)
|
||||
}
|
||||
}
|
||||
|
||||
impl UProgram {
|
||||
pub fn resolve_types(&mut self) {
|
||||
// I LOVE RUST
|
||||
let mut vars = self.vars.clone();
|
||||
for f in self.fns.iter().flatten() {
|
||||
for i in &f.instructions {
|
||||
self.resolve_instr_types(&mut vars, &i.i);
|
||||
for (i, f) in self.iter_fns() {
|
||||
let mut redo_iter = Vec::new();
|
||||
let mut ph_vars = Vec::new();
|
||||
let mut redo_new = Vec::new();
|
||||
for i in f.flat_iter() {
|
||||
if let Err(id) = self.resolve_instr_types(&mut vars, &i.i) {
|
||||
redo_iter.push(i);
|
||||
ph_vars.push(id);
|
||||
}
|
||||
}
|
||||
while !redo_iter.is_empty() {
|
||||
let mut new_ph = Vec::new();
|
||||
for id in &ph_vars {
|
||||
let i = id.0;
|
||||
let Some(var) = &vars[i] else {
|
||||
continue;
|
||||
};
|
||||
if var.ty == Type::Placeholder
|
||||
&& let Some(parent) = var.parent.as_ref()
|
||||
{
|
||||
let pty = &vars[parent.var.0].as_ref().unwrap().ty;
|
||||
if let Some(ft) = self.field_type(pty, &parent.field) {
|
||||
vars[i].as_mut().unwrap().ty = ft.clone();
|
||||
} else {
|
||||
new_ph.push(parent.var);
|
||||
}
|
||||
}
|
||||
}
|
||||
ph_vars = new_ph;
|
||||
for &i in &redo_iter {
|
||||
if let Err(id) = self.resolve_instr_types(&mut vars, &i.i) {
|
||||
redo_new.push(i);
|
||||
ph_vars.push(id);
|
||||
}
|
||||
}
|
||||
std::mem::swap(&mut redo_iter, &mut redo_new);
|
||||
redo_new.clear();
|
||||
}
|
||||
}
|
||||
self.vars = vars;
|
||||
}
|
||||
|
||||
pub fn resolve_instr_types(&self, vars: &mut Vec<Option<UVar>>, i: &UInstruction) {
|
||||
match &i {
|
||||
UInstruction::Call { dest, f, args } => {
|
||||
let ret = self.get_fn_var(f.id).expect("bruh").ret.clone();
|
||||
vars[dest.id.0].as_mut().expect("bruh").ty = ret;
|
||||
}
|
||||
UInstruction::Mv { dest, src } => {
|
||||
let dest_ty = get(vars, dest.id);
|
||||
let src_ty = get(vars, src.id);
|
||||
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||
set(vars, dest.id, ty.clone());
|
||||
set(vars, src.id, ty);
|
||||
pub fn resolve_instr_types(
|
||||
&self,
|
||||
vars: &mut Vec<Option<UVar>>,
|
||||
i: &UInstruction,
|
||||
) -> Result<(), VarID> {
|
||||
'outer: {
|
||||
match &i {
|
||||
UInstruction::Call { dest, f, args } => {
|
||||
let fun = self.get_fn_var(f.id).expect("bruh");
|
||||
vars[dest.id.0].as_mut().expect("bruh").ty = fun.ret.clone();
|
||||
for (src, &dest) in args.iter().zip(&fun.args) {
|
||||
let dest_ty = get(vars, dest)?;
|
||||
let src_ty = get(vars, src.id)?;
|
||||
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||
set(vars, dest, ty.clone());
|
||||
set(vars, src.id, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
UInstruction::Ref { dest, src } => {
|
||||
let dest_ty = get(vars, dest.id);
|
||||
let src_ty = get(vars, src.id);
|
||||
if let Type::Ref(dest_ty) = dest_ty {
|
||||
UInstruction::Mv { dest, src } => {
|
||||
let dest_ty = get(vars, dest.id)?;
|
||||
let src_ty = get(vars, src.id)?;
|
||||
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||
set(vars, dest.id, ty.clone());
|
||||
set(vars, src.id, ty);
|
||||
}
|
||||
}
|
||||
UInstruction::Ref { dest, src } => {
|
||||
let dest_ty = get(vars, dest.id)?;
|
||||
let src_ty = get(vars, src.id)?;
|
||||
let Type::Ref(dest_ty) = dest_ty else {
|
||||
break 'outer;
|
||||
};
|
||||
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||
set(vars, dest.id, ty.clone().rf());
|
||||
set(vars, src.id, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
UInstruction::LoadData { dest, src } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::LoadSlice { dest, src } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::LoadFn { dest, src } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::AsmBlock { instructions, args } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::Ret { .. } => {}
|
||||
UInstruction::Construct { dest, fields } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::If { cond, body } => {
|
||||
for i in body {
|
||||
self.resolve_instr_types(vars, &i.i);
|
||||
UInstruction::LoadData { dest, src } => {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
UInstruction::Loop { body } => {
|
||||
for i in body {
|
||||
self.resolve_instr_types(vars, &i.i);
|
||||
UInstruction::LoadSlice { dest, src } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::LoadFn { dest, src } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::AsmBlock { instructions, args } => {
|
||||
// TODO
|
||||
}
|
||||
UInstruction::Ret { .. } => {}
|
||||
UInstruction::Construct { dest, fields } => {
|
||||
let dest_ty = get(vars, dest.id)?;
|
||||
let Type::Struct { id, args } = dest_ty else {
|
||||
break 'outer;
|
||||
};
|
||||
let id = *id;
|
||||
let Some(struc) = self.get(id) else {
|
||||
break 'outer;
|
||||
};
|
||||
let mut new = HashMap::new();
|
||||
for (name, field) in &struc.fields {
|
||||
let Some(src) = fields.get(name) else {
|
||||
continue;
|
||||
};
|
||||
let src_ty = get(vars, src.id)?;
|
||||
if let Some(ty) = match_types(&field.ty, src_ty) {
|
||||
if let Type::Generic { id } = field.ty {
|
||||
new.insert(id, ty.clone());
|
||||
}
|
||||
set(vars, src.id, ty);
|
||||
}
|
||||
}
|
||||
let mut args: Vec<_> = struc
|
||||
.generics
|
||||
.iter()
|
||||
.map(|&id| Type::Generic { id })
|
||||
.collect();
|
||||
for (i, g) in struc.generics.iter().enumerate() {
|
||||
if let Some(ty) = new.remove(g) {
|
||||
args[i] = ty;
|
||||
}
|
||||
}
|
||||
// for arg in &args {
|
||||
// println!("{:?}", self.type_name(arg));
|
||||
// }
|
||||
set(vars, dest.id, Type::Struct { id, args });
|
||||
}
|
||||
UInstruction::If { cond, body } => {}
|
||||
UInstruction::Loop { body } => {}
|
||||
UInstruction::Break => {}
|
||||
UInstruction::Continue => {}
|
||||
}
|
||||
UInstruction::Break => {}
|
||||
UInstruction::Continue => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(vars: &[Option<UVar>], id: VarID) -> &Type {
|
||||
&vars[id.0]
|
||||
pub fn get(vars: &[Option<UVar>], id: VarID) -> Result<&Type, VarID> {
|
||||
let var = vars[id.0]
|
||||
.as_ref()
|
||||
.expect("PARTIAL BORROWING WOULD BE REALLY COOL")
|
||||
.ty
|
||||
.expect("PARTIAL BORROWING WOULD BE REALLY COOL");
|
||||
if var.ty == Type::Placeholder {
|
||||
return Err(id);
|
||||
}
|
||||
Ok(&var.ty)
|
||||
}
|
||||
|
||||
pub fn set(vars: &mut [Option<UVar>], id: VarID, ty: Type) {
|
||||
@@ -112,8 +198,11 @@ pub fn match_types(dest: &Type, src: &Type) -> Option<Type> {
|
||||
return None;
|
||||
}
|
||||
match (dest, src) {
|
||||
(Type::Error, x) | (x, Type::Error) => None,
|
||||
(Type::Error, _) | (_, Type::Error) => None,
|
||||
(Type::Placeholder, _) | (_, Type::Placeholder) => None,
|
||||
(Type::Infer, x) | (x, Type::Infer) => Some(x.clone()),
|
||||
// TODO: handle constraints?
|
||||
(Type::Generic { id }, x) | (x, Type::Generic { id }) => Some(x.clone()),
|
||||
(
|
||||
Type::Struct {
|
||||
id: dest_id,
|
||||
|
||||
@@ -21,6 +21,23 @@ impl UProgram {
|
||||
spans: vec![var.origin],
|
||||
});
|
||||
}
|
||||
if var.ty == Type::Placeholder {
|
||||
output.err(CompilerMsg {
|
||||
msg: format!("Var {:?} still placeholder!", id),
|
||||
spans: vec![var.origin],
|
||||
});
|
||||
}
|
||||
if let Some(parent) = &var.parent {
|
||||
let pty = &self.get(parent.var).unwrap().ty;
|
||||
if let Some(ft) = self.field_type(pty, &parent.field) {
|
||||
output.check_assign(self, &var.ty, ft, var.origin);
|
||||
} else {
|
||||
output.err(CompilerMsg {
|
||||
msg: format!("invalid parent!"),
|
||||
spans: vec![var.origin],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
output
|
||||
}
|
||||
@@ -81,14 +98,15 @@ impl UProgram {
|
||||
}
|
||||
UInstruction::AsmBlock { instructions, args } => {
|
||||
for arg in args {
|
||||
if let Some(size) = self.size_of_var(arg.var.id)
|
||||
&& size != 64
|
||||
{
|
||||
output.err(CompilerMsg {
|
||||
msg: format!("asm block args must be size 64, is size {}", size),
|
||||
spans: vec![arg.var.span],
|
||||
});
|
||||
}
|
||||
// TODO: validate size with enabled targets
|
||||
// if let Some(size) = self.size_of_var(arg.var.id)
|
||||
// && size != 64
|
||||
// {
|
||||
// output.err(CompilerMsg {
|
||||
// msg: format!("asm block args must be size 64, is size {}", size),
|
||||
// spans: vec![arg.var.span],
|
||||
// });
|
||||
// }
|
||||
}
|
||||
}
|
||||
UInstruction::Ret { src } => {
|
||||
@@ -98,24 +116,35 @@ impl UProgram {
|
||||
}
|
||||
UInstruction::Construct { dest, fields } => {
|
||||
let dest_def = self.expect(dest.id);
|
||||
let tyid = match &dest_def.ty {
|
||||
Type::Struct { id, args } => *id,
|
||||
let (tyid, args) = match &dest_def.ty {
|
||||
Type::Struct { id, args } => (*id, args),
|
||||
_ => {
|
||||
output.err(CompilerMsg {
|
||||
msg: "uhh type is not struct".to_string(),
|
||||
msg: format!(
|
||||
"Type {} cannot be constructed",
|
||||
self.type_name(&dest_def.ty)
|
||||
),
|
||||
spans: vec![dest.span],
|
||||
});
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let def = self.expect(tyid);
|
||||
for (id, field) in def.iter_fields() {
|
||||
if let Some(var) = fields.get(&id) {
|
||||
for (name, field) in &def.fields {
|
||||
if let Some(var) = fields.get(name) {
|
||||
let mut sty = &field.ty;
|
||||
if let Type::Generic { id } = sty {
|
||||
for (g, a) in def.generics.iter().zip(args) {
|
||||
if *g == *id {
|
||||
sty = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
let ety = &self.expect(var.id).ty;
|
||||
output.check_assign(self, &field.ty, ety, var.span);
|
||||
output.check_assign(self, ety, sty, var.span);
|
||||
} else {
|
||||
output.err(CompilerMsg {
|
||||
msg: format!("field '{}' missing from struct", field.name),
|
||||
msg: format!("field '{}' missing from struct", name),
|
||||
spans: vec![dest.span],
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user