More type unification is working.
This commit is contained in:
parent
48c66442e5
commit
c465cdf9a4
17 changed files with 497 additions and 121 deletions
82
.vscode/launch.json
vendored
Normal file
82
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in library 'huia-compiler'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--lib",
|
||||
"--package=huia-compiler"
|
||||
],
|
||||
"filter": {
|
||||
"name": "huia-compiler",
|
||||
"kind": "lib"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in library 'huia-parser'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--lib",
|
||||
"--package=huia-parser"
|
||||
],
|
||||
"filter": {
|
||||
"name": "huia-parser",
|
||||
"kind": "lib"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'huia'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--bin=huia",
|
||||
"--package=huia"
|
||||
],
|
||||
"filter": {
|
||||
"name": "huia",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in executable 'huia'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--bin=huia",
|
||||
"--package=huia"
|
||||
],
|
||||
"filter": {
|
||||
"name": "huia",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -8,3 +8,4 @@ edition = "2018"
|
|||
huia-parser = { path = "../huia-parser" }
|
||||
string-interner = "0.7.0"
|
||||
cranelift = "0.29.0"
|
||||
cranelift-module = "0.29.0"
|
||||
|
|
|
@ -8,13 +8,26 @@ use std::slice::IterMut;
|
|||
/// A basic block.
|
||||
///
|
||||
/// A basic block is a collection of
|
||||
#[derive(Debug, Default, PartialEq, Clone)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Block {
|
||||
env: Env,
|
||||
ir: Vec<IR>,
|
||||
result_type: TyIdx,
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn env(&self) -> &Env {
|
||||
&self.env
|
||||
}
|
||||
|
||||
pub fn env_get(&self, name: StringIdx) -> Option<&TyIdx> {
|
||||
self.env.get(name)
|
||||
}
|
||||
|
||||
pub fn env_set(&mut self, name: StringIdx, ty: TyIdx) {
|
||||
self.env.set(name, ty)
|
||||
}
|
||||
|
||||
/// Perform IR-wise improvement.
|
||||
///
|
||||
/// See `IR.improve` for more information.
|
||||
|
@ -45,14 +58,20 @@ impl Block {
|
|||
self.ir.iter_mut()
|
||||
}
|
||||
|
||||
pub fn last_ir(&self) -> Option<&IR> {
|
||||
let len = self.ir.len();
|
||||
self.ir.get(len - 1)
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.ir.len()
|
||||
}
|
||||
|
||||
pub fn new(env: Env) -> Block {
|
||||
pub fn new(env: Env, result_type: TyIdx) -> Block {
|
||||
Block {
|
||||
env,
|
||||
ir: Vec::default(),
|
||||
result_type,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,16 +88,8 @@ impl Block {
|
|||
self.ir.push(ir);
|
||||
}
|
||||
|
||||
pub fn env(&self) -> &Env {
|
||||
&self.env
|
||||
}
|
||||
|
||||
pub fn env_get(&self, name: StringIdx) -> Option<&TyIdx> {
|
||||
self.env.get(name)
|
||||
}
|
||||
|
||||
pub fn env_set(&mut self, name: StringIdx, ty: TyIdx) {
|
||||
self.env.set(name, ty)
|
||||
pub fn result_type(&self) -> &TyIdx {
|
||||
&self.result_type
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,26 @@
|
|||
use crate::block::BlockIdx;
|
||||
use crate::stable::StringIdx;
|
||||
use crate::ty::TyIdx;
|
||||
use crate::ty::{ResultType, TyIdx};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Clause {
|
||||
arguments: BTreeMap<StringIdx, TyIdx>,
|
||||
body: BlockIdx,
|
||||
result_type: TyIdx,
|
||||
}
|
||||
|
||||
impl Clause {
|
||||
pub fn new(arguments: Vec<(StringIdx, TyIdx)>, body: BlockIdx) -> Clause {
|
||||
pub fn new(arguments: Vec<(StringIdx, TyIdx)>, body: BlockIdx, result_type: TyIdx) -> Clause {
|
||||
let arguments = arguments.iter().fold(BTreeMap::new(), |mut args, (k, v)| {
|
||||
args.insert(k.clone(), v.clone());
|
||||
args
|
||||
});
|
||||
Clause { arguments, body }
|
||||
Clause {
|
||||
arguments,
|
||||
body,
|
||||
result_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arguments(&self) -> Vec<(&StringIdx, &TyIdx)> {
|
||||
|
@ -27,6 +32,12 @@ impl Clause {
|
|||
}
|
||||
}
|
||||
|
||||
impl ResultType for Clause {
|
||||
fn result_type(&self) -> Option<&TyIdx> {
|
||||
Some(&self.result_type)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ClauseIdx(usize);
|
||||
|
||||
|
@ -51,5 +62,10 @@ impl From<&ClauseIdx> for usize {
|
|||
pub trait Clauseable {
|
||||
fn clauses(&self) -> Vec<&Clause>;
|
||||
fn has_clauses(&self) -> bool;
|
||||
fn push_clause(&mut self, arguments: Vec<(StringIdx, TyIdx)>, block: BlockIdx) -> ClauseIdx;
|
||||
fn push_clause(
|
||||
&mut self,
|
||||
arguments: Vec<(StringIdx, TyIdx)>,
|
||||
block: BlockIdx,
|
||||
result_type: TyIdx,
|
||||
) -> ClauseIdx;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ use super::Context;
|
|||
use crate::block::BlockIdx;
|
||||
use crate::clause::Clauseable;
|
||||
use crate::ir::IR;
|
||||
use crate::location::Locatable;
|
||||
use crate::ty::ResultType;
|
||||
use crate::ty::TyIdx;
|
||||
use std::fmt;
|
||||
|
||||
|
@ -51,6 +53,15 @@ fn fmt_ty_name(idx: &TyIdx, context: &Context) -> String {
|
|||
if let Some(name) = ty.name() {
|
||||
return context.get_string(&name).unwrap().to_string();
|
||||
}
|
||||
if ty.is_impl() {
|
||||
let tr = fmt_ty_name(ty.impl_of().unwrap(), &context);
|
||||
let ty = fmt_ty_name(ty.impl_for().unwrap(), &context);
|
||||
return format!("{}<{}>", tr, ty);
|
||||
}
|
||||
if ty.is_resolved() {
|
||||
let ty = fmt_ty_name(ty.target().unwrap(), &context);
|
||||
return format!("&{}", ty);
|
||||
}
|
||||
}
|
||||
format!("T{:0>4}", usize::from(idx))
|
||||
}
|
||||
|
@ -65,6 +76,13 @@ fn fmt_types(buffer: &mut String, context: &Context) {
|
|||
if let Some(name) = ty.name() {
|
||||
let name = context.get_string(&name).unwrap();
|
||||
buffer.push_str(&format!("{} = ", name));
|
||||
} else if ty.is_impl() {
|
||||
let tr = fmt_ty_name(ty.impl_of().unwrap(), &context);
|
||||
let ty = fmt_ty_name(ty.impl_for().unwrap(), &context);
|
||||
buffer.push_str(&format!("{}<{}> = ", tr, ty));
|
||||
} else if ty.is_resolved() {
|
||||
let ty = fmt_ty_name(ty.target().unwrap(), &context);
|
||||
buffer.push_str(&format!("&{} = ", ty));
|
||||
} else {
|
||||
buffer.push_str(&format!("T{:0>4} = ", i));
|
||||
};
|
||||
|
@ -135,6 +153,9 @@ fn fmt_types(buffer: &mut String, context: &Context) {
|
|||
let tr = fmt_ty_name(ty.impl_of().unwrap(), &context);
|
||||
let ty = fmt_ty_name(ty.impl_for().unwrap(), &context);
|
||||
buffer.push_str(&format!("impl {} for {}", tr, ty));
|
||||
} else if ty.is_resolved() {
|
||||
let target_ty = fmt_ty_name(ty.target().unwrap(), &context);
|
||||
buffer.push_str(&format!("alias for {}", target_ty));
|
||||
} else if ty.is_unresolved() {
|
||||
buffer.push_str("unknown type");
|
||||
}
|
||||
|
@ -174,7 +195,7 @@ fn fmt_functions(mut buffer: &mut String, context: &Context) {
|
|||
}
|
||||
buffer.push_str(&format!(
|
||||
" -> {}\n",
|
||||
fmt_ty_name(fun.return_type(), &context)
|
||||
fmt_ty_name(clause.result_type().unwrap(), &context)
|
||||
));
|
||||
|
||||
let mut jumps = Vec::new();
|
||||
|
@ -197,7 +218,14 @@ fn fmt_block(
|
|||
mut jumps: &mut Vec<BlockIdx>,
|
||||
) {
|
||||
if let Some(block) = context.get_block(idx) {
|
||||
buffer.push_str(&format!(" {}:\n", fmt_block_name(idx)));
|
||||
buffer.push_str(&format!(" {}:", fmt_block_name(idx)));
|
||||
|
||||
buffer.push_str(&format!(
|
||||
" -> {}",
|
||||
fmt_ty_name(block.result_type(), &context)
|
||||
));
|
||||
|
||||
buffer.push_str("\n");
|
||||
|
||||
let mut i: usize = 0;
|
||||
for ir in block.ir_ref() {
|
||||
|
@ -225,7 +253,7 @@ fn fmt_ir(
|
|||
fmt_ir(&mut buffer, &context, arg, &mut i, &mut jumps);
|
||||
ivs.push(*i);
|
||||
}
|
||||
buffer.push_str(&format!(" @{:0>2}: @{:0>2}", *i, callee));
|
||||
buffer.push_str(&format!(" v{:0>2}: v{:0>2}", *i, callee));
|
||||
if ivs.is_empty() {
|
||||
buffer.push_str("()");
|
||||
}
|
||||
|
@ -234,7 +262,7 @@ fn fmt_ir(
|
|||
buffer.push_str("(");
|
||||
}
|
||||
|
||||
buffer.push_str(&format!("@{:0>2}", k));
|
||||
buffer.push_str(&format!("v{:0>2}", k));
|
||||
|
||||
if j == ivs.len() - 1 {
|
||||
buffer.push_str(")");
|
||||
|
@ -251,13 +279,13 @@ fn fmt_ir(
|
|||
ivs.push(*i);
|
||||
}
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: ", *i));
|
||||
buffer.push_str(&format!(" v{:0>2}: ", *i));
|
||||
for (j, k) in ivs.iter().enumerate() {
|
||||
if j == 0 {
|
||||
buffer.push_str("[");
|
||||
}
|
||||
|
||||
buffer.push_str(&format!("@{:0>2}", k));
|
||||
buffer.push_str(&format!("v{:0>2}", k));
|
||||
|
||||
if j == ivs.len() - 1 {
|
||||
buffer.push_str("]");
|
||||
|
@ -269,19 +297,19 @@ fn fmt_ir(
|
|||
let atom = value.atom().unwrap();
|
||||
let atom = context.get_string(atom).unwrap();
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: {}", i, atom));
|
||||
buffer.push_str(&format!(" v{:0>2}: {}", i, atom));
|
||||
} else if value.is_boolean() {
|
||||
let boolean = value.boolean().unwrap();
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: {}", i, boolean));
|
||||
buffer.push_str(&format!(" v{:0>2}: {}", i, boolean));
|
||||
} else if value.is_float() {
|
||||
let float = value.float().unwrap();
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: {}", i, float));
|
||||
buffer.push_str(&format!(" v{:0>2}: {}", i, float));
|
||||
} else if value.is_integer() {
|
||||
let int = value.integer().unwrap();
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: {}", i, int));
|
||||
buffer.push_str(&format!(" v{:0>2}: {}", i, int));
|
||||
} else if value.is_map() {
|
||||
let map = value.map().unwrap();
|
||||
let mut ivs = Vec::new();
|
||||
|
@ -292,13 +320,13 @@ fn fmt_ir(
|
|||
ivs.push(*i);
|
||||
}
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: ", *i));
|
||||
buffer.push_str(&format!(" v{:0>2}: ", *i));
|
||||
for (j, k) in ivs.iter().enumerate() {
|
||||
if j == 0 {
|
||||
buffer.push_str("{");
|
||||
}
|
||||
|
||||
buffer.push_str(&format!("@{:0>2}", k));
|
||||
buffer.push_str(&format!("v{:0>2}", k));
|
||||
|
||||
if j == ivs.len() - 1 {
|
||||
buffer.push_str("}");
|
||||
|
@ -312,7 +340,7 @@ fn fmt_ir(
|
|||
let string = value.string().unwrap();
|
||||
let string = context.get_string(string).unwrap();
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: {:?}", *i, string));
|
||||
buffer.push_str(&format!(" v{:0>2}: {:?}", *i, string));
|
||||
}
|
||||
} else if ir.is_constructor() {
|
||||
let constructor = ir.get_constructor().unwrap();
|
||||
|
@ -322,7 +350,7 @@ fn fmt_ir(
|
|||
ivs.push(*i);
|
||||
}
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: ", *i));
|
||||
buffer.push_str(&format!(" v{:0>2}: ", *i));
|
||||
buffer.push_str(&fmt_ty_name(&ir.result_type(), &context));
|
||||
for (j, (key, _val)) in constructor.iter().enumerate() {
|
||||
if j == 0 {
|
||||
|
@ -330,7 +358,7 @@ fn fmt_ir(
|
|||
}
|
||||
|
||||
let key = context.get_string(key).unwrap();
|
||||
buffer.push_str(&format!("{}: @{:0>2}", key, ivs[j]));
|
||||
buffer.push_str(&format!("{}: v{:0>2}", key, ivs[j]));
|
||||
|
||||
if j == ivs.len() - 1 {
|
||||
buffer.push_str("}");
|
||||
|
@ -341,15 +369,15 @@ fn fmt_ir(
|
|||
} else if ir.is_function() {
|
||||
let idx = ir.get_function().unwrap();
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: ref f{}", *i, usize::from(idx)));
|
||||
buffer.push_str(&format!(" v{:0>2}: ref f{}", *i, usize::from(idx)));
|
||||
} else if ir.is_get_local() {
|
||||
let name = context.get_string(ir.get_local().unwrap()).unwrap();
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: get {}", *i, name));
|
||||
buffer.push_str(&format!(" v{:0>2}: get {}", *i, name));
|
||||
} else if ir.is_get_property() {
|
||||
let name = context.get_string(ir.get_property().unwrap()).unwrap();
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: get @{}", *i, name));
|
||||
buffer.push_str(&format!(" v{:0>2}: get @{}", *i, name));
|
||||
} else if ir.is_infix() {
|
||||
let (op, lhs, rhs) = ir.get_infix().unwrap();
|
||||
fmt_ir(&mut buffer, &context, lhs, &mut i, &mut jumps);
|
||||
|
@ -358,18 +386,19 @@ fn fmt_ir(
|
|||
let rhs = *i;
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(
|
||||
" @{:0>2}: {} @{:0>2} @{:0>2}",
|
||||
" v{:0>2}: {} v{:0>2} v{:0>2}",
|
||||
*i, op, lhs, rhs
|
||||
));
|
||||
} else if ir.is_jump() {
|
||||
let idx = ir.get_jump().unwrap();
|
||||
buffer.push_str(&format!(" @{:0>2}: jump {}", *i, fmt_block_name(idx)));
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" v{:0>2}: jump {}", *i, fmt_block_name(idx)));
|
||||
} else if ir.is_jump_if_false() {
|
||||
let (ir, idx) = ir.get_jump_if_false().unwrap();
|
||||
fmt_ir(&mut buffer, &context, ir, &mut i, &mut jumps);
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(
|
||||
" @{:0>2}: jump if false {}",
|
||||
" v{:0>2}: jump if false {}",
|
||||
*i,
|
||||
fmt_block_name(idx)
|
||||
));
|
||||
|
@ -378,7 +407,7 @@ fn fmt_ir(
|
|||
fmt_ir(&mut buffer, &context, ir, &mut i, &mut jumps);
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(
|
||||
" @{:0>2}: jump if true {}",
|
||||
" v{:0>2}: jump if true {}",
|
||||
*i,
|
||||
fmt_block_name(idx)
|
||||
));
|
||||
|
@ -393,7 +422,7 @@ fn fmt_ir(
|
|||
ivs.push(*i);
|
||||
}
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: @{:0>2}.{}", *i, rx, name));
|
||||
buffer.push_str(&format!(" v{:0>2}: v{:0>2}.{}", *i, rx, name));
|
||||
if ivs.is_empty() {
|
||||
buffer.push_str("()");
|
||||
}
|
||||
|
@ -402,7 +431,7 @@ fn fmt_ir(
|
|||
buffer.push_str("(");
|
||||
}
|
||||
|
||||
buffer.push_str(&format!("@{:0>2}", k));
|
||||
buffer.push_str(&format!("v{:0>2}", k));
|
||||
|
||||
if j == ivs.len() - 1 {
|
||||
buffer.push_str(")");
|
||||
|
@ -415,14 +444,14 @@ fn fmt_ir(
|
|||
fmt_ir(&mut buffer, &context, value, &mut i, &mut jumps);
|
||||
let value = *i;
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: return @{:0>2}", *i, value));
|
||||
buffer.push_str(&format!(" v{:0>2}: return v{:0>2}", *i, value));
|
||||
} else if ir.is_set_local() {
|
||||
let (name, value) = ir.get_set_local().unwrap();
|
||||
fmt_ir(&mut buffer, &context, value, &mut i, &mut jumps);
|
||||
let value = *i;
|
||||
let name = context.get_string(name).unwrap();
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: set {} @{:0>2}", *i, name, value));
|
||||
buffer.push_str(&format!(" v{:0>2}: set {} v{:0>2}", *i, name, value));
|
||||
} else if ir.is_set_properties() {
|
||||
let properties = ir.get_set_properties().unwrap();
|
||||
let mut ivs = Vec::new();
|
||||
|
@ -431,14 +460,14 @@ fn fmt_ir(
|
|||
ivs.push(*i);
|
||||
}
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: ", *i));
|
||||
buffer.push_str(&format!(" v{:0>2}: ", *i));
|
||||
for (j, (key, _val)) in properties.iter().enumerate() {
|
||||
if j == 0 {
|
||||
buffer.push_str("@{");
|
||||
}
|
||||
|
||||
let key = context.get_string(key).unwrap();
|
||||
buffer.push_str(&format!("{}: @{:0>2}", key, ivs[j]));
|
||||
buffer.push_str(&format!("{}: v{:0>2}", key, ivs[j]));
|
||||
|
||||
if j == ivs.len() - 1 {
|
||||
buffer.push_str("}");
|
||||
|
@ -448,13 +477,13 @@ fn fmt_ir(
|
|||
}
|
||||
} else if ir.is_type_reference() {
|
||||
let ty = ir.get_type_reference().unwrap();
|
||||
buffer.push_str(&format!(" @{:0>2}: {}", i, fmt_ty_name(ty, &context)));
|
||||
buffer.push_str(&format!(" v{:0>2}: {}", i, fmt_ty_name(ty, &context)));
|
||||
} else if ir.is_unary() {
|
||||
let (op, rhs) = ir.get_unary().unwrap();
|
||||
fmt_ir(&mut buffer, &context, rhs, &mut i, &mut jumps);
|
||||
let rhs = *i;
|
||||
*i += 1;
|
||||
buffer.push_str(&format!(" @{:0>2}: {} @{:0>2}", *i, op, rhs));
|
||||
buffer.push_str(&format!(" v{:0>2}: {} v{:0>2}", *i, op, rhs));
|
||||
}
|
||||
|
||||
buffer.push_str(&format!(" <{}>", fmt_ty_name(&ir.result_type(), &context)));
|
||||
|
@ -501,7 +530,7 @@ fn fmt_methods(mut buffer: &mut String, context: &Context) {
|
|||
}
|
||||
buffer.push_str(&format!(
|
||||
" -> {}\n",
|
||||
fmt_ty_name(method.return_type(), &context)
|
||||
fmt_ty_name(clause.result_type().unwrap(), &context)
|
||||
));
|
||||
|
||||
let mut jumps = vec![clause.body().clone()];
|
||||
|
|
|
@ -156,11 +156,19 @@ impl Context {
|
|||
self.blocks.get(usize::from(idx))
|
||||
}
|
||||
|
||||
pub fn get_block_mut(&mut self, idx: &BlockIdx) -> Option<&mut Block> {
|
||||
self.blocks.get_mut(usize::from(idx))
|
||||
}
|
||||
|
||||
/// Retrieve a specific function by it's index.
|
||||
pub fn get_function(&self, idx: FunctionIdx) -> Option<&Function> {
|
||||
self.functions.get(usize::from(idx))
|
||||
}
|
||||
|
||||
pub fn get_method(&self, idx: MethodIdx) -> Option<&Method> {
|
||||
self.methods.get(usize::from(idx))
|
||||
}
|
||||
|
||||
pub fn get_method_mut(&mut self, idx: MethodIdx) -> Option<&mut Method> {
|
||||
self.methods.get_mut(usize::from(idx))
|
||||
}
|
||||
|
@ -179,6 +187,31 @@ impl Context {
|
|||
self.types.get_mut(usize::from(idx))
|
||||
}
|
||||
|
||||
/// Perform blockwise improvement.
|
||||
///
|
||||
/// Iterates through all blocks in the context applying a provided improver
|
||||
/// function.
|
||||
pub fn improve_blocks<F: Fn(&mut Block, &mut Context)>(&mut self, improver: F) {
|
||||
let mut blocks = self.blocks.clone();
|
||||
|
||||
for block in blocks.iter_mut() {
|
||||
improver(block, self);
|
||||
}
|
||||
|
||||
self.blocks = blocks;
|
||||
}
|
||||
|
||||
/// Perform a function-wise improvement.
|
||||
pub fn improve_functions<F: Fn(&mut Function, &mut Context)>(&mut self, improver: F) {
|
||||
let mut functions = self.functions.clone();
|
||||
|
||||
for function in functions.iter_mut() {
|
||||
improver(function, self);
|
||||
}
|
||||
|
||||
self.functions = functions;
|
||||
}
|
||||
|
||||
/// Perform IR-wise improvement.
|
||||
///
|
||||
/// Iterates through all blocks in the context and all IRs in each block
|
||||
|
@ -199,18 +232,15 @@ impl Context {
|
|||
self.blocks = blocks;
|
||||
}
|
||||
|
||||
/// Perform blockwise improvement.
|
||||
///
|
||||
/// Iterates through all blocks in the context applying a provided improver
|
||||
/// function.
|
||||
pub fn improve_blocks<F: Fn(&mut Block, &mut Context)>(&mut self, improver: F) {
|
||||
let mut blocks = self.blocks.clone();
|
||||
/// Perform a method-wise improvement.
|
||||
pub fn improve_methods<F: Fn(&mut Method, &mut Context)>(&mut self, improver: F) {
|
||||
let mut methods = self.methods.clone();
|
||||
|
||||
for block in blocks.iter_mut() {
|
||||
improver(block, self);
|
||||
for method in methods.iter_mut() {
|
||||
improver(method, self);
|
||||
}
|
||||
|
||||
self.blocks = blocks;
|
||||
self.methods = methods;
|
||||
}
|
||||
|
||||
/// Convert an AST `InputLocation` into a compiler `Location`.
|
||||
|
|
|
@ -48,4 +48,6 @@ impl Error for CompileError {
|
|||
pub enum ErrorKind {
|
||||
TypeRedefined,
|
||||
UnknownVariable,
|
||||
InconsistentBranchTypes,
|
||||
TypeInferenceFailure,
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use crate::block::BlockIdx;
|
||||
use crate::clause::{Clause, ClauseIdx, Clauseable};
|
||||
use crate::location::Location;
|
||||
use crate::location::{Locatable, Location};
|
||||
use crate::stable::StringIdx;
|
||||
use crate::ty::TyIdx;
|
||||
use crate::ty::{ResultType, TyIdx};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Function {
|
||||
clauses: Vec<Clause>,
|
||||
location: Location,
|
||||
|
@ -16,10 +16,6 @@ impl Function {
|
|||
self.clauses.is_empty()
|
||||
}
|
||||
|
||||
pub fn location(&self) -> &Location {
|
||||
&self.location
|
||||
}
|
||||
|
||||
pub fn new(return_type: TyIdx, location: Location) -> Function {
|
||||
Function {
|
||||
clauses: Vec::new(),
|
||||
|
@ -27,10 +23,6 @@ impl Function {
|
|||
return_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn return_type(&self) -> &TyIdx {
|
||||
&self.return_type
|
||||
}
|
||||
}
|
||||
|
||||
impl Clauseable for Function {
|
||||
|
@ -42,13 +34,77 @@ impl Clauseable for Function {
|
|||
!self.clauses.is_empty()
|
||||
}
|
||||
|
||||
fn push_clause(&mut self, arguments: Vec<(StringIdx, TyIdx)>, block: BlockIdx) -> ClauseIdx {
|
||||
fn push_clause(
|
||||
&mut self,
|
||||
arguments: Vec<(StringIdx, TyIdx)>,
|
||||
block: BlockIdx,
|
||||
result_type: TyIdx,
|
||||
) -> ClauseIdx {
|
||||
let idx = self.clauses.len();
|
||||
self.clauses.push(Clause::new(arguments, block));
|
||||
self.clauses
|
||||
.push(Clause::new(arguments, block, result_type));
|
||||
idx.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clauseable for &mut Function {
|
||||
fn clauses(&self) -> Vec<&Clause> {
|
||||
self.clauses.iter().collect()
|
||||
}
|
||||
|
||||
fn has_clauses(&self) -> bool {
|
||||
!self.clauses.is_empty()
|
||||
}
|
||||
|
||||
fn push_clause(
|
||||
&mut self,
|
||||
arguments: Vec<(StringIdx, TyIdx)>,
|
||||
block: BlockIdx,
|
||||
result_type: TyIdx,
|
||||
) -> ClauseIdx {
|
||||
let idx = self.clauses.len();
|
||||
self.clauses
|
||||
.push(Clause::new(arguments, block, result_type));
|
||||
idx.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Locatable for Function {
|
||||
fn location(&self) -> &Location {
|
||||
&self.location
|
||||
}
|
||||
}
|
||||
|
||||
impl Locatable for &Function {
|
||||
fn location(&self) -> &Location {
|
||||
&self.location
|
||||
}
|
||||
}
|
||||
|
||||
impl Locatable for &mut Function {
|
||||
fn location(&self) -> &Location {
|
||||
&self.location
|
||||
}
|
||||
}
|
||||
|
||||
impl ResultType for Function {
|
||||
fn result_type(&self) -> Option<&TyIdx> {
|
||||
Some(&self.return_type)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResultType for &Function {
|
||||
fn result_type(&self) -> Option<&TyIdx> {
|
||||
Some(&self.return_type)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResultType for &mut Function {
|
||||
fn result_type(&self) -> Option<&TyIdx> {
|
||||
Some(&self.return_type)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct FunctionIdx(usize);
|
||||
|
||||
|
@ -77,10 +133,10 @@ mod test {
|
|||
#[test]
|
||||
fn test_function_new() {
|
||||
let rt = TyIdx::from(13);
|
||||
let mut fun = Function::new(rt, Location::test());
|
||||
let mut fun = Function::new(rt.clone(), Location::test());
|
||||
assert!(fun.is_empty());
|
||||
|
||||
fun.push_clause(Vec::new(), BlockIdx::from(123));
|
||||
fun.push_clause(Vec::new(), BlockIdx::from(123), rt);
|
||||
|
||||
assert!(!fun.is_empty());
|
||||
}
|
||||
|
|
32
huia-compiler/src/improvements/block_result_types.rs
Normal file
32
huia-compiler/src/improvements/block_result_types.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
use crate::block::BlockIdx;
|
||||
use crate::clause::Clauseable;
|
||||
use crate::context::Context;
|
||||
|
||||
pub fn pass<T: Clauseable>(fun: &mut T, mut context: &mut Context) {
|
||||
for clause in fun.clauses() {
|
||||
let block_idx = clause.body();
|
||||
set_block_result_type(block_idx, &mut context);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_block_result_type(block_idx: &BlockIdx, mut context: &mut Context) {
|
||||
let block = context.get_block(block_idx).unwrap().clone();
|
||||
if block.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
for ir in block.ir_ref() {
|
||||
if let Some(target_idx) = ir.get_target() {
|
||||
set_block_result_type(target_idx, &mut context);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(last_ir) = block.last_ir() {
|
||||
if last_ir.is_terminator() {
|
||||
let block = context.get_block(block_idx).unwrap().clone();
|
||||
let block_ty_idx = block.result_type();
|
||||
let block_ty = context.get_type_mut(block_ty_idx).unwrap();
|
||||
block_ty.resolve(&last_ir.result_type());
|
||||
}
|
||||
}
|
||||
}
|
14
huia-compiler/src/improvements/clause_return_types.rs
Normal file
14
huia-compiler/src/improvements/clause_return_types.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use crate::clause::Clauseable;
|
||||
use crate::context::Context;
|
||||
use crate::location::Locatable;
|
||||
use crate::ty::ResultType;
|
||||
|
||||
pub fn pass<T: Clauseable + Locatable + ResultType>(fun: &mut T, context: &mut Context) {
|
||||
for clause in fun.clauses() {
|
||||
let block_idx = clause.body();
|
||||
let ty_idx = clause.result_type().unwrap();
|
||||
let result_type = context.get_block(block_idx).unwrap().result_type().clone();
|
||||
let ty = context.get_type_mut(ty_idx).unwrap();
|
||||
ty.resolve(&result_type);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
pub mod block_result_types;
|
||||
pub mod clause_return_types;
|
||||
pub mod desugar_infix;
|
||||
pub mod desugar_unary;
|
||||
pub mod infix_folding;
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use crate::block::{Block, BlockIdx};
|
||||
use crate::clause::Clauseable;
|
||||
use crate::context::Context;
|
||||
use crate::env::Env;
|
||||
use crate::error::ErrorKind;
|
||||
use crate::function::Function;
|
||||
use crate::ir::{Val, IR};
|
||||
use crate::location::Locatable;
|
||||
use crate::location::Location as Loc;
|
||||
use crate::method::{Method, MethodIdx, Modifier};
|
||||
use crate::stable::StringIdx;
|
||||
|
@ -88,11 +90,10 @@ impl Builder {
|
|||
self.build(callee.clone(), &mut context);
|
||||
let callee = self.pop_ir().unwrap();
|
||||
|
||||
self.push_block();
|
||||
for node in args {
|
||||
let arguments = args.iter().map(|node| {
|
||||
self.build(node.clone(), &mut context);
|
||||
}
|
||||
let arguments = self.pop_block().unwrap().ir();
|
||||
self.pop_ir().unwrap()
|
||||
}).collect();
|
||||
|
||||
let result_type = context.unknown_type(location.clone());
|
||||
|
||||
|
@ -139,7 +140,7 @@ impl Builder {
|
|||
|
||||
|
||||
for clause in function.value_ref() {
|
||||
self.build_function_clause(&mut context, &mut fun, clause.arguments(), clause.body());
|
||||
self.build_function_clause(&mut context, &mut fun, clause.arguments(), clause.body(), location.clone());
|
||||
}
|
||||
|
||||
let fun_idx = context.define_function(fun);
|
||||
|
@ -163,11 +164,13 @@ impl Builder {
|
|||
following_block_idx += 1;
|
||||
}
|
||||
|
||||
self.push_block();
|
||||
self.push_block(context.unknown_type(location.clone()));
|
||||
for node in positive {
|
||||
self.build(node.clone(), &mut context);
|
||||
}
|
||||
if let Some(last_ir) = self.pop_ir() {
|
||||
let rt = context.get_type_mut(&result_type).unwrap();
|
||||
rt.resolve(&last_ir.result_type());
|
||||
self.push_ir(IR::new_set_local(last_ir.result_type(), location.clone(), value_var_name.clone(), last_ir.clone()));
|
||||
self.push_ir(IR::new_jump(last_ir.result_type(), location.clone(), following_block_idx.into()));
|
||||
} else {
|
||||
|
@ -188,13 +191,17 @@ impl Builder {
|
|||
// with a jump to the following block and push a `jump_if_false`
|
||||
// to the block.
|
||||
if !negative.is_empty() {
|
||||
self.push_block();
|
||||
self.push_block(context.unknown_type(location.clone()));
|
||||
for node in negative {
|
||||
self.build(node.clone(), &mut context);
|
||||
}
|
||||
|
||||
if let Some(last_ir) = self.pop_ir() {
|
||||
self.env_set(&value_var_name, &last_ir.result_type());
|
||||
let rt = context.get_type(&result_type).unwrap();
|
||||
if rt.target().unwrap() != &last_ir.result_type() {
|
||||
context.compile_error("Both branches of an if statement must result in the same type.", location.clone(), ErrorKind::InconsistentBranchTypes);
|
||||
}
|
||||
|
||||
self.push_ir(IR::new_set_local(last_ir.result_type(), location.clone(), value_var_name.clone(), last_ir.clone()));
|
||||
self.push_ir(IR::new_jump(last_ir.result_type(), location.clone(), following_block_idx.into()));
|
||||
} else {
|
||||
|
@ -212,7 +219,7 @@ impl Builder {
|
|||
}
|
||||
|
||||
// Finally, push the following block onto the stack for the following instructions.
|
||||
self.push_block();
|
||||
self.push_block(context.unknown_type(location.clone()));
|
||||
|
||||
if let Some(result_type) = self.env_get(&value_var_name) {
|
||||
self.push_ir(IR::new_get_local(result_type.clone(), location, value_var_name));
|
||||
|
@ -228,10 +235,10 @@ impl Builder {
|
|||
// implementation whilst not inside a type definition.
|
||||
let ty = self.peek_ty().unwrap().clone();
|
||||
|
||||
let im = context.declare_impl(tr, ty, location);
|
||||
let im = context.declare_impl(tr, ty, location.clone());
|
||||
|
||||
self.push_ty(im.clone());
|
||||
self.push_block();
|
||||
self.push_block(context.unknown_type(location.clone()));
|
||||
|
||||
for node in body {
|
||||
self.build(node.clone(), &mut context);
|
||||
|
@ -256,8 +263,13 @@ impl Builder {
|
|||
match self.env_get(&constant_name) {
|
||||
Some(result_type) => self.push_ir(IR::new_get_local(result_type.clone(), location, constant_name)),
|
||||
None => {
|
||||
// Add a compiler error.
|
||||
let message = format!("Unknown variable {}", name);
|
||||
context.compile_error(&message, location, ErrorKind::UnknownVariable);
|
||||
context.compile_error(&message, location.clone(), ErrorKind::UnknownVariable);
|
||||
|
||||
// Push a value of unknown type to the IR so that we can try and continue.
|
||||
let result_type = context.unknown_type(location.clone());
|
||||
self.push_ir(IR::new_get_local(result_type, location, constant_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -288,12 +300,10 @@ impl Builder {
|
|||
self.build(callee.clone(), &mut context);
|
||||
let callee = self.pop_ir().unwrap();
|
||||
|
||||
self.push_block();
|
||||
for argument in arguments {
|
||||
self.build(argument.clone(), &mut context);
|
||||
}
|
||||
let arguments = self.pop_block().unwrap().ir();
|
||||
|
||||
let arguments = arguments.iter().map(|node| {
|
||||
self.build(node.clone(), &mut context);
|
||||
self.pop_ir().unwrap()
|
||||
}).collect();
|
||||
let result_type = context.unknown_type(location.clone());
|
||||
|
||||
self.push_ir(IR::new_method_call(result_type, location, callee, method_name, arguments))
|
||||
|
@ -395,9 +405,9 @@ impl Builder {
|
|||
Vec::new()
|
||||
};
|
||||
|
||||
let ty = context.declare_trait(&ty_idx, types, location);
|
||||
let ty = context.declare_trait(&ty_idx, types, location.clone());
|
||||
self.push_ty(ty.clone());
|
||||
self.push_block();
|
||||
self.push_block(context.unknown_type(location));
|
||||
|
||||
for node in body {
|
||||
self.build(node.clone(), &mut context);
|
||||
|
@ -429,9 +439,9 @@ impl Builder {
|
|||
})
|
||||
.collect();
|
||||
|
||||
let ty = context.declare_type(&ty_idx, properties, location);
|
||||
let ty = context.declare_type(&ty_idx, properties, location.clone());
|
||||
self.push_ty(ty.clone());
|
||||
self.push_block();
|
||||
self.push_block(context.unknown_type(location));
|
||||
for node in body {
|
||||
self.build(node.clone(), &mut context);
|
||||
}
|
||||
|
@ -494,7 +504,7 @@ impl Builder {
|
|||
) -> (Vec<(StringIdx, TyIdx)>, BlockIdx) {
|
||||
let arguments = self.build_arguments(&mut context, arguments);
|
||||
|
||||
self.push_block();
|
||||
self.push_block(context.unknown_type(context.location(body[0].location())));
|
||||
let current_block_len = self.blocks.len();
|
||||
|
||||
for (name, ty) in &arguments {
|
||||
|
@ -538,9 +548,11 @@ impl Builder {
|
|||
fun: &mut Function,
|
||||
arguments: &[(Identifier, TypeSpec)],
|
||||
body: &[Term],
|
||||
location: Loc,
|
||||
) {
|
||||
let (arguments, block_idx) = self.build_clause(&mut context, arguments, body);
|
||||
fun.push_clause(arguments, block_idx);
|
||||
let result_type = context.unknown_type(location.clone());
|
||||
fun.push_clause(arguments, block_idx, result_type);
|
||||
}
|
||||
|
||||
fn build_method(
|
||||
|
@ -580,8 +592,10 @@ impl Builder {
|
|||
body: &[Term],
|
||||
) {
|
||||
let (arguments, block_idx) = self.build_clause(&mut context, arguments, body);
|
||||
let method = context.get_method(method_idx.clone()).unwrap();
|
||||
let result_type = context.unknown_type(method.location().clone());
|
||||
let method = context.get_method_mut(method_idx.clone()).unwrap();
|
||||
method.push_clause(arguments, block_idx);
|
||||
method.push_clause(arguments, block_idx, result_type);
|
||||
}
|
||||
|
||||
fn env_set(&mut self, name: &StringIdx, ty: &TyIdx) {
|
||||
|
@ -654,14 +668,15 @@ impl Builder {
|
|||
None
|
||||
}
|
||||
|
||||
fn push_block(&mut self) {
|
||||
fn push_block(&mut self, result_type: TyIdx) {
|
||||
match self.peek_block() {
|
||||
Some(ref block) => {
|
||||
let env = block.env().clone();
|
||||
self.blocks.push(Block::new(env));
|
||||
self.blocks.push(Block::new(env, result_type));
|
||||
}
|
||||
None => {
|
||||
self.blocks.push(Block::default());
|
||||
let env = Env::default();
|
||||
self.blocks.push(Block::new(env, result_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -677,7 +692,7 @@ impl Builder {
|
|||
|
||||
impl Default for Builder {
|
||||
fn default() -> Builder {
|
||||
let blocks = vec![Block::default()];
|
||||
let blocks = Vec::default();
|
||||
let types = Vec::default();
|
||||
Builder { blocks, types }
|
||||
}
|
||||
|
|
|
@ -292,6 +292,15 @@ impl IR {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_jump_any(&self) -> bool {
|
||||
match self.kind {
|
||||
IRKind::Jump(..) => true,
|
||||
IRKind::JumpIfFalse(..) => true,
|
||||
IRKind::JumpIfTrue(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_jump_if_false(&self) -> bool {
|
||||
match self.kind {
|
||||
IRKind::JumpIfFalse(..) => true,
|
||||
|
|
|
@ -32,5 +32,15 @@ pub fn compile_file(path: &str) -> Context {
|
|||
improvements::desugar_unary::pass(&mut ir, &mut context);
|
||||
});
|
||||
|
||||
context.improve_functions(|mut function, mut context| {
|
||||
improvements::block_result_types::pass(&mut function, &mut context);
|
||||
improvements::clause_return_types::pass(&mut function, &mut context);
|
||||
});
|
||||
|
||||
context.improve_methods(|mut method, mut context| {
|
||||
improvements::block_result_types::pass(&mut method, &mut context);
|
||||
improvements::clause_return_types::pass(&mut method, &mut context);
|
||||
});
|
||||
|
||||
context
|
||||
}
|
||||
|
|
|
@ -29,3 +29,7 @@ impl fmt::Display for Location {
|
|||
write!(f, "{}:{}", self.source_path, self.location)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Locatable {
|
||||
fn location(&self) -> &Location;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use crate::block::BlockIdx;
|
||||
use crate::clause::{Clause, ClauseIdx, Clauseable};
|
||||
use crate::location::Location;
|
||||
use crate::location::{Locatable, Location};
|
||||
use crate::stable::StringIdx;
|
||||
use crate::ty::TyIdx;
|
||||
use crate::ty::{ResultType, TyIdx};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Method {
|
||||
clauses: Vec<Clause>,
|
||||
modifier: Modifier,
|
||||
|
@ -105,9 +105,15 @@ impl Clauseable for Method {
|
|||
!self.clauses.is_empty()
|
||||
}
|
||||
|
||||
fn push_clause(&mut self, arguments: Vec<(StringIdx, TyIdx)>, block: BlockIdx) -> ClauseIdx {
|
||||
fn push_clause(
|
||||
&mut self,
|
||||
arguments: Vec<(StringIdx, TyIdx)>,
|
||||
block: BlockIdx,
|
||||
result_type: TyIdx,
|
||||
) -> ClauseIdx {
|
||||
let idx = self.clauses.len();
|
||||
self.clauses.push(Clause::new(arguments, block));
|
||||
self.clauses
|
||||
.push(Clause::new(arguments, block, result_type));
|
||||
idx.into()
|
||||
}
|
||||
}
|
||||
|
@ -121,13 +127,43 @@ impl Clauseable for &mut Method {
|
|||
!self.clauses.is_empty()
|
||||
}
|
||||
|
||||
fn push_clause(&mut self, arguments: Vec<(StringIdx, TyIdx)>, block: BlockIdx) -> ClauseIdx {
|
||||
fn push_clause(
|
||||
&mut self,
|
||||
arguments: Vec<(StringIdx, TyIdx)>,
|
||||
block: BlockIdx,
|
||||
result_type: TyIdx,
|
||||
) -> ClauseIdx {
|
||||
let idx = self.clauses.len();
|
||||
self.clauses.push(Clause::new(arguments, block));
|
||||
self.clauses
|
||||
.push(Clause::new(arguments, block, result_type));
|
||||
idx.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Locatable for Method {
|
||||
fn location(&self) -> &Location {
|
||||
&self.location
|
||||
}
|
||||
}
|
||||
|
||||
impl Locatable for &Method {
|
||||
fn location(&self) -> &Location {
|
||||
&self.location
|
||||
}
|
||||
}
|
||||
|
||||
impl Locatable for &mut Method {
|
||||
fn location(&self) -> &Location {
|
||||
&self.location
|
||||
}
|
||||
}
|
||||
|
||||
impl ResultType for &mut Method {
|
||||
fn result_type(&self) -> Option<&TyIdx> {
|
||||
Some(&self.return_type)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Modifier {
|
||||
Public,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::location::Location;
|
||||
use crate::stable::StringIdx;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
|
||||
/// The main "Type" struct.
|
||||
/// Holds information about Huia Types and Traits.
|
||||
|
@ -122,6 +121,13 @@ impl Ty {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_resolved(&self) -> bool {
|
||||
match self.kind {
|
||||
TyKind::Variable => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_unresolved(&self) -> bool {
|
||||
match self.kind {
|
||||
TyKind::Unresolved => true,
|
||||
|
@ -278,6 +284,31 @@ impl Ty {
|
|||
inner: TyInner::NativeType,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve(&mut self, target: &TyIdx) {
|
||||
match self.kind {
|
||||
TyKind::Unresolved => {
|
||||
self.kind = TyKind::Variable;
|
||||
self.inner = TyInner::Variable {
|
||||
target: target.clone(),
|
||||
};
|
||||
}
|
||||
TyKind::Variable => {
|
||||
if self.target().unwrap() == target {
|
||||
return;
|
||||
}
|
||||
panic!("Attempt to resolve already resolved type");
|
||||
}
|
||||
_ => panic!("Attempt to resolve unresolvable type"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn target(&self) -> Option<&TyIdx> {
|
||||
match self.inner {
|
||||
TyInner::Variable { ref target } => Some(target),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq)]
|
||||
|
@ -308,18 +339,7 @@ pub enum TyKind {
|
|||
Trait,
|
||||
Impl,
|
||||
Unresolved,
|
||||
}
|
||||
|
||||
impl fmt::Display for TyKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
TyKind::Native => write!(f, "native type"),
|
||||
TyKind::Type => write!(f, "type"),
|
||||
TyKind::Trait => write!(f, "trait"),
|
||||
TyKind::Impl => write!(f, "trait implementation"),
|
||||
TyKind::Unresolved => write!(f, "unresolved type"),
|
||||
}
|
||||
}
|
||||
Variable,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -343,4 +363,11 @@ enum TyInner {
|
|||
Type {
|
||||
properties: BTreeMap<StringIdx, TyIdx>,
|
||||
},
|
||||
Variable {
|
||||
target: TyIdx,
|
||||
},
|
||||
}
|
||||
|
||||
pub trait ResultType {
|
||||
fn result_type(&self) -> Option<&TyIdx>;
|
||||
}
|
||||
|
|
Reference in a new issue