Improve binop type narrowing
This commit is contained in:
parent
f8d2e4996a
commit
8d3dd4a49f
@ -48,8 +48,8 @@ impl TypeKind {
|
|||||||
rhs: &TypeKind,
|
rhs: &TypeKind,
|
||||||
binop: &ScopeBinopDef,
|
binop: &ScopeBinopDef,
|
||||||
) -> Option<(TypeKind, TypeKind, TypeKind)> {
|
) -> Option<(TypeKind, TypeKind, TypeKind)> {
|
||||||
let lhs_ty = lhs.collapse_into(&binop.hands.0);
|
let lhs_ty = lhs.narrow_into(&binop.hands.0);
|
||||||
let rhs_ty = rhs.collapse_into(&binop.hands.1);
|
let rhs_ty = rhs.narrow_into(&binop.hands.1);
|
||||||
if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) {
|
if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) {
|
||||||
Some((lhs_ty, rhs_ty, binop.return_ty.clone()))
|
Some((lhs_ty, rhs_ty, binop.return_ty.clone()))
|
||||||
} else {
|
} else {
|
||||||
@ -74,22 +74,6 @@ impl TypeKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn binop_hint(
|
|
||||||
&self,
|
|
||||||
lhs: &TypeKind,
|
|
||||||
rhs: &TypeKind,
|
|
||||||
binop: &ScopeBinopDef,
|
|
||||||
) -> Option<(TypeKind, TypeKind)> {
|
|
||||||
self.collapse_into(&binop.return_ty).ok()?;
|
|
||||||
let lhs_ty = lhs.collapse_into(&binop.hands.0);
|
|
||||||
let rhs_ty = rhs.collapse_into(&binop.hands.1);
|
|
||||||
if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) {
|
|
||||||
Some((lhs_ty, rhs_ty))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn signed(&self) -> bool {
|
pub fn signed(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
TypeKind::Bool => false,
|
TypeKind::Bool => false,
|
||||||
@ -230,9 +214,9 @@ impl TypeKind {
|
|||||||
(lhs1, rhs1): (&TypeKind, &TypeKind),
|
(lhs1, rhs1): (&TypeKind, &TypeKind),
|
||||||
(lhs2, rhs2): (&TypeKind, &TypeKind),
|
(lhs2, rhs2): (&TypeKind, &TypeKind),
|
||||||
) -> Option<(TypeKind, TypeKind)> {
|
) -> Option<(TypeKind, TypeKind)> {
|
||||||
if let (Ok(lhs), Ok(rhs)) = (lhs1.collapse_into(&lhs2), rhs1.collapse_into(&rhs2)) {
|
if let (Ok(lhs), Ok(rhs)) = (lhs1.narrow_into(&lhs2), rhs1.narrow_into(&rhs2)) {
|
||||||
Some((lhs, rhs))
|
Some((lhs, rhs))
|
||||||
} else if let (Ok(lhs), Ok(rhs)) = (lhs1.collapse_into(&rhs2), rhs1.collapse_into(&lhs2)) {
|
} else if let (Ok(lhs), Ok(rhs)) = (lhs1.narrow_into(&rhs2), rhs1.narrow_into(&lhs2)) {
|
||||||
Some((rhs, lhs))
|
Some((rhs, lhs))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -112,7 +112,9 @@ pub enum TypeKind {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum VagueType {
|
pub enum VagueType {
|
||||||
Unknown,
|
Unknown,
|
||||||
|
/// Some integer value (e.g. 5)
|
||||||
Integer,
|
Integer,
|
||||||
|
/// Some decimal fractional value (e.g. 1.5)
|
||||||
Decimal,
|
Decimal,
|
||||||
TypeRef(usize),
|
TypeRef(usize),
|
||||||
}
|
}
|
||||||
|
@ -121,9 +121,11 @@ impl<Key: std::hash::Hash + Eq, T: Clone + std::fmt::Debug> Storage<Key, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type BinopMap = Storage<ScopeBinopKey, ScopeBinopDef>;
|
||||||
|
|
||||||
#[derive(Clone, Default, Debug)]
|
#[derive(Clone, Default, Debug)]
|
||||||
pub struct Scope<Data: Clone + Default> {
|
pub struct Scope<Data: Clone + Default> {
|
||||||
pub binops: Storage<ScopeBinopKey, ScopeBinopDef>,
|
pub binops: BinopMap,
|
||||||
pub function_returns: Storage<String, ScopeFunction>,
|
pub function_returns: Storage<String, ScopeFunction>,
|
||||||
pub variables: Storage<String, ScopeVariable>,
|
pub variables: Storage<String, ScopeVariable>,
|
||||||
pub types: Storage<CustomTypeKey, TypeDefinition>,
|
pub types: Storage<CustomTypeKey, TypeDefinition>,
|
||||||
@ -223,6 +225,34 @@ pub struct ScopeBinopDef {
|
|||||||
pub return_ty: TypeKind,
|
pub return_ty: TypeKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ScopeBinopDef {
|
||||||
|
pub fn binop_hint_old(
|
||||||
|
&self,
|
||||||
|
lhs: &TypeKind,
|
||||||
|
rhs: &TypeKind,
|
||||||
|
ret_ty: &TypeKind,
|
||||||
|
) -> Option<(TypeKind, TypeKind)> {
|
||||||
|
ret_ty.narrow_into(&self.return_ty).ok()?;
|
||||||
|
let lhs_ty = lhs.narrow_into(&self.hands.0);
|
||||||
|
let rhs_ty = rhs.narrow_into(&self.hands.1);
|
||||||
|
if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) {
|
||||||
|
Some((lhs_ty, rhs_ty))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn binop_ret_ty(&self, lhs: &TypeKind, rhs: &TypeKind) -> Option<TypeKind> {
|
||||||
|
let lhs_ty = lhs.narrow_into(&self.hands.0);
|
||||||
|
let rhs_ty = rhs.narrow_into(&self.hands.1);
|
||||||
|
if let (Ok(_), Ok(_)) = (lhs_ty, rhs_ty) {
|
||||||
|
Some(self.return_ty.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PassState<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> {
|
pub struct PassState<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> {
|
||||||
state: &'st mut State<TError>,
|
state: &'st mut State<TError>,
|
||||||
pub scope: &'sc mut Scope<Data>,
|
pub scope: &'sc mut Scope<Data>,
|
||||||
|
@ -79,7 +79,7 @@ pub enum ErrorKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TypeKind {
|
impl TypeKind {
|
||||||
pub(super) fn collapse_into(&self, other: &TypeKind) -> Result<TypeKind, ErrorKind> {
|
pub(super) fn narrow_into(&self, other: &TypeKind) -> Result<TypeKind, ErrorKind> {
|
||||||
if self == other {
|
if self == other {
|
||||||
return Ok(self.clone());
|
return Ok(self.clone());
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ impl TypeKind {
|
|||||||
}
|
}
|
||||||
(TypeKind::Borrow(val1, mut1), TypeKind::Borrow(val2, mut2)) => {
|
(TypeKind::Borrow(val1, mut1), TypeKind::Borrow(val2, mut2)) => {
|
||||||
// Extracted to give priority for other collapse-error
|
// Extracted to give priority for other collapse-error
|
||||||
let collapsed = val1.collapse_into(val2)?;
|
let collapsed = val1.narrow_into(val2)?;
|
||||||
if mut1 == mut2 {
|
if mut1 == mut2 {
|
||||||
Ok(TypeKind::Borrow(Box::new(collapsed), *mut1 && *mut2))
|
Ok(TypeKind::Borrow(Box::new(collapsed), *mut1 && *mut2))
|
||||||
} else {
|
} else {
|
||||||
@ -132,14 +132,84 @@ impl TypeKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
(TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => {
|
(TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => {
|
||||||
Ok(TypeKind::UserPtr(Box::new(val1.collapse_into(val2)?)))
|
Ok(TypeKind::UserPtr(Box::new(val1.narrow_into(val2)?)))
|
||||||
}
|
}
|
||||||
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
|
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn widen_into(&self, other: &TypeKind) -> TypeKind {
|
||||||
|
if self == other {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
match (self, other) {
|
||||||
|
(TypeKind::Vague(Vague::Unknown), other) | (other, TypeKind::Vague(Vague::Unknown)) => {
|
||||||
|
TypeKind::Vague(VagueType::Unknown)
|
||||||
|
}
|
||||||
|
(TypeKind::Vague(Vague::Integer), other) | (other, TypeKind::Vague(Vague::Integer)) => {
|
||||||
|
match other {
|
||||||
|
TypeKind::I8
|
||||||
|
| TypeKind::I16
|
||||||
|
| TypeKind::I32
|
||||||
|
| TypeKind::I64
|
||||||
|
| TypeKind::I128
|
||||||
|
| TypeKind::U8
|
||||||
|
| TypeKind::U16
|
||||||
|
| TypeKind::U32
|
||||||
|
| TypeKind::U64
|
||||||
|
| TypeKind::U128 => TypeKind::Vague(VagueType::Integer),
|
||||||
|
_ => TypeKind::Vague(VagueType::Unknown),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => {
|
||||||
|
match other {
|
||||||
|
TypeKind::F16
|
||||||
|
| TypeKind::F32B
|
||||||
|
| TypeKind::F32
|
||||||
|
| TypeKind::F64
|
||||||
|
| TypeKind::F80
|
||||||
|
| TypeKind::F128
|
||||||
|
| TypeKind::F128PPC => TypeKind::Vague(VagueType::Decimal),
|
||||||
|
_ => TypeKind::Vague(VagueType::Unknown),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => {
|
||||||
|
TypeKind::UserPtr(Box::new(val1.widen_into(val2)))
|
||||||
|
}
|
||||||
|
(TypeKind::CodegenPtr(val1), TypeKind::CodegenPtr(val2)) => {
|
||||||
|
TypeKind::CodegenPtr(Box::new(val1.widen_into(val2)))
|
||||||
|
}
|
||||||
|
(TypeKind::Array(val1, len1), TypeKind::Array(val2, len2)) => {
|
||||||
|
if len1 == len2 {
|
||||||
|
TypeKind::Array(Box::new(val1.widen_into(val2)), *len1)
|
||||||
|
} else {
|
||||||
|
TypeKind::Vague(VagueType::Unknown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(TypeKind::Borrow(val1, mutable1), TypeKind::Borrow(val2, mutable2)) => {
|
||||||
|
if mutable1 == mutable2 {
|
||||||
|
TypeKind::Borrow(Box::new(val1.widen_into(val2)), *mutable1)
|
||||||
|
} else {
|
||||||
|
TypeKind::Vague(VagueType::Unknown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if self.category() == other.category() {
|
||||||
|
match self.category() {
|
||||||
|
TypeCategory::Integer => TypeKind::Vague(VagueType::Integer),
|
||||||
|
TypeCategory::Real => TypeKind::Vague(VagueType::Decimal),
|
||||||
|
TypeCategory::Bool => TypeKind::Bool,
|
||||||
|
_ => TypeKind::Vague(VagueType::Unknown),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TypeKind::Vague(VagueType::Unknown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn cast_into(&self, other: &TypeKind) -> Result<TypeKind, ErrorKind> {
|
pub(super) fn cast_into(&self, other: &TypeKind) -> Result<TypeKind, ErrorKind> {
|
||||||
if let Ok(collapsed) = self.collapse_into(other) {
|
if let Ok(collapsed) = self.narrow_into(other) {
|
||||||
Ok(collapsed)
|
Ok(collapsed)
|
||||||
} else {
|
} else {
|
||||||
let self_cat = self.category();
|
let self_cat = self.category();
|
||||||
@ -191,7 +261,7 @@ impl TypeKind {
|
|||||||
|
|
||||||
pub(super) fn resolve_weak(&self, refs: &TypeRefs) -> TypeKind {
|
pub(super) fn resolve_weak(&self, refs: &TypeRefs) -> TypeKind {
|
||||||
match self {
|
match self {
|
||||||
TypeKind::Vague(Vague::TypeRef(idx)) => refs.retrieve_type(*idx).unwrap(),
|
TypeKind::Vague(Vague::TypeRef(idx)) => refs.retrieve_wide_type(*idx).unwrap(),
|
||||||
_ => self.clone(),
|
_ => self.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ impl BinopDefinition {
|
|||||||
|
|
||||||
match inferred {
|
match inferred {
|
||||||
Ok(t) => return_type
|
Ok(t) => return_type
|
||||||
.collapse_into(&t.1)
|
.narrow_into(&t.1)
|
||||||
.or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))),
|
.or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))),
|
||||||
Err(e) => Ok(state.or_else(
|
Err(e) => Ok(state.or_else(
|
||||||
Err(e),
|
Err(e),
|
||||||
@ -191,7 +191,7 @@ impl FunctionDefinition {
|
|||||||
|
|
||||||
match inferred {
|
match inferred {
|
||||||
Ok(t) => return_type
|
Ok(t) => return_type
|
||||||
.collapse_into(&t.1)
|
.narrow_into(&t.1)
|
||||||
.or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))),
|
.or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))),
|
||||||
Err(e) => Ok(state.or_else(Err(e), return_type, self.block_meta())),
|
Err(e) => Ok(state.or_else(Err(e), return_type, self.block_meta())),
|
||||||
}
|
}
|
||||||
@ -250,7 +250,7 @@ impl Block {
|
|||||||
|
|
||||||
// Make sure the expression and variable type really is the same
|
// Make sure the expression and variable type really is the same
|
||||||
let res_t = state.or_else(
|
let res_t = state.or_else(
|
||||||
res.collapse_into(&var_t_resolved),
|
res.narrow_into(&var_t_resolved),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
variable_reference.2 + expression.1,
|
variable_reference.2 + expression.1,
|
||||||
);
|
);
|
||||||
@ -315,7 +315,7 @@ impl Block {
|
|||||||
|
|
||||||
// Make sure the expression and variable type to really
|
// Make sure the expression and variable type to really
|
||||||
// be the same
|
// be the same
|
||||||
state.ok(lhs_ty.collapse_into(&rhs_ty), lhs.1 + rhs.1);
|
state.ok(lhs_ty.narrow_into(&rhs_ty), lhs.1 + rhs.1);
|
||||||
|
|
||||||
if let Some(named_var) = lhs.backing_var() {
|
if let Some(named_var) = lhs.backing_var() {
|
||||||
if let Some(scope_var) = state.scope.variables.get(&named_var.1) {
|
if let Some(scope_var) = state.scope.variables.get(&named_var.1) {
|
||||||
@ -435,7 +435,7 @@ impl Expression {
|
|||||||
|
|
||||||
// Update typing to be more accurate
|
// Update typing to be more accurate
|
||||||
var_ref.0 = state.or_else(
|
var_ref.0 = state.or_else(
|
||||||
var_ref.0.resolve_ref(typerefs).collapse_into(&existing),
|
var_ref.0.resolve_ref(typerefs).narrow_into(&existing),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
var_ref.2,
|
var_ref.2,
|
||||||
);
|
);
|
||||||
@ -499,7 +499,7 @@ impl Expression {
|
|||||||
let rhs_res = rhs.typecheck(state, &typerefs, Some(&lhs_type));
|
let rhs_res = rhs.typecheck(state, &typerefs, Some(&lhs_type));
|
||||||
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
|
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
|
||||||
|
|
||||||
let both_t = lhs_type.collapse_into(&rhs_type)?;
|
let both_t = lhs_type.narrow_into(&rhs_type)?;
|
||||||
|
|
||||||
if *op == BinaryOperator::Minus && !lhs_type.signed() {
|
if *op == BinaryOperator::Minus && !lhs_type.signed() {
|
||||||
if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value()?, rhs.num_value()?)
|
if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value()?, rhs.num_value()?)
|
||||||
@ -510,7 +510,7 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(collapsed) = state.ok(rhs_type.collapse_into(&rhs_type), self.1) {
|
if let Some(collapsed) = state.ok(rhs_type.narrow_into(&rhs_type), self.1) {
|
||||||
// Try to coerce both sides again with collapsed type
|
// Try to coerce both sides again with collapsed type
|
||||||
lhs.typecheck(state, &typerefs, Some(&collapsed)).ok();
|
lhs.typecheck(state, &typerefs, Some(&collapsed)).ok();
|
||||||
rhs.typecheck(state, &typerefs, Some(&collapsed)).ok();
|
rhs.typecheck(state, &typerefs, Some(&collapsed)).ok();
|
||||||
@ -558,14 +558,14 @@ impl Expression {
|
|||||||
let param_res = param.typecheck(state, &typerefs, Some(&true_param_t));
|
let param_res = param.typecheck(state, &typerefs, Some(&true_param_t));
|
||||||
let param_t =
|
let param_t =
|
||||||
state.or_else(param_res, TypeKind::Vague(Vague::Unknown), param.1);
|
state.or_else(param_res, TypeKind::Vague(Vague::Unknown), param.1);
|
||||||
state.ok(param_t.collapse_into(&true_param_t), param.1);
|
state.ok(param_t.narrow_into(&true_param_t), param.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure function return type is the same as the claimed
|
// Make sure function return type is the same as the claimed
|
||||||
// return type
|
// return type
|
||||||
let ret_t = f
|
let ret_t = f
|
||||||
.ret
|
.ret
|
||||||
.collapse_into(&function_call.return_type.resolve_ref(typerefs))?;
|
.narrow_into(&function_call.return_type.resolve_ref(typerefs))?;
|
||||||
// Update typing to be more accurate
|
// Update typing to be more accurate
|
||||||
function_call.return_type = ret_t.clone();
|
function_call.return_type = ret_t.clone();
|
||||||
Ok(ret_t.resolve_ref(typerefs))
|
Ok(ret_t.resolve_ref(typerefs))
|
||||||
@ -576,7 +576,7 @@ impl Expression {
|
|||||||
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
||||||
let cond_res = cond.typecheck(state, &typerefs, Some(&TypeKind::Bool));
|
let cond_res = cond.typecheck(state, &typerefs, Some(&TypeKind::Bool));
|
||||||
let cond_t = state.or_else(cond_res, TypeKind::Vague(Vague::Unknown), cond.1);
|
let cond_t = state.or_else(cond_res, TypeKind::Vague(Vague::Unknown), cond.1);
|
||||||
state.ok(cond_t.collapse_into(&TypeKind::Bool), cond.1);
|
state.ok(cond_t.narrow_into(&TypeKind::Bool), cond.1);
|
||||||
|
|
||||||
// Typecheck then/else return types and make sure they are the
|
// Typecheck then/else return types and make sure they are the
|
||||||
// same, if else exists.
|
// same, if else exists.
|
||||||
@ -596,7 +596,7 @@ impl Expression {
|
|||||||
|
|
||||||
// Make sure then and else -blocks have the same return type
|
// Make sure then and else -blocks have the same return type
|
||||||
let collapsed = then_ret_t
|
let collapsed = then_ret_t
|
||||||
.collapse_into(&else_ret_t)
|
.narrow_into(&else_ret_t)
|
||||||
.or(Err(ErrorKind::BranchTypesDiffer(then_ret_t, else_ret_t)))?;
|
.or(Err(ErrorKind::BranchTypesDiffer(then_ret_t, else_ret_t)))?;
|
||||||
|
|
||||||
if let Some(rhs) = rhs.as_mut() {
|
if let Some(rhs) = rhs.as_mut() {
|
||||||
@ -632,7 +632,7 @@ impl Expression {
|
|||||||
match expr_t {
|
match expr_t {
|
||||||
TypeKind::Array(inferred_ty, _) | TypeKind::UserPtr(inferred_ty) => {
|
TypeKind::Array(inferred_ty, _) | TypeKind::UserPtr(inferred_ty) => {
|
||||||
let ty = state.or_else(
|
let ty = state.or_else(
|
||||||
elem_ty.resolve_ref(typerefs).collapse_into(&inferred_ty),
|
elem_ty.resolve_ref(typerefs).narrow_into(&inferred_ty),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
self.1,
|
self.1,
|
||||||
);
|
);
|
||||||
@ -660,7 +660,7 @@ impl Expression {
|
|||||||
let mut iter = expr_types.iter_mut();
|
let mut iter = expr_types.iter_mut();
|
||||||
if let Some(first) = iter.next() {
|
if let Some(first) = iter.next() {
|
||||||
for other in iter {
|
for other in iter {
|
||||||
state.ok(first.collapse_into(other), self.1);
|
state.ok(first.narrow_into(other), self.1);
|
||||||
}
|
}
|
||||||
Ok(TypeKind::Array(
|
Ok(TypeKind::Array(
|
||||||
Box::new(first.clone()),
|
Box::new(first.clone()),
|
||||||
@ -696,7 +696,7 @@ impl Expression {
|
|||||||
if let Some(expr_field_ty) = struct_type.get_field_ty(&field_name) {
|
if let Some(expr_field_ty) = struct_type.get_field_ty(&field_name) {
|
||||||
// Make sure they are the same
|
// Make sure they are the same
|
||||||
let true_ty = state.or_else(
|
let true_ty = state.or_else(
|
||||||
expr_field_ty.collapse_into(&expected_ty),
|
expr_field_ty.narrow_into(&expected_ty),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
self.1,
|
self.1,
|
||||||
);
|
);
|
||||||
@ -736,7 +736,7 @@ impl Expression {
|
|||||||
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), field_expr.1);
|
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), field_expr.1);
|
||||||
|
|
||||||
// Make sure both are the same type, report error if not
|
// Make sure both are the same type, report error if not
|
||||||
state.ok(expr_ty.collapse_into(&expr_ty), field_expr.1);
|
state.ok(expr_ty.narrow_into(&expr_ty), field_expr.1);
|
||||||
}
|
}
|
||||||
Ok(TypeKind::CustomType(type_key))
|
Ok(TypeKind::CustomType(type_key))
|
||||||
}
|
}
|
||||||
@ -762,7 +762,7 @@ impl Expression {
|
|||||||
|
|
||||||
// Update typing to be more accurate
|
// Update typing to be more accurate
|
||||||
var_ref.0 = state.or_else(
|
var_ref.0 = state.or_else(
|
||||||
var_ref.0.resolve_ref(typerefs).collapse_into(&existing),
|
var_ref.0.resolve_ref(typerefs).narrow_into(&existing),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
var_ref.2,
|
var_ref.2,
|
||||||
);
|
);
|
||||||
@ -786,7 +786,7 @@ impl Expression {
|
|||||||
|
|
||||||
// Update typing to be more accurate
|
// Update typing to be more accurate
|
||||||
let TypeKind::Borrow(inner, mutable) = state.or_else(
|
let TypeKind::Borrow(inner, mutable) = state.or_else(
|
||||||
var_ref.0.resolve_ref(typerefs).collapse_into(&existing),
|
var_ref.0.resolve_ref(typerefs).narrow_into(&existing),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
var_ref.2,
|
var_ref.2,
|
||||||
) else {
|
) else {
|
||||||
|
@ -4,7 +4,7 @@ use std::{
|
|||||||
rc::Rc,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::mir::{BinaryOperator, TypeKind, VagueType};
|
use crate::mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
super::pass::{ScopeBinopDef, ScopeBinopKey, Storage},
|
super::pass::{ScopeBinopDef, ScopeBinopKey, Storage},
|
||||||
@ -21,7 +21,7 @@ impl<'scope> TypeRef<'scope> {
|
|||||||
/// Resolve current type in a weak manner, not resolving any Arrays or
|
/// Resolve current type in a weak manner, not resolving any Arrays or
|
||||||
/// further inner types
|
/// further inner types
|
||||||
pub fn resolve_weak(&self) -> Option<TypeKind> {
|
pub fn resolve_weak(&self) -> Option<TypeKind> {
|
||||||
Some(self.1.types.retrieve_type(*self.0.borrow())?)
|
Some(self.1.types.retrieve_wide_type(*self.0.borrow())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve type deeply, trying to resolve any inner types as well.
|
/// Resolve type deeply, trying to resolve any inner types as well.
|
||||||
@ -57,12 +57,46 @@ impl<'scope> std::fmt::Debug for TypeRef<'scope> {
|
|||||||
|
|
||||||
type TypeIdRef = Rc<RefCell<usize>>;
|
type TypeIdRef = Rc<RefCell<usize>>;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
|
||||||
|
pub enum TypeRefKind {
|
||||||
|
Direct(TypeKind),
|
||||||
|
BinOp(BinaryOperator, TypeKind, TypeKind),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeRefKind {
|
||||||
|
pub fn widen(&self, types: &TypeRefs) -> Option<TypeKind> {
|
||||||
|
match self {
|
||||||
|
TypeRefKind::BinOp(op, lhs, rhs) => {
|
||||||
|
let mut binops = types
|
||||||
|
.binop_types
|
||||||
|
.iter()
|
||||||
|
.filter(|b| b.1.operator == *op)
|
||||||
|
.map(|b| b.1.binop_ret_ty(&lhs, &rhs))
|
||||||
|
.filter_map(|s| s);
|
||||||
|
if let Some(mut ty) = binops.next() {
|
||||||
|
while let Some(other) = binops.next() {
|
||||||
|
ty = ty.widen_into(&other);
|
||||||
|
}
|
||||||
|
Some(ty)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeRefKind::Direct(ty) => match ty {
|
||||||
|
TypeKind::Vague(VagueType::TypeRef(id)) => types.retrieve_wide_type(*id),
|
||||||
|
_ => Some(ty.clone()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct TypeRefs {
|
pub struct TypeRefs {
|
||||||
/// Simple list of types that variables can refrence
|
/// Simple list of types that variables can refrence
|
||||||
pub(super) hints: RefCell<Vec<TypeKind>>,
|
pub(super) hints: RefCell<Vec<TypeRefKind>>,
|
||||||
/// Indirect ID-references, referring to hints-vec
|
/// Indirect ID-references, referring to hints-vec
|
||||||
pub(super) type_refs: RefCell<Vec<TypeIdRef>>,
|
pub(super) type_refs: RefCell<Vec<TypeIdRef>>,
|
||||||
|
binop_types: BinopMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for TypeRefs {
|
impl std::fmt::Display for TypeRefs {
|
||||||
@ -74,7 +108,7 @@ impl std::fmt::Display for TypeRefs {
|
|||||||
"{:<3} = {:<3} = {:?} = {}",
|
"{:<3} = {:<3} = {:?} = {}",
|
||||||
i,
|
i,
|
||||||
unsafe { *self.recurse_type_ref(idx).borrow() },
|
unsafe { *self.recurse_type_ref(idx).borrow() },
|
||||||
self.retrieve_type(idx),
|
self.retrieve_wide_type(idx),
|
||||||
TypeKind::Vague(VagueType::TypeRef(idx)).resolve_ref(self)
|
TypeKind::Vague(VagueType::TypeRef(idx)).resolve_ref(self)
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@ -87,7 +121,9 @@ impl TypeRefs {
|
|||||||
let idx = self.hints.borrow().len();
|
let idx = self.hints.borrow().len();
|
||||||
let typecell = Rc::new(RefCell::new(idx));
|
let typecell = Rc::new(RefCell::new(idx));
|
||||||
self.type_refs.borrow_mut().push(typecell.clone());
|
self.type_refs.borrow_mut().push(typecell.clone());
|
||||||
self.hints.borrow_mut().push(ty.clone());
|
self.hints
|
||||||
|
.borrow_mut()
|
||||||
|
.push(TypeRefKind::Direct(ty.clone()));
|
||||||
typecell
|
typecell
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +139,7 @@ impl TypeRefs {
|
|||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, t)| *t == ty)
|
.find(|(_, t)| t == &&TypeRefKind::Direct(ty.clone()))
|
||||||
.map(|(i, _)| i)
|
.map(|(i, _)| i)
|
||||||
{
|
{
|
||||||
Some(Rc::new(RefCell::new(idx)))
|
Some(Rc::new(RefCell::new(idx)))
|
||||||
@ -124,16 +160,13 @@ impl TypeRefs {
|
|||||||
return refs.get_unchecked(idx).clone();
|
return refs.get_unchecked(idx).clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn retrieve_type(&self, idx: usize) -> Option<TypeKind> {
|
pub fn retrieve_wide_type(&self, idx: usize) -> Option<TypeKind> {
|
||||||
let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() };
|
let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() };
|
||||||
self.hints
|
self.hints
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(inner_idx)
|
.get(inner_idx)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|t| match t {
|
.map(|t| t.widen(self))
|
||||||
TypeKind::Vague(VagueType::TypeRef(id)) => self.retrieve_type(id),
|
|
||||||
_ => Some(t),
|
|
||||||
})
|
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,7 +236,27 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let mut hints = self.types.hints.borrow_mut();
|
let mut hints = self.types.hints.borrow_mut();
|
||||||
let existing = hints.get_unchecked_mut(*hint.0.borrow());
|
let existing = hints.get_unchecked_mut(*hint.0.borrow());
|
||||||
*existing = existing.collapse_into(&ty).ok()?;
|
match existing {
|
||||||
|
TypeRefKind::Direct(type_kind) => {
|
||||||
|
*type_kind = type_kind.narrow_into(&ty).ok()?;
|
||||||
|
}
|
||||||
|
TypeRefKind::BinOp(op, lhs, rhs) => {
|
||||||
|
let binops = self
|
||||||
|
.types
|
||||||
|
.binop_types
|
||||||
|
.iter()
|
||||||
|
.filter(|b| b.1.operator == *op && b.1.return_ty == *ty);
|
||||||
|
for binop in binops {
|
||||||
|
if let (Ok(lhs_narrow), Ok(rhs_narrow)) = (
|
||||||
|
lhs.narrow_into(&binop.1.hands.0),
|
||||||
|
rhs.narrow_into(&binop.1.hands.1),
|
||||||
|
) {
|
||||||
|
*lhs = lhs_narrow;
|
||||||
|
*rhs = rhs_narrow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some(TypeRef(hint.0.clone(), self))
|
Some(TypeRef(hint.0.clone(), self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,7 +268,9 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
|||||||
.hints
|
.hints
|
||||||
.borrow()
|
.borrow()
|
||||||
.get_unchecked(*hint2.0.borrow())
|
.get_unchecked(*hint2.0.borrow())
|
||||||
.clone();
|
.clone()
|
||||||
|
.widen(self.types)
|
||||||
|
.unwrap();
|
||||||
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 && idx != &hint1.0 {
|
if *idx == hint2.0 && idx != &hint1.0 {
|
||||||
|
Loading…
Reference in New Issue
Block a user