Skip to content

Implement DependencyGraph and foundational driver architecture#271

Open
LesterEvSe wants to merge 1 commit intoBlockstreamResearch:dev/importsfrom
LesterEvSe:feature/simple-driver
Open

Implement DependencyGraph and foundational driver architecture#271
LesterEvSe wants to merge 1 commit intoBlockstreamResearch:dev/importsfrom
LesterEvSe:feature/simple-driver

Conversation

@LesterEvSe
Copy link
Copy Markdown
Collaborator

Project Graph: Added driver.rs featuring the ProjectGraph implementation to build a Directed Acyclic Graph of project dependencies.
Trait Refactoring: Updated the ParseFromStrWithErrors trait to accept a full SourceFile (containing both metadata and source text) instead of just the raw string content.

@LesterEvSe LesterEvSe requested a review from KyrylR April 3, 2026 13:48
@LesterEvSe LesterEvSe self-assigned this Apr 3, 2026
@LesterEvSe LesterEvSe requested a review from delta1 as a code owner April 3, 2026 13:48
@LesterEvSe LesterEvSe added the enhancement New feature or request label Apr 3, 2026
src/driver.rs Outdated
pub struct ProjectGraph {
/// Arena Pattern: the data itself lives here.
/// A flat vector guarantees that module data is stored contiguously in memory.
#[expect(dead_code)]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[expect(dead_code)]
#[allow(dead_code)]

@LesterEvSe LesterEvSe force-pushed the feature/simple-driver branch from 874e4a5 to 77e449a Compare April 6, 2026 09:27
@LesterEvSe LesterEvSe changed the title Implement ProjectGraph and foundational driver architecture Implement DependencyGraph and foundational driver architecture Apr 6, 2026
@@ -0,0 +1,327 @@
use std::collections::{HashMap, VecDeque};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we move it to driver/mod.rs?
The reasoning is that we gonna introduce a few independent algorithms here, so we could have them under same module, as they are just related to the driver itself

///
/// This function will return an `Err(String)` only for critical internal compiler errors
/// (e.g., if a provided `SourceFile` is unexpectedly missing its underlying file path).
pub fn new(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have pub functions first then private

src/driver.rs Outdated

while let Some(curr_id) = queue.pop_front() {
// We need this to report errors inside THIS file.
let importer_source = graph.modules[curr_id].source.clone();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's handle modules[curr_id], via let statement to avoid panic

@LesterEvSe LesterEvSe force-pushed the feature/simple-driver branch from 77e449a to 006099a Compare April 6, 2026 13:23
);
}

Ok((!handler.has_errors()).then_some(graph))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it expected that ParseFromStrWithErrors now returns None whenever the shared ErrorCollector already contains any earlier error, and DependencyGraph::new reuses one collector across the entire BFS?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not expected. I could add a local ErrorCollector inside the parse_and_get_program function to parse more files and collect more errors. I think this would be better than the current approach

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, then you could return Result<Self, ErrorCollector>

Comment on lines +227 to +231
if let Some(&existing_id) = self.lookup.get(&path) {
let deps = self.dependencies.entry(curr_id).or_default();
if !deps.contains(&existing_id) {
deps.push(existing_id);
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it actually detect import cycles? As it is written it treats any already-seen path as a normal resolved dependency and continues. For A -> B -> A, B’s import of A hits the existing_id branch, and in Ok((!handler.has_errors()).then_some(graph)) still returns Some(graph) with no diagnostic

Copy link
Copy Markdown
Collaborator Author

@LesterEvSe LesterEvSe Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it will be the responsibility of C3 and the other algorithms in the following PR

@LesterEvSe LesterEvSe force-pushed the feature/simple-driver branch from 006099a to 571453c Compare April 6, 2026 14:56
@LesterEvSe LesterEvSe requested a review from KyrylR April 6, 2026 16:14
Comment on lines +244 to +248
let Some(module) =
Self::parse_and_get_program(&path, importer_source.clone(), import_span, handler)
else {
continue;
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If parse_and_get_program fails here, the path is never recorded in lookup, so another parent importing the same file will try to parse it again and emit the same lex or syntax errors again

We could try to fix it here, or have a GitHub issue for it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants