Skip to content

Commit

Permalink
Merge pull request #7254 from roc-lang/allow-suffixed-host-exposed-pure
Browse files Browse the repository at this point in the history
  • Loading branch information
agu-z authored Nov 28, 2024
2 parents b178b41 + 2e7e670 commit c4fcd0d
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 45 deletions.
7 changes: 7 additions & 0 deletions crates/compiler/can/src/constraint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,13 @@ impl FxSuffixKind {
Self::UnsuffixedRecordField => IdentSuffix::None,
}
}

pub fn symbol(&self) -> Option<&Symbol> {
match self {
Self::Let(symbol) | Self::Pattern(symbol) => Some(symbol),
Self::UnsuffixedRecordField => None,
}
}
}

#[derive(Debug, Clone, Copy, PartialEq)]
Expand Down
5 changes: 3 additions & 2 deletions crates/compiler/load/tests/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ pub fn infer_expr(
exposed_by_module: &Default::default(),
derived_module,
function_kind: FunctionKind::LambdaSet,
#[cfg(debug_assertions)]
checkmate: None,
module_params: None,
module_params_vars: Default::default(),
host_exposed_symbols: None,
#[cfg(debug_assertions)]
checkmate: None,
};

let RunSolveOutput { solved, .. } =
Expand Down
45 changes: 6 additions & 39 deletions crates/compiler/load/tests/test_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14812,7 +14812,7 @@ All branches in an `if` must have the same type!
Str.trim msg
"#
),
@r###"
@r#"
── EFFECT IN PURE FUNCTION in /code/proj/Main.roc ──────────────────────────────
This call to `Effect.putLine!` might produce an effect:
Expand All @@ -14829,18 +14829,7 @@ All branches in an `if` must have the same type!
You can still run the program with this error, which can be helpful
when you're debugging.
── UNNECESSARY EXCLAMATION in /code/proj/Main.roc ──────────────────────────────
This function is pure, but its name suggests otherwise:
5│ main! = \{} ->
^^^^^
The exclamation mark at the end is reserved for effectful functions.
Hint: Did you forget to run an effect? Is the type annotation wrong?
"###
"#
);

test_report!(
Expand Down Expand Up @@ -15423,7 +15412,7 @@ All branches in an `if` must have the same type!
pureHigherOrder = \f, x -> f x
"#
),
@r###"
@r#"
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────
This 1st argument to `pureHigherOrder` has an unexpected type:
Expand All @@ -15438,18 +15427,7 @@ All branches in an `if` must have the same type!
But `pureHigherOrder` needs its 1st argument to be:
Str -> {}
── UNNECESSARY EXCLAMATION in /code/proj/Main.roc ──────────────────────────────
This function is pure, but its name suggests otherwise:
5│ main! = \{} ->
^^^^^
The exclamation mark at the end is reserved for effectful functions.
Hint: Did you forget to run an effect? Is the type annotation wrong?
"###
"#
);

test_report!(
Expand All @@ -15467,7 +15445,7 @@ All branches in an `if` must have the same type!
pureHigherOrder = \f, x -> f x
"#
),
@r###"
@r#"
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────
This 1st argument to `pureHigherOrder` has an unexpected type:
Expand All @@ -15482,17 +15460,6 @@ All branches in an `if` must have the same type!
But `pureHigherOrder` needs its 1st argument to be:
Str -> {}
── UNNECESSARY EXCLAMATION in /code/proj/Main.roc ──────────────────────────────
This function is pure, but its name suggests otherwise:
5│ main! = \{} ->
^^^^^
The exclamation mark at the end is reserved for effectful functions.
Hint: Did you forget to run an effect? Is the type annotation wrong?
"###
"#
);
}
19 changes: 19 additions & 0 deletions crates/compiler/load_internal/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,8 @@ fn start_phase<'a>(
None
};

let is_host_exposed = state.root_id == module.module_id;

BuildTask::solve_module(
module,
ident_ids,
Expand All @@ -367,6 +369,7 @@ fn start_phase<'a>(
state.cached_types.clone(),
derived_module,
state.exec_mode,
is_host_exposed,
//
#[cfg(debug_assertions)]
checkmate,
Expand Down Expand Up @@ -922,6 +925,7 @@ enum BuildTask<'a> {
cached_subs: CachedTypeState,
derived_module: SharedDerivedModule,
exec_mode: ExecutionMode,
is_host_exposed: bool,

#[cfg(debug_assertions)]
checkmate: Option<roc_checkmate::Collector>,
Expand Down Expand Up @@ -4331,6 +4335,7 @@ impl<'a> BuildTask<'a> {
cached_subs: CachedTypeState,
derived_module: SharedDerivedModule,
exec_mode: ExecutionMode,
is_host_exposed: bool,

#[cfg(debug_assertions)] checkmate: Option<roc_checkmate::Collector>,
) -> Self {
Expand All @@ -4355,6 +4360,7 @@ impl<'a> BuildTask<'a> {
cached_subs,
derived_module,
exec_mode,
is_host_exposed,

#[cfg(debug_assertions)]
checkmate,
Expand Down Expand Up @@ -4661,6 +4667,7 @@ fn run_solve_solve(
var_store: VarStore,
module: Module,
derived_module: SharedDerivedModule,
is_host_exposed: bool,

#[cfg(debug_assertions)] checkmate: Option<roc_checkmate::Collector>,
) -> SolveResult {
Expand Down Expand Up @@ -4711,6 +4718,12 @@ fn run_solve_solve(
let (solve_output, solved_implementations, exposed_vars_by_symbol) = {
let module_id = module.module_id;

let host_exposed_idents = if is_host_exposed {
Some(&exposed_symbols)
} else {
None
};

let solve_config = SolveConfig {
home: module_id,
types,
Expand All @@ -4724,6 +4737,7 @@ fn run_solve_solve(
checkmate,
module_params,
module_params_vars: imported_param_vars,
host_exposed_symbols: host_exposed_idents,
};

let solve_output = roc_solve::module::run_solve(
Expand Down Expand Up @@ -4800,6 +4814,7 @@ fn run_solve<'a>(
cached_types: CachedTypeState,
derived_module: SharedDerivedModule,
exec_mode: ExecutionMode,
is_host_exposed: bool,

#[cfg(debug_assertions)] checkmate: Option<roc_checkmate::Collector>,
) -> Msg<'a> {
Expand Down Expand Up @@ -4831,6 +4846,7 @@ fn run_solve<'a>(
var_store,
module,
derived_module,
is_host_exposed,
//
#[cfg(debug_assertions)]
checkmate,
Expand Down Expand Up @@ -4863,6 +4879,7 @@ fn run_solve<'a>(
var_store,
module,
derived_module,
is_host_exposed,
//
#[cfg(debug_assertions)]
checkmate,
Expand Down Expand Up @@ -6256,6 +6273,7 @@ fn run_task<'a>(
cached_subs,
derived_module,
exec_mode,
is_host_exposed,

#[cfg(debug_assertions)]
checkmate,
Expand All @@ -6275,6 +6293,7 @@ fn run_task<'a>(
cached_subs,
derived_module,
exec_mode,
is_host_exposed,
//
#[cfg(debug_assertions)]
checkmate,
Expand Down
4 changes: 3 additions & 1 deletion crates/compiler/solve/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use roc_can::constraint::{Constraint, Constraints};
use roc_can::expr::PendingDerives;
use roc_can::module::{ExposedByModule, ModuleParams, ResolvedImplementations, RigidVariables};
use roc_collections::all::MutMap;
use roc_collections::VecMap;
use roc_collections::{VecMap, VecSet};
use roc_derive::SharedDerivedModule;
use roc_error_macros::internal_error;
use roc_module::symbol::{ModuleId, Symbol};
Expand Down Expand Up @@ -76,6 +76,8 @@ pub struct SolveConfig<'a> {
/// Needed during solving to resolve lambda sets from derived implementations that escape into
/// the user module.
pub derived_module: SharedDerivedModule,
/// Symbols that are exposed to the host which might need special treatment.
pub host_exposed_symbols: Option<&'a VecSet<Symbol>>,

#[cfg(debug_assertions)]
/// The checkmate collector for this module.
Expand Down
20 changes: 17 additions & 3 deletions crates/compiler/solve/src/solve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use roc_can::constraint::{
};
use roc_can::expected::{Expected, PExpected};
use roc_can::module::ModuleParams;
use roc_collections::VecMap;
use roc_collections::{VecMap, VecSet};
use roc_debug_flags::dbg_do;
#[cfg(debug_assertions)]
use roc_debug_flags::ROC_VERIFY_RIGID_LET_GENERALIZED;
Expand Down Expand Up @@ -136,6 +136,7 @@ fn run_help(
function_kind,
module_params,
module_params_vars,
host_exposed_symbols,
..
} = config;

Expand Down Expand Up @@ -190,6 +191,7 @@ fn run_help(
&mut awaiting_specializations,
module_params,
module_params_vars,
host_exposed_symbols,
);

RunSolveOutput {
Expand Down Expand Up @@ -249,6 +251,7 @@ fn solve(
awaiting_specializations: &mut AwaitingSpecializations,
module_params: Option<ModuleParams>,
module_params_vars: VecMap<ModuleId, Variable>,
host_exposed_symbols: Option<&VecSet<Symbol>>,
) -> State {
let scope = Scope::new(module_params);

Expand Down Expand Up @@ -455,6 +458,7 @@ fn solve(
solve_suffix_fx(
env,
problems,
host_exposed_symbols,
FxSuffixKind::Let(*symbol),
loc_var.value,
&loc_var.region,
Expand Down Expand Up @@ -853,7 +857,7 @@ fn solve(
*type_index,
);

solve_suffix_fx(env, problems, *kind, actual, region);
solve_suffix_fx(env, problems, host_exposed_symbols, *kind, actual, region);
state
}
ExpectEffectful(variable, reason, region) => {
Expand Down Expand Up @@ -1625,6 +1629,7 @@ fn solve(
fn solve_suffix_fx(
env: &mut InferenceEnv<'_>,
problems: &mut Vec<TypeError>,
host_exposed_symbols: Option<&VecSet<Symbol>>,
kind: FxSuffixKind,
variable: Variable,
region: &Region,
Expand All @@ -1651,7 +1656,16 @@ fn solve_suffix_fx(
let fx = *fx;
match env.subs.get_content_without_compacting(fx) {
Content::Pure => {
problems.push(TypeError::SuffixedPureFunction(*region, kind));
match (kind.symbol(), host_exposed_symbols) {
(Some(sym), Some(host_exposed)) if host_exposed.contains(sym) => {
// If exposed to the platform, it's allowed to be suffixed but pure
// The platform might require a `main!` function that could perform
// effects, but that's not a requirement.
}
_ => {
problems.push(TypeError::SuffixedPureFunction(*region, kind));
}
}
}
Content::FlexVar(_) => {
env.subs.set_content(fx, Content::Effectful);
Expand Down
1 change: 1 addition & 0 deletions crates/compiler/test_derive/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ fn check_derived_typechecks_and_golden(
derived_module: Default::default(),
module_params: None,
module_params_vars: imported_param_vars,
host_exposed_symbols: None,

#[cfg(debug_assertions)]
checkmate: None,
Expand Down
1 change: 1 addition & 0 deletions crates/test_compile/src/help_solve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ impl SolvedExpr {
derived_module: SharedDerivedModule::default(),
module_params: None,
module_params_vars: VecMap::default(),
host_exposed_symbols: None,
#[cfg(debug_assertions)]
checkmate: None,
};
Expand Down

0 comments on commit c4fcd0d

Please sign in to comment.