From ff67973b0fef3e9f6fad33455127b4b7fbb57d28 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 13 Aug 2024 15:19:05 -0300 Subject: [PATCH 1/3] Add `Type::get_trait_impl` --- .../src/hir/comptime/interpreter/builtin.rs | 31 +++++++++++++++++++ .../noirc_frontend/src/hir/comptime/value.rs | 12 ++++++- compiler/noirc_frontend/src/hir_def/types.rs | 2 ++ compiler/noirc_frontend/src/lexer/token.rs | 3 ++ .../noirc_frontend/src/parser/parser/types.rs | 6 ++++ noir_stdlib/src/meta/typ.nr | 3 ++ .../comptime_type/src/main.nr | 4 +++ .../lsp/src/requests/completion/builtins.rs | 2 ++ 8 files changed, 62 insertions(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index ef7b9f2be55..2115d854dd3 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -93,6 +93,9 @@ impl<'local, 'context> Interpreter<'local, 'context> { "type_as_struct" => type_as_struct(arguments, return_type, location), "type_as_tuple" => type_as_tuple(arguments, return_type, location), "type_eq" => type_eq(arguments, location), + "type_get_trait_impl" => { + type_get_trait_impl(interner, arguments, return_type, location) + } "type_implements" => type_implements(interner, arguments, location), "type_is_bool" => type_is_bool(arguments, location), "type_is_field" => type_is_field(arguments, location), @@ -507,6 +510,34 @@ fn type_eq(arguments: Vec<(Value, Location)>, location: Location) -> IResult Option +fn type_get_trait_impl( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + let (typ, constraint) = check_two_arguments(arguments, location)?; + + let typ = get_type(typ)?; + let (trait_id, generics) = get_trait_constraint(constraint)?; + + let option_value = if let Ok((trait_impl_kind, _)) = + interner.try_lookup_trait_implementation(&typ, trait_id, &generics) + { + match trait_impl_kind { + crate::node_interner::TraitImplKind::Normal(trait_impl_id) => { + Some(Value::TraitImpl(trait_impl_id)) + } + crate::node_interner::TraitImplKind::Assumed { .. } => None, + } + } else { + None + }; + + option(return_type, option_value) +} + // fn implements(self, constraint: TraitConstraint) -> bool fn type_implements( interner: &NodeInterner, diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index d5408309e55..52ee087c72d 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -14,7 +14,7 @@ use crate::{ Expression, ExpressionKind, HirExpression, HirLiteral, Literal, NodeInterner, Path, StructId, }, - node_interner::{ExprId, FuncId, TraitId}, + node_interner::{ExprId, FuncId, TraitId, TraitImplId}, parser::{self, NoirParser, TopLevelStatement}, token::{SpannedToken, Token, Tokens}, QuotedType, Shared, Type, TypeBindings, @@ -53,6 +53,7 @@ pub enum Value { StructDefinition(StructId), TraitConstraint(TraitId, /* trait generics */ Vec), TraitDefinition(TraitId), + TraitImpl(TraitImplId), FunctionDefinition(FuncId), ModuleDefinition(ModuleId), Type(Type), @@ -100,6 +101,7 @@ impl Value { } Value::TraitConstraint { .. } => Type::Quoted(QuotedType::TraitConstraint), Value::TraitDefinition(_) => Type::Quoted(QuotedType::TraitDefinition), + Value::TraitImpl(_) => Type::Quoted(QuotedType::TraitImpl), Value::FunctionDefinition(_) => Type::Quoted(QuotedType::FunctionDefinition), Value::ModuleDefinition(_) => Type::Quoted(QuotedType::Module), Value::Type(_) => Type::Quoted(QuotedType::Type), @@ -230,6 +232,7 @@ impl Value { | Value::StructDefinition(_) | Value::TraitConstraint(..) | Value::TraitDefinition(_) + | Value::TraitImpl(_) | Value::FunctionDefinition(_) | Value::Zeroed(_) | Value::Type(_) @@ -353,6 +356,7 @@ impl Value { | Value::StructDefinition(_) | Value::TraitConstraint(..) | Value::TraitDefinition(_) + | Value::TraitImpl(_) | Value::FunctionDefinition(_) | Value::Zeroed(_) | Value::Type(_) @@ -528,6 +532,12 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> { let trait_ = self.interner.get_trait(*trait_id); write!(f, "{}", trait_.name) } + Value::TraitImpl(trait_impl_id) => { + let trait_impl = self.interner.get_trait_implementation(*trait_impl_id); + let trait_impl = trait_impl.borrow(); + // TODO: what's a good display for a trait impl? + write!(f, "{}", trait_impl.ident) + } Value::FunctionDefinition(function_id) => { write!(f, "{}", self.interner.function_name(function_id)) } diff --git a/compiler/noirc_frontend/src/hir_def/types.rs b/compiler/noirc_frontend/src/hir_def/types.rs index 177d23c74dd..979263a26f6 100644 --- a/compiler/noirc_frontend/src/hir_def/types.rs +++ b/compiler/noirc_frontend/src/hir_def/types.rs @@ -146,6 +146,7 @@ pub enum QuotedType { StructDefinition, TraitConstraint, TraitDefinition, + TraitImpl, FunctionDefinition, Module, } @@ -727,6 +728,7 @@ impl std::fmt::Display for QuotedType { QuotedType::StructDefinition => write!(f, "StructDefinition"), QuotedType::TraitDefinition => write!(f, "TraitDefinition"), QuotedType::TraitConstraint => write!(f, "TraitConstraint"), + QuotedType::TraitImpl => write!(f, "TraitImpl"), QuotedType::FunctionDefinition => write!(f, "FunctionDefinition"), QuotedType::Module => write!(f, "Module"), } diff --git a/compiler/noirc_frontend/src/lexer/token.rs b/compiler/noirc_frontend/src/lexer/token.rs index 4222d2b585f..c4145c62791 100644 --- a/compiler/noirc_frontend/src/lexer/token.rs +++ b/compiler/noirc_frontend/src/lexer/token.rs @@ -925,6 +925,7 @@ pub enum Keyword { Trait, TraitConstraint, TraitDefinition, + TraitImpl, Type, TypeType, Unchecked, @@ -977,6 +978,7 @@ impl fmt::Display for Keyword { Keyword::Trait => write!(f, "trait"), Keyword::TraitConstraint => write!(f, "TraitConstraint"), Keyword::TraitDefinition => write!(f, "TraitDefinition"), + Keyword::TraitImpl => write!(f, "TraitImpl"), Keyword::Type => write!(f, "type"), Keyword::TypeType => write!(f, "Type"), Keyword::Unchecked => write!(f, "unchecked"), @@ -1031,6 +1033,7 @@ impl Keyword { "trait" => Keyword::Trait, "TraitConstraint" => Keyword::TraitConstraint, "TraitDefinition" => Keyword::TraitDefinition, + "TraitImpl" => Keyword::TraitImpl, "type" => Keyword::Type, "Type" => Keyword::TypeType, "StructDefinition" => Keyword::StructDefinition, diff --git a/compiler/noirc_frontend/src/parser/parser/types.rs b/compiler/noirc_frontend/src/parser/parser/types.rs index 7c551ca96d1..7644c451dff 100644 --- a/compiler/noirc_frontend/src/parser/parser/types.rs +++ b/compiler/noirc_frontend/src/parser/parser/types.rs @@ -31,6 +31,7 @@ pub(super) fn parse_type_inner<'a>( struct_definition_type(), trait_constraint_type(), trait_definition_type(), + trait_impl_type(), function_definition_type(), module_type(), top_level_item_type(), @@ -107,6 +108,11 @@ pub(super) fn trait_definition_type() -> impl NoirParser { }) } +pub(super) fn trait_impl_type() -> impl NoirParser { + keyword(Keyword::TraitImpl) + .map_with_span(|_, span| UnresolvedTypeData::Quoted(QuotedType::TraitImpl).with_span(span)) +} + pub(super) fn function_definition_type() -> impl NoirParser { keyword(Keyword::FunctionDefinition).map_with_span(|_, span| { UnresolvedTypeData::Quoted(QuotedType::FunctionDefinition).with_span(span) diff --git a/noir_stdlib/src/meta/typ.nr b/noir_stdlib/src/meta/typ.nr index ad669e93c0a..67ad2a96739 100644 --- a/noir_stdlib/src/meta/typ.nr +++ b/noir_stdlib/src/meta/typ.nr @@ -20,6 +20,9 @@ impl Type { #[builtin(type_as_tuple)] fn as_tuple(self) -> Option<[Type]> {} + #[builtin(type_get_trait_impl)] + fn get_trait_impl(self, constraint: TraitConstraint) -> Option {} + #[builtin(type_implements)] fn implements(self, constraint: TraitConstraint) -> bool {} diff --git a/test_programs/compile_success_empty/comptime_type/src/main.nr b/test_programs/compile_success_empty/comptime_type/src/main.nr index 170292b0e37..f0b53a392ed 100644 --- a/test_programs/compile_success_empty/comptime_type/src/main.nr +++ b/test_programs/compile_success_empty/comptime_type/src/main.nr @@ -108,6 +108,8 @@ fn main() { let some_trait_field = quote { SomeTrait }.as_trait_constraint(); assert(!struct_implements_some_trait.implements(some_trait_field)); assert(!struct_does_not_implement_some_trait.implements(some_trait_field)); + + let _trait_impl = struct_implements_some_trait.get_trait_impl(some_trait_i32).unwrap(); } } @@ -117,5 +119,7 @@ fn function_with_where(_x: T) where T: SomeTrait { let t = quote { T }.as_type(); let some_trait_i32 = quote { SomeTrait }.as_trait_constraint(); assert(t.implements(some_trait_i32)); + + assert(t.get_trait_impl(some_trait_i32).is_none()); } } diff --git a/tooling/lsp/src/requests/completion/builtins.rs b/tooling/lsp/src/requests/completion/builtins.rs index 070be109f13..00f7717046c 100644 --- a/tooling/lsp/src/requests/completion/builtins.rs +++ b/tooling/lsp/src/requests/completion/builtins.rs @@ -14,6 +14,7 @@ pub(super) fn keyword_builtin_type(keyword: &Keyword) -> Option<&'static str> { Keyword::StructDefinition => Some("StructDefinition"), Keyword::TraitConstraint => Some("TraitConstraint"), Keyword::TraitDefinition => Some("TraitDefinition"), + Keyword::TraitImpl => Some("TraitImpl"), Keyword::TypeType => Some("Type"), Keyword::As @@ -116,6 +117,7 @@ pub(super) fn keyword_builtin_function(keyword: &Keyword) -> Option Date: Tue, 13 Aug 2024 16:08:26 -0300 Subject: [PATCH 2/3] Shorten code --- .../src/hir/comptime/interpreter/builtin.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 2115d854dd3..12bc6fe2c62 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -23,7 +23,7 @@ use crate::{ hir::comptime::{errors::IResult, value::add_token_spans, InterpreterError, Value}, hir_def::function::FunctionBody, macros_api::{ModuleDefId, NodeInterner, Signedness}, - node_interner::DefinitionKind, + node_interner::{DefinitionKind, TraitImplKind}, parser::{self}, token::{SpannedToken, Token}, QuotedType, Shared, Type, @@ -522,17 +522,9 @@ fn type_get_trait_impl( let typ = get_type(typ)?; let (trait_id, generics) = get_trait_constraint(constraint)?; - let option_value = if let Ok((trait_impl_kind, _)) = - interner.try_lookup_trait_implementation(&typ, trait_id, &generics) - { - match trait_impl_kind { - crate::node_interner::TraitImplKind::Normal(trait_impl_id) => { - Some(Value::TraitImpl(trait_impl_id)) - } - crate::node_interner::TraitImplKind::Assumed { .. } => None, - } - } else { - None + let option_value = match interner.try_lookup_trait_implementation(&typ, trait_id, &generics) { + Ok((TraitImplKind::Normal(trait_impl_id), _)) => Some(Value::TraitImpl(trait_impl_id)), + _ => None, }; option(return_type, option_value) From 26d01f2b81c89a21af9d09888b3b6d8a0fc6f65e Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 13 Aug 2024 16:40:06 -0300 Subject: [PATCH 3/3] Display for Value::TraitImpl --- .../noirc_frontend/src/hir/comptime/value.rs | 62 ++++++++++++++++--- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index 52ee087c72d..d65c2bb7dcc 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -9,7 +9,10 @@ use noirc_errors::{Location, Span}; use crate::{ ast::{ArrayLiteral, ConstructorExpression, Ident, IntegerBitSize, Signedness}, hir::def_map::ModuleId, - hir_def::expr::{HirArrayLiteral, HirConstructorExpression, HirIdent, HirLambda, ImplKind}, + hir_def::{ + expr::{HirArrayLiteral, HirConstructorExpression, HirIdent, HirLambda, ImplKind}, + traits::TraitConstraint, + }, macros_api::{ Expression, ExpressionKind, HirExpression, HirLiteral, Literal, NodeInterner, Path, StructId, @@ -520,13 +523,7 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> { write!(f, "{}", def.name) } Value::TraitConstraint(trait_id, generics) => { - let trait_ = self.interner.get_trait(*trait_id); - let generic_string = vecmap(generics, ToString::to_string).join(", "); - if generics.is_empty() { - write!(f, "{}", trait_.name) - } else { - write!(f, "{}<{generic_string}>", trait_.name) - } + write!(f, "{}", display_trait_id_and_generics(self.interner, trait_id, generics)) } Value::TraitDefinition(trait_id) => { let trait_ = self.interner.get_trait(*trait_id); @@ -535,8 +532,30 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> { Value::TraitImpl(trait_impl_id) => { let trait_impl = self.interner.get_trait_implementation(*trait_impl_id); let trait_impl = trait_impl.borrow(); - // TODO: what's a good display for a trait impl? - write!(f, "{}", trait_impl.ident) + + let generic_string = + vecmap(&trait_impl.trait_generics, ToString::to_string).join(", "); + let generic_string = if generic_string.is_empty() { + generic_string + } else { + format!("<{}>", generic_string) + }; + + let where_clause = vecmap(&trait_impl.where_clause, |trait_constraint| { + display_trait_constraint(self.interner, trait_constraint) + }); + let where_clause = where_clause.join(", "); + let where_clause = if where_clause.is_empty() { + where_clause + } else { + format!(" where {}", where_clause) + }; + + write!( + f, + "impl {}{} for {}{}", + trait_impl.ident, generic_string, trait_impl.typ, where_clause + ) } Value::FunctionDefinition(function_id) => { write!(f, "{}", self.interner.function_name(function_id)) @@ -548,3 +567,26 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> { } } } + +fn display_trait_id_and_generics( + interner: &NodeInterner, + trait_id: &TraitId, + generics: &Vec, +) -> String { + let trait_ = interner.get_trait(*trait_id); + let generic_string = vecmap(generics, ToString::to_string).join(", "); + if generics.is_empty() { + format!("{}", trait_.name) + } else { + format!("{}<{generic_string}>", trait_.name) + } +} + +fn display_trait_constraint(interner: &NodeInterner, trait_constraint: &TraitConstraint) -> String { + let trait_constraint_string = display_trait_id_and_generics( + interner, + &trait_constraint.trait_id, + &trait_constraint.trait_generics, + ); + format!("{}: {}", trait_constraint.typ, trait_constraint_string) +}