Skip to content

Commit 30cb65a

Browse files
author
jfecher
authored
feat: Add TraitConstraint type (#5499)
# Description ## Problem\* Resolves #5480 Resolves #5481 ## Summary\* Adds: - The `TraitConstraint` type - `impl Eq for TraitConstraint` - `impl Hash for TraitConstraint` - `Quoted::as_trait_constraint` ## Additional Context Ran into the type error when calling trait impls issue again while working on this. Hence why it is a draft. ## 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.
1 parent 6a7f593 commit 30cb65a

File tree

23 files changed

+323
-120
lines changed

23 files changed

+323
-120
lines changed

aztec_macros/src/transforms/note_interface.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ pub fn generate_note_interface_impl(module: &mut SortedModule) -> Result<(), Azt
7373
generics: vec![],
7474
methods: vec![],
7575
where_clause: vec![],
76+
is_comptime: false,
7677
};
7778
module.impls.push(default_impl.clone());
7879
module.impls.last_mut().unwrap()

aztec_macros/src/transforms/storage.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ pub fn generate_storage_implementation(
248248
methods: vec![(init, Span::default())],
249249

250250
where_clause: vec![],
251+
is_comptime: false,
251252
};
252253
module.impls.push(storage_impl);
253254

compiler/noirc_frontend/src/ast/structure.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,7 @@ pub struct NoirStruct {
1414
pub generics: UnresolvedGenerics,
1515
pub fields: Vec<(Ident, UnresolvedType)>,
1616
pub span: Span,
17-
}
18-
19-
impl NoirStruct {
20-
pub fn new(
21-
name: Ident,
22-
attributes: Vec<SecondaryAttribute>,
23-
generics: UnresolvedGenerics,
24-
fields: Vec<(Ident, UnresolvedType)>,
25-
span: Span,
26-
) -> NoirStruct {
27-
NoirStruct { name, attributes, generics, fields, span }
28-
}
17+
pub is_comptime: bool,
2918
}
3019

3120
impl Display for NoirStruct {

compiler/noirc_frontend/src/ast/traits.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub struct TypeImpl {
5353
pub generics: UnresolvedGenerics,
5454
pub where_clause: Vec<UnresolvedTraitConstraint>,
5555
pub methods: Vec<(NoirFunction, Span)>,
56+
pub is_comptime: bool,
5657
}
5758

5859
/// Ast node for an implementation of a trait for a particular type
@@ -69,6 +70,8 @@ pub struct NoirTraitImpl {
6970
pub where_clause: Vec<UnresolvedTraitConstraint>,
7071

7172
pub items: Vec<TraitImplItem>,
73+
74+
pub is_comptime: bool,
7275
}
7376

7477
/// Represents a simple trait constraint such as `where Foo: TraitY<U, V>`
@@ -84,7 +87,7 @@ pub struct UnresolvedTraitConstraint {
8487
}
8588

8689
/// Represents a single trait bound, such as `TraitX` or `TraitY<U, V>`
87-
#[derive(Clone, Debug, PartialEq, Eq)]
90+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
8891
pub struct TraitBound {
8992
pub trait_path: Path,
9093
pub trait_id: Option<TraitId>, // initially None, gets assigned during DC

compiler/noirc_frontend/src/elaborator/mod.rs

Lines changed: 85 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,17 +1636,25 @@ impl<'context> Elaborator<'context> {
16361636
function_sets.push(UnresolvedFunctions { functions, file_id, trait_id, self_type });
16371637
}
16381638

1639+
let (comptime_trait_impls, trait_impls) =
1640+
items.trait_impls.into_iter().partition(|trait_impl| trait_impl.is_comptime);
1641+
1642+
let (comptime_structs, structs) =
1643+
items.types.into_iter().partition(|typ| typ.1.struct_def.is_comptime);
1644+
16391645
let comptime = CollectedItems {
16401646
functions: comptime_function_sets,
1641-
types: BTreeMap::new(),
1647+
types: comptime_structs,
16421648
type_aliases: BTreeMap::new(),
16431649
traits: BTreeMap::new(),
1644-
trait_impls: Vec::new(),
1650+
trait_impls: comptime_trait_impls,
16451651
globals: Vec::new(),
16461652
impls: rustc_hash::FxHashMap::default(),
16471653
};
16481654

16491655
items.functions = function_sets;
1656+
items.trait_impls = trait_impls;
1657+
items.types = structs;
16501658
(comptime, items)
16511659
}
16521660

@@ -1657,75 +1665,85 @@ impl<'context> Elaborator<'context> {
16571665
location: Location,
16581666
) {
16591667
for item in items {
1660-
match item {
1661-
TopLevelStatement::Function(function) => {
1662-
let id = self.interner.push_empty_fn();
1663-
let module = self.module_id();
1664-
self.interner.push_function(id, &function.def, module, location);
1665-
let functions = vec![(self.local_module, id, function)];
1666-
generated_items.functions.push(UnresolvedFunctions {
1667-
file_id: self.file,
1668-
functions,
1669-
trait_id: None,
1670-
self_type: None,
1671-
});
1672-
}
1673-
TopLevelStatement::TraitImpl(mut trait_impl) => {
1674-
let methods = dc_mod::collect_trait_impl_functions(
1675-
self.interner,
1676-
&mut trait_impl,
1677-
self.crate_id,
1678-
self.file,
1679-
self.local_module,
1680-
);
1668+
self.add_item(item, generated_items, location);
1669+
}
1670+
}
16811671

1682-
generated_items.trait_impls.push(UnresolvedTraitImpl {
1683-
file_id: self.file,
1684-
module_id: self.local_module,
1685-
trait_generics: trait_impl.trait_generics,
1686-
trait_path: trait_impl.trait_name,
1687-
object_type: trait_impl.object_type,
1688-
methods,
1689-
generics: trait_impl.impl_generics,
1690-
where_clause: trait_impl.where_clause,
1691-
1692-
// These last fields are filled in later
1693-
trait_id: None,
1694-
impl_id: None,
1695-
resolved_object_type: None,
1696-
resolved_generics: Vec::new(),
1697-
resolved_trait_generics: Vec::new(),
1698-
});
1699-
}
1700-
TopLevelStatement::Global(global) => {
1701-
let (global, error) = dc_mod::collect_global(
1702-
self.interner,
1703-
self.def_maps.get_mut(&self.crate_id).unwrap(),
1704-
global,
1705-
self.file,
1706-
self.local_module,
1707-
);
1672+
fn add_item(
1673+
&mut self,
1674+
item: TopLevelStatement,
1675+
generated_items: &mut CollectedItems,
1676+
location: Location,
1677+
) {
1678+
match item {
1679+
TopLevelStatement::Function(function) => {
1680+
let id = self.interner.push_empty_fn();
1681+
let module = self.module_id();
1682+
self.interner.push_function(id, &function.def, module, location);
1683+
let functions = vec![(self.local_module, id, function)];
1684+
generated_items.functions.push(UnresolvedFunctions {
1685+
file_id: self.file,
1686+
functions,
1687+
trait_id: None,
1688+
self_type: None,
1689+
});
1690+
}
1691+
TopLevelStatement::TraitImpl(mut trait_impl) => {
1692+
let methods = dc_mod::collect_trait_impl_functions(
1693+
self.interner,
1694+
&mut trait_impl,
1695+
self.crate_id,
1696+
self.file,
1697+
self.local_module,
1698+
);
17081699

1709-
generated_items.globals.push(global);
1710-
if let Some(error) = error {
1711-
self.errors.push(error);
1712-
}
1713-
}
1714-
// Assume that an error has already been issued
1715-
TopLevelStatement::Error => (),
1716-
1717-
TopLevelStatement::Module(_)
1718-
| TopLevelStatement::Import(_)
1719-
| TopLevelStatement::Struct(_)
1720-
| TopLevelStatement::Trait(_)
1721-
| TopLevelStatement::Impl(_)
1722-
| TopLevelStatement::TypeAlias(_)
1723-
| TopLevelStatement::SubModule(_) => {
1724-
let item = item.to_string();
1725-
let error = InterpreterError::UnsupportedTopLevelItemUnquote { item, location };
1726-
self.errors.push(error.into_compilation_error_pair());
1700+
generated_items.trait_impls.push(UnresolvedTraitImpl {
1701+
file_id: self.file,
1702+
module_id: self.local_module,
1703+
trait_generics: trait_impl.trait_generics,
1704+
trait_path: trait_impl.trait_name,
1705+
object_type: trait_impl.object_type,
1706+
methods,
1707+
generics: trait_impl.impl_generics,
1708+
where_clause: trait_impl.where_clause,
1709+
is_comptime: trait_impl.is_comptime,
1710+
1711+
// These last fields are filled in later
1712+
trait_id: None,
1713+
impl_id: None,
1714+
resolved_object_type: None,
1715+
resolved_generics: Vec::new(),
1716+
resolved_trait_generics: Vec::new(),
1717+
});
1718+
}
1719+
TopLevelStatement::Global(global) => {
1720+
let (global, error) = dc_mod::collect_global(
1721+
self.interner,
1722+
self.def_maps.get_mut(&self.crate_id).unwrap(),
1723+
global,
1724+
self.file,
1725+
self.local_module,
1726+
);
1727+
1728+
generated_items.globals.push(global);
1729+
if let Some(error) = error {
1730+
self.errors.push(error);
17271731
}
17281732
}
1733+
// Assume that an error has already been issued
1734+
TopLevelStatement::Error => (),
1735+
1736+
TopLevelStatement::Module(_)
1737+
| TopLevelStatement::Import(_)
1738+
| TopLevelStatement::Struct(_)
1739+
| TopLevelStatement::Trait(_)
1740+
| TopLevelStatement::Impl(_)
1741+
| TopLevelStatement::TypeAlias(_)
1742+
| TopLevelStatement::SubModule(_) => {
1743+
let item = item.to_string();
1744+
let error = InterpreterError::UnsupportedTopLevelItemUnquote { item, location };
1745+
self.errors.push(error.into_compilation_error_pair());
1746+
}
17291747
}
17301748
}
17311749

compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
use std::rc::Rc;
1+
use std::{
2+
hash::{Hash, Hasher},
3+
rc::Rc,
4+
};
25

6+
use chumsky::Parser;
37
use noirc_errors::Location;
48

59
use crate::{
6-
ast::IntegerBitSize,
10+
ast::{IntegerBitSize, TraitBound},
711
hir::comptime::{errors::IResult, InterpreterError, Value},
812
macros_api::{NodeInterner, Signedness},
13+
parser,
914
token::{SpannedToken, Token, Tokens},
1015
QuotedType, Type,
1116
};
@@ -29,6 +34,9 @@ pub(super) fn call_builtin(
2934
"struct_def_as_type" => struct_def_as_type(interner, arguments, location),
3035
"struct_def_fields" => struct_def_fields(interner, arguments, location),
3136
"struct_def_generics" => struct_def_generics(interner, arguments, location),
37+
"trait_constraint_eq" => trait_constraint_eq(interner, arguments, location),
38+
"trait_constraint_hash" => trait_constraint_hash(interner, arguments, location),
39+
"quoted_as_trait_constraint" => quoted_as_trait_constraint(interner, arguments, location),
3240
_ => {
3341
let item = format!("Comptime evaluation for builtin function {name}");
3442
Err(InterpreterError::Unimplemented { item, location })
@@ -79,6 +87,26 @@ fn get_u32(value: Value, location: Location) -> IResult<u32> {
7987
}
8088
}
8189

90+
fn get_trait_constraint(value: Value, location: Location) -> IResult<TraitBound> {
91+
match value {
92+
Value::TraitConstraint(bound) => Ok(bound),
93+
value => {
94+
let expected = Type::Quoted(QuotedType::TraitConstraint);
95+
Err(InterpreterError::TypeMismatch { expected, value, location })
96+
}
97+
}
98+
}
99+
100+
fn get_quoted(value: Value, location: Location) -> IResult<Rc<Tokens>> {
101+
match value {
102+
Value::Code(tokens) => Ok(tokens),
103+
value => {
104+
let expected = Type::Quoted(QuotedType::Quoted);
105+
Err(InterpreterError::TypeMismatch { expected, value, location })
106+
}
107+
}
108+
}
109+
82110
fn array_len(
83111
interner: &NodeInterner,
84112
mut arguments: Vec<(Value, Location)>,
@@ -231,7 +259,7 @@ fn slice_remove(
231259
interner: &mut NodeInterner,
232260
mut arguments: Vec<(Value, Location)>,
233261
location: Location,
234-
) -> Result<Value, InterpreterError> {
262+
) -> IResult<Value> {
235263
check_argument_count(2, &arguments, location)?;
236264

237265
let index = get_u32(arguments.pop().unwrap().0, location)? as usize;
@@ -257,7 +285,7 @@ fn slice_push_front(
257285
interner: &mut NodeInterner,
258286
mut arguments: Vec<(Value, Location)>,
259287
location: Location,
260-
) -> Result<Value, InterpreterError> {
288+
) -> IResult<Value> {
261289
check_argument_count(2, &arguments, location)?;
262290

263291
let (element, _) = arguments.pop().unwrap();
@@ -270,7 +298,7 @@ fn slice_pop_front(
270298
interner: &mut NodeInterner,
271299
mut arguments: Vec<(Value, Location)>,
272300
location: Location,
273-
) -> Result<Value, InterpreterError> {
301+
) -> IResult<Value> {
274302
check_argument_count(1, &arguments, location)?;
275303

276304
let (mut values, typ) = get_slice(interner, arguments.pop().unwrap().0, location)?;
@@ -284,7 +312,7 @@ fn slice_pop_back(
284312
interner: &mut NodeInterner,
285313
mut arguments: Vec<(Value, Location)>,
286314
location: Location,
287-
) -> Result<Value, InterpreterError> {
315+
) -> IResult<Value> {
288316
check_argument_count(1, &arguments, location)?;
289317

290318
let (mut values, typ) = get_slice(interner, arguments.pop().unwrap().0, location)?;
@@ -298,7 +326,7 @@ fn slice_insert(
298326
interner: &mut NodeInterner,
299327
mut arguments: Vec<(Value, Location)>,
300328
location: Location,
301-
) -> Result<Value, InterpreterError> {
329+
) -> IResult<Value> {
302330
check_argument_count(3, &arguments, location)?;
303331

304332
let (element, _) = arguments.pop().unwrap();
@@ -307,3 +335,54 @@ fn slice_insert(
307335
values.insert(index as usize, element);
308336
Ok(Value::Slice(values, typ))
309337
}
338+
339+
// fn as_trait_constraint(quoted: Quoted) -> TraitConstraint
340+
fn quoted_as_trait_constraint(
341+
_interner: &mut NodeInterner,
342+
mut arguments: Vec<(Value, Location)>,
343+
location: Location,
344+
) -> IResult<Value> {
345+
check_argument_count(1, &arguments, location)?;
346+
347+
let tokens = get_quoted(arguments.pop().unwrap().0, location)?;
348+
let quoted = tokens.as_ref().clone();
349+
350+
let trait_bound = parser::trait_bound().parse(quoted).map_err(|mut errors| {
351+
let error = errors.swap_remove(0);
352+
let rule = "a trait constraint";
353+
InterpreterError::FailedToParseMacro { error, tokens, rule, file: location.file }
354+
})?;
355+
356+
Ok(Value::TraitConstraint(trait_bound))
357+
}
358+
359+
// fn constraint_hash(constraint: TraitConstraint) -> Field
360+
fn trait_constraint_hash(
361+
_interner: &mut NodeInterner,
362+
mut arguments: Vec<(Value, Location)>,
363+
location: Location,
364+
) -> IResult<Value> {
365+
check_argument_count(1, &arguments, location)?;
366+
367+
let bound = get_trait_constraint(arguments.pop().unwrap().0, location)?;
368+
369+
let mut hasher = std::collections::hash_map::DefaultHasher::new();
370+
bound.hash(&mut hasher);
371+
let hash = hasher.finish();
372+
373+
Ok(Value::Field((hash as u128).into()))
374+
}
375+
376+
// fn constraint_eq(constraint_a: TraitConstraint, constraint_b: TraitConstraint) -> bool
377+
fn trait_constraint_eq(
378+
_interner: &mut NodeInterner,
379+
mut arguments: Vec<(Value, Location)>,
380+
location: Location,
381+
) -> IResult<Value> {
382+
check_argument_count(2, &arguments, location)?;
383+
384+
let constraint_b = get_trait_constraint(arguments.pop().unwrap().0, location)?;
385+
let constraint_a = get_trait_constraint(arguments.pop().unwrap().0, location)?;
386+
387+
Ok(Value::Bool(constraint_a == constraint_b))
388+
}

0 commit comments

Comments
 (0)