Merge remote-tracking branch 'origin/main'

This commit is contained in:
flameyosflow 2025-12-15 14:58:10 +02:00
commit 872c8e356d
9 changed files with 131 additions and 6 deletions

View file

@ -11,6 +11,7 @@ pub enum TypeAnnot {
Function(Vec<TypeAnnot>, Box<TypeAnnot>),
Tuple(Vec<TypeAnnot>),
Array(Box<TypeAnnot>),
Ptr(Box<TypeAnnot>),
}
#[derive(Debug, Clone)]
@ -264,6 +265,8 @@ pub enum BinOp {
pub enum UnOp {
Neg,
Not,
Ref,
Deref,
}
#[derive(Debug, Clone)]
@ -399,7 +402,13 @@ pub enum TypedExprKind {
EarlyReturn(Option<Box<TypedExpr>>),
OptionalChain(Option<Box<TypedExpr>>, String),
Lambda(Vec<(BindingId, String, Option<TypeAnnot>)>, Box<TypedExpr>),
Let(BindingId, String, BindingKind, Option<TypeAnnot>, Box<TypedExpr>),
Let(
BindingId,
String,
BindingKind,
Option<TypeAnnot>,
Box<TypedExpr>,
),
Assign(Box<TypedExpr>, Box<TypedExpr>),
Cast(Box<TypedExpr>, TypeAnnot),
If(Box<TypedExpr>, Box<TypedExpr>, Option<Box<TypedExpr>>),

View file

@ -174,6 +174,9 @@ pub enum Token {
#[token("@")]
At,
#[token("&")]
Amp,
#[token("==")]
Eq,

View file

@ -121,7 +121,7 @@ fn test_assignment_operators() {
#[test]
fn test_punctuation() {
let mut lexer = Token::lexer("( ) [ ] { } , ; : . ... .. :: -> ~ ! => | |> ?. ?");
let mut lexer = Token::lexer("( ) [ ] { } , ; : . ... .. :: -> ~ ! => & | ?. ?");
assert_eq!(lexer.next(), Some(Ok(Token::LParen)));
assert_eq!(lexer.next(), Some(Ok(Token::RParen)));
@ -140,6 +140,7 @@ fn test_punctuation() {
assert_eq!(lexer.next(), Some(Ok(Token::Tilde)));
assert_eq!(lexer.next(), Some(Ok(Token::Bang)));
assert_eq!(lexer.next(), Some(Ok(Token::FatArrow)));
assert_eq!(lexer.next(), Some(Ok(Token::Amp)));
assert_eq!(lexer.next(), Some(Ok(Token::Union)));
assert_eq!(lexer.next(), Some(Ok(Token::OptionalChain)));
assert_eq!(lexer.next(), Some(Ok(Token::Unwrap)));

View file

@ -757,6 +757,10 @@ impl Monomorphizer {
let new_inner = self.substitute_in_type_annot(inner, subst_map)?;
Ok(TypeAnnot::Array(Box::new(new_inner)))
}
TypeAnnot::Ptr(inner) => {
let new_inner = self.substitute_in_type_annot(inner, subst_map)?;
Ok(TypeAnnot::Ptr(Box::new(new_inner)))
}
}
}
@ -768,6 +772,7 @@ impl Monomorphizer {
Type::String => TypeAnnot::Var("string".to_string()),
Type::Unit => TypeAnnot::Tuple(Vec::new()),
Type::Array(inner) => TypeAnnot::Array(Box::new(self.type_to_type_annot(inner))),
Type::Ptr(inner) => TypeAnnot::Ptr(Box::new(self.type_to_type_annot(inner))),
Type::Tuple(types) => {
let annots = types.iter().map(|t| self.type_to_type_annot(t)).collect();
TypeAnnot::Tuple(annots)
@ -886,6 +891,9 @@ impl Monomorphizer {
TypeAnnot::Array(inner) => {
self.collect_needs_from_type(inner, needs);
}
TypeAnnot::Ptr(inner) => {
self.collect_needs_from_type(inner, needs);
}
}
}
@ -918,6 +926,10 @@ impl Monomorphizer {
let inner_type = self.type_annot_to_type(inner);
Type::Array(Box::new(inner_type))
}
TypeAnnot::Ptr(inner) => {
let inner_type = self.type_annot_to_type(inner);
Type::Ptr(Box::new(inner_type))
}
}
}
@ -1194,5 +1206,6 @@ fn has_typevars_in_type_annot(ty: &TypeAnnot) -> bool {
}
TypeAnnot::Tuple(types) => types.iter().any(has_typevars_in_type_annot),
TypeAnnot::Array(inner) => has_typevars_in_type_annot(inner),
TypeAnnot::Ptr(inner) => has_typevars_in_type_annot(inner),
}
}

View file

@ -690,6 +690,13 @@ impl Parser {
fn parse_type_annot(&mut self) -> Result<TypeAnnot, ParseError> {
let start = self.peek_span().unwrap_or(0..0).start;
// Check for pointer type: *T
if matches!(self.peek(), Some(Token::Mul)) {
self.next();
let inner = self.parse_type_annot()?;
return Ok(TypeAnnot::Ptr(Box::new(inner)));
}
// Check for function type: fn (args)->ret
if matches!(self.peek(), Some(Token::KeywordFn)) {
self.next();
@ -1052,6 +1059,26 @@ impl Parser {
attributes: Vec::new(),
})
}
Some(Token::Amp) => {
self.next();
let expr = self.parse_unary_expr()?;
let end = expr.span.end;
Ok(Expr {
kind: ExprKind::UnOp(UnOp::Ref, Box::new(expr)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::Mul) => {
self.next();
let expr = self.parse_unary_expr()?;
let end = expr.span.end;
Ok(Expr {
kind: ExprKind::UnOp(UnOp::Deref, Box::new(expr)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
_ => self.parse_postfix_expr(),
}
}

View file

@ -11,6 +11,7 @@ pub enum Type {
Unit,
Never,
Array(Box<Type>),
Ptr(Box<Type>),
Tuple(Vec<Type>),
Function(Vec<Type>, Box<Type>),
Struct(String, Vec<Type>), // name and type arguments
@ -30,6 +31,7 @@ impl Type {
Type::Unit => "()".to_string(),
Type::Never => "!".to_string(),
Type::Array(inner) => format!("[{}]", inner.to_string()),
Type::Ptr(inner) => format!("*{}", inner.to_string()),
Type::Tuple(types) => {
let type_strs: Vec<String> = types.iter().map(|t| t.to_string()).collect();
format!("({})", type_strs.join(", "))
@ -733,6 +735,25 @@ impl TypeChecker {
}
Type::Bool
}
UnOp::Ref => {
// &expr creates a pointer to expr
Type::Ptr(Box::new(typed_inner.ty.clone()))
}
UnOp::Deref => {
// *expr dereferences a pointer
match &typed_inner.ty {
Type::Ptr(inner_ty) => (**inner_ty).clone(),
_ => {
return Err(TypeError {
kind: TypeErrorKind::TypeMismatch(
Type::Ptr(Box::new(Type::Unknown)),
typed_inner.ty.clone(),
),
span: inner.span.clone(),
});
}
}
}
};
(
TypedExprKind::UnOp(op.clone(), Box::new(typed_inner)),
@ -1322,6 +1343,9 @@ impl TypeChecker {
(TypeAnnot::Array(inner), Type::Array(actual_inner)) => {
self.infer_type_args(inner, actual_inner, type_params, type_map);
}
(TypeAnnot::Ptr(inner), Type::Ptr(actual_inner)) => {
self.infer_type_args(inner, actual_inner, type_params, type_map);
}
(TypeAnnot::Tuple(expected_types), Type::Tuple(actual_types)) => {
for (e, a) in expected_types.iter().zip(actual_types.iter()) {
self.infer_type_args(e, a, type_params, type_map);
@ -1605,6 +1629,9 @@ impl TypeChecker {
TypeAnnot::Array(inner) => {
Type::Array(Box::new(self.substitute_type(inner, subst_map)))
}
TypeAnnot::Ptr(inner) => {
Type::Ptr(Box::new(self.substitute_type(inner, subst_map)))
}
TypeAnnot::Tuple(types) => {
let substituted_types: Vec<Type> = types
.iter()
@ -1677,6 +1704,7 @@ impl TypeChecker {
Type::Tuple(tuple_types)
}
TypeAnnot::Array(inner) => Type::Array(Box::new(self.type_annot_to_type(inner))),
TypeAnnot::Ptr(inner) => Type::Ptr(Box::new(self.type_annot_to_type(inner))),
}
}
@ -1690,6 +1718,7 @@ impl TypeChecker {
(Type::Unit, Type::Unit) => true,
(Type::Never, _) | (_, Type::Never) => true,
(Type::Array(a), Type::Array(b)) => self.types_compatible(a, b),
(Type::Ptr(a), Type::Ptr(b)) => self.types_compatible(a, b),
(Type::Tuple(a), Type::Tuple(b)) => {
a.len() == b.len()
&& a.iter()

View file

@ -127,7 +127,6 @@ fn process_list(items: int) -> int do
result + items
end
fn literals() -> bool do
let int_val = 42
let float_val = 3.14
@ -140,7 +139,6 @@ fn literals() -> bool do
true
end
fn collections() -> bool do
let arr = [1, 2, 3, 4, 5]
let empty_arr = []
@ -149,7 +147,6 @@ fn collections() -> bool do
true
end
fn struct_enum_literals() -> bool do
let point = Point { x: 10, y: 20 }
let option_val = Option::Some(42)
@ -160,7 +157,6 @@ fn struct_enum_literals() -> bool do
true
end
fn arithmetic_logic() -> int do
let a = 10
let b = 5

View file

@ -0,0 +1,41 @@
# Pointer in struct
struct Point
x: *int,
y: int,
end
# Pointer in function parameter
fn take_ptr(ptr: *int) -> int do
0 # dummy
end
# Pointer in return type
fn return_ptr(x: int) -> *int do
x as *int
end
fn main() -> int do
# Basic pointer
let x: *int = 0 as *int;
let y = x; # Should infer *int
# Reference and dereference
let val = 42;
let ptr = &val; # Should be *int
let deref_val = *ptr; # Should be int
let ptr_to_ptr: *(*int) = &ptr; # **int
let p = Point { x: ptr, y: 42 };
take_ptr(ptr);
let z = return_ptr(deref_val);
# Nested operations
let nested_ptr = &ptr; # **int
let deref_once = *nested_ptr; # *int
let deref_twice = *deref_once; # int
42
end

6
tests/pointers.sui Normal file
View file

@ -0,0 +1,6 @@
# Pointer type test
fn main() -> int do
let x: *int = 0 as *int; # Cast to pointer for now
let y = x; # Should infer *int
42
end