Skip to content

Commit 8c7e493

Browse files
authored
feat: add TraitImpl::trait_generic_args and TraitImpl::methods (#5722)
# Description ## Problem Part of #5668 ## Summary ## Additional Context ## 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 03ba6dd commit 8c7e493

6 files changed

Lines changed: 115 additions & 57 deletions

File tree

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

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use acvm::{AcirField, FieldElement};
77
use builtin_helpers::{
88
check_argument_count, check_function_not_yet_resolved, check_one_argument,
99
check_three_arguments, check_two_arguments, get_expr, get_function_def, get_module, get_quoted,
10-
get_slice, get_struct, get_trait_constraint, get_trait_def, get_tuple, get_type, get_u32,
11-
hir_pattern_to_tokens, mutate_func_meta_type, parse, parse_tokens,
10+
get_slice, get_struct, get_trait_constraint, get_trait_def, get_trait_impl, get_tuple,
11+
get_type, get_u32, hir_pattern_to_tokens, mutate_func_meta_type, parse, parse_tokens,
1212
replace_func_meta_parameters, replace_func_meta_return_type,
1313
};
1414
use iter_extended::{try_vecmap, vecmap};
@@ -86,6 +86,10 @@ impl<'local, 'context> Interpreter<'local, 'context> {
8686
}
8787
"trait_def_eq" => trait_def_eq(interner, arguments, location),
8888
"trait_def_hash" => trait_def_hash(interner, arguments, location),
89+
"trait_impl_methods" => trait_impl_methods(interner, arguments, location),
90+
"trait_impl_trait_generic_args" => {
91+
trait_impl_trait_generic_args(interner, arguments, location)
92+
}
8993
"type_as_array" => type_as_array(arguments, return_type, location),
9094
"type_as_constant" => type_as_constant(arguments, return_type, location),
9195
"type_as_integer" => type_as_integer(arguments, return_type, location),
@@ -630,6 +634,41 @@ fn trait_def_eq(
630634
Ok(Value::Bool(id_a == id_b))
631635
}
632636

637+
// fn methods(self) -> [FunctionDefinition]
638+
fn trait_impl_methods(
639+
interner: &mut NodeInterner,
640+
arguments: Vec<(Value, Location)>,
641+
location: Location,
642+
) -> IResult<Value> {
643+
let argument = check_one_argument(arguments, location)?;
644+
645+
let trait_impl_id = get_trait_impl(argument)?;
646+
let trait_impl = interner.get_trait_implementation(trait_impl_id);
647+
let trait_impl = trait_impl.borrow();
648+
let methods =
649+
trait_impl.methods.iter().map(|func_id| Value::FunctionDefinition(*func_id)).collect();
650+
let slice_type = Type::Slice(Box::new(Type::Quoted(QuotedType::FunctionDefinition)));
651+
652+
Ok(Value::Slice(methods, slice_type))
653+
}
654+
655+
// fn trait_generic_args(self) -> [Type]
656+
fn trait_impl_trait_generic_args(
657+
interner: &mut NodeInterner,
658+
arguments: Vec<(Value, Location)>,
659+
location: Location,
660+
) -> IResult<Value> {
661+
let argument = check_one_argument(arguments, location)?;
662+
663+
let trait_impl_id = get_trait_impl(argument)?;
664+
let trait_impl = interner.get_trait_implementation(trait_impl_id);
665+
let trait_impl = trait_impl.borrow();
666+
let trait_generics = trait_impl.trait_generics.iter().map(|t| Value::Type(t.clone())).collect();
667+
let slice_type = Type::Slice(Box::new(Type::Quoted(QuotedType::Type)));
668+
669+
Ok(Value::Slice(trait_generics, slice_type))
670+
}
671+
633672
// fn zeroed<T>() -> T
634673
fn zeroed(return_type: Type) -> IResult<Value> {
635674
match return_type {

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

Lines changed: 27 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::{
1414
stmt::HirPattern,
1515
},
1616
macros_api::{NodeInterner, StructId},
17-
node_interner::{FuncId, TraitId},
17+
node_interner::{FuncId, TraitId, TraitImplId},
1818
parser::NoirParser,
1919
token::{Token, Tokens},
2020
QuotedType, Type,
@@ -77,8 +77,7 @@ pub(crate) fn get_array(
7777
value => {
7878
let type_var = Box::new(interner.next_type_variable());
7979
let expected = Type::Array(type_var.clone(), type_var);
80-
let actual = value.get_type().into_owned();
81-
Err(InterpreterError::TypeMismatch { expected, actual, location })
80+
type_mismatch(value, expected, location)
8281
}
8382
}
8483
}
@@ -92,8 +91,7 @@ pub(crate) fn get_slice(
9291
value => {
9392
let type_var = Box::new(interner.next_type_variable());
9493
let expected = Type::Slice(type_var);
95-
let actual = value.get_type().into_owned();
96-
Err(InterpreterError::TypeMismatch { expected, actual, location })
94+
type_mismatch(value, expected, location)
9795
}
9896
}
9997
}
@@ -107,19 +105,15 @@ pub(crate) fn get_tuple(
107105
value => {
108106
let type_var = interner.next_type_variable();
109107
let expected = Type::Tuple(vec![type_var]);
110-
let actual = value.get_type().into_owned();
111-
Err(InterpreterError::TypeMismatch { expected, actual, location })
108+
type_mismatch(value, expected, location)
112109
}
113110
}
114111
}
115112

116113
pub(crate) fn get_field((value, location): (Value, Location)) -> IResult<FieldElement> {
117114
match value {
118115
Value::Field(value) => Ok(value),
119-
value => {
120-
let actual = value.get_type().into_owned();
121-
Err(InterpreterError::TypeMismatch { expected: Type::FieldElement, actual, location })
122-
}
116+
value => type_mismatch(value, Type::FieldElement, location),
123117
}
124118
}
125119

@@ -128,8 +122,7 @@ pub(crate) fn get_u8((value, location): (Value, Location)) -> IResult<u8> {
128122
Value::U8(value) => Ok(value),
129123
value => {
130124
let expected = Type::Integer(Signedness::Unsigned, IntegerBitSize::Eight);
131-
let actual = value.get_type().into_owned();
132-
Err(InterpreterError::TypeMismatch { expected, actual, location })
125+
type_mismatch(value, expected, location)
133126
}
134127
}
135128
}
@@ -139,53 +132,36 @@ pub(crate) fn get_u32((value, location): (Value, Location)) -> IResult<u32> {
139132
Value::U32(value) => Ok(value),
140133
value => {
141134
let expected = Type::Integer(Signedness::Unsigned, IntegerBitSize::ThirtyTwo);
142-
let actual = value.get_type().into_owned();
143-
Err(InterpreterError::TypeMismatch { expected, actual, location })
135+
type_mismatch(value, expected, location)
144136
}
145137
}
146138
}
147139

148140
pub(crate) fn get_expr((value, location): (Value, Location)) -> IResult<ExpressionKind> {
149141
match value {
150142
Value::Expr(expr) => Ok(expr),
151-
value => {
152-
let expected = Type::Quoted(QuotedType::Expr);
153-
let actual = value.get_type().into_owned();
154-
Err(InterpreterError::TypeMismatch { expected, actual, location })
155-
}
143+
value => type_mismatch(value, Type::Quoted(QuotedType::Expr), location),
156144
}
157145
}
158146

159147
pub(crate) fn get_function_def((value, location): (Value, Location)) -> IResult<FuncId> {
160148
match value {
161149
Value::FunctionDefinition(id) => Ok(id),
162-
value => {
163-
let expected = Type::Quoted(QuotedType::FunctionDefinition);
164-
let actual = value.get_type().into_owned();
165-
Err(InterpreterError::TypeMismatch { expected, actual, location })
166-
}
150+
value => type_mismatch(value, Type::Quoted(QuotedType::FunctionDefinition), location),
167151
}
168152
}
169153

170154
pub(crate) fn get_module((value, location): (Value, Location)) -> IResult<ModuleId> {
171155
match value {
172156
Value::ModuleDefinition(module_id) => Ok(module_id),
173-
value => {
174-
let expected = Type::Quoted(QuotedType::Module);
175-
let actual = value.get_type().into_owned();
176-
Err(InterpreterError::TypeMismatch { expected, actual, location })
177-
}
157+
value => type_mismatch(value, Type::Quoted(QuotedType::Module), location),
178158
}
179159
}
180160

181161
pub(crate) fn get_struct((value, location): (Value, Location)) -> IResult<StructId> {
182162
match value {
183163
Value::StructDefinition(id) => Ok(id),
184-
_ => {
185-
let expected = Type::Quoted(QuotedType::StructDefinition);
186-
let actual = value.get_type().into_owned();
187-
Err(InterpreterError::TypeMismatch { expected, location, actual })
188-
}
164+
_ => type_mismatch(value, Type::Quoted(QuotedType::StructDefinition), location),
189165
}
190166
}
191167

@@ -194,47 +170,43 @@ pub(crate) fn get_trait_constraint(
194170
) -> IResult<(TraitId, Vec<Type>)> {
195171
match value {
196172
Value::TraitConstraint(trait_id, generics) => Ok((trait_id, generics)),
197-
value => {
198-
let expected = Type::Quoted(QuotedType::TraitConstraint);
199-
let actual = value.get_type().into_owned();
200-
Err(InterpreterError::TypeMismatch { expected, actual, location })
201-
}
173+
value => type_mismatch(value, Type::Quoted(QuotedType::TraitConstraint), location),
202174
}
203175
}
204176

205177
pub(crate) fn get_trait_def((value, location): (Value, Location)) -> IResult<TraitId> {
206178
match value {
207179
Value::TraitDefinition(id) => Ok(id),
208-
value => {
209-
let expected = Type::Quoted(QuotedType::TraitDefinition);
210-
let actual = value.get_type().into_owned();
211-
Err(InterpreterError::TypeMismatch { expected, actual, location })
212-
}
180+
value => type_mismatch(value, Type::Quoted(QuotedType::TraitDefinition), location),
181+
}
182+
}
183+
184+
pub(crate) fn get_trait_impl((value, location): (Value, Location)) -> IResult<TraitImplId> {
185+
match value {
186+
Value::TraitImpl(id) => Ok(id),
187+
value => type_mismatch(value, Type::Quoted(QuotedType::TraitImpl), location),
213188
}
214189
}
215190

216191
pub(crate) fn get_type((value, location): (Value, Location)) -> IResult<Type> {
217192
match value {
218193
Value::Type(typ) => Ok(typ),
219-
value => {
220-
let expected = Type::Quoted(QuotedType::Type);
221-
let actual = value.get_type().into_owned();
222-
Err(InterpreterError::TypeMismatch { expected, actual, location })
223-
}
194+
value => type_mismatch(value, Type::Quoted(QuotedType::Type), location),
224195
}
225196
}
226197

227198
pub(crate) fn get_quoted((value, location): (Value, Location)) -> IResult<Rc<Vec<Token>>> {
228199
match value {
229200
Value::Quoted(tokens) => Ok(tokens),
230-
value => {
231-
let expected = Type::Quoted(QuotedType::Quoted);
232-
let actual = value.get_type().into_owned();
233-
Err(InterpreterError::TypeMismatch { expected, actual, location })
234-
}
201+
value => type_mismatch(value, Type::Quoted(QuotedType::Quoted), location),
235202
}
236203
}
237204

205+
fn type_mismatch<T>(value: Value, expected: Type, location: Location) -> IResult<T> {
206+
let actual = value.get_type().into_owned();
207+
Err(InterpreterError::TypeMismatch { expected, actual, location })
208+
}
209+
238210
pub(crate) fn hir_pattern_to_tokens(
239211
interner: &NodeInterner,
240212
hir_pattern: &HirPattern,

noir_stdlib/src/meta/mod.nr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod module;
88
mod struct_def;
99
mod trait_constraint;
1010
mod trait_def;
11+
mod trait_impl;
1112
mod typ;
1213
mod quoted;
1314

noir_stdlib/src/meta/trait_impl.nr

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
impl TraitImpl {
2+
#[builtin(trait_impl_trait_generic_args)]
3+
fn trait_generic_args(self) -> [Type] {}
4+
5+
#[builtin(trait_impl_methods)]
6+
fn methods(self) -> [FunctionDefinition] {}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "comptime_trait_impl"
3+
type = "bin"
4+
authors = [""]
5+
compiler_version = ">=0.31.0"
6+
7+
[dependencies]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use std::meta::type_of;
2+
3+
trait SomeTrait<X, Y> {
4+
fn foo();
5+
}
6+
struct SomeStruct {
7+
8+
}
9+
10+
impl SomeTrait<i32, i64> for SomeStruct {
11+
fn foo() {}
12+
}
13+
14+
fn main() {
15+
comptime
16+
{
17+
let some_struct = quote { SomeStruct }.as_type();
18+
let some_trait = quote { SomeTrait<i32, i64> }.as_trait_constraint();
19+
let trait_impl = some_struct.get_trait_impl(some_trait).unwrap();
20+
21+
// Check TraitImpl::trait_generic_args
22+
let trait_generic_args = trait_impl.trait_generic_args();
23+
assert_eq(trait_generic_args.len(), 2);
24+
assert_eq(trait_generic_args[0], quote { i32 }.as_type());
25+
assert_eq(trait_generic_args[1], quote { i64 }.as_type());
26+
27+
// Check TraitImpl::methods
28+
let methods = trait_impl.methods();
29+
assert_eq(methods.len(), 1);
30+
assert_eq(methods[0].name(), quote { foo });
31+
}
32+
}

0 commit comments

Comments
 (0)