Compare commits
No commits in common. "fef4b2a5ce5c0685f597695ef5c640ce2f1625ce" and "e328e44c9a6a424d916e628960b1f6eb56cd916f" have entirely different histories.
fef4b2a5ce
...
e328e44c9a
@ -3,7 +3,7 @@ use crate::typecheck::typedef::TypeEnum;
|
|||||||
use super::type_inferencer::Inferencer;
|
use super::type_inferencer::Inferencer;
|
||||||
use super::typedef::Type;
|
use super::typedef::Type;
|
||||||
use nac3parser::ast::{self, Constant, Expr, ExprKind, Operator::{LShift, RShift}, Stmt, StmtKind, StrRef};
|
use nac3parser::ast::{self, Constant, Expr, ExprKind, Operator::{LShift, RShift}, Stmt, StmtKind, StrRef};
|
||||||
use std::{collections::HashSet, iter::once, ops::Not};
|
use std::{collections::HashSet, iter::once};
|
||||||
|
|
||||||
impl<'a> Inferencer<'a> {
|
impl<'a> Inferencer<'a> {
|
||||||
fn should_have_value(&mut self, expr: &Expr<Option<Type>>) -> Result<(), HashSet<String>> {
|
fn should_have_value(&mut self, expr: &Expr<Option<Type>>) -> Result<(), HashSet<String>> {
|
||||||
@ -302,31 +302,6 @@ impl<'a> Inferencer<'a> {
|
|||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
self.check_expr(value, defined_identifiers)?;
|
self.check_expr(value, defined_identifiers)?;
|
||||||
self.should_have_value(value)?;
|
self.should_have_value(value)?;
|
||||||
|
|
||||||
// Check that the return value is a non-`alloca` type, effectively only allowing primitive types.
|
|
||||||
// This is a workaround preventing the caller from using a variable `alloca`-ed in the body, which
|
|
||||||
// is freed when the function returns.
|
|
||||||
if let Some(ret_ty) = value.custom {
|
|
||||||
if [
|
|
||||||
self.primitives.int32,
|
|
||||||
self.primitives.int64,
|
|
||||||
self.primitives.uint32,
|
|
||||||
self.primitives.uint64,
|
|
||||||
self.primitives.float,
|
|
||||||
self.primitives.bool,
|
|
||||||
].iter().any(|allowed_ty| self.unifier.unioned(ret_ty, *allowed_ty)).not() {
|
|
||||||
// Explicitly allow ellipsis as a return value, as the type of the ellipsis is contextually
|
|
||||||
// inferred and just generates an unconditional assertion
|
|
||||||
if matches!(value.node, ExprKind::Constant { value: Constant::Ellipsis, .. }).not() {
|
|
||||||
return Err(HashSet::from([
|
|
||||||
format!(
|
|
||||||
"return value of type {} must be a primitive",
|
|
||||||
self.unifier.stringify(ret_ty),
|
|
||||||
),
|
|
||||||
]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@ class A:
|
|||||||
def get_a(self) -> int32:
|
def get_a(self) -> int32:
|
||||||
return self.a
|
return self.a
|
||||||
|
|
||||||
# def get_b(self) -> B:
|
def get_b(self) -> B:
|
||||||
# return self.b
|
return self.b
|
||||||
|
|
||||||
|
|
||||||
def run() -> int32:
|
def run() -> int32:
|
||||||
|
@ -21,8 +21,8 @@ def run() -> int32:
|
|||||||
test_uint32()
|
test_uint32()
|
||||||
test_int64()
|
test_int64()
|
||||||
test_uint64()
|
test_uint64()
|
||||||
# test_A()
|
test_A()
|
||||||
# test_B()
|
test_B()
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def test_int32():
|
def test_int32():
|
||||||
@ -173,92 +173,91 @@ def test_uint64():
|
|||||||
a >>= uint32(b)
|
a >>= uint32(b)
|
||||||
output_uint64(a)
|
output_uint64(a)
|
||||||
|
|
||||||
# FIXME Fix returning objects of non-primitive types; Currently this is disabled in the function checker
|
class A:
|
||||||
# class A:
|
a: int32
|
||||||
# a: int32
|
def __init__(self, a: int32):
|
||||||
# def __init__(self, a: int32):
|
self.a = a
|
||||||
# self.a = a
|
|
||||||
#
|
def __add__(self, other: A) -> A:
|
||||||
# def __add__(self, other: A) -> A:
|
output_int32(self.a + other.a)
|
||||||
# output_int32(self.a + other.a)
|
return A(self.a + other.a)
|
||||||
# return A(self.a + other.a)
|
|
||||||
#
|
def __sub__(self, other: A) -> A:
|
||||||
# def __sub__(self, other: A) -> A:
|
output_int32(self.a - other.a)
|
||||||
# output_int32(self.a - other.a)
|
return A(self.a - other.a)
|
||||||
# return A(self.a - other.a)
|
|
||||||
#
|
def test_A():
|
||||||
# def test_A():
|
a = A(17)
|
||||||
# a = A(17)
|
b = A(3)
|
||||||
# b = A(3)
|
|
||||||
#
|
c = a + b
|
||||||
# c = a + b
|
# fail due to alloca in __add__ function
|
||||||
# # fail due to alloca in __add__ function
|
# output_int32(c.a)
|
||||||
# # output_int32(c.a)
|
|
||||||
#
|
a += b
|
||||||
# a += b
|
# fail due to alloca in __add__ function
|
||||||
# # fail due to alloca in __add__ function
|
# output_int32(a.a)
|
||||||
# # output_int32(a.a)
|
|
||||||
#
|
a = A(17)
|
||||||
# a = A(17)
|
b = A(3)
|
||||||
# b = A(3)
|
d = a - b
|
||||||
# d = a - b
|
# fail due to alloca in __add__ function
|
||||||
# # fail due to alloca in __add__ function
|
# output_int32(c.a)
|
||||||
# # output_int32(c.a)
|
|
||||||
#
|
a -= b
|
||||||
# a -= b
|
# fail due to alloca in __add__ function
|
||||||
# # fail due to alloca in __add__ function
|
# output_int32(a.a)
|
||||||
# # output_int32(a.a)
|
|
||||||
#
|
a = A(17)
|
||||||
# a = A(17)
|
b = A(3)
|
||||||
# b = A(3)
|
a.__add__(b)
|
||||||
# a.__add__(b)
|
a.__sub__(b)
|
||||||
# a.__sub__(b)
|
|
||||||
#
|
|
||||||
#
|
class B:
|
||||||
# class B:
|
a: int32
|
||||||
# a: int32
|
def __init__(self, a: int32):
|
||||||
# def __init__(self, a: int32):
|
self.a = a
|
||||||
# self.a = a
|
|
||||||
#
|
def __add__(self, other: B) -> B:
|
||||||
# def __add__(self, other: B) -> B:
|
output_int32(self.a + other.a)
|
||||||
# output_int32(self.a + other.a)
|
return B(self.a + other.a)
|
||||||
# return B(self.a + other.a)
|
|
||||||
#
|
def __sub__(self, other: B) -> B:
|
||||||
# def __sub__(self, other: B) -> B:
|
output_int32(self.a - other.a)
|
||||||
# output_int32(self.a - other.a)
|
return B(self.a - other.a)
|
||||||
# return B(self.a - other.a)
|
|
||||||
#
|
def __iadd__(self, other: B) -> B:
|
||||||
# def __iadd__(self, other: B) -> B:
|
output_int32(self.a + other.a + 24)
|
||||||
# output_int32(self.a + other.a + 24)
|
return B(self.a + other.a + 24)
|
||||||
# return B(self.a + other.a + 24)
|
|
||||||
#
|
def __isub__(self, other: B) -> B:
|
||||||
# def __isub__(self, other: B) -> B:
|
output_int32(self.a - other.a - 24)
|
||||||
# output_int32(self.a - other.a - 24)
|
return B(self.a - other.a - 24)
|
||||||
# return B(self.a - other.a - 24)
|
|
||||||
#
|
def test_B():
|
||||||
# def test_B():
|
a = B(17)
|
||||||
# a = B(17)
|
b = B(3)
|
||||||
# b = B(3)
|
|
||||||
#
|
c = a + b
|
||||||
# c = a + b
|
# fail due to alloca in __add__ function
|
||||||
# # fail due to alloca in __add__ function
|
# output_int32(c.a)
|
||||||
# # output_int32(c.a)
|
|
||||||
#
|
a += b
|
||||||
# a += b
|
# fail due to alloca in __add__ function
|
||||||
# # fail due to alloca in __add__ function
|
# output_int32(a.a)
|
||||||
# # output_int32(a.a)
|
|
||||||
#
|
a = B(17)
|
||||||
# a = B(17)
|
b = B(3)
|
||||||
# b = B(3)
|
d = a - b
|
||||||
# d = a - b
|
# fail due to alloca in __add__ function
|
||||||
# # fail due to alloca in __add__ function
|
# output_int32(c.a)
|
||||||
# # output_int32(c.a)
|
|
||||||
#
|
a -= b
|
||||||
# a -= b
|
# fail due to alloca in __add__ function
|
||||||
# # fail due to alloca in __add__ function
|
# output_int32(a.a)
|
||||||
# # output_int32(a.a)
|
|
||||||
#
|
a = B(17)
|
||||||
# a = B(17)
|
b = B(3)
|
||||||
# b = B(3)
|
a.__add__(b)
|
||||||
# a.__add__(b)
|
a.__sub__(b)
|
||||||
# a.__sub__(b)
|
|
Loading…
Reference in New Issue
Block a user