mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-24 06:55:15 +00:00
Merge remote-tracking branch 'origin/main' into expect-fx-codegen
This commit is contained in:
commit
a22e04361c
222 changed files with 10039 additions and 1945 deletions
|
@ -29,10 +29,10 @@ roc_debug_flags = { path = "../debug_flags" }
|
|||
ven_pretty = { path = "../../vendor/pretty" }
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
parking_lot = "0.12"
|
||||
crossbeam = "0.8.1"
|
||||
crossbeam = "0.8.2"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.0.0"
|
||||
maplit = "1.0.2"
|
||||
indoc = "1.0.3"
|
||||
indoc = "1.0.7"
|
||||
roc_test_utils = { path = "../../test_utils" }
|
||||
|
|
|
@ -130,13 +130,15 @@ pub enum ExecutionMode {
|
|||
Test,
|
||||
Check,
|
||||
Executable,
|
||||
/// Like [`ExecutionMode::Executable`], but stops in the presence of type errors.
|
||||
ExecutableIfCheck,
|
||||
}
|
||||
|
||||
impl ExecutionMode {
|
||||
fn goal_phase(&self) -> Phase {
|
||||
match self {
|
||||
ExecutionMode::Test | ExecutionMode::Executable => Phase::MakeSpecializations,
|
||||
ExecutionMode::Check => Phase::SolveTypes,
|
||||
ExecutionMode::Check | ExecutionMode::ExecutableIfCheck => Phase::SolveTypes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,6 +170,22 @@ struct ModuleCache<'a> {
|
|||
sources: MutMap<ModuleId, (PathBuf, &'a str)>,
|
||||
}
|
||||
|
||||
impl<'a> ModuleCache<'a> {
|
||||
pub fn total_problems(&self) -> usize {
|
||||
let mut total = 0;
|
||||
|
||||
for problems in self.can_problems.values() {
|
||||
total += problems.len();
|
||||
}
|
||||
|
||||
for problems in self.type_problems.values() {
|
||||
total += problems.len();
|
||||
}
|
||||
|
||||
total
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ModuleCache<'_> {
|
||||
fn default() -> Self {
|
||||
let mut module_names = MutMap::default();
|
||||
|
@ -2385,12 +2403,35 @@ fn update<'a>(
|
|||
.extend(solved_module.aliases.keys().copied());
|
||||
}
|
||||
|
||||
if is_host_exposed && state.goal_phase() == Phase::SolveTypes {
|
||||
let finish_type_checking = is_host_exposed &&
|
||||
(state.goal_phase() == Phase::SolveTypes)
|
||||
// If we're running in check-and-then-build mode, only exit now there are errors.
|
||||
&& (!matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck) || state.module_cache.total_problems() > 0);
|
||||
|
||||
if finish_type_checking {
|
||||
debug_assert!(work.is_empty());
|
||||
debug_assert!(state.dependencies.solved_all());
|
||||
|
||||
state.timings.insert(module_id, module_timing);
|
||||
|
||||
if matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck) {
|
||||
// We there may outstanding modules in the typecheked cache whose ident IDs
|
||||
// aren't registered; transfer all of their idents over to the state, since
|
||||
// we're now done and ready to report errors.
|
||||
for (
|
||||
module_id,
|
||||
TypeCheckedModule {
|
||||
ident_ids,
|
||||
module_timing,
|
||||
..
|
||||
},
|
||||
) in state.module_cache.typechecked.drain()
|
||||
{
|
||||
state.constrained_ident_ids.insert(module_id, ident_ids);
|
||||
state.timings.insert(module_id, module_timing);
|
||||
}
|
||||
}
|
||||
|
||||
let documentation = {
|
||||
let mut empty = MutMap::default();
|
||||
std::mem::swap(&mut empty, &mut state.module_cache.documentation);
|
||||
|
@ -2427,7 +2468,9 @@ fn update<'a>(
|
|||
},
|
||||
);
|
||||
|
||||
if state.goal_phase() > Phase::SolveTypes {
|
||||
if state.goal_phase() > Phase::SolveTypes
|
||||
|| matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck)
|
||||
{
|
||||
let layout_cache = state
|
||||
.layout_caches
|
||||
.pop()
|
||||
|
@ -2452,6 +2495,25 @@ fn update<'a>(
|
|||
state.timings.insert(module_id, module_timing);
|
||||
}
|
||||
|
||||
let work = if is_host_exposed
|
||||
&& matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck)
|
||||
{
|
||||
debug_assert!(
|
||||
work.is_empty(),
|
||||
"work left over after host exposed is checked"
|
||||
);
|
||||
|
||||
// Update the goal phase to target full codegen.
|
||||
state.exec_mode = ExecutionMode::Executable;
|
||||
|
||||
// Load the find + make specializations portion of the dependency graph.
|
||||
state
|
||||
.dependencies
|
||||
.load_find_and_make_specializations_after_check()
|
||||
} else {
|
||||
work
|
||||
};
|
||||
|
||||
start_tasks(arena, &mut state, work, injector, worker_listeners)?;
|
||||
}
|
||||
|
||||
|
@ -2810,7 +2872,7 @@ fn finish_specialization(
|
|||
let entry_point = {
|
||||
match exec_mode {
|
||||
ExecutionMode::Test => EntryPoint::Test,
|
||||
ExecutionMode::Executable => {
|
||||
ExecutionMode::Executable | ExecutionMode::ExecutableIfCheck => {
|
||||
let path_to_platform = {
|
||||
use PlatformPath::*;
|
||||
let package_name = match platform_path {
|
||||
|
@ -5007,7 +5069,9 @@ fn build_pending_specializations<'a>(
|
|||
// skip expectations if we're not going to run them
|
||||
match execution_mode {
|
||||
ExecutionMode::Test => { /* fall through */ }
|
||||
ExecutionMode::Check | ExecutionMode::Executable => continue,
|
||||
ExecutionMode::Check
|
||||
| ExecutionMode::Executable
|
||||
| ExecutionMode::ExecutableIfCheck => continue,
|
||||
}
|
||||
|
||||
// mark this symbol as a top-level thunk before any other work on the procs
|
||||
|
@ -5081,7 +5145,9 @@ fn build_pending_specializations<'a>(
|
|||
// skip expectations if we're not going to run them
|
||||
match execution_mode {
|
||||
ExecutionMode::Test => { /* fall through */ }
|
||||
ExecutionMode::Check | ExecutionMode::Executable => continue,
|
||||
ExecutionMode::Check
|
||||
| ExecutionMode::Executable
|
||||
| ExecutionMode::ExecutableIfCheck => continue,
|
||||
}
|
||||
|
||||
// mark this symbol as a top-level thunk before any other work on the procs
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![warn(clippy::dbg_macro)]
|
||||
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
||||
// See github.com/roc-lang/roc/issues/800 for discussion of the large_enum_variant check.
|
||||
#![allow(clippy::large_enum_variant)]
|
||||
pub mod docs;
|
||||
pub mod file;
|
||||
|
|
|
@ -166,11 +166,10 @@ impl<'a> Dependencies<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if goal_phase >= MakeSpecializations {
|
||||
// Add make specialization dependents
|
||||
self.make_specializations_dependents
|
||||
.add_succ(module_id, dependencies.iter().map(|dep| *dep.as_inner()));
|
||||
}
|
||||
// Add "make specialization" dependents. Even if we're not targeting making
|
||||
// specializations right now, we may re-enter to do so later.
|
||||
self.make_specializations_dependents
|
||||
.add_succ(module_id, dependencies.iter().map(|dep| *dep.as_inner()));
|
||||
|
||||
// add dependencies for self
|
||||
// phase i + 1 of a file always depends on phase i being completed
|
||||
|
@ -374,6 +373,80 @@ impl<'a> Dependencies<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Loads the dependency graph to find and make specializations, and returns the next jobs to
|
||||
/// be run.
|
||||
///
|
||||
/// This should be used when the compiler wants to build or run a Roc executable if and only if
|
||||
/// previous stages succeed; in such cases we load the dependency graph dynamically.
|
||||
pub fn load_find_and_make_specializations_after_check(&mut self) -> MutSet<(ModuleId, Phase)> {
|
||||
let mut output = MutSet::default();
|
||||
|
||||
let mut make_specializations_dependents = MakeSpecializationsDependents::default();
|
||||
let default_make_specializations_dependents_len = make_specializations_dependents.0.len();
|
||||
std::mem::swap(
|
||||
&mut self.make_specializations_dependents,
|
||||
&mut make_specializations_dependents,
|
||||
);
|
||||
|
||||
for (&module, info) in make_specializations_dependents.0.iter_mut() {
|
||||
debug_assert!(self.status.get_mut(&Job::Step(module, Phase::FindSpecializations)).is_none(), "should only have targeted solving types, but there is already a goal to find specializations");
|
||||
debug_assert!(self.status.get_mut(&Job::Step(module, Phase::MakeSpecializations)).is_none(), "should only have targeted solving types, but there is already a goal to make specializations");
|
||||
debug_assert!(
|
||||
module == ModuleId::DERIVED_GEN || info.succ.contains(&ModuleId::DERIVED_GEN),
|
||||
"derived module not accounted for in {:?}",
|
||||
(module, info)
|
||||
);
|
||||
|
||||
let mut has_find_specialization_dep = false;
|
||||
for &module_dep in info.succ.iter() {
|
||||
// The modules in `succ` are the modules for which specializations should be made
|
||||
// after the current one. But, their specializations should be found before the
|
||||
// current one.
|
||||
if module_dep != ModuleId::DERIVED_GEN {
|
||||
// We never find specializations for DERIVED_GEN
|
||||
self.add_dependency(module, module_dep, Phase::FindSpecializations);
|
||||
has_find_specialization_dep = true;
|
||||
}
|
||||
|
||||
self.add_dependency(module_dep, module, Phase::MakeSpecializations);
|
||||
self.add_dependency(ModuleId::DERIVED_GEN, module, Phase::MakeSpecializations);
|
||||
|
||||
// `module_dep` can't make its specializations until the current module does.
|
||||
info.has_pred = true;
|
||||
}
|
||||
|
||||
if module != ModuleId::DERIVED_GEN {
|
||||
self.add_to_status_for_phase(module, Phase::FindSpecializations);
|
||||
self.add_dependency_help(
|
||||
module,
|
||||
module,
|
||||
Phase::MakeSpecializations,
|
||||
Phase::FindSpecializations,
|
||||
);
|
||||
}
|
||||
self.add_to_status_for_phase(module, Phase::MakeSpecializations);
|
||||
|
||||
if !has_find_specialization_dep && module != ModuleId::DERIVED_GEN {
|
||||
// We don't depend on any other modules having their specializations found first,
|
||||
// so start finding specializations from this module.
|
||||
output.insert((module, Phase::FindSpecializations));
|
||||
}
|
||||
}
|
||||
|
||||
std::mem::swap(
|
||||
&mut self.make_specializations_dependents,
|
||||
&mut make_specializations_dependents,
|
||||
);
|
||||
debug_assert_eq!(
|
||||
make_specializations_dependents.0.len(),
|
||||
default_make_specializations_dependents_len,
|
||||
"more modules were added to the graph: {:?}",
|
||||
make_specializations_dependents
|
||||
);
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
/// Load the entire "make specializations" dependency graph and start from the top.
|
||||
pub fn reload_make_specialization_pass(&mut self) -> MutSet<(ModuleId, Phase)> {
|
||||
let mut output = MutSet::default();
|
||||
|
|
|
@ -699,7 +699,7 @@ fn platform_parse_error() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
// See https://github.com/rtfeldman/roc/issues/2413
|
||||
// See https://github.com/roc-lang/roc/issues/2413
|
||||
fn platform_exposes_main_return_by_pointer_issue() {
|
||||
let modules = vec![
|
||||
(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue