-
Notifications
You must be signed in to change notification settings - Fork 244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Epic: Metaprogramming MVP #4594
Comments
# Description ## Problem\* Resolves #4586 Part of #4594 ## Summary\* Adds a `quote { ... }` expression to the parser along with a new builtin `Code` type which it is the only method of creating. ## Additional Context The quote expression can only currently quote expressions and statements. It cannot yet quote top-level statements - we'd need more parser changes for this. In particular the top level statement parser would now need to be recursive and passed down all the way to the expression level... Trying to use `quote` in a program gives you an `experimental feature` warning. Indeed, the only thing you can do with it currently is panic once it gets to monomorphization without being removed from the runtime program yet. ## Documentation\* Check one: - [x] No documentation needed. - I'm following the pattern with other experimental features and waiting to document them until they're stable. For this, it means quote won't be documented until the base for metaprogramming is completed. - [ ] Documentation included in this PR. - [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
# Description ## Problem\* Resolves #4586 Part of #4594 ## Summary\* Adds a `quote { ... }` expression to the parser along with a new builtin `Code` type which it is the only method of creating. ## Additional Context The quote expression can only currently quote expressions and statements. It cannot yet quote top-level statements - we'd need more parser changes for this. In particular the top level statement parser would now need to be recursive and passed down all the way to the expression level... Trying to use `quote` in a program gives you an `experimental feature` warning. Indeed, the only thing you can do with it currently is panic once it gets to monomorphization without being removed from the runtime program yet. ## Documentation\* Check one: - [x] No documentation needed. - I'm following the pattern with other experimental features and waiting to document them until they're stable. For this, it means quote won't be documented until the base for metaprogramming is completed. - [ ] Documentation included in this PR. - [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
) # Description ## Problem\* Working towards #4594 ## Summary\* Adds a hidden compiler option `--use-elaborator` to enable the experimental elaborator code to be run on a codebase. This also connects the elaborator with `dc_crate` (and thus the cli flag above) by filling in the stub for elaborating functions. Filling in the stub required quite a bit of code but it was as usual just copied from name resolution and type checking. ## Additional Context Originally I wanted to connect the elaborator to more of the frontend (e.g. resolve globals, types, traits, etc) but this already ballooned to a large line count. To review I'd recommend reviewing the non-elaborator portions first then just skimming through the elaborator portions since they are copied from `Resolver::resolve_function`, `Resolver::extract_meta`, `Resolver::intern_function`, and `type_check_func`. ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [ ] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
# Description ## Problem\* Working towards #4594 ## Summary\* Adds support for impls and trait impls to the elaborator. This was somewhat satisfying to add since the existing code for this in `dc_crate.rs` is very messy & long winded due to our current design of creating a new `NameResolver` for every resolution. Keeping everything in the same elaborator and not needing to keep setting the interner, def maps, current crate, module, generics, append errors, etc saved many lines. I think this implementation is roughly half the size as a result. ## Additional Context Still need types, type aliases, and globals after this. The pass is testable after that but is expected to fail the comptime tests at least. So I'll need to inline the comptime scanning pass in the elaborator as well. After that the pass is theoretically done but realistically there will be bugs to fix before we can make it the default. ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
# Description ## Problem\* Working towards #4594 ## Summary\* Adds support for resolving top-level traits and type definitions to the elaborator. ## Additional Context After this PR only globals will need to be resolved in the elaborator. ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
# Description ## Problem\* Working towards #4594 ## Summary\* When run on a program the elaborator would always panic previously due to `FuncMeta`s not yet being set for other functions while one function was being elaborated. This is because we used to set them during name resolution and only check them during type checking, but now that these two passes are merged we'll need to set them all before elaboration instead. This PR creates a new `define_function_metas` function to create the `FuncMeta`s beforehand. I imagine there are more changes required here related to scoping / generics / parameters but this at least stops the panic. ## Additional Context This is the first of the elaborator PRs to feature only new changes rather than largely copied code, so feel free to critique as usual if you think a different approach would be better, notice an issue, etc. After this PR the elaborator will run on a small example program, only producing 1052 errors in the standard library 🙂. Most of these errors appear to be variants of "no method named '...' found for ..." and "no matching impl found for ..." ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --------- Co-authored-by: Tom French <[email protected]> Co-authored-by: Maxim Vezenov <[email protected]>
Current goal is to get a vertical slice of metaprogramming working to support deriving a trait impl of a simple type on a simple trait like Default: comptime fn derive_default(typ: TypeDefinition) -> Quoted {
let generics: [Quoted] = typ.generics();
assert(generics.is_empty(), "derive_default: Deriving Default on generic types is currently unimplemented");
let type_name: Type = typ.as_type();
let fields: [(Quoted, Type)] = typ.fields();
let fields: Quoted = fields.map(|(name, _)| quote { $name : Default::default(), })
.join();
quote {
impl Default for $type_name {
fn default() -> Self {
Self { $fields }
}
}
}
}
#[derive_default]
struct Foo {
x: Field
}
// Expected output:
//
// impl Default for Foo {
// fn default(this: Self) -> Self {
// Foo {
// x: Default::default(),
// }
// }
// } Required unimplemented features:
fn join(slice: [Quoted]) -> Quoted {
let mut ret = quote {};
for element in slice {
// Since quoted values are token streams, we do not need (or want) a `;` separator.
ret = quote { $ret $element };
}
ret
}
Edit: We used to have a |
# Description ## Problem\* Resolves the vertical slice from this comment #4594 (comment) ## Summary\* This PR lets us actually insert the generated trait impl from the called macro into the program. Currently we only support inserting trait impls, functions, and globals to keep things simple. Each time these are inserted we have to call the def collection code on them so I wanted to avoid adding them all at once in a larger PR. ## Additional Context We can now generate impls for simple traits on a type! See the `derive_impl` test for details. The call site currently looks like this: ```rs #[derive_default] struct Foo { x: Field, y: Bar, } #[derive_default] struct Bar {} fn main() { let _foo: Foo = Default::default(); } ``` If `Bar` doesn't also derive `Default` the error that is issued is in the code to derive the impl unfortunately: ``` error: No matching impl found for `Bar: Default` ┌─ /.../derive_impl/src/main.nr:33:50 │ 33 │ result = result.push_back(quote { $name: Default::default(), }); │ ---------------- No impl for `Bar: Default` │ ``` Since we only support unquoting a few items at top-level currently, here is what it looks like when we try to unquote a different item. In this case, a non-trait impl: ``` error: Unsupported statement type to unquote ┌─ /.../derive_impl/src/main.nr:23:1 │ 23 │ ╭ #[derive_default] 24 │ │ struct Foo { 25 │ │ x: Field, 26 │ │ y: Bar, 27 │ │ } │ ╰─' Only functions, globals, and trait impls can be unquoted here │ = Unquoted item was: impl Foo { Attributes { function: None, secondary: [] } fn bar(self: Self) -> Self { self } } ``` ## Documentation\* Check one: - [ ] No documentation needed. - [ ] Documentation included in this PR. - [x] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --------- Co-authored-by: Tom French <[email protected]>
Next goal is getting the full #[derive(Default, Eq, Cmp)]
struct MyStruct { my_field: u32 }
type DeriveFunction = fn(StructDefinition) -> Quoted
comptime mut global HANDLERS: HashMap<TraitConstraint, DeriveFunction> = HashMap::new();
comptime fn derive(s: StructDefinition, traits: [Quoted]) -> Quoted {
let mut result = quote {};
for trait_to_derive in traits {
let handler = HANDLERS.get(trait_to_derive);
assert(handler.is_some(), f"No derive function registered for `{trait_to_derive}`");
let trait_impl = handler.unwrap()(s);
result = quote { $result $trait_impl };
}
result
}
comptime fn derive_via(t: TraitDefinition, f: Quoted) {
HANDLERS.insert(t.as_constraint(), unquote!(f));
}
#[derive_via(derive_do_nothing)]
trait DoNothing {
fn do_nothing(self);
}
comptime fn derive_do_nothing(s: StructDefinition) -> Quoted {
let typ = s.as_type();
let generics = s.generics().join(quote {,});
quote {
impl<$generics> DoNothing for $typ {
fn do_nothing(self) {
// Traits can't tell us what to do
println("something");
}
}
}
} Features we still need to do this:
|
This issue is subject to feature creep particularly since there's no set amount to comptime functions or functionality we should support. As a result, after my above comment on features we need to complete a general Any remaining issues we can keep as separate bugs / feature requests. |
# Description ## Problem\* Part of work towards #4594 (comment), forgot an issue for this one. ## Summary\* ## Additional Context ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
# Description ## Problem\* Resolves #4594 First traits to derive in the stdlib! ## Summary\* Lets us derive the `Eq` and `Default` traits for almost any type. I anticipate there will be issues with deriving generic types. I'll fix this in another PR. ## Additional Context Since derive is in the stdlib and we can derive traits now, I'm arbitrarily marking the epic for metaprogramming as completed. There are still bugs to fix and many helper functions we can add but the bulk of the work and infrastructure is all in. ## Documentation\* Check one: - [ ] No documentation needed. - [ ] Documentation included in this PR. - [x] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [ ] I have tested the changes locally. - [ ] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
Proposal: https://hackmd.io/Tkzo_ryvTsWMPESmWHPiZw?view
Core Tasks for Noir 1.0
quote
expressions for metaprogramming #4586comptime
modifier for variables/functions which only exist at compile-time #4588Hir -> Ast
conversion #4796comptime
globals #4916comptime
globals #4917comptime
context #4924comptime
expressions have been evaluated #5168comptime
code when a type definition is annotated with acomptime
function #5255TypeDefinition
#5285quote
token streams #5284TraitConstraint
as a comptime type #5480Quoted::as_trait_constraint
method #5481Bugs for Noir 1.0
comptime
context #5333comptime let
variable in runtime code #5388Nice-to-haves for Noir 1.0+
derive
attribute with support for (de)serialize macros on existing complex types #3379unquote
method to stdlib #5478The text was updated successfully, but these errors were encountered: