Skip to content

Commit

Permalink
Merge #148
Browse files Browse the repository at this point in the history
148: Modal harmony r=nikomatsakis a=nikomatsakis

This branch implements #143. It's not quite where I want it to be yet, but close enough I figured I'd open it up so that there's a preview + playground etc.

Here is a list of things I have done and have yet to do (will update as I go, this is off the top of my head):

* [x] Add specifiers `my`, `our`, etc
* [x] Change leasing an `our` value to yield another `our` value, instead of `our leased` (preserves all invariants, more convenient overall)
* [x] Check that values assigned to a `my` etc location meet the requirements
* [x] Change the default specifier from `any` to `our leased`
* [x] Ensure that when unique things are stored in shared locations, they are shared ([example where it goes wrong today](https://deploy-preview-148--dada-lang.netlify.app/playground/?code=class+Point%28x%2C+y%29%0A%0Aasync+fn+main%28%29+%7B%0A++++our+s+%3D+%22foo%22%0A++++our+t+%3D+foo%28s%29%0A++++p+%3D+Point%28s%2C+t%29%0A++++q+%3D+p%0A++++print%28p%29.await%0A%7D%0A%0Afn+foo%28our+s%29+%7B%0A++++s%0A%7D%0A))

Co-authored-by: Niko Matsakis <[email protected]>
  • Loading branch information
bors[bot] and nikomatsakis authored Apr 19, 2022
2 parents e8845dd + 44adcbd commit f572cbe
Show file tree
Hide file tree
Showing 304 changed files with 9,190 additions and 1,705 deletions.
100 changes: 84 additions & 16 deletions components/dada-brew/src/brew.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use dada_ir::{
bir::{self, BirData},
validated::{self, ExprOrigin},
},
storage_mode::Atomic,
storage::Atomic,
};
use salsa::DebugWithDb;

Expand Down Expand Up @@ -85,7 +85,7 @@ impl Cursor {
validated::ExprData::Continue(from_expr) => {
self.push_breakpoint_start(brewery, origin);
let loop_context = brewery.loop_context(*from_expr);
self.push_breakpoint_end(brewery, None, origin);
self.push_breakpoint_end(brewery, None::<bir::Place>, origin);
self.terminate_and_goto(brewery, loop_context.continue_block, origin);
}

Expand All @@ -103,22 +103,49 @@ impl Cursor {

validated::ExprData::Error => {
self.push_breakpoint_start(brewery, origin);
self.push_breakpoint_end(brewery, None, origin);
self.push_breakpoint_end(brewery, None::<bir::Place>, origin);
self.terminate_and_diverge(brewery, bir::TerminatorData::Error, origin)
}

validated::ExprData::Assign(place, value_expr) => {
validated::ExprData::AssignTemporary(place, value_expr) => {
// temporaries are always created with "any" specifier, which ensures
// that we will never have to apply specifier to `value_expr`
assert_eq!(brewery.validated_tables()[*place].specifier, None);

// we only ever use this for temporaries, user-created values use `AssignFromPlace`
assert!(matches!(
brewery.origin(*place),
validated::LocalVariableOrigin::Temporary(_)
));

self.push_breakpoint_start(brewery, origin);
let (place, origins) = self.brew_place(brewery, *place);
let place = self.brew_target_variable(brewery, *place, origin);
self.brew_expr_and_assign_to(brewery, place, *value_expr);
self.push_breakpoint_ends(brewery, None, origins, origin)
self.push_breakpoint_end(brewery, None::<bir::Place>, origin)
}

validated::ExprData::AssignFromPlace(target_place, source_place) => {
let (target_place, target_origins) = self.brew_target_place(brewery, *target_place);
let (source_place, source_origins) = self.brew_place(brewery, *source_place);
self.push_breakpoint_starts(
brewery,
target_origins.iter().chain(source_origins.iter()).copied(),
origin,
);
self.push_assignment_from_place(brewery, target_place, source_place, origin);
self.push_breakpoint_ends(
brewery,
None::<bir::Place>,
target_origins.into_iter().chain(source_origins),
origin,
)
}

validated::ExprData::Declare(vars, subexpr) => {
self.push_breakpoint_start(brewery, origin);
self.brew_expr_for_side_effects(brewery, *subexpr);
self.pop_declared_variables(brewery, vars, origin);
self.push_breakpoint_end(brewery, None, origin);
self.push_breakpoint_end(brewery, None::<bir::Place>, origin);
}

validated::ExprData::Await(_)
Expand All @@ -134,6 +161,7 @@ impl Cursor {
| validated::ExprData::FloatLiteral(_)
| validated::ExprData::StringLiteral(_)
| validated::ExprData::Call(_, _)
| validated::ExprData::Reserve(_)
| validated::ExprData::Share(_)
| validated::ExprData::Lease(_)
| validated::ExprData::Give(_)
Expand All @@ -145,6 +173,8 @@ impl Cursor {
self.pop_temporary_scope(brewery, temporary_scope);
}

/// Compiles expr into a temporary `t` and returns `Some(t)`.
/// Returns `None` if this is dead code.
pub(crate) fn brew_expr_to_temporary(
&mut self,
brewery: &mut Brewery<'_>,
Expand All @@ -154,7 +184,7 @@ impl Cursor {
// Spill into a temporary
let temp_place = add_temporary_place(brewery, origin);
self.brew_expr_and_assign_to(brewery, temp_place, expr);
Some(temp_place)
Some(brewery.place_from_target_place(temp_place))
}

/// Compiles an expression down to the value it produces.
Expand All @@ -164,7 +194,7 @@ impl Cursor {
pub(crate) fn brew_expr_and_assign_to(
&mut self,
brewery: &mut Brewery<'_>,
target: bir::Place,
target: bir::TargetPlace,
expr: validated::Expr,
) {
let origin = brewery.origin(expr);
Expand Down Expand Up @@ -238,10 +268,18 @@ impl Cursor {
);
}

validated::ExprData::Share(place) => {
validated::ExprData::Share(operand) => {
if let Some(temp) = self.brew_expr_to_temporary(brewery, *operand) {
self.push_breakpoint_start(brewery, origin);
self.push_assignment(brewery, target, bir::ExprData::Share(temp), origin);
self.push_breakpoint_end(brewery, Some(target), origin);
}
}

validated::ExprData::Reserve(place) => {
let (place, origins) = self.brew_place(brewery, *place);
self.push_breakpoint_starts(brewery, origins.iter().copied(), origin);
self.push_assignment(brewery, target, bir::ExprData::GiveShare(place), origin);
self.push_assignment(brewery, target, bir::ExprData::Reserve(place), origin);
self.push_breakpoint_ends(brewery, Some(target), origins, origin);
}

Expand Down Expand Up @@ -375,8 +413,7 @@ impl Cursor {
}
}

validated::ExprData::Assign(_, _) => {
self.push_breakpoint_start(brewery, origin);
validated::ExprData::AssignTemporary(..) | validated::ExprData::AssignFromPlace(..) => {
self.brew_expr_for_side_effects(brewery, expr);
self.push_assignment(brewery, target, bir::ExprData::Unit, origin);
}
Expand Down Expand Up @@ -429,7 +466,7 @@ impl Cursor {
self.push_breakpoint_start(brewery, origin);
self.brew_expr_and_assign_to(brewery, target, *subexpr);
self.pop_declared_variables(brewery, vars, origin);
self.push_breakpoint_end(brewery, None, origin);
self.push_breakpoint_end(brewery, None::<bir::Place>, origin);
}

validated::ExprData::Error
Expand Down Expand Up @@ -485,21 +522,52 @@ impl Cursor {
}
}
}

pub(crate) fn brew_target_place(
&mut self,
brewery: &mut Brewery<'_>,
place: validated::TargetPlace,
) -> (bir::TargetPlace, Vec<ExprOrigin>) {
let origin = brewery.origin(place);
match brewery.validated_tables()[place] {
validated::TargetPlaceData::LocalVariable(validated_var) => {
let place = self.brew_target_variable(brewery, validated_var, origin);
(place, vec![origin])
}
validated::TargetPlaceData::Dot(base, field) => {
let (base, mut origins) = self.brew_place(brewery, base);
let place = brewery.add(bir::TargetPlaceData::Dot(base, field), origin);
origins.push(origin);
(place, origins)
}
}
}
pub(crate) fn brew_target_variable(
&mut self,
brewery: &mut Brewery<'_>,
validated_var: validated::LocalVariable,
origin: ExprOrigin,
) -> bir::TargetPlace {
let bir_var = brewery.variable(validated_var);
brewery.add(bir::TargetPlaceData::LocalVariable(bir_var), origin)
}
}

fn add_temporary(brewery: &mut Brewery, origin: ExprOrigin) -> bir::LocalVariable {
let temporary = brewery.add(
bir::LocalVariableData {
name: None,
specifier: None,
atomic: Atomic::No,
},
validated::LocalVariableOrigin::Temporary(origin.into()),
);
tracing::debug!("created temporary: temp{{{:?}}}", u32::from(temporary));
brewery.push_temporary(temporary);
temporary
}

fn add_temporary_place(brewery: &mut Brewery, origin: ExprOrigin) -> bir::Place {
fn add_temporary_place(brewery: &mut Brewery, origin: ExprOrigin) -> bir::TargetPlace {
let temporary_var = add_temporary(brewery, origin);
brewery.add(bir::PlaceData::LocalVariable(temporary_var), origin)
brewery.add(bir::TargetPlaceData::LocalVariable(temporary_var), origin)
}
18 changes: 16 additions & 2 deletions components/dada-brew/src/brewery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use dada_ir::{
pub struct Brewery<'me> {
db: &'me dyn crate::Db,
code: Code,
breakpoints: &'me [syntax::Expr],
pub(crate) breakpoints: &'me [syntax::Expr],
validated_tree_data: &'me validated::TreeData,
validated_origins: &'me validated::Origins,
tables: &'me mut bir::Tables,
Expand Down Expand Up @@ -43,7 +43,7 @@ pub struct Brewery<'me> {
pub struct LoopContext {
pub continue_block: bir::BasicBlock,
pub break_block: bir::BasicBlock,
pub loop_value: bir::Place,
pub loop_value: bir::TargetPlace,
}

impl<'me> Brewery<'me> {
Expand Down Expand Up @@ -154,6 +154,18 @@ impl<'me> Brewery<'me> {
add(self.tables, self.origins, data, origin)
}

/// Converts a target-place into a place.
pub fn place_from_target_place(&mut self, place: bir::TargetPlace) -> bir::Place {
match self.tables[place] {
bir::TargetPlaceData::LocalVariable(lv) => {
self.add(bir::PlaceData::LocalVariable(lv), self.origins[place])
}
bir::TargetPlaceData::Dot(owner_place, name) => {
self.add(bir::PlaceData::Dot(owner_place, name), self.origins[place])
}
}
}

/// Find the loop context for a given loop expression.
///
/// Panics if that loop context has not been pushed.
Expand Down Expand Up @@ -185,6 +197,7 @@ impl<'me> Brewery<'me> {
///
/// See the comments on the `temporaries` field for more information.
pub fn push_temporary(&mut self, lv: bir::LocalVariable) {
tracing::debug!("pushing temporary: {:?}", lv);
self.temporaries.push(lv);
}

Expand Down Expand Up @@ -217,6 +230,7 @@ fn map_variables(
origins,
bir::LocalVariableData {
name: validated_var_data.name,
specifier: validated_var_data.specifier,
atomic: validated_var_data.atomic,
},
validated_var_origin,
Expand Down
44 changes: 40 additions & 4 deletions components/dada-brew/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,26 @@ impl Cursor {
pub(crate) fn push_assignment(
&mut self,
brewery: &mut Brewery<'_>,
target: bir::Place,
target: bir::TargetPlace,
value: bir::ExprData,
origin: ExprOrigin,
) {
if self.end_block.is_some() {
let value = brewery.add(value, origin);
let statement = brewery.add(bir::StatementData::Assign(target, value), origin);
let statement = brewery.add(bir::StatementData::AssignExpr(target, value), origin);
self.push_statement(brewery, statement);
}
}

pub(crate) fn push_assignment_from_place(
&mut self,
brewery: &mut Brewery<'_>,
target: bir::TargetPlace,
source: bir::Place,
origin: ExprOrigin,
) {
if self.end_block.is_some() {
let statement = brewery.add(bir::StatementData::AssignPlace(target, source), origin);
self.push_statement(brewery, statement);
}
}
Expand All @@ -167,6 +180,11 @@ impl Cursor {
/// If `origin` is a breakpoint expression, push a "breakpoint-start"
/// statement onto the current basic block.
pub(crate) fn push_breakpoint_start(&mut self, brewery: &mut Brewery<'_>, origin: ExprOrigin) {
tracing::debug!(
"push_breakpoint_start: origin={:?} breakpoints={:?}",
origin,
brewery.breakpoints
);
if !origin.synthesized && self.end_block.is_some() {
if let Some(breakpoint_index) = brewery.expr_is_breakpoint(origin.syntax_expr) {
let filename = brewery.code().filename(brewery.db());
Expand All @@ -186,10 +204,11 @@ impl Cursor {
pub(crate) fn push_breakpoint_ends(
&mut self,
brewery: &mut Brewery<'_>,
place: Option<bir::Place>,
place: Option<impl AnyPlace>,
origins: impl IntoIterator<Item = ExprOrigin>,
origin: ExprOrigin,
) {
let place = place.map(|p| p.into_place(brewery));
for o in origins.into_iter().chain(Some(origin)) {
self.push_breakpoint_end_with_distinct_origin(brewery, origin.syntax_expr, place, o);
}
Expand All @@ -200,9 +219,10 @@ impl Cursor {
pub(crate) fn push_breakpoint_end(
&mut self,
brewery: &mut Brewery<'_>,
place: Option<bir::Place>,
place: Option<impl AnyPlace>,
origin: ExprOrigin,
) {
let place = place.map(|p| p.into_place(brewery));
self.push_breakpoint_end_with_distinct_origin(brewery, origin.syntax_expr, place, origin);
}

Expand Down Expand Up @@ -245,3 +265,19 @@ impl Cursor {
Some((place, *name))
}
}

pub(crate) trait AnyPlace {
fn into_place(self, brewery: &mut Brewery<'_>) -> bir::Place;
}

impl AnyPlace for bir::Place {
fn into_place(self, _brewery: &mut Brewery<'_>) -> bir::Place {
self
}
}

impl AnyPlace for bir::TargetPlace {
fn into_place(self, brewery: &mut Brewery<'_>) -> bir::Place {
brewery.place_from_target_place(self)
}
}
2 changes: 1 addition & 1 deletion components/dada-db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl Db {
for item in filename.items(self) {
if let Item::Function(function) = item {
let function_name = function.name(self);
if name == function_name {
if name == function_name.word(self) {
return Some(*function);
}
}
Expand Down
Loading

0 comments on commit f572cbe

Please sign in to comment.