Skip to content

Commit

Permalink
feat: add TraitImpl::trait_generic_args and TraitImpl::methods (#…
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
asterite authored Aug 14, 2024
1 parent 03ba6dd commit 8c7e493
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 57 deletions.
43 changes: 41 additions & 2 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use acvm::{AcirField, FieldElement};
use builtin_helpers::{
check_argument_count, check_function_not_yet_resolved, check_one_argument,
check_three_arguments, check_two_arguments, get_expr, get_function_def, get_module, get_quoted,
get_slice, get_struct, get_trait_constraint, get_trait_def, get_tuple, get_type, get_u32,
hir_pattern_to_tokens, mutate_func_meta_type, parse, parse_tokens,
get_slice, get_struct, get_trait_constraint, get_trait_def, get_trait_impl, get_tuple,
get_type, get_u32, hir_pattern_to_tokens, mutate_func_meta_type, parse, parse_tokens,
replace_func_meta_parameters, replace_func_meta_return_type,
};
use iter_extended::{try_vecmap, vecmap};
Expand Down Expand Up @@ -86,6 +86,10 @@ impl<'local, 'context> Interpreter<'local, 'context> {
}
"trait_def_eq" => trait_def_eq(interner, arguments, location),
"trait_def_hash" => trait_def_hash(interner, arguments, location),
"trait_impl_methods" => trait_impl_methods(interner, arguments, location),
"trait_impl_trait_generic_args" => {
trait_impl_trait_generic_args(interner, arguments, location)
}
"type_as_array" => type_as_array(arguments, return_type, location),
"type_as_constant" => type_as_constant(arguments, return_type, location),
"type_as_integer" => type_as_integer(arguments, return_type, location),
Expand Down Expand Up @@ -630,6 +634,41 @@ fn trait_def_eq(
Ok(Value::Bool(id_a == id_b))
}

// fn methods(self) -> [FunctionDefinition]
fn trait_impl_methods(
interner: &mut NodeInterner,
arguments: Vec<(Value, Location)>,
location: Location,
) -> IResult<Value> {
let argument = check_one_argument(arguments, location)?;

let trait_impl_id = get_trait_impl(argument)?;
let trait_impl = interner.get_trait_implementation(trait_impl_id);
let trait_impl = trait_impl.borrow();
let methods =
trait_impl.methods.iter().map(|func_id| Value::FunctionDefinition(*func_id)).collect();
let slice_type = Type::Slice(Box::new(Type::Quoted(QuotedType::FunctionDefinition)));

Ok(Value::Slice(methods, slice_type))
}

// fn trait_generic_args(self) -> [Type]
fn trait_impl_trait_generic_args(
interner: &mut NodeInterner,
arguments: Vec<(Value, Location)>,
location: Location,
) -> IResult<Value> {
let argument = check_one_argument(arguments, location)?;

let trait_impl_id = get_trait_impl(argument)?;
let trait_impl = interner.get_trait_implementation(trait_impl_id);
let trait_impl = trait_impl.borrow();
let trait_generics = trait_impl.trait_generics.iter().map(|t| Value::Type(t.clone())).collect();
let slice_type = Type::Slice(Box::new(Type::Quoted(QuotedType::Type)));

Ok(Value::Slice(trait_generics, slice_type))
}

// fn zeroed<T>() -> T
fn zeroed(return_type: Type) -> IResult<Value> {
match return_type {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
stmt::HirPattern,
},
macros_api::{NodeInterner, StructId},
node_interner::{FuncId, TraitId},
node_interner::{FuncId, TraitId, TraitImplId},
parser::NoirParser,
token::{Token, Tokens},
QuotedType, Type,
Expand Down Expand Up @@ -77,8 +77,7 @@ pub(crate) fn get_array(
value => {
let type_var = Box::new(interner.next_type_variable());
let expected = Type::Array(type_var.clone(), type_var);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
type_mismatch(value, expected, location)
}
}
}
Expand All @@ -92,8 +91,7 @@ pub(crate) fn get_slice(
value => {
let type_var = Box::new(interner.next_type_variable());
let expected = Type::Slice(type_var);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
type_mismatch(value, expected, location)
}
}
}
Expand All @@ -107,19 +105,15 @@ pub(crate) fn get_tuple(
value => {
let type_var = interner.next_type_variable();
let expected = Type::Tuple(vec![type_var]);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
type_mismatch(value, expected, location)
}
}
}

pub(crate) fn get_field((value, location): (Value, Location)) -> IResult<FieldElement> {
match value {
Value::Field(value) => Ok(value),
value => {
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected: Type::FieldElement, actual, location })
}
value => type_mismatch(value, Type::FieldElement, location),
}
}

Expand All @@ -128,8 +122,7 @@ pub(crate) fn get_u8((value, location): (Value, Location)) -> IResult<u8> {
Value::U8(value) => Ok(value),
value => {
let expected = Type::Integer(Signedness::Unsigned, IntegerBitSize::Eight);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
type_mismatch(value, expected, location)
}
}
}
Expand All @@ -139,53 +132,36 @@ pub(crate) fn get_u32((value, location): (Value, Location)) -> IResult<u32> {
Value::U32(value) => Ok(value),
value => {
let expected = Type::Integer(Signedness::Unsigned, IntegerBitSize::ThirtyTwo);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
type_mismatch(value, expected, location)
}
}
}

pub(crate) fn get_expr((value, location): (Value, Location)) -> IResult<ExpressionKind> {
match value {
Value::Expr(expr) => Ok(expr),
value => {
let expected = Type::Quoted(QuotedType::Expr);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
value => type_mismatch(value, Type::Quoted(QuotedType::Expr), location),
}
}

pub(crate) fn get_function_def((value, location): (Value, Location)) -> IResult<FuncId> {
match value {
Value::FunctionDefinition(id) => Ok(id),
value => {
let expected = Type::Quoted(QuotedType::FunctionDefinition);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
value => type_mismatch(value, Type::Quoted(QuotedType::FunctionDefinition), location),
}
}

pub(crate) fn get_module((value, location): (Value, Location)) -> IResult<ModuleId> {
match value {
Value::ModuleDefinition(module_id) => Ok(module_id),
value => {
let expected = Type::Quoted(QuotedType::Module);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
value => type_mismatch(value, Type::Quoted(QuotedType::Module), location),
}
}

pub(crate) fn get_struct((value, location): (Value, Location)) -> IResult<StructId> {
match value {
Value::StructDefinition(id) => Ok(id),
_ => {
let expected = Type::Quoted(QuotedType::StructDefinition);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, location, actual })
}
_ => type_mismatch(value, Type::Quoted(QuotedType::StructDefinition), location),
}
}

Expand All @@ -194,47 +170,43 @@ pub(crate) fn get_trait_constraint(
) -> IResult<(TraitId, Vec<Type>)> {
match value {
Value::TraitConstraint(trait_id, generics) => Ok((trait_id, generics)),
value => {
let expected = Type::Quoted(QuotedType::TraitConstraint);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
value => type_mismatch(value, Type::Quoted(QuotedType::TraitConstraint), location),
}
}

pub(crate) fn get_trait_def((value, location): (Value, Location)) -> IResult<TraitId> {
match value {
Value::TraitDefinition(id) => Ok(id),
value => {
let expected = Type::Quoted(QuotedType::TraitDefinition);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
value => type_mismatch(value, Type::Quoted(QuotedType::TraitDefinition), location),
}
}

pub(crate) fn get_trait_impl((value, location): (Value, Location)) -> IResult<TraitImplId> {
match value {
Value::TraitImpl(id) => Ok(id),
value => type_mismatch(value, Type::Quoted(QuotedType::TraitImpl), location),
}
}

pub(crate) fn get_type((value, location): (Value, Location)) -> IResult<Type> {
match value {
Value::Type(typ) => Ok(typ),
value => {
let expected = Type::Quoted(QuotedType::Type);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
value => type_mismatch(value, Type::Quoted(QuotedType::Type), location),
}
}

pub(crate) fn get_quoted((value, location): (Value, Location)) -> IResult<Rc<Vec<Token>>> {
match value {
Value::Quoted(tokens) => Ok(tokens),
value => {
let expected = Type::Quoted(QuotedType::Quoted);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
value => type_mismatch(value, Type::Quoted(QuotedType::Quoted), location),
}
}

fn type_mismatch<T>(value: Value, expected: Type, location: Location) -> IResult<T> {
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}

pub(crate) fn hir_pattern_to_tokens(
interner: &NodeInterner,
hir_pattern: &HirPattern,
Expand Down
1 change: 1 addition & 0 deletions noir_stdlib/src/meta/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod module;
mod struct_def;
mod trait_constraint;
mod trait_def;
mod trait_impl;
mod typ;
mod quoted;

Expand Down
7 changes: 7 additions & 0 deletions noir_stdlib/src/meta/trait_impl.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
impl TraitImpl {
#[builtin(trait_impl_trait_generic_args)]
fn trait_generic_args(self) -> [Type] {}

#[builtin(trait_impl_methods)]
fn methods(self) -> [FunctionDefinition] {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "comptime_trait_impl"
type = "bin"
authors = [""]
compiler_version = ">=0.31.0"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use std::meta::type_of;

trait SomeTrait<X, Y> {
fn foo();
}
struct SomeStruct {

}

impl SomeTrait<i32, i64> for SomeStruct {
fn foo() {}
}

fn main() {
comptime
{
let some_struct = quote { SomeStruct }.as_type();
let some_trait = quote { SomeTrait<i32, i64> }.as_trait_constraint();
let trait_impl = some_struct.get_trait_impl(some_trait).unwrap();

// Check TraitImpl::trait_generic_args
let trait_generic_args = trait_impl.trait_generic_args();
assert_eq(trait_generic_args.len(), 2);
assert_eq(trait_generic_args[0], quote { i32 }.as_type());
assert_eq(trait_generic_args[1], quote { i64 }.as_type());

// Check TraitImpl::methods
let methods = trait_impl.methods();
assert_eq(methods.len(), 1);
assert_eq(methods[0].name(), quote { foo });
}
}

0 comments on commit 8c7e493

Please sign in to comment.