Skip to content

Commit 9e77379

Browse files
committed
Merge #354: feat: unstable with traits
b8d2b34 Add unstable features docs (Sdoba16) 822af47 Add unstable features check to compiler (Sdoba16) 105f2ca Add RequireFeature trait for current AST nodes (Sdoba16) b8b83f7 Add unstable features basic functionality (Sdoba16) Pull request description: Closes #317 Replaces #329 Added `UnstableFeature` enum to track available unstable features Added `UnstableFeatures` to check whether a feature is enabled Added `RequireFeature` trait, implemented for every AST node. Each node reports which unstable features it requires. Struct impls use full field destructuring and enum impls use exhaustive matches, so new nodes or fields cause a compile error until the impl is updated. The check runs at parse time: once a program parses without errors, any use of a disabled feature is reported with an error naming the feature and the `-Z` flag that enables it. Added a `-Z <feature>` flag to the CLI. Multiple features can be passed with repeated flags. Available features are listed in the help output. `simc program.simf -Z imports` Added `doc/unstable-features.md` with user and developer guides. ACKs for top commit: KyrylR: ACK b8d2b34; successfully ran local tests Tree-SHA512: af9b3f392692605bffd4dec1bd40acd47d27d98c483360fe17be531095c2cdf98476f1c05706115a0c732db5f0c7b023681ac0cda4bed87302dac6a16f87b3bf
2 parents d99be12 + b8d2b34 commit 9e77379

11 files changed

Lines changed: 967 additions & 73 deletions

File tree

doc/unstable-features.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Unstable features
2+
3+
Unstable features are experimental compiler capabilities. They may change
4+
or be removed before stabilization.
5+
6+
## Viewing available unstable features
7+
8+
Run `simc --help`; the features are listed under the `-Z` flag.
9+
10+
## Enabling an unstable feature
11+
12+
Pass `-Z <feature-name>` to `simc`.
13+
14+
## Adding or stabilizing a feature
15+
16+
See the rustdoc on `UnstableFeature` in `src/unstable.rs`; the procedures
17+
live next to the code they mutate, so they cannot drift.

src/compile/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ struct Scope<'brand> {
6363
///
6464
/// Inner scopes occur higher in the tree than outer scopes.
6565
/// Later assignments occur higher in the tree than earlier assignments.
66-
/// ```
6766
variables: Vec<Vec<Pattern>>,
6867
ctx: simplicity::types::Context<'brand>,
6968
/// Tracker of function calls.

src/driver/mod.rs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(rustdoc::private_intra_doc_links)]
12
//! The `driver` module is responsible for module resolution and dependency management.
23
//!
34
//! Our compiler operates in a strict pipeline: `Lexer -> Parser -> Driver -> AST`.
@@ -36,6 +37,7 @@ use crate::error::{Error, ErrorCollector, RichError, Span};
3637
use crate::parse::{self, ParseFromStrWithErrors};
3738
use crate::resolution::{DependencyMap, ResolvedUse};
3839
use crate::source::{CanonPath, CanonSourceFile};
40+
use crate::unstable::UnstableFeatures;
3941

4042
/// The reserved identifier for the program's entry point.
4143
pub(crate) const MAIN_STR: &str = "main";
@@ -178,6 +180,7 @@ impl DependencyGraph {
178180
dependency_map: Arc<DependencyMap>,
179181
root_program: &parse::Program,
180182
handler: &mut ErrorCollector,
183+
unstable_features: &UnstableFeatures,
181184
) -> Result<Option<Self>, String> {
182185
let mut graph = Self {
183186
modules: vec![SourceModule {
@@ -226,6 +229,7 @@ impl DependencyGraph {
226229
invalid_imports: &mut invalid_imports,
227230
handler,
228231
queue: &mut queue,
232+
unstable_features,
229233
};
230234
graph.load_and_parse_dependencies(&current, valid_imports, &mut ctx);
231235
}
@@ -246,6 +250,7 @@ impl DependencyGraph {
246250
importer_source: &CanonSourceFile,
247251
span: Span,
248252
handler: &mut ErrorCollector,
253+
unstable_features: &UnstableFeatures,
249254
) -> Option<SourceModule> {
250255
let Ok(content) = std::fs::read_to_string(path.as_path()) else {
251256
let err = RichError::new(
@@ -263,7 +268,11 @@ impl DependencyGraph {
263268
let mut error_handler = ErrorCollector::new();
264269
let source = CanonSourceFile::new(path.clone(), Arc::from(content));
265270

266-
let ast = parse::Program::parse_from_str_with_errors(source.clone(), &mut error_handler);
271+
let ast = parse::Program::parse_from_str_with_errors(
272+
source.clone(),
273+
unstable_features,
274+
&mut error_handler,
275+
);
267276

268277
if error_handler.has_errors() {
269278
handler.extend_with_handler(source, &error_handler);
@@ -321,9 +330,13 @@ impl DependencyGraph {
321330
continue;
322331
}
323332

324-
let Some(module) =
325-
Self::parse_and_get_source_module(&path, &current.source, import_span, ctx.handler)
326-
else {
333+
let Some(module) = Self::parse_and_get_source_module(
334+
&path,
335+
&current.source,
336+
import_span,
337+
ctx.handler,
338+
ctx.unstable_features,
339+
) else {
327340
// Safe to ignore output: previous `.contains` check prevents collisions.
328341
let _ = ctx.invalid_imports.insert(path);
329342
continue;
@@ -346,7 +359,7 @@ impl DependencyGraph {
346359
}
347360

348361
/// Groups all shared state for import resolution to avoid threading a lot of parameters
349-
/// through every recursive call. Lives only for the duration of [`resolve_imports`].
362+
/// through every recursive call. Lives only for the duration of [`DependencyGraph::resolve_imports`].
350363
struct ImportContext<'a> {
351364
current: CurrentModule,
352365
dependency_map: &'a DependencyMap,
@@ -421,6 +434,7 @@ struct LoadContext<'a> {
421434
invalid_imports: &'a mut HashSet<CanonPath>,
422435
handler: &'a mut ErrorCollector,
423436
queue: &'a mut VecDeque<usize>,
437+
unstable_features: &'a UnstableFeatures,
424438
}
425439

426440
/// The currently processed module and its source, used for error reporting
@@ -493,15 +507,24 @@ pub(crate) mod tests {
493507
let root_p = root_file_path.expect("main.simf must be defined in file list");
494508
let main_canon_source = CanonSourceFile::new(root_p, Arc::from(root_content));
495509

496-
let main_program_option =
497-
parse::Program::parse_from_str_with_errors(main_canon_source.clone(), &mut handler);
510+
let main_program_option = parse::Program::parse_from_str_with_errors(
511+
main_canon_source.clone(),
512+
&UnstableFeatures::all(),
513+
&mut handler,
514+
);
498515

499516
let Some(main_program) = main_program_option else {
500517
return (None, HashMap::new(), ws, handler);
501518
};
502519

503-
let graph_option =
504-
DependencyGraph::new(main_canon_source, map, &main_program, &mut handler).unwrap();
520+
let graph_option = DependencyGraph::new(
521+
main_canon_source,
522+
map,
523+
&main_program,
524+
&mut handler,
525+
&UnstableFeatures::all(),
526+
)
527+
.unwrap();
505528

506529
let mut file_ids = HashMap::new();
507530

src/error.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::parse::MatchPattern;
1818
use crate::source::SourceFile;
1919
use crate::str::{AliasName, FunctionName, Identifier, JetName, ModuleName, WitnessName};
2020
use crate::types::{ResolvedType, UIntType};
21+
use crate::unstable::UnstableFeature;
2122

2223
/// Area that an object spans inside a file.
2324
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
@@ -478,6 +479,9 @@ impl fmt::Display for ErrorCollector {
478479
/// Records _what_ happened but not where.
479480
#[derive(Debug, Clone)]
480481
pub enum Error {
482+
UnstableFeature {
483+
feature: UnstableFeature,
484+
},
481485
DependencyPathNotFound {
482486
path: PathBuf,
483487
},
@@ -643,15 +647,16 @@ pub enum Error {
643647
declared: ResolvedType,
644648
assigned: ResolvedType,
645649
},
646-
// TODO: Remove these once `use` and `mod` are supported by the AST
647-
UseKeywordIsNotSupported,
648-
ModuleKeywordIsNotSupported,
649650
}
650651

651652
#[rustfmt::skip]
652653
impl fmt::Display for Error {
653654
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
654655
match self {
656+
Error::UnstableFeature { feature } => write!(
657+
f,
658+
"The '{feature}' feature is not enabled.\nEnable it with: -Z {feature}"
659+
),
655660
Error::DependencyPathNotFound { path } => write!(
656661
f,
657662
"Path not found: {}", path.display()
@@ -880,14 +885,6 @@ impl fmt::Display for Error {
880885
f,
881886
"Parameter `{name}` was declared with type `{declared}` but its assigned argument is of type `{assigned}`"
882887
),
883-
Error::UseKeywordIsNotSupported => write!(
884-
f,
885-
"The `use` keyword is not supported yet"
886-
),
887-
Error::ModuleKeywordIsNotSupported => write!(
888-
f,
889-
"The `mod` keyword is not supported yet"
890-
),
891888
}
892889
}
893890
}

0 commit comments

Comments
 (0)