Remove redundant TypeRef, add other optimizations
This commit is contained in:
parent
29e78cf1aa
commit
0d631bfa89
@ -1,8 +1,14 @@
|
|||||||
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
use std::{
|
||||||
|
any::TypeId,
|
||||||
|
cell::RefCell,
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
hint::black_box,
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
typecheck::{Collapsable, ErrorKind},
|
typecheck::{Collapsable, ErrorKind},
|
||||||
BinaryOperator, Literal, TypeKind, VagueType,
|
BinaryOperator, TypeKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -13,11 +19,8 @@ impl<'scope> ScopeHint<'scope> {
|
|||||||
unsafe { *self.1.types.hints.borrow().get_unchecked(*self.0.borrow()) }
|
unsafe { *self.1.types.hints.borrow().get_unchecked(*self.0.borrow()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn narrow(&mut self, ty_ref: &TypeRef) -> Result<ScopeHint<'scope>, ErrorKind> {
|
pub fn narrow(&mut self, other: &ScopeHint) -> Result<ScopeHint<'scope>, ErrorKind> {
|
||||||
match ty_ref {
|
self.1.combine_vars(self, other)
|
||||||
TypeRef::Hint(other) => self.1.combine_vars(self, other),
|
|
||||||
TypeRef::Literal(ty) => self.1.narrow_to_type(self, ty),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_type(&self) -> TypeKind {
|
pub fn as_type(&self) -> TypeKind {
|
||||||
@ -52,6 +55,39 @@ impl TypeHints {
|
|||||||
self.hints.borrow_mut().push(ty);
|
self.hints.borrow_mut().push(ty);
|
||||||
typecell
|
typecell
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find(&self, ty: TypeKind) -> Option<TypeIdRef> {
|
||||||
|
if ty.known().is_err() {
|
||||||
|
// Only do this for non-vague types that can not be further narrowed
|
||||||
|
// down.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(idx) = self
|
||||||
|
.hints
|
||||||
|
.borrow_mut()
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|(_, t)| **t == ty)
|
||||||
|
.map(|(i, _)| i)
|
||||||
|
{
|
||||||
|
Some(Rc::new(RefCell::new(idx)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn recurse_type_ref(&self, mut idx: usize) -> TypeIdRef {
|
||||||
|
let refs = self.type_refs.borrow();
|
||||||
|
let mut inner_idx = refs.get_unchecked(idx);
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
while (*inner_idx.borrow()) != idx && !seen.contains(&idx) {
|
||||||
|
seen.insert(idx);
|
||||||
|
idx = *inner_idx.borrow();
|
||||||
|
inner_idx = refs.get_unchecked(idx);
|
||||||
|
}
|
||||||
|
return refs.get_unchecked(idx).clone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -72,12 +108,7 @@ impl<'outer> ScopeHints<'outer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn retrieve_type(&self, idx: usize) -> Option<TypeKind> {
|
pub fn retrieve_type(&self, idx: usize) -> Option<TypeKind> {
|
||||||
let inner_idx = self
|
let inner_idx = unsafe { *self.types.recurse_type_ref(idx).borrow() };
|
||||||
.types
|
|
||||||
.type_refs
|
|
||||||
.borrow()
|
|
||||||
.get(idx)
|
|
||||||
.map(|i| *i.borrow())?;
|
|
||||||
self.types.hints.borrow().get(inner_idx).copied()
|
self.types.hints.borrow().get(inner_idx).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,9 +128,22 @@ impl<'outer> ScopeHints<'outer> {
|
|||||||
Ok(ScopeHint(idx, self))
|
Ok(ScopeHint(idx, self))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_vague(&'outer self, vague: &VagueType) -> ScopeHint<'outer> {
|
pub fn from_type(&'outer self, ty: &TypeKind) -> Option<ScopeHint<'outer>> {
|
||||||
let idx = self.types.new(TypeKind::Vague(*vague));
|
let idx = match ty {
|
||||||
ScopeHint(idx, self)
|
TypeKind::Vague(super::VagueType::Hinted(idx)) => {
|
||||||
|
let inner_idx = unsafe { *self.types.recurse_type_ref(*idx).borrow() };
|
||||||
|
self.types.type_refs.borrow().get(inner_idx).cloned()?
|
||||||
|
}
|
||||||
|
TypeKind::Vague(_) => self.types.new(*ty),
|
||||||
|
_ => {
|
||||||
|
if let Some(ty_ref) = self.types.find(*ty) {
|
||||||
|
ty_ref
|
||||||
|
} else {
|
||||||
|
self.types.new(*ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(ScopeHint(idx, self))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn narrow_to_type(
|
fn narrow_to_type(
|
||||||
@ -129,7 +173,7 @@ impl<'outer> ScopeHints<'outer> {
|
|||||||
.clone();
|
.clone();
|
||||||
self.narrow_to_type(&hint1, &ty)?;
|
self.narrow_to_type(&hint1, &ty)?;
|
||||||
for idx in self.types.type_refs.borrow_mut().iter_mut() {
|
for idx in self.types.type_refs.borrow_mut().iter_mut() {
|
||||||
if *idx == hint2.0 {
|
if *idx == hint2.0 && idx != &hint1.0 {
|
||||||
*idx.borrow_mut() = *hint1.0.borrow();
|
*idx.borrow_mut() = *hint1.0.borrow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,58 +200,16 @@ impl<'outer> ScopeHints<'outer> {
|
|||||||
pub fn binop(
|
pub fn binop(
|
||||||
&'outer self,
|
&'outer self,
|
||||||
op: &BinaryOperator,
|
op: &BinaryOperator,
|
||||||
lhs: &mut TypeRef<'outer>,
|
lhs: &mut ScopeHint<'outer>,
|
||||||
rhs: &mut TypeRef<'outer>,
|
rhs: &mut ScopeHint<'outer>,
|
||||||
) -> Result<TypeRef<'outer>, ErrorKind> {
|
) -> Result<ScopeHint<'outer>, ErrorKind> {
|
||||||
let ty = lhs.narrow(rhs)?;
|
let ty = lhs.narrow(rhs)?;
|
||||||
Ok(match op {
|
Ok(match op {
|
||||||
BinaryOperator::Add => ty,
|
BinaryOperator::Add => ty,
|
||||||
BinaryOperator::Minus => ty,
|
BinaryOperator::Minus => ty,
|
||||||
BinaryOperator::Mult => ty,
|
BinaryOperator::Mult => ty,
|
||||||
BinaryOperator::And => TypeRef::Literal(TypeKind::Bool),
|
BinaryOperator::And => self.from_type(&TypeKind::Bool).unwrap(),
|
||||||
BinaryOperator::Cmp(_) => TypeRef::Literal(TypeKind::Bool),
|
BinaryOperator::Cmp(_) => self.from_type(&TypeKind::Bool).unwrap(),
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum TypeRef<'scope> {
|
|
||||||
Hint(ScopeHint<'scope>),
|
|
||||||
Literal(TypeKind),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'scope> TypeRef<'scope> {
|
|
||||||
pub fn narrow(&mut self, other: &mut TypeRef<'scope>) -> Result<TypeRef<'scope>, ErrorKind> {
|
|
||||||
match (self, other) {
|
|
||||||
(TypeRef::Hint(hint), unk) | (unk, TypeRef::Hint(hint)) => {
|
|
||||||
Ok(TypeRef::Hint(hint.narrow(unk)?))
|
|
||||||
}
|
|
||||||
(TypeRef::Literal(lit1), TypeRef::Literal(lit2)) => {
|
|
||||||
Ok(TypeRef::Literal(lit1.collapse_into(lit2)?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_type(hints: &'scope ScopeHints<'scope>, ty: TypeKind) -> TypeRef<'scope> {
|
|
||||||
match &ty.known() {
|
|
||||||
Ok(ty) => TypeRef::Literal(*ty),
|
|
||||||
Err(vague) => match &vague {
|
|
||||||
super::VagueType::Hinted(idx) => TypeRef::Hint(ScopeHint(
|
|
||||||
unsafe { hints.types.type_refs.borrow().get_unchecked(*idx).clone() },
|
|
||||||
hints,
|
|
||||||
)),
|
|
||||||
_ => TypeRef::Hint(hints.new_vague(vague)),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_literal(
|
|
||||||
hints: &'scope ScopeHints<'scope>,
|
|
||||||
lit: Literal,
|
|
||||||
) -> Result<TypeRef<'scope>, ErrorKind> {
|
|
||||||
Ok(match lit {
|
|
||||||
Literal::Vague(vague) => TypeRef::Hint(hints.new_vague(&vague.as_type())),
|
|
||||||
_ => TypeRef::Literal(lit.as_type()),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use VagueType::*;
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
pass::{Pass, PassState, ScopeFunction, ScopeVariable},
|
pass::{Pass, PassState, ScopeFunction, ScopeVariable},
|
||||||
scopehints::{ScopeHints, TypeHints, TypeRef},
|
scopehints::{ScopeHint, ScopeHints, TypeHints},
|
||||||
types::{pick_return, ReturnType},
|
types::{pick_return, ReturnType},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -82,6 +82,7 @@ impl FunctionDefinition {
|
|||||||
let hints = ScopeHints::from(&types);
|
let hints = ScopeHints::from(&types);
|
||||||
if let Ok(_) = block.infer_hints(state, &hints) {
|
if let Ok(_) = block.infer_hints(state, &hints) {
|
||||||
print!("{}", block);
|
print!("{}", block);
|
||||||
|
dbg!(&hints);
|
||||||
block.typecheck(state, &hints, Some(return_type))
|
block.typecheck(state, &hints, Some(return_type))
|
||||||
} else {
|
} else {
|
||||||
Ok(Vague(Unknown))
|
Ok(Vague(Unknown))
|
||||||
@ -104,7 +105,7 @@ impl Block {
|
|||||||
&mut self,
|
&mut self,
|
||||||
state: &mut PassState<ErrorKind>,
|
state: &mut PassState<ErrorKind>,
|
||||||
outer_hints: &'s ScopeHints,
|
outer_hints: &'s ScopeHints,
|
||||||
) -> Result<(ReturnKind, TypeRef<'s>), ErrorKind> {
|
) -> Result<(ReturnKind, ScopeHint<'s>), ErrorKind> {
|
||||||
let mut state = state.inner();
|
let mut state = state.inner();
|
||||||
let inner_hints = outer_hints.inner();
|
let inner_hints = outer_hints.inner();
|
||||||
|
|
||||||
@ -149,12 +150,12 @@ impl Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (kind, ty) = self.return_type().ok().unwrap_or((ReturnKind::Soft, Void));
|
let (kind, ty) = self.return_type().ok().unwrap_or((ReturnKind::Soft, Void));
|
||||||
let mut ret_type_ref = TypeRef::from_type(&outer_hints, ty);
|
let mut ret_type_ref = outer_hints.from_type(&ty).unwrap();
|
||||||
|
|
||||||
if kind == ReturnKind::Hard {
|
if kind == ReturnKind::Hard {
|
||||||
if let Some(hint) = state.scope.return_type_hint {
|
if let Some(hint) = state.scope.return_type_hint {
|
||||||
state.ok(
|
state.ok(
|
||||||
ret_type_ref.narrow(&mut TypeRef::from_type(outer_hints, hint)),
|
ret_type_ref.narrow(&mut outer_hints.from_type(&hint).unwrap()),
|
||||||
self.meta,
|
self.meta,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -312,7 +313,7 @@ impl Expression {
|
|||||||
&mut self,
|
&mut self,
|
||||||
state: &mut PassState<ErrorKind>,
|
state: &mut PassState<ErrorKind>,
|
||||||
hints: &'s ScopeHints<'s>,
|
hints: &'s ScopeHints<'s>,
|
||||||
) -> Result<TypeRef<'s>, ErrorKind> {
|
) -> Result<ScopeHint<'s>, ErrorKind> {
|
||||||
match &mut self.0 {
|
match &mut self.0 {
|
||||||
ExprKind::Variable(var) => {
|
ExprKind::Variable(var) => {
|
||||||
let hint = hints
|
let hint = hints
|
||||||
@ -322,9 +323,9 @@ impl Expression {
|
|||||||
if let Ok(hint) = &hint {
|
if let Ok(hint) = &hint {
|
||||||
var.0 = hint.as_type()
|
var.0 = hint.as_type()
|
||||||
}
|
}
|
||||||
Ok(TypeRef::Hint(hint?))
|
hint
|
||||||
}
|
}
|
||||||
ExprKind::Literal(literal) => TypeRef::from_literal(hints, *literal),
|
ExprKind::Literal(literal) => Ok(hints.from_type(&literal.as_type()).unwrap()),
|
||||||
ExprKind::BinOp(op, lhs, rhs) => {
|
ExprKind::BinOp(op, lhs, rhs) => {
|
||||||
let mut lhs_ref = lhs.infer_hints(state, hints)?;
|
let mut lhs_ref = lhs.infer_hints(state, hints)?;
|
||||||
let mut rhs_ref = rhs.infer_hints(state, hints)?;
|
let mut rhs_ref = rhs.infer_hints(state, hints)?;
|
||||||
@ -346,20 +347,23 @@ impl Expression {
|
|||||||
let expr_res = param_expr.infer_hints(state, hints);
|
let expr_res = param_expr.infer_hints(state, hints);
|
||||||
if let Some(mut param_ref) = state.ok(expr_res, param_expr.1) {
|
if let Some(mut param_ref) = state.ok(expr_res, param_expr.1) {
|
||||||
state.ok(
|
state.ok(
|
||||||
param_ref.narrow(&mut TypeRef::from_type(hints, *param_t)),
|
param_ref.narrow(&mut hints.from_type(param_t).unwrap()),
|
||||||
param_expr.1,
|
param_expr.1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(TypeRef::from_type(hints, fn_call.ret))
|
Ok(hints.from_type(&fn_call.ret).unwrap())
|
||||||
}
|
}
|
||||||
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
||||||
let cond_res = cond.infer_hints(state, hints);
|
let cond_res = cond.infer_hints(state, hints);
|
||||||
let cond_hints = state.ok(cond_res, cond.1);
|
let cond_hints = state.ok(cond_res, cond.1);
|
||||||
|
|
||||||
if let Some(mut cond_hints) = cond_hints {
|
if let Some(mut cond_hints) = cond_hints {
|
||||||
state.ok(cond_hints.narrow(&mut TypeRef::Literal(Bool)), cond.1);
|
state.ok(
|
||||||
|
cond_hints.narrow(&mut hints.from_type(&Bool).unwrap()),
|
||||||
|
cond.1,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let lhs_res = lhs.infer_hints(state, hints);
|
let lhs_res = lhs.infer_hints(state, hints);
|
||||||
@ -374,20 +378,20 @@ impl Expression {
|
|||||||
Ok(pick_return(lhs_hints, rhs_hints).1)
|
Ok(pick_return(lhs_hints, rhs_hints).1)
|
||||||
} else {
|
} else {
|
||||||
// Failed to retrieve types from either
|
// Failed to retrieve types from either
|
||||||
Ok(TypeRef::from_type(hints, Vague(Unknown)))
|
Ok(hints.from_type(&Vague(Unknown)).unwrap())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Some((_, type_ref)) = lhs_hints {
|
if let Some((_, type_ref)) = lhs_hints {
|
||||||
Ok(type_ref)
|
Ok(type_ref)
|
||||||
} else {
|
} else {
|
||||||
Ok(TypeRef::from_type(hints, Vague(Unknown)))
|
Ok(hints.from_type(&Vague(Unknown)).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Block(block) => {
|
ExprKind::Block(block) => {
|
||||||
let block_ref = block.infer_hints(state, hints)?;
|
let block_ref = block.infer_hints(state, hints)?;
|
||||||
match block_ref.0 {
|
match block_ref.0 {
|
||||||
ReturnKind::Hard => Ok(TypeRef::from_type(hints, Void)),
|
ReturnKind::Hard => Ok(hints.from_type(&Void).unwrap()),
|
||||||
ReturnKind::Soft => Ok(block_ref.1),
|
ReturnKind::Soft => Ok(block_ref.1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user