From 875cfe649e76d96a2b07a25c870500543566efd1 Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Wed, 11 Sep 2024 08:46:58 -0400 Subject: [PATCH] feat: Sync from noir (#8482) Automated pull of development from the [noir](https://github.com/noir-lang/noir) programming language, a dependency of Aztec. BEGIN_COMMIT_OVERRIDE feat: Sync from aztec-packages (https://github.com/noir-lang/noir/pull/5971) feat: LSP completion function detail (https://github.com/noir-lang/noir/pull/5993) feat: add `TypedExpr::get_type` (https://github.com/noir-lang/noir/pull/5992) feat: better error message for misplaced doc comments (https://github.com/noir-lang/noir/pull/5990) fix: Error when comptime types are used in runtime code (https://github.com/noir-lang/noir/pull/5987) END_COMMIT_OVERRIDE --- .noir-sync-commit | 2 +- .../noirc_frontend/src/elaborator/types.rs | 10 +- .../src/hir/comptime/interpreter/builtin.rs | 26 +++++ .../src/hir/resolution/errors.rs | 9 ++ .../src/monomorphization/errors.rs | 7 ++ .../src/monomorphization/mod.rs | 5 +- .../noirc_frontend/src/parser/errors.rs | 14 ++- .../compiler/noirc_frontend/src/tests.rs | 11 +++ .../noir/standard_library/meta/typed_expr.md | 10 +- noir/noir-repo/noir_stdlib/src/meta/expr.nr | 98 +++++++++---------- .../noir_stdlib/src/meta/format_string.nr | 2 +- .../noir_stdlib/src/meta/function_def.nr | 26 ++--- noir/noir-repo/noir_stdlib/src/meta/module.nr | 10 +- noir/noir-repo/noir_stdlib/src/meta/quoted.nr | 14 +-- .../noir_stdlib/src/meta/struct_def.nr | 18 ++-- .../noir_stdlib/src/meta/trait_constraint.nr | 8 +- .../noir_stdlib/src/meta/trait_def.nr | 10 +- .../noir_stdlib/src/meta/trait_impl.nr | 4 +- noir/noir-repo/noir_stdlib/src/meta/typ.nr | 28 +++--- .../noir_stdlib/src/meta/typed_expr.nr | 10 +- .../noir_stdlib/src/meta/unresolved_type.nr | 2 +- .../comptime_fmt_strings/src/main.nr | 2 +- .../comptime_function_definition/src/main.nr | 2 +- .../comptime_typed_expr/Nargo.toml | 7 ++ .../comptime_typed_expr/src/main.nr | 7 ++ .../requests/completion/completion_items.rs | 48 ++++++--- .../lsp/src/requests/completion/tests.rs | 71 +++++--------- 27 files changed, 281 insertions(+), 180 deletions(-) create mode 100644 noir/noir-repo/test_programs/compile_success_empty/comptime_typed_expr/Nargo.toml create mode 100644 noir/noir-repo/test_programs/compile_success_empty/comptime_typed_expr/src/main.nr diff --git a/.noir-sync-commit b/.noir-sync-commit index 9326943a310..f2fa0b3c445 100644 --- a/.noir-sync-commit +++ b/.noir-sync-commit @@ -1 +1 @@ -d6f60d70dc41640ad84f7a968927b20818bcaf2a +3c3ed1e3d28946a02071c524dd128afe131bc3da diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs index 39ef4e0bb8e..46c779dc4ff 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs @@ -118,7 +118,15 @@ impl<'context> Elaborator<'context> { let fields = self.resolve_type_inner(*fields, kind); Type::FmtString(Box::new(resolved_size), Box::new(fields)) } - Quoted(quoted) => Type::Quoted(quoted), + Quoted(quoted) => { + let in_function = matches!(self.current_item, Some(DependencyId::Function(_))); + if in_function && !self.in_comptime_context() { + let span = typ.span; + let typ = quoted.to_string(); + self.push_err(ResolverError::ComptimeTypeInRuntimeCode { span, typ }); + } + Type::Quoted(quoted) + } Unit => Type::Unit, Unspecified => { let span = typ.span; diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 899d62ecb61..166c6479b15 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -189,6 +189,9 @@ impl<'local, 'context> Interpreter<'local, 'context> { "typed_expr_as_function_definition" => { typed_expr_as_function_definition(interner, arguments, return_type, location) } + "typed_expr_get_type" => { + typed_expr_get_type(interner, arguments, return_type, location) + } "unresolved_type_is_field" => unresolved_type_is_field(interner, arguments, location), "zeroed" => zeroed(return_type), _ => { @@ -1070,6 +1073,7 @@ fn trait_impl_trait_generic_args( Ok(Value::Slice(trait_generics, slice_type)) } +// fn as_function_definition(self) -> Option fn typed_expr_as_function_definition( interner: &NodeInterner, arguments: Vec<(Value, Location)>, @@ -1087,6 +1091,28 @@ fn typed_expr_as_function_definition( option(return_type, option_value) } +// fn get_type(self) -> Option +fn typed_expr_get_type( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + let self_argument = check_one_argument(arguments, location)?; + let typed_expr = get_typed_expr(self_argument)?; + let option_value = if let TypedExpr::ExprId(expr_id) = typed_expr { + let typ = interner.id_type(expr_id); + if typ == Type::Error { + None + } else { + Some(Value::Type(typ)) + } + } else { + None + }; + option(return_type, option_value) +} + // fn is_field(self) -> bool fn unresolved_type_is_field( interner: &NodeInterner, diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs index 5abc94b89a2..ec22c8f1986 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -126,6 +126,8 @@ pub enum ResolverError { OverflowInType { lhs: u32, op: crate::BinaryTypeOperator, rhs: u32, span: Span }, #[error("`quote` cannot be used in runtime code")] QuoteInRuntimeCode { span: Span }, + #[error("Comptime-only type `{typ}` cannot be used in runtime code")] + ComptimeTypeInRuntimeCode { typ: String, span: Span }, } impl ResolverError { @@ -513,6 +515,13 @@ impl<'a> From<&'a ResolverError> for Diagnostic { *span, ) }, + ResolverError::ComptimeTypeInRuntimeCode { typ, span } => { + Diagnostic::simple_error( + format!("Comptime-only type `{typ}` cannot be used in runtime code"), + "Comptime-only type used here".to_string(), + *span, + ) + }, } } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/errors.rs index 66db72eef55..7f4172017e2 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/errors.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/errors.rs @@ -9,6 +9,7 @@ pub enum MonomorphizationError { InternalError { message: &'static str, location: Location }, InterpreterError(InterpreterError), ComptimeFnInRuntimeCode { name: String, location: Location }, + ComptimeTypeInRuntimeCode { typ: String, location: Location }, } impl MonomorphizationError { @@ -17,6 +18,7 @@ impl MonomorphizationError { MonomorphizationError::UnknownArrayLength { location, .. } | MonomorphizationError::InternalError { location, .. } | MonomorphizationError::ComptimeFnInRuntimeCode { location, .. } + | MonomorphizationError::ComptimeTypeInRuntimeCode { location, .. } | MonomorphizationError::NoDefaultType { location, .. } => *location, MonomorphizationError::InterpreterError(error) => error.get_location(), } @@ -51,6 +53,11 @@ impl MonomorphizationError { "Comptime functions must be in a comptime block to be called".into(); return CustomDiagnostic::simple_error(message, secondary, location.span); } + MonomorphizationError::ComptimeTypeInRuntimeCode { typ, location } => { + let message = format!("Comptime-only type `{typ}` used in runtime code"); + let secondary = "Comptime type used here".into(); + return CustomDiagnostic::simple_error(message, secondary, location.span); + } }; let location = self.location(); diff --git a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs index 9357cc65c14..fd06a2b04a8 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -1056,7 +1056,10 @@ impl<'interner> Monomorphizer<'interner> { let message = "Unexpected Type::Error found during monomorphization"; return Err(MonomorphizationError::InternalError { message, location }); } - HirType::Quoted(_) => unreachable!("Tried to translate Code type into runtime code"), + HirType::Quoted(typ) => { + let typ = typ.to_string(); + return Err(MonomorphizationError::ComptimeTypeInRuntimeCode { typ, location }); + } }) } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/errors.rs index ad6f6b928ab..6ba4cb68500 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/errors.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/errors.rs @@ -1,6 +1,7 @@ use crate::ast::{Expression, IntegerBitSize}; use crate::lexer::errors::LexerErrorKind; use crate::lexer::token::Token; +use crate::token::TokenKind; use small_ord_set::SmallOrdSet; use thiserror::Error; @@ -211,8 +212,17 @@ impl<'a> From<&'a ParserError> for Diagnostic { other => Diagnostic::simple_error(format!("{other}"), String::new(), error.span), }, None => { - let primary = error.to_string(); - Diagnostic::simple_error(primary, String::new(), error.span) + if matches!( + error.found.kind(), + TokenKind::InnerDocComment | TokenKind::OuterDocComment + ) { + let primary = "This doc comment doesn't document anything".to_string(); + let secondary = "Consider changing it to a regular `//` comment".to_string(); + Diagnostic::simple_error(primary, secondary, error.span) + } else { + let primary = error.to_string(); + Diagnostic::simple_error(primary, String::new(), error.span) + } } } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs index 64c9b7471b4..414bfa5fa5b 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs @@ -3451,3 +3451,14 @@ fn constrained_reference_to_unconstrained() { panic!("Expected an error about passing a constrained reference to unconstrained"); }; } + +#[test] +fn comptime_type_in_runtime_code() { + let source = "pub fn foo(_f: FunctionDefinition) {}"; + let errors = get_program_errors(source); + assert_eq!(errors.len(), 1); + assert!(matches!( + errors[0].0, + CompilationError::ResolverError(ResolverError::ComptimeTypeInRuntimeCode { .. }) + )); +} diff --git a/noir/noir-repo/docs/docs/noir/standard_library/meta/typed_expr.md b/noir/noir-repo/docs/docs/noir/standard_library/meta/typed_expr.md index eacfd9c1230..24b23f2ec19 100644 --- a/noir/noir-repo/docs/docs/noir/standard_library/meta/typed_expr.md +++ b/noir/noir-repo/docs/docs/noir/standard_library/meta/typed_expr.md @@ -6,8 +6,14 @@ title: TypedExpr ## Methods -### as_function_definition +### get_type #include_code as_function_definition noir_stdlib/src/meta/typed_expr.nr rust -If this expression refers to a function definitions, returns it. Otherwise returns `Option::none()`. \ No newline at end of file +If this expression refers to a function definitions, returns it. Otherwise returns `Option::none()`. + +### get_type + +#include_code get_type noir_stdlib/src/meta/typed_expr.nr rust + +Returns the type of the expression, or `Option::none()` if there were errors when the expression was previously resolved. \ No newline at end of file diff --git a/noir/noir-repo/noir_stdlib/src/meta/expr.nr b/noir/noir-repo/noir_stdlib/src/meta/expr.nr index 642dbecc36b..72e1a88cea8 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/expr.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/expr.nr @@ -5,129 +5,129 @@ use crate::meta::op::BinaryOp; impl Expr { #[builtin(expr_as_array)] // docs:start:as_array - fn as_array(self) -> Option<[Expr]> {} + comptime fn as_array(self) -> Option<[Expr]> {} // docs:end:as_array #[builtin(expr_as_assert)] // docs:start:as_assert - fn as_assert(self) -> Option<(Expr, Option)> {} + comptime fn as_assert(self) -> Option<(Expr, Option)> {} // docs:end:as_assert #[builtin(expr_as_assert_eq)] // docs:start:as_assert_eq - fn as_assert_eq(self) -> Option<(Expr, Expr, Option)> {} + comptime fn as_assert_eq(self) -> Option<(Expr, Expr, Option)> {} // docs:end:as_assert_eq #[builtin(expr_as_assign)] // docs:start:as_assign - fn as_assign(self) -> Option<(Expr, Expr)> {} + comptime fn as_assign(self) -> Option<(Expr, Expr)> {} // docs:end:as_assign #[builtin(expr_as_integer)] // docs:start:as_integer - fn as_integer(self) -> Option<(Field, bool)> {} + comptime fn as_integer(self) -> Option<(Field, bool)> {} // docs:end:as_integer #[builtin(expr_as_binary_op)] // docs:start:as_binary_op - fn as_binary_op(self) -> Option<(Expr, BinaryOp, Expr)> {} + comptime fn as_binary_op(self) -> Option<(Expr, BinaryOp, Expr)> {} // docs:end:as_binary_op #[builtin(expr_as_block)] // docs:start:as_block - fn as_block(self) -> Option<[Expr]> {} + comptime fn as_block(self) -> Option<[Expr]> {} // docs:end:as_block #[builtin(expr_as_bool)] // docs:start:as_bool - fn as_bool(self) -> Option {} + comptime fn as_bool(self) -> Option {} // docs:end:as_bool #[builtin(expr_as_cast)] - fn as_cast(self) -> Option<(Expr, UnresolvedType)> {} + comptime fn as_cast(self) -> Option<(Expr, UnresolvedType)> {} #[builtin(expr_as_comptime)] // docs:start:as_comptime - fn as_comptime(self) -> Option<[Expr]> {} + comptime fn as_comptime(self) -> Option<[Expr]> {} // docs:end:as_comptime #[builtin(expr_as_function_call)] // docs:start:as_function_call - fn as_function_call(self) -> Option<(Expr, [Expr])> {} + comptime fn as_function_call(self) -> Option<(Expr, [Expr])> {} // docs:end:as_function_call #[builtin(expr_as_if)] // docs:start:as_if - fn as_if(self) -> Option<(Expr, Expr, Option)> {} + comptime fn as_if(self) -> Option<(Expr, Expr, Option)> {} // docs:end:as_if #[builtin(expr_as_index)] // docs:start:as_index - fn as_index(self) -> Option<(Expr, Expr)> {} + comptime fn as_index(self) -> Option<(Expr, Expr)> {} // docs:end:as_index #[builtin(expr_as_let)] // docs:start:as_let - fn as_let(self) -> Option<(Expr, Option, Expr)> {} + comptime fn as_let(self) -> Option<(Expr, Option, Expr)> {} // docs:end:as_let #[builtin(expr_as_member_access)] // docs:start:as_member_access - fn as_member_access(self) -> Option<(Expr, Quoted)> {} + comptime fn as_member_access(self) -> Option<(Expr, Quoted)> {} // docs:end:as_member_access #[builtin(expr_as_method_call)] // docs:start:as_method_call - fn as_method_call(self) -> Option<(Expr, Quoted, [UnresolvedType], [Expr])> {} + comptime fn as_method_call(self) -> Option<(Expr, Quoted, [UnresolvedType], [Expr])> {} // docs:end:as_method_call #[builtin(expr_as_repeated_element_array)] // docs:start:as_repeated_element_array - fn as_repeated_element_array(self) -> Option<(Expr, Expr)> {} + comptime fn as_repeated_element_array(self) -> Option<(Expr, Expr)> {} // docs:end:as_repeated_element_array #[builtin(expr_as_repeated_element_slice)] // docs:start:as_repeated_element_slice - fn as_repeated_element_slice(self) -> Option<(Expr, Expr)> {} + comptime fn as_repeated_element_slice(self) -> Option<(Expr, Expr)> {} // docs:end:as_repeated_element_slice #[builtin(expr_as_slice)] // docs:start:as_slice - fn as_slice(self) -> Option<[Expr]> {} + comptime fn as_slice(self) -> Option<[Expr]> {} // docs:end:as_slice #[builtin(expr_as_tuple)] // docs:start:as_tuple - fn as_tuple(self) -> Option<[Expr]> {} + comptime fn as_tuple(self) -> Option<[Expr]> {} // docs:end:as_tuple #[builtin(expr_as_unary_op)] // docs:start:as_unary_op - fn as_unary_op(self) -> Option<(UnaryOp, Expr)> {} + comptime fn as_unary_op(self) -> Option<(UnaryOp, Expr)> {} // docs:end:as_unary_op #[builtin(expr_as_unsafe)] // docs:start:as_unsafe - fn as_unsafe(self) -> Option<[Expr]> {} + comptime fn as_unsafe(self) -> Option<[Expr]> {} // docs:end:as_unsafe #[builtin(expr_has_semicolon)] // docs:start:has_semicolon - fn has_semicolon(self) -> bool {} + comptime fn has_semicolon(self) -> bool {} // docs:end:has_semicolon #[builtin(expr_is_break)] // docs:start:is_break - fn is_break(self) -> bool {} + comptime fn is_break(self) -> bool {} // docs:end:is_break #[builtin(expr_is_continue)] // docs:start:is_continue - fn is_continue(self) -> bool {} + comptime fn is_continue(self) -> bool {} // docs:end:is_continue // docs:start:modify - fn modify(self, f: fn[Env](Expr) -> Option) -> Expr { + comptime fn modify(self, f: fn[Env](Expr) -> Option) -> Expr { // docs:end:modify let result = modify_array(self, f); let result = result.or_else(|| modify_assert(self, f)); @@ -166,11 +166,11 @@ impl Expr { #[builtin(expr_resolve)] // docs:start:resolve - fn resolve(self, in_function: Option) -> TypedExpr {} + comptime fn resolve(self, in_function: Option) -> TypedExpr {} // docs:end:resolve } -fn modify_array(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_array(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_array().map( |exprs: [Expr]| { let exprs = modify_expressions(exprs, f); @@ -179,7 +179,7 @@ fn modify_array(expr: Expr, f: fn[Env](Expr) -> Option) -> Option(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_assert(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_assert().map( |expr: (Expr, Option)| { let (predicate, msg) = expr; @@ -190,7 +190,7 @@ fn modify_assert(expr: Expr, f: fn[Env](Expr) -> Option) -> Option(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_assert_eq(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_assert_eq().map( |expr: (Expr, Expr, Option)| { let (lhs, rhs, msg) = expr; @@ -202,7 +202,7 @@ fn modify_assert_eq(expr: Expr, f: fn[Env](Expr) -> Option) -> Option ) } -fn modify_assign(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_assign(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_assign().map( |expr: (Expr, Expr)| { let (lhs, rhs) = expr; @@ -213,7 +213,7 @@ fn modify_assign(expr: Expr, f: fn[Env](Expr) -> Option) -> Option(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_binary_op(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_binary_op().map( |expr: (Expr, BinaryOp, Expr)| { let (lhs, op, rhs) = expr; @@ -224,7 +224,7 @@ fn modify_binary_op(expr: Expr, f: fn[Env](Expr) -> Option) -> Option ) } -fn modify_block(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_block(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_block().map( |exprs: [Expr]| { let exprs = modify_expressions(exprs, f); @@ -233,7 +233,7 @@ fn modify_block(expr: Expr, f: fn[Env](Expr) -> Option) -> Option(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_cast(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_cast().map( |expr: (Expr, UnresolvedType)| { let (expr, typ) = expr; @@ -243,7 +243,7 @@ fn modify_cast(expr: Expr, f: fn[Env](Expr) -> Option) -> Option(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_comptime(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_comptime().map( |exprs: [Expr]| { let exprs = exprs.map(|expr: Expr| expr.modify(f)); @@ -252,7 +252,7 @@ fn modify_comptime(expr: Expr, f: fn[Env](Expr) -> Option) -> Option< ) } -fn modify_function_call(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_function_call(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_function_call().map( |expr: (Expr, [Expr])| { let (function, arguments) = expr; @@ -263,7 +263,7 @@ fn modify_function_call(expr: Expr, f: fn[Env](Expr) -> Option) -> Op ) } -fn modify_if(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_if(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_if().map( |expr: (Expr, Expr, Option)| { let (condition, consequence, alternative) = expr; @@ -275,7 +275,7 @@ fn modify_if(expr: Expr, f: fn[Env](Expr) -> Option) -> Option ) } -fn modify_index(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_index(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_index().map( |expr: (Expr, Expr)| { let (object, index) = expr; @@ -286,7 +286,7 @@ fn modify_index(expr: Expr, f: fn[Env](Expr) -> Option) -> Option(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_let(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_let().map( |expr: (Expr, Option, Expr)| { let (pattern, typ, expr) = expr; @@ -297,7 +297,7 @@ fn modify_let(expr: Expr, f: fn[Env](Expr) -> Option) -> Option ) } -fn modify_member_access(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_member_access(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_member_access().map( |expr: (Expr, Quoted)| { let (object, name) = expr; @@ -307,7 +307,7 @@ fn modify_member_access(expr: Expr, f: fn[Env](Expr) -> Option) -> Op ) } -fn modify_method_call(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_method_call(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_method_call().map( |expr: (Expr, Quoted, [UnresolvedType], [Expr])| { let (object, name, generics, arguments) = expr; @@ -318,7 +318,7 @@ fn modify_method_call(expr: Expr, f: fn[Env](Expr) -> Option) -> Opti ) } -fn modify_repeated_element_array(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_repeated_element_array(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_repeated_element_array().map( |expr: (Expr, Expr)| { let (expr, length) = expr; @@ -329,7 +329,7 @@ fn modify_repeated_element_array(expr: Expr, f: fn[Env](Expr) -> Option(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_repeated_element_slice(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_repeated_element_slice().map( |expr: (Expr, Expr)| { let (expr, length) = expr; @@ -340,7 +340,7 @@ fn modify_repeated_element_slice(expr: Expr, f: fn[Env](Expr) -> Option(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_slice(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_slice().map( |exprs: [Expr]| { let exprs = modify_expressions(exprs, f); @@ -349,7 +349,7 @@ fn modify_slice(expr: Expr, f: fn[Env](Expr) -> Option) -> Option(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_tuple(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_tuple().map( |exprs: [Expr]| { let exprs = modify_expressions(exprs, f); @@ -358,7 +358,7 @@ fn modify_tuple(expr: Expr, f: fn[Env](Expr) -> Option) -> Option(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_unary_op(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_unary_op().map( |expr: (UnaryOp, Expr)| { let (op, rhs) = expr; @@ -368,7 +368,7 @@ fn modify_unary_op(expr: Expr, f: fn[Env](Expr) -> Option) -> Option< ) } -fn modify_unsafe(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { +comptime fn modify_unsafe(expr: Expr, f: fn[Env](Expr) -> Option) -> Option { expr.as_unsafe().map( |exprs: [Expr]| { let exprs = exprs.map(|expr: Expr| expr.modify(f)); @@ -377,7 +377,7 @@ fn modify_unsafe(expr: Expr, f: fn[Env](Expr) -> Option) -> Option(exprs: [Expr], f: fn[Env](Expr) -> Option) -> [Expr] { +comptime fn modify_expressions(exprs: [Expr], f: fn[Env](Expr) -> Option) -> [Expr] { exprs.map(|expr: Expr| expr.modify(f)) } @@ -498,7 +498,7 @@ comptime fn new_unsafe(exprs: [Expr]) -> Expr { quote { unsafe { $exprs }}.as_expr().unwrap() } -fn join_expressions(exprs: [Expr], separator: Quoted) -> Quoted { +comptime fn join_expressions(exprs: [Expr], separator: Quoted) -> Quoted { exprs.map(|expr: Expr| expr.quoted()).join(separator) } diff --git a/noir/noir-repo/noir_stdlib/src/meta/format_string.nr b/noir/noir-repo/noir_stdlib/src/meta/format_string.nr index 44b69719efe..075a69fdafb 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/format_string.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/format_string.nr @@ -1,6 +1,6 @@ impl fmtstr { #[builtin(fmtstr_quoted_contents)] // docs:start:quoted_contents - fn quoted_contents(self) -> Quoted {} + comptime fn quoted_contents(self) -> Quoted {} // docs:end:quoted_contents } diff --git a/noir/noir-repo/noir_stdlib/src/meta/function_def.nr b/noir/noir-repo/noir_stdlib/src/meta/function_def.nr index 5ce3dbeabff..5d536d60ae1 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/function_def.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/function_def.nr @@ -1,66 +1,66 @@ impl FunctionDefinition { #[builtin(function_def_add_attribute)] // docs:start:add_attribute - fn add_attribute(self, attribute: str) {} + comptime fn add_attribute(self, attribute: str) {} // docs:end:add_attribute #[builtin(function_def_body)] // docs:start:body - fn body(self) -> Expr {} + comptime fn body(self) -> Expr {} // docs:end:body #[builtin(function_def_has_named_attribute)] // docs:start:has_named_attribute - fn has_named_attribute(self, name: Quoted) -> bool {} + comptime fn has_named_attribute(self, name: Quoted) -> bool {} // docs:end:has_named_attribute #[builtin(function_def_is_unconstrained)] // docs:start:is_unconstrained - fn is_unconstrained(self) -> bool {} + comptime fn is_unconstrained(self) -> bool {} // docs:end:is_unconstrained #[builtin(function_def_module)] // docs:start:module - fn module(self) -> Module {} + comptime fn module(self) -> Module {} // docs:end:module #[builtin(function_def_name)] // docs:start:name - fn name(self) -> Quoted {} + comptime fn name(self) -> Quoted {} // docs:end:name #[builtin(function_def_parameters)] // docs:start:parameters - fn parameters(self) -> [(Quoted, Type)] {} + comptime fn parameters(self) -> [(Quoted, Type)] {} // docs:end:parameters #[builtin(function_def_return_type)] // docs:start:return_type - fn return_type(self) -> Type {} + comptime fn return_type(self) -> Type {} // docs:end:return_type #[builtin(function_def_set_body)] // docs:start:set_body - fn set_body(self, body: Expr) {} + comptime fn set_body(self, body: Expr) {} // docs:end:set_body #[builtin(function_def_set_parameters)] // docs:start:set_parameters - fn set_parameters(self, parameters: [(Quoted, Type)]) {} + comptime fn set_parameters(self, parameters: [(Quoted, Type)]) {} // docs:end:set_parameters #[builtin(function_def_set_return_type)] // docs:start:set_return_type - fn set_return_type(self, return_type: Type) {} + comptime fn set_return_type(self, return_type: Type) {} // docs:end:set_return_type #[builtin(function_def_set_return_public)] // docs:start:set_return_public - fn set_return_public(self, public: bool) {} + comptime fn set_return_public(self, public: bool) {} // docs:end:set_return_public #[builtin(function_def_set_unconstrained)] // docs:start:set_unconstrained - fn set_unconstrained(self, value: bool) {} + comptime fn set_unconstrained(self, value: bool) {} // docs:end:set_unconstrained } diff --git a/noir/noir-repo/noir_stdlib/src/meta/module.nr b/noir/noir-repo/noir_stdlib/src/meta/module.nr index bee6612e1bf..6f936bf4c57 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/module.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/module.nr @@ -1,26 +1,26 @@ impl Module { #[builtin(module_add_item)] // docs:start:add_item - fn add_item(self, item: Quoted) {} + comptime fn add_item(self, item: Quoted) {} // docs:end:add_item #[builtin(module_has_named_attribute)] // docs:start:has_named_attribute - fn has_named_attribute(self, name: Quoted) -> bool {} + comptime fn has_named_attribute(self, name: Quoted) -> bool {} // docs:end:has_named_attribute #[builtin(module_is_contract)] // docs:start:is_contract - fn is_contract(self) -> bool {} + comptime fn is_contract(self) -> bool {} // docs:end:is_contract #[builtin(module_functions)] // docs:start:functions - fn functions(self) -> [FunctionDefinition] {} + comptime fn functions(self) -> [FunctionDefinition] {} // docs:end:functions #[builtin(module_name)] // docs:start:name - fn name(self) -> Quoted {} + comptime fn name(self) -> Quoted {} // docs:end:name } diff --git a/noir/noir-repo/noir_stdlib/src/meta/quoted.nr b/noir/noir-repo/noir_stdlib/src/meta/quoted.nr index 3fab43359c1..ff74580ce20 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/quoted.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/quoted.nr @@ -4,36 +4,36 @@ use crate::option::Option; impl Quoted { #[builtin(quoted_as_expr)] // docs:start:as_expr - fn as_expr(self) -> Option {} + comptime fn as_expr(self) -> Option {} // docs:end:as_expr #[builtin(quoted_as_module)] // docs:start:as_module - fn as_module(self) -> Option {} + comptime fn as_module(self) -> Option {} // docs:end:as_module #[builtin(quoted_as_trait_constraint)] // docs:start:as_trait_constraint - fn as_trait_constraint(self) -> TraitConstraint {} + comptime fn as_trait_constraint(self) -> TraitConstraint {} // docs:end:as_trait_constraint #[builtin(quoted_as_type)] // docs:start:as_type - fn as_type(self) -> Type {} + comptime fn as_type(self) -> Type {} // docs:end:as_type #[builtin(quoted_tokens)] // docs:start:tokens - fn tokens(self) -> [Quoted] {} + comptime fn tokens(self) -> [Quoted] {} // docs:end:tokens } impl Eq for Quoted { - fn eq(self, other: Quoted) -> bool { + comptime fn eq(self, other: Quoted) -> bool { quoted_eq(self, other) } } #[builtin(quoted_eq)] -fn quoted_eq(_first: Quoted, _second: Quoted) -> bool {} +comptime fn quoted_eq(_first: Quoted, _second: Quoted) -> bool {} diff --git a/noir/noir-repo/noir_stdlib/src/meta/struct_def.nr b/noir/noir-repo/noir_stdlib/src/meta/struct_def.nr index 5db720b91d3..e3621b3482e 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/struct_def.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/struct_def.nr @@ -1,47 +1,47 @@ impl StructDefinition { #[builtin(struct_def_add_attribute)] // docs:start:add_attribute - fn add_attribute(self, attribute: str) {} + comptime fn add_attribute(self, attribute: str) {} // docs:end:add_attribute #[builtin(struct_def_add_generic)] // docs:start:add_generic - fn add_generic(self, generic_name: str) -> Type {} + comptime fn add_generic(self, generic_name: str) -> Type {} // docs:end:add_generic /// Return a syntactic version of this struct definition as a type. /// For example, `as_type(quote { type Foo { ... } })` would return `Foo` #[builtin(struct_def_as_type)] // docs:start:as_type - fn as_type(self) -> Type {} + comptime fn as_type(self) -> Type {} // docs:end:as_type #[builtin(struct_def_has_named_attribute)] // docs:start:has_named_attribute - fn has_named_attribute(self, name: Quoted) -> bool {} + comptime fn has_named_attribute(self, name: Quoted) -> bool {} // docs:end:has_named_attribute /// Return each generic on this struct. #[builtin(struct_def_generics)] // docs:start:generics - fn generics(self) -> [Type] {} + comptime fn generics(self) -> [Type] {} // docs:end:generics /// Returns (name, type) pairs of each field in this struct. Each type is as-is /// with any generic arguments unchanged. #[builtin(struct_def_fields)] // docs:start:fields - fn fields(self) -> [(Quoted, Type)] {} + comptime fn fields(self) -> [(Quoted, Type)] {} // docs:end:fields #[builtin(struct_def_module)] // docs:start:module - fn module(self) -> Module {} + comptime fn module(self) -> Module {} // docs:end:module #[builtin(struct_def_name)] // docs:start:name - fn name(self) -> Quoted {} + comptime fn name(self) -> Quoted {} // docs:end:name /// Sets the fields of this struct to the given fields list. @@ -50,6 +50,6 @@ impl StructDefinition { /// Each name is expected to be a single identifier. #[builtin(struct_def_set_fields)] // docs:start:set_fields - fn set_fields(self, new_fields: [(Quoted, Type)]) {} + comptime fn set_fields(self, new_fields: [(Quoted, Type)]) {} // docs:end:set_fields } diff --git a/noir/noir-repo/noir_stdlib/src/meta/trait_constraint.nr b/noir/noir-repo/noir_stdlib/src/meta/trait_constraint.nr index f0276608974..b90f0b590d5 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/trait_constraint.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/trait_constraint.nr @@ -2,19 +2,19 @@ use crate::hash::{Hash, Hasher}; use crate::cmp::Eq; impl Eq for TraitConstraint { - fn eq(self, other: Self) -> bool { + comptime fn eq(self, other: Self) -> bool { constraint_eq(self, other) } } impl Hash for TraitConstraint { - fn hash(self, state: &mut H) where H: Hasher { + comptime fn hash(self, state: &mut H) where H: Hasher { state.write(constraint_hash(self)); } } #[builtin(trait_constraint_eq)] -fn constraint_eq(_first: TraitConstraint, _second: TraitConstraint) -> bool {} +comptime fn constraint_eq(_first: TraitConstraint, _second: TraitConstraint) -> bool {} #[builtin(trait_constraint_hash)] -fn constraint_hash(_constraint: TraitConstraint) -> Field {} +comptime fn constraint_hash(_constraint: TraitConstraint) -> Field {} diff --git a/noir/noir-repo/noir_stdlib/src/meta/trait_def.nr b/noir/noir-repo/noir_stdlib/src/meta/trait_def.nr index c26b571240b..51676efbc34 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/trait_def.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/trait_def.nr @@ -4,24 +4,24 @@ use crate::cmp::Eq; impl TraitDefinition { #[builtin(trait_def_as_trait_constraint)] // docs:start:as_trait_constraint - fn as_trait_constraint(_self: Self) -> TraitConstraint {} + comptime fn as_trait_constraint(_self: Self) -> TraitConstraint {} // docs:end:as_trait_constraint } impl Eq for TraitDefinition { - fn eq(self, other: Self) -> bool { + comptime fn eq(self, other: Self) -> bool { trait_def_eq(self, other) } } impl Hash for TraitDefinition { - fn hash(self, state: &mut H) where H: Hasher { + comptime fn hash(self, state: &mut H) where H: Hasher { state.write(trait_def_hash(self)); } } #[builtin(trait_def_eq)] -fn trait_def_eq(_first: TraitDefinition, _second: TraitDefinition) -> bool {} +comptime fn trait_def_eq(_first: TraitDefinition, _second: TraitDefinition) -> bool {} #[builtin(trait_def_hash)] -fn trait_def_hash(_def: TraitDefinition) -> Field {} +comptime fn trait_def_hash(_def: TraitDefinition) -> Field {} diff --git a/noir/noir-repo/noir_stdlib/src/meta/trait_impl.nr b/noir/noir-repo/noir_stdlib/src/meta/trait_impl.nr index 15b02eac6bd..6755a5c2031 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/trait_impl.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/trait_impl.nr @@ -1,11 +1,11 @@ impl TraitImpl { #[builtin(trait_impl_trait_generic_args)] // docs:start:trait_generic_args - fn trait_generic_args(self) -> [Type] {} + comptime fn trait_generic_args(self) -> [Type] {} // docs:end:trait_generic_args #[builtin(trait_impl_methods)] // docs:start:methods - fn methods(self) -> [FunctionDefinition] {} + comptime fn methods(self) -> [FunctionDefinition] {} // docs:end:methods } diff --git a/noir/noir-repo/noir_stdlib/src/meta/typ.nr b/noir/noir-repo/noir_stdlib/src/meta/typ.nr index 71bd6fd7f1c..d692f6e5a7e 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/typ.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/typ.nr @@ -3,71 +3,71 @@ use crate::option::Option; #[builtin(fresh_type_variable)] // docs:start:fresh_type_variable -pub fn fresh_type_variable() -> Type {} +pub comptime fn fresh_type_variable() -> Type {} // docs:end:fresh_type_variable impl Type { #[builtin(type_as_array)] // docs:start:as_array - fn as_array(self) -> Option<(Type, Type)> {} + comptime fn as_array(self) -> Option<(Type, Type)> {} // docs:end:as_array #[builtin(type_as_constant)] // docs:start:as_constant - fn as_constant(self) -> Option {} + comptime fn as_constant(self) -> Option {} // docs:end:as_constant #[builtin(type_as_integer)] // docs:start:as_integer - fn as_integer(self) -> Option<(bool, u8)> {} + comptime fn as_integer(self) -> Option<(bool, u8)> {} // docs:end:as_integer #[builtin(type_as_slice)] // docs:start:as_slice - fn as_slice(self) -> Option {} + comptime fn as_slice(self) -> Option {} // docs:end:as_slice #[builtin(type_as_str)] // docs:start:as_str - fn as_str(self) -> Option {} + comptime fn as_str(self) -> Option {} // docs:end:as_str #[builtin(type_as_struct)] // docs:start:as_struct - fn as_struct(self) -> Option<(StructDefinition, [Type])> {} + comptime fn as_struct(self) -> Option<(StructDefinition, [Type])> {} // docs:end:as_struct #[builtin(type_as_tuple)] // docs:start:as_tuple - fn as_tuple(self) -> Option<[Type]> {} + comptime fn as_tuple(self) -> Option<[Type]> {} // docs:end:as_tuple #[builtin(type_get_trait_impl)] // docs:start:get_trait_impl - fn get_trait_impl(self, constraint: TraitConstraint) -> Option {} + comptime fn get_trait_impl(self, constraint: TraitConstraint) -> Option {} // docs:end:get_trait_impl #[builtin(type_implements)] // docs:start:implements - fn implements(self, constraint: TraitConstraint) -> bool {} + comptime fn implements(self, constraint: TraitConstraint) -> bool {} // docs:end:implements #[builtin(type_is_bool)] // docs:start:is_bool - fn is_bool(self) -> bool {} + comptime fn is_bool(self) -> bool {} // docs:end:is_bool #[builtin(type_is_field)] // docs:start:is_field - fn is_field(self) -> bool {} + comptime fn is_field(self) -> bool {} // docs:end:is_field } impl Eq for Type { - fn eq(self, other: Self) -> bool { + comptime fn eq(self, other: Self) -> bool { type_eq(self, other) } } #[builtin(type_eq)] -fn type_eq(_first: Type, _second: Type) -> bool {} +comptime fn type_eq(_first: Type, _second: Type) -> bool {} diff --git a/noir/noir-repo/noir_stdlib/src/meta/typed_expr.nr b/noir/noir-repo/noir_stdlib/src/meta/typed_expr.nr index 8daede97438..1d3b073b6da 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/typed_expr.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/typed_expr.nr @@ -1,8 +1,16 @@ +//! Contains methods on the built-in `TypedExpr` type for resolved and type-checked expressions. use crate::option::Option; impl TypedExpr { + /// If this expression refers to a function definitions, returns it. Otherwise returns `Option::none()`. #[builtin(typed_expr_as_function_definition)] // docs:start:as_function_definition - fn as_function_definition(self) -> Option {} + comptime fn as_function_definition(self) -> Option {} // docs:end:as_function_definition + + /// Returns the type of the expression, if the expression could be resolved without errors. + #[builtin(typed_expr_get_type)] + // docs:start:get_type + comptime fn get_type(self) -> Option {} + // docs:end:get_type } diff --git a/noir/noir-repo/noir_stdlib/src/meta/unresolved_type.nr b/noir/noir-repo/noir_stdlib/src/meta/unresolved_type.nr index 2589174ed64..f53635414cc 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/unresolved_type.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/unresolved_type.nr @@ -1,6 +1,6 @@ impl UnresolvedType { #[builtin(unresolved_type_is_field)] // docs:start:is_field - fn is_field(self) -> bool {} + comptime fn is_field(self) -> bool {} // docs:end:is_field } diff --git a/noir/noir-repo/test_programs/compile_success_empty/comptime_fmt_strings/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/comptime_fmt_strings/src/main.nr index 0e2d459a00f..ca337c822d8 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/comptime_fmt_strings/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/comptime_fmt_strings/src/main.nr @@ -17,7 +17,7 @@ fn main() { call!(glue(quote { hello }, quote { world })); } -fn glue(x: Quoted, y: Quoted) -> Quoted { +comptime fn glue(x: Quoted, y: Quoted) -> Quoted { f"{x}_{y}".quoted_contents() } diff --git a/noir/noir-repo/test_programs/compile_success_empty/comptime_function_definition/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/comptime_function_definition/src/main.nr index 6bfd8ef9699..e01ff4a71f1 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/comptime_function_definition/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/comptime_function_definition/src/main.nr @@ -66,7 +66,7 @@ contract some_contract { } } -fn set_pub_return(f: FunctionDefinition) { +comptime fn set_pub_return(f: FunctionDefinition) { f.set_return_public(true); } diff --git a/noir/noir-repo/test_programs/compile_success_empty/comptime_typed_expr/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/comptime_typed_expr/Nargo.toml new file mode 100644 index 00000000000..151b8b8e9d0 --- /dev/null +++ b/noir/noir-repo/test_programs/compile_success_empty/comptime_typed_expr/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "comptime_typed_expr" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/compile_success_empty/comptime_typed_expr/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/comptime_typed_expr/src/main.nr new file mode 100644 index 00000000000..ba2594f1da9 --- /dev/null +++ b/noir/noir-repo/test_programs/compile_success_empty/comptime_typed_expr/src/main.nr @@ -0,0 +1,7 @@ +fn main() { + comptime + { + let expr = quote { [1, 3] }.as_expr().unwrap().resolve(Option::none()); + assert_eq(expr.get_type().unwrap(), quote { [Field; 2] }.as_type()); + } +} diff --git a/noir/noir-repo/tooling/lsp/src/requests/completion/completion_items.rs b/noir/noir-repo/tooling/lsp/src/requests/completion/completion_items.rs index 7e7511cdaa3..163a4e15d00 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/completion/completion_items.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/completion/completion_items.rs @@ -213,11 +213,14 @@ impl<'a> NodeFinder<'a> { let name = if self_prefix { format!("self.{}", name) } else { name.clone() }; let name = &name; let description = func_meta_type_to_string(func_meta, func_self_type.is_some()); + let mut has_arguments = false; let completion_item = match function_completion_kind { - FunctionCompletionKind::Name => { - simple_completion_item(name, CompletionItemKind::FUNCTION, Some(description)) - } + FunctionCompletionKind::Name => simple_completion_item( + name, + CompletionItemKind::FUNCTION, + Some(description.clone()), + ), FunctionCompletionKind::NameAndParameters => { let kind = CompletionItemKind::FUNCTION; let skip_first_argument = attribute_first_type.is_some(); @@ -227,20 +230,25 @@ impl<'a> NodeFinder<'a> { function_kind, skip_first_argument, ); - let (label, insert_text) = if insert_text.ends_with("()") { - if skip_first_argument { - (name.to_string(), insert_text.strip_suffix("()").unwrap().to_string()) - } else { - (format!("{}()", name), insert_text) - } - } else { - (format!("{}(…)", name), insert_text) - }; - snippet_completion_item(label, kind, insert_text, Some(description)) + if insert_text.ends_with("()") { + let label = + if skip_first_argument { name.to_string() } else { format!("{}()", name) }; + simple_completion_item(label, kind, Some(description.clone())) + } else { + has_arguments = true; + snippet_completion_item( + format!("{}(…)", name), + kind, + insert_text, + Some(description.clone()), + ) + } } }; + let completion_item = completion_item_with_detail(completion_item, description); + let completion_item = if is_operator { completion_item_with_sort_text(completion_item, operator_sort_text()) } else if function_kind == FunctionKind::Any && name == "new" { @@ -254,11 +262,16 @@ impl<'a> NodeFinder<'a> { let completion_item = match function_completion_kind { FunctionCompletionKind::Name => completion_item, FunctionCompletionKind::NameAndParameters => { - completion_item_with_trigger_parameter_hints_command(completion_item) + if has_arguments { + completion_item_with_trigger_parameter_hints_command(completion_item) + } else { + completion_item + } } }; let completion_item = self.completion_item_with_doc_comments(ReferenceId::Function(func_id), completion_item); + Some(completion_item) } @@ -494,3 +507,10 @@ pub(super) fn completion_item_with_trigger_parameter_hints_command( ..completion_item } } + +pub(super) fn completion_item_with_detail( + completion_item: CompletionItem, + detail: String, +) -> CompletionItem { + CompletionItem { detail: Some(detail), ..completion_item } +} diff --git a/noir/noir-repo/tooling/lsp/src/requests/completion/tests.rs b/noir/noir-repo/tooling/lsp/src/requests/completion/tests.rs index 1b04e060e2c..7e11e0d9d52 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/completion/tests.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/completion/tests.rs @@ -5,7 +5,7 @@ mod completion_tests { requests::{ completion::{ completion_items::{ - completion_item_with_sort_text, + completion_item_with_detail, completion_item_with_sort_text, completion_item_with_trigger_parameter_hints_command, module_completion_item, simple_completion_item, snippet_completion_item, }, @@ -107,12 +107,22 @@ mod completion_tests { insert_text: impl Into, description: impl Into, ) -> CompletionItem { - completion_item_with_trigger_parameter_hints_command(snippet_completion_item( - label, - CompletionItemKind::FUNCTION, - insert_text, - Some(description.into()), - )) + let insert_text: String = insert_text.into(); + let description: String = description.into(); + + let has_arguments = insert_text.ends_with(')') && !insert_text.ends_with("()"); + let completion_item = if has_arguments { + completion_item_with_trigger_parameter_hints_command(snippet_completion_item( + label, + CompletionItemKind::FUNCTION, + insert_text, + Some(description.clone()), + )) + } else { + simple_completion_item(label, CompletionItemKind::FUNCTION, Some(description.clone())) + }; + + completion_item_with_detail(completion_item, description) } fn field_completion_item(field: &str, typ: impl Into) -> CompletionItem { @@ -191,15 +201,8 @@ mod completion_tests { use foo::>|< "#; - assert_completion( - src, - vec![simple_completion_item( - "bar", - CompletionItemKind::FUNCTION, - Some("fn(i32) -> u64".to_string()), - )], - ) - .await; + assert_completion(src, vec![function_completion_item("bar", "bar()", "fn(i32) -> u64")]) + .await; } #[test] @@ -1672,11 +1675,7 @@ mod completion_tests { "#; assert_completion_excluding_auto_import( src, - vec![simple_completion_item( - "hello_world", - CompletionItemKind::FUNCTION, - Some("fn()".to_string()), - )], + vec![function_completion_item("hello_world", "hello_world()", "fn()")], ) .await; } @@ -1694,11 +1693,7 @@ mod completion_tests { "#; assert_completion_excluding_auto_import( src, - vec![simple_completion_item( - "bar", - CompletionItemKind::FUNCTION, - Some("fn()".to_string()), - )], + vec![function_completion_item("bar", "bar()", "fn()")], ) .await; } @@ -1716,11 +1711,7 @@ mod completion_tests { "#; assert_completion_excluding_auto_import( src, - vec![simple_completion_item( - "bar", - CompletionItemKind::FUNCTION, - Some("fn()".to_string()), - )], + vec![function_completion_item("bar", "bar()", "fn()")], ) .await; } @@ -1738,11 +1729,7 @@ mod completion_tests { "#; assert_completion_excluding_auto_import( src, - vec![simple_completion_item( - "bar", - CompletionItemKind::FUNCTION, - Some("fn()".to_string()), - )], + vec![function_completion_item("bar", "bar()", "fn()")], ) .await; } @@ -1762,11 +1749,7 @@ mod completion_tests { "#; assert_completion_excluding_auto_import( src, - vec![simple_completion_item( - "bar", - CompletionItemKind::FUNCTION, - Some("fn(self)".to_string()), - )], + vec![function_completion_item("bar", "bar()", "fn(self)")], ) .await; } @@ -1786,11 +1769,7 @@ mod completion_tests { "#; assert_completion_excluding_auto_import( src, - vec![simple_completion_item( - "bar", - CompletionItemKind::FUNCTION, - Some("fn(self)".to_string()), - )], + vec![function_completion_item("bar", "bar()", "fn(self)")], ) .await; }