Skip to content

Commit

Permalink
Reintroduce futures using Future and Promise
Browse files Browse the repository at this point in the history
This commit reintroduces futures, allowing messages to send their
results back to the sender of the message, without the need for a
channel. Futures are split into two user facing types: Future and
Promise. A Future is a proxy for a value to be computed in the future,
while a Promise is used for specifying what that value is. Both a Future
and Promise can only be used once (e.g. Future.get consumes its
receiver). This in turn allows for a simple and efficient
implementation, rather than the more complex implementation of the old
Channel type.

TODO: add deque
TODO: replace channels

Changelog: changed
  • Loading branch information
yorickpeterse committed Sep 17, 2024
1 parent e0feaae commit 442ecab
Show file tree
Hide file tree
Showing 20 changed files with 1,123 additions and 379 deletions.
4 changes: 2 additions & 2 deletions compiler/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,14 +444,14 @@ impl Diagnostics {
);
}

pub(crate) fn builtin_function_not_available(
pub(crate) fn intrinsic_not_available(
&mut self,
file: PathBuf,
location: SourceLocation,
) {
self.error(
DiagnosticId::InvalidCall,
"builtin functions can only be used in the standard library",
"intrinsics can only be used in the standard library",
file,
location,
);
Expand Down
43 changes: 40 additions & 3 deletions compiler/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,14 @@ pub(crate) struct Call {
/// `Option<Vec<Argument>>` since we don't care about the presence (or lack)
/// of parentheses 99% of the time.
pub(crate) parens: bool,
/// A flag indicating if the call resides directly in a `mut` expression.
pub(crate) in_mut: bool,
pub(crate) location: SourceLocation,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct BuiltinCall {
pub(crate) info: Option<types::BuiltinCallInfo>,
pub(crate) info: Option<types::IntrinsicCall>,
pub(crate) name: Identifier,
pub(crate) arguments: Vec<Expression>,
pub(crate) location: SourceLocation,
Expand Down Expand Up @@ -859,6 +861,7 @@ pub(crate) struct FieldRef {
pub(crate) name: String,
pub(crate) resolved_type: types::TypeRef,
pub(crate) location: SourceLocation,
pub(crate) in_mut: bool,
}

#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -2065,6 +2068,7 @@ impl<'a> LowerToHir<'a> {
location: loc.clone(),
},
parens: false,
in_mut: false,
arguments: Vec::new(),
location: loc,
}));
Expand Down Expand Up @@ -2131,6 +2135,7 @@ impl<'a> LowerToHir<'a> {
location: node.location.clone(),
},
parens: true,
in_mut: false,
arguments: vec![Argument::Positional(Box::new(
PositionalArgument {
value: Expression::Int(Box::new(IntLiteral {
Expand Down Expand Up @@ -2165,6 +2170,7 @@ impl<'a> LowerToHir<'a> {
location: node.location.clone(),
},
parens: true,
in_mut: false,
arguments: vec![Argument::Positional(Box::new(
PositionalArgument {
value: arg,
Expand Down Expand Up @@ -2405,6 +2411,7 @@ impl<'a> LowerToHir<'a> {
location: node.operator.location,
},
parens: true,
in_mut: false,
arguments: vec![Argument::Positional(Box::new(
PositionalArgument {
value: self.expression(node.right),
Expand All @@ -2420,6 +2427,7 @@ impl<'a> LowerToHir<'a> {
field_id: None,
name: node.name,
resolved_type: types::TypeRef::Unknown,
in_mut: false,
location: node.location,
})
}
Expand All @@ -2445,7 +2453,7 @@ impl<'a> LowerToHir<'a> {
fn call(&mut self, node: ast::Call) -> Expression {
if self.is_builtin_call(&node) {
if !self.module.is_std(&self.state.db) {
self.state.diagnostics.builtin_function_not_available(
self.state.diagnostics.intrinsic_not_available(
self.file(),
node.location.clone(),
);
Expand All @@ -2471,6 +2479,7 @@ impl<'a> LowerToHir<'a> {
receiver: node.receiver.map(|n| self.expression(n)),
name: self.identifier(node.name),
parens: node.arguments.is_some(),
in_mut: false,
arguments: self.optional_call_arguments(node.arguments),
location: node.location,
}))
Expand Down Expand Up @@ -2641,6 +2650,7 @@ impl<'a> LowerToHir<'a> {
},
receiver: Some(receiver),
parens: true,
in_mut: false,
arguments: vec![Argument::Positional(Box::new(
PositionalArgument {
value: self.expression(node.value),
Expand All @@ -2664,6 +2674,7 @@ impl<'a> LowerToHir<'a> {
field_id: None,
name: field.name.clone(),
resolved_type: types::TypeRef::Unknown,
in_mut: false,
location: field.location.clone(),
}));

Expand All @@ -2678,6 +2689,7 @@ impl<'a> LowerToHir<'a> {
},
receiver: Some(receiver),
parens: true,
in_mut: false,
arguments: vec![Argument::Positional(Box::new(
PositionalArgument {
value: self.expression(node.value),
Expand Down Expand Up @@ -2730,6 +2742,7 @@ impl<'a> LowerToHir<'a> {
receiver: Some(setter_rec.clone()),
name: name.clone(),
parens: false,
in_mut: false,
arguments: Vec::new(),
location: getter_loc,
}));
Expand All @@ -2742,6 +2755,7 @@ impl<'a> LowerToHir<'a> {
kind: types::CallKind::Unknown,
receiver: Some(getter_rec),
parens: true,
in_mut: false,
arguments: vec![Argument::Positional(Box::new(
PositionalArgument {
value: self.expression(node.value),
Expand Down Expand Up @@ -2855,10 +2869,18 @@ impl<'a> LowerToHir<'a> {
}

fn mut_reference(&mut self, node: ast::Mut) -> Box<Mut> {
let mut value = self.expression(node.value);

match &mut value {
Expression::Call(n) => n.in_mut = true,
Expression::FieldRef(n) => n.in_mut = true,
_ => {}
}

Box::new(Mut {
pointer_to_method: None,
resolved_type: types::TypeRef::Unknown,
value: self.expression(node.value),
value,
location: node.location,
})
}
Expand Down Expand Up @@ -5172,6 +5194,7 @@ mod tests {
location: cols(12, 13)
},
parens: false,
in_mut: false,
arguments: Vec::new(),
location: cols(12, 13)
})),
Expand Down Expand Up @@ -5220,6 +5243,7 @@ mod tests {
location: cols(8, 11),
},
parens: true,
in_mut: false,
arguments: vec![Argument::Positional(Box::new(
PositionalArgument {
value: Expression::Int(Box::new(
Expand Down Expand Up @@ -5251,6 +5275,7 @@ mod tests {
location: cols(8, 11),
},
parens: true,
in_mut: false,
arguments: vec![Argument::Positional(Box::new(
PositionalArgument {
value: Expression::Int(Box::new(IntLiteral {
Expand Down Expand Up @@ -5308,6 +5333,7 @@ mod tests {
location: cols(8, 8)
}))),
parens: true,
in_mut: false,
arguments: vec![Argument::Positional(Box::new(
PositionalArgument {
value: Expression::Int(Box::new(IntLiteral {
Expand Down Expand Up @@ -5337,6 +5363,7 @@ mod tests {
field_id: None,
name: "a".to_string(),
resolved_type: types::TypeRef::Unknown,
in_mut: false,
location: cols(8, 9)
}))
);
Expand Down Expand Up @@ -5378,6 +5405,7 @@ mod tests {
location: cols(10, 10)
},
parens: false,
in_mut: false,
arguments: Vec::new(),
location: cols(8, 10)
}))
Expand Down Expand Up @@ -5412,6 +5440,7 @@ mod tests {
location: cols(8, 8)
},
parens: true,
in_mut: false,
arguments: vec![Argument::Positional(Box::new(
PositionalArgument {
value: Expression::Int(Box::new(IntLiteral {
Expand Down Expand Up @@ -5441,6 +5470,7 @@ mod tests {
location: cols(8, 8)
},
parens: true,
in_mut: false,
arguments: vec![Argument::Named(Box::new(NamedArgument {
index: 0,
name: Identifier {
Expand Down Expand Up @@ -5480,6 +5510,7 @@ mod tests {
location: cols(10, 10)
},
parens: false,
in_mut: false,
arguments: Vec::new(),
location: cols(8, 10)
}))
Expand Down Expand Up @@ -5655,6 +5686,7 @@ mod tests {
}
))),
parens: true,
in_mut: false,
arguments: vec![Argument::Positional(Box::new(
PositionalArgument {
value: Expression::Int(Box::new(IntLiteral {
Expand Down Expand Up @@ -5738,10 +5770,12 @@ mod tests {
location: cols(10, 10)
},
parens: false,
in_mut: false,
arguments: Vec::new(),
location: cols(8, 10)
}))),
parens: true,
in_mut: false,
arguments: vec![Argument::Positional(Box::new(
PositionalArgument {
value: Expression::Int(Box::new(IntLiteral {
Expand Down Expand Up @@ -5779,9 +5813,11 @@ mod tests {
field_id: None,
name: "a".to_string(),
resolved_type: types::TypeRef::Unknown,
in_mut: false,
location: cols(8, 9)
}))),
parens: true,
in_mut: false,
arguments: vec![Argument::Positional(Box::new(
PositionalArgument {
value: Expression::Int(Box::new(IntLiteral {
Expand Down Expand Up @@ -6167,6 +6203,7 @@ mod tests {
location: cols(12, 12)
},
parens: true,
in_mut: false,
arguments: Vec::new(),
location: cols(12, 14)
})),
Expand Down
42 changes: 30 additions & 12 deletions compiler/src/llvm/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,16 @@ impl<'ctx> Builder<'ctx> {
.into_float_value()
}

pub(crate) fn load_bool(
&self,
variable: PointerValue<'ctx>,
) -> IntValue<'ctx> {
self.inner
.build_load(self.context.bool_type(), variable, "")
.unwrap()
.into_int_value()
}

pub(crate) fn load_pointer(
&self,
variable: PointerValue<'ctx>,
Expand Down Expand Up @@ -299,6 +309,26 @@ impl<'ctx> Builder<'ctx> {
.unwrap()
}

pub(crate) fn atomic_swap<V: BasicValue<'ctx>>(
&self,
pointer: PointerValue<'ctx>,
old: V,
new: V,
) -> IntValue<'ctx> {
let res = self
.inner
.build_cmpxchg(
pointer,
old,
new,
AtomicOrdering::AcquireRelease,
AtomicOrdering::Acquire,
)
.unwrap();

self.extract_field(res, 1).into_int_value()
}

pub(crate) fn load_atomic_counter(
&self,
variable: PointerValue<'ctx>,
Expand Down Expand Up @@ -484,18 +514,6 @@ impl<'ctx> Builder<'ctx> {
self.inner.build_int_cast_sign_flag(value, target, signed, "").unwrap()
}

pub(crate) fn bool_to_int(&self, value: IntValue<'ctx>) -> IntValue<'ctx> {
let typ = self.context.i64_type();

self.inner.build_int_cast_sign_flag(value, typ, false, "").unwrap()
}

pub(crate) fn int_to_bool(&self, value: IntValue<'ctx>) -> IntValue<'ctx> {
let typ = self.context.bool_type();

self.inner.build_int_cast_sign_flag(value, typ, true, "").unwrap()
}

pub(crate) fn float_to_float(
&self,
value: FloatValue<'ctx>,
Expand Down
17 changes: 8 additions & 9 deletions compiler/src/llvm/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,15 @@ impl Context {
layouts: &Layouts<'a>,
type_ref: TypeRef,
) -> BasicTypeEnum<'a> {
if let TypeRef::Pointer(_) = type_ref {
return self.pointer_type().as_basic_type_enum();
}

let Ok(id) = type_ref.type_id(db) else {
return self.pointer_type().as_basic_type_enum();
};

let base = match id {
match id {
TypeId::Foreign(ForeignType::Int(8, _)) => {
self.i8_type().as_basic_type_enum()
}
Expand All @@ -186,21 +190,16 @@ impl Context {
.as_basic_type_enum()
} else {
match cls.0 {
INT_ID | BOOL_ID | NIL_ID => {
self.i64_type().as_basic_type_enum()
BOOL_ID | NIL_ID => {
self.bool_type().as_basic_type_enum()
}
INT_ID => self.i64_type().as_basic_type_enum(),
FLOAT_ID => self.f64_type().as_basic_type_enum(),
_ => self.pointer_type().as_basic_type_enum(),
}
}
}
_ => self.pointer_type().as_basic_type_enum(),
};

if let TypeRef::Pointer(_) = type_ref {
self.pointer_type().as_basic_type_enum()
} else {
base
}
}

Expand Down
8 changes: 1 addition & 7 deletions compiler/src/llvm/layouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,7 @@ impl<'ctx> Layouts<'ctx> {
// defined.
for &id in mir.classes.keys() {
let instance = match id.0 {
INT_ID => {
context.builtin_type(header, context.i64_type().into())
}
FLOAT_ID => {
context.builtin_type(header, context.f64_type().into())
}
BOOL_ID | NIL_ID => {
INT_ID | FLOAT_ID | BOOL_ID | NIL_ID => {
let typ = context.opaque_struct("");

typ.set_body(&[header.into()], false);
Expand Down
Loading

0 comments on commit 442ecab

Please sign in to comment.