Skip to content

Commit

Permalink
Merge branch 'references'
Browse files Browse the repository at this point in the history
  • Loading branch information
jfecher committed Jul 4, 2024
2 parents bba2bba + 6ebd8c3 commit c6d1681
Show file tree
Hide file tree
Showing 19 changed files with 216 additions and 117 deletions.
2 changes: 1 addition & 1 deletion examples/codegen/mutability.an
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ print num
mutate num
print num

mutate (n: Ref I32) =
mutate (n: &mut I32) =
x = double @n
n := x

Expand Down
4 changes: 2 additions & 2 deletions examples/codegen/string_builder.an
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import StringBuilder

sb: Ref StringBuilder = mut empty ()
sb: &mut StringBuilder = mut empty ()
reserve sb 10
append sb "你好,"
append sb " World!"

print (to_string sb)
print (to_string @sb)

// args: --delete-binary
// expected stdout: 你好, World!
4 changes: 2 additions & 2 deletions examples/nameresolution/type_decl.an
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

type Struct1 = a:I32, b:F64, c:String

type Thingy is Struct1
type Thingy = Struct1

type Generic a b = first: a, second: b

Expand All @@ -17,7 +17,7 @@ type Option a =

t = Just 1

type UniquePtr a is Ref a
type MyRef a = &a

// args: --check
// expected stdout:
8 changes: 4 additions & 4 deletions examples/parsing/type_decl.an
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ type Maybe a =
| Some a
| None

type List a = | Nil | Cons a (ref (List a))
type List a = | Nil | Cons a (&List a)


type UniquePtr a is ref a
type UniquePtr a = &a

t = 3 : I32

Expand All @@ -24,6 +24,6 @@ t = 3 : I32
// (type Struct2 t = a: Thingy, b: (Generic t Thingy));
// (type Union1 ab = | Variant1 | Variant2 );
// (type Maybe a = | Some a| None );
// (type List a = | Nil | Cons a (ref (List a)));
// (type UniquePtr a = (ref a));
// (type List a = | Nil | Cons a (& (List a)));
// (type UniquePtr a = (& a));
// (t = (: 3 I32))
13 changes: 11 additions & 2 deletions src/hir/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ impl std::hash::Hash for DefinitionType {
types::Type::TypeVariable(_) => (), // Do nothing
types::Type::Function(_) => (),
types::Type::TypeApplication(_, _) => (),
types::Type::Ref(_) => (),
types::Type::Ref(shared, mutable, _) => {
shared.hash(state);
mutable.hash(state);
},
types::Type::Struct(field_names, _) => {
for name in field_names {
name.hash(state);
Expand Down Expand Up @@ -91,7 +94,13 @@ fn definition_type_eq(a: &types::Type, b: &types::Type) -> bool {
match (a, b) {
(Type::Primitive(primitive1), Type::Primitive(primitive2)) => primitive1 == primitive2,
(Type::UserDefined(id1), Type::UserDefined(id2)) => id1 == id2,
(Type::TypeVariable(_), Type::TypeVariable(_)) | (Type::Ref(_), Type::Ref(_)) => true, // Do nothing
(Type::TypeVariable(_), Type::TypeVariable(_)) => true, // Do nothing
// This will monomorphize separate definitions for polymorphically-owned references
// which is undesired. Defaulting them to shared/owned though can change behavior
// if traits are involved.
(Type::Ref(shared1, mutable1, _), Type::Ref(shared2, mutable2, _)) => {
shared1 == shared2 && mutable1 == mutable2
},
(Type::Function(f1), Type::Function(f2)) => {
if f1.parameters.len() != f2.parameters.len() {
return false;
Expand Down
16 changes: 8 additions & 8 deletions src/hir/monomorphisation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,12 @@ impl<'c> Context<'c> {

let fuel = fuel - 1;
match &self.cache.type_bindings[id.0] {
Bound(TypeVariable(id2) | Ref(id2)) => self.find_binding(*id2, fuel),
Bound(TypeVariable(id2) | Ref(_, _, id2)) => self.find_binding(*id2, fuel),
Bound(binding) => Ok(binding),
Unbound(..) => {
for bindings in self.monomorphisation_bindings.iter().rev() {
match bindings.get(&id) {
Some(TypeVariable(id2) | Ref(id2)) => return self.find_binding(*id2, fuel),
Some(TypeVariable(id2) | Ref(_, _, id2)) => return self.find_binding(*id2, fuel),
Some(binding) => return Ok(binding),
None => (),
}
Expand Down Expand Up @@ -204,7 +204,7 @@ impl<'c> Context<'c> {
let args = fmap(args, |arg| self.follow_all_bindings_inner(arg, fuel));
TypeApplication(Box::new(con), args)
},
Ref(_) => typ.clone(),
Ref(..) => typ.clone(),
Struct(fields, id) => match self.find_binding(*id, fuel) {
Ok(binding) => self.follow_all_bindings_inner(binding, fuel),
Err(_) => {
Expand Down Expand Up @@ -346,7 +346,7 @@ impl<'c> Context<'c> {
_ => unreachable!("Kind error inside size_of_type"),
},

Ref(_) => Self::ptr_size(),
Ref(..) => Self::ptr_size(),
Struct(fields, rest) => {
if let Ok(binding) = self.find_binding(*rest, RECURSION_LIMIT) {
let binding = binding.clone();
Expand Down Expand Up @@ -519,7 +519,7 @@ impl<'c> Context<'c> {
let typ = self.follow_bindings_shallow(typ);

match typ {
Ok(Primitive(PrimitiveType::Ptr) | Ref(_)) => Type::Primitive(hir::PrimitiveType::Pointer),
Ok(Primitive(PrimitiveType::Ptr) | Ref(..)) => Type::Primitive(hir::PrimitiveType::Pointer),
Ok(Primitive(PrimitiveType::IntegerType)) => {
if self.is_type_variable(&args[0]) {
// Default to i32
Expand Down Expand Up @@ -553,7 +553,7 @@ impl<'c> Context<'c> {
}
},

Ref(_) => {
Ref(..) => {
unreachable!(
"Kind error during monomorphisation. Attempted to translate a `ref` without a type argument"
)
Expand Down Expand Up @@ -1517,7 +1517,7 @@ impl<'c> Context<'c> {
TypeApplication(typ, args) => {
match typ.as_ref() {
// Pass through ref types transparently
types::Type::Ref(_) => self.get_field_index(field_name, &args[0]),
types::Type::Ref(..) => self.get_field_index(field_name, &args[0]),
// These last 2 cases are the same. They're duplicated to avoid another follow_bindings_shallow call.
typ => self.get_field_index(field_name, typ),
}
Expand Down Expand Up @@ -1551,7 +1551,7 @@ impl<'c> Context<'c> {
let ref_type = match lhs_type {
types::Type::TypeApplication(constructor, args) => match self.follow_bindings_shallow(constructor.as_ref())
{
Ok(types::Type::Ref(_)) => Some(self.convert_type(&args[0])),
Ok(types::Type::Ref(..)) => Some(self.convert_type(&args[0])),
_ => None,
},
_ => None,
Expand Down
14 changes: 6 additions & 8 deletions src/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,35 +121,33 @@ impl<'cache, 'contents> Lexer<'cache, 'contents> {
("Ptr", Token::PointerType),
("Bool", Token::BooleanType),
("Unit", Token::UnitType),
("Ref", Token::Ref),
("mut", Token::Mut),
("true", Token::BooleanLiteral(true)),
("false", Token::BooleanLiteral(false)),
("and", Token::And),
("as", Token::As),
("block", Token::Block),
("break", Token::Break),
("continue", Token::Continue),
("do", Token::Do),
("effect", Token::Effect),
("else", Token::Else),
("extern", Token::Extern),
("for", Token::For),
("fn", Token::Fn),
("given", Token::Given),
("handle", Token::Handle),
("if", Token::If),
("impl", Token::Impl),
("import", Token::Import),
("in", Token::In),
("is", Token::Is),
("isnt", Token::Isnt),
("loop", Token::Loop),
("match", Token::Match),
("module", Token::Module),
("not", Token::Not),
("or", Token::Or),
("owned", Token::Owned),
("return", Token::Return),
("ref", Token::Ref),
("return", Token::Return),
("shared", Token::Shared),
("then", Token::Then),
("trait", Token::Trait),
("type", Token::Type),
Expand Down Expand Up @@ -590,7 +588,7 @@ impl<'cache, 'contents> Iterator for Lexer<'cache, 'contents> {
// This will overflow if there are mismatched parenthesis,
// should we handle this inside the lexer,
// or leave that to the parsing stage?
self.open_braces.parenthesis -= 1;
self.open_braces.parenthesis = self.open_braces.parenthesis.saturating_sub(1);
self.advance_with(Token::ParenthesisRight)
},
('+', _) => self.advance_with(Token::Add),
Expand All @@ -599,7 +597,7 @@ impl<'cache, 'contents> Iterator for Lexer<'cache, 'contents> {
self.advance_with(Token::BracketLeft)
},
(']', _) => {
self.open_braces.square -= 1;
self.open_braces.square = self.open_braces.square.saturating_sub(1);
self.advance_with(Token::BracketRight)
},
('|', _) => self.advance_with(Token::Pipe),
Expand Down
22 changes: 7 additions & 15 deletions src/lexer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,35 +85,32 @@ pub enum Token {
PointerType,
BooleanType,
UnitType,
Ref,
Mut,

// Keywords
And,
As,
Block,
Break,
Continue,
Do,
Effect,
Else,
Extern,
For,
Fn,
Given,
Handle,
If,
Impl,
Import,
In,
Is,
Isnt,
Loop,
Match,
Module,
Not,
Or,
Owned,
Ref,
Return,
Shared,
Then,
Trait,
Type,
Expand Down Expand Up @@ -166,8 +163,6 @@ impl Token {
And | As
| At
| In
| Is
| Isnt
| Not
| Or
| EqualEqual
Expand All @@ -186,7 +181,7 @@ impl Token {
| LessThanOrEqual
| GreaterThanOrEqual
| Divide
| Ampersand
| Range
)
}
}
Expand Down Expand Up @@ -271,35 +266,32 @@ impl Display for Token {
Token::PointerType => write!(f, "'Ptr'"),
Token::BooleanType => write!(f, "'bool'"),
Token::UnitType => write!(f, "'unit'"),
Token::Ref => write!(f, "'ref'"),
Token::Mut => write!(f, "'mut'"),

// Keywords
Token::And => write!(f, "'and'"),
Token::As => write!(f, "'as'"),
Token::Block => write!(f, "'block'"),
Token::Break => write!(f, "'break'"),
Token::Continue => write!(f, "'continue'"),
Token::Do => write!(f, "'do'"),
Token::Effect => write!(f, "'effect'"),
Token::Else => write!(f, "'else'"),
Token::Extern => write!(f, "'extern'"),
Token::For => write!(f, "'for'"),
Token::Fn => write!(f, "'fn'"),
Token::Given => write!(f, "'given'"),
Token::Handle => write!(f, "'handle'"),
Token::If => write!(f, "'if'"),
Token::Impl => write!(f, "'impl'"),
Token::Import => write!(f, "'import'"),
Token::In => write!(f, "'in'"),
Token::Is => write!(f, "'is'"),
Token::Isnt => write!(f, "'isnt'"),
Token::Loop => write!(f, "'loop'"),
Token::Match => write!(f, "'match'"),
Token::Module => write!(f, "'module'"),
Token::Not => write!(f, "'not'"),
Token::Or => write!(f, "'or'"),
Token::Owned => write!(f, "'owned'"),
Token::Return => write!(f, "'return'"),
Token::Ref => write!(f, "'ref'"),
Token::Shared => write!(f, "'shared'"),
Token::Then => write!(f, "'then'"),
Token::Trait => write!(f, "'trait'"),
Token::Type => write!(f, "'type'"),
Expand Down
6 changes: 3 additions & 3 deletions src/nameresolution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ impl<'c> NameResolver {
Type::TypeVariable(_) => 0,
Type::UserDefined(id) => cache[*id].args.len(),
Type::TypeApplication(_, _) => 0,
Type::Ref(_) => 1,
Type::Ref(..) => 1,
Type::Struct(_, _) => 0,
Type::Effects(_) => 0,
}
Expand Down Expand Up @@ -739,14 +739,14 @@ impl<'c> NameResolver {

Type::TypeApplication(Box::new(pair), args)
},
ast::Type::Reference(_) => {
ast::Type::Reference(sharednes, mutability, _) => {
// When translating ref types, all have a hidden lifetime variable that is unified
// under the hood by the compiler to determine the reference's stack lifetime.
// This is never able to be manually specified by the programmer, so we use
// next_type_variable_id on the cache rather than the NameResolver's version which
// would add a name into scope.
let lifetime_variable = cache.next_type_variable_id(self.let_binding_level);
Type::Ref(lifetime_variable)
Type::Ref(*sharednes, *mutability, lifetime_variable)
},
}
}
Expand Down
Loading

0 comments on commit c6d1681

Please sign in to comment.