Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions compiler/noirc_frontend/src/elaborator/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1537,8 +1537,22 @@ impl Elaborator<'_> {
location: Location,
target_type: Option<&Type>,
) -> (ExprId, Type) {
let (block, _typ) = self.elaborate_in_comptime_context(|this| {
this.elaborate_block_expression(block, target_type)
let block = self.elaborate_in_comptime_context(|this| {
let (block, block_type) = this.elaborate_block_expression(block, target_type);

// If the comptime block is expected to return a specific type, unify their types.
// This for example allows this code to compile: `let x: u8 = comptime { 1 }`.
// If we don't do this, "1" will end up with the default integer or field type,
// which is Field.
if let Some(target_type) = target_type {
this.unify(&block_type, target_type, || TypeCheckError::TypeMismatch {
expected_typ: target_type.to_string(),
expr_typ: block_type.to_string(),
expr_location: location,
});
}

block
});

let mut interpreter = self.setup_interpreter();
Expand Down
43 changes: 37 additions & 6 deletions compiler/noirc_frontend/src/elaborator/statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ impl Elaborator<'_> {
StatementKind::While(while_) => self.elaborate_while(while_),
StatementKind::Break => self.elaborate_jump(true, statement.location),
StatementKind::Continue => self.elaborate_jump(false, statement.location),
StatementKind::Comptime(statement) => self.elaborate_comptime_statement(*statement),
StatementKind::Comptime(statement) => {
self.elaborate_comptime_statement(*statement, target_type)
}
StatementKind::Expression(expr) => {
let (expr, typ) = self.elaborate_expression_with_target_type(expr, target_type);
(HirStatement::Expression(expr), typ)
Expand Down Expand Up @@ -117,8 +119,11 @@ impl Elaborator<'_> {

let pattern_location = let_stmt.pattern.location();
let expr_location = let_stmt.expression.location;
let (expression, expr_type) =
self.elaborate_expression_with_target_type(let_stmt.expression, Some(&annotated_type));
let (expression, expr_type) = if no_type {
self.elaborate_expression(let_stmt.expression)
} else {
self.elaborate_expression_with_target_type(let_stmt.expression, Some(&annotated_type))
};

// Require the top-level of a global's type to be fully-specified
if global_id.is_some() && (no_type || annotated_type.contains_type_variable()) {
Expand Down Expand Up @@ -626,10 +631,36 @@ impl Elaborator<'_> {
Some((let_, ident_id))
}

fn elaborate_comptime_statement(&mut self, statement: Statement) -> (HirStatement, Type) {
fn elaborate_comptime_statement(
&mut self,
statement: Statement,
target_type: Option<&Type>,
) -> (HirStatement, Type) {
let location = statement.location;
let (hir_statement, _typ) =
self.elaborate_in_comptime_context(|this| this.elaborate_statement(statement));
let hir_statement = self.elaborate_in_comptime_context(|this| {
let (hir_statement, typ) = this.elaborate_statement(statement);

// If the comptime statement is expected to return a specific type, unify their types.
// This for example allows this code to compile:
//
// ```
// fn foo() -> u8 {
// comptime { 1 }
// }
// ```
//
// If we don't do this, "1" will end up with the default integer or field type,
// which is Field.
if let Some(target_type) = target_type {
this.unify(&typ, target_type, || TypeCheckError::TypeMismatch {
expected_typ: target_type.to_string(),
expr_typ: typ.to_string(),
expr_location: location,
});
}

hir_statement
});

// Run the interpreter - it will check if execution has been halted
let mut interpreter = self.setup_interpreter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -645,21 +645,11 @@ pub(crate) fn byte_array_type(len: usize) -> Type {
)
}

/// Type to be used in `Value::Vector(<values>, <vector-type>)`.
pub(crate) fn byte_vector_type() -> Type {
Type::Vector(Box::new(Type::Integer(Signedness::Unsigned, IntegerBitSize::Eight)))
}

/// Create a `Value::Array` from bytes.
pub(crate) fn to_byte_array(values: &[u8]) -> Value {
Value::Array(values.iter().copied().map(Value::U8).collect(), byte_array_type(values.len()))
}

/// Create a `Value::Vector` from bytes.
pub(crate) fn to_byte_vector(values: &[u8]) -> Value {
Value::Vector(values.iter().copied().map(Value::U8).collect(), byte_vector_type())
}

/// Create a `Value::Struct` from fields and the expected return type.
pub(crate) fn to_struct(
fields: impl IntoIterator<Item = (&'static str, Value)>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
builtin::builtin_helpers::{
check_arguments, check_one_argument, check_three_arguments, check_two_arguments,
get_array_map, get_bool, get_field, get_fixed_array_map, get_struct_field,
get_struct_fields, get_u8, get_u32, get_u64, to_byte_vector, to_struct,
get_struct_fields, get_u8, get_u32, get_u64, to_struct,
},
};

Expand Down Expand Up @@ -52,11 +52,11 @@
"blake3" => blake_hash(args, location, acvm::blackbox_solver::blake3),
// cSpell:disable-next-line
"ecdsa_secp256k1" => {
ecdsa_secp256_verify(args, location, acvm::blackbox_solver::ecdsa_secp256k1_verify)

Check warning on line 55 in compiler/noirc_frontend/src/hir/comptime/interpreter/foreign.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (secp)
}
// cSpell:disable-next-line
"ecdsa_secp256r1" => {
ecdsa_secp256_verify(args, location, acvm::blackbox_solver::ecdsa_secp256r1_verify)

Check warning on line 59 in compiler/noirc_frontend/src/hir/comptime/interpreter/foreign.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (secp)
}
"embedded_curve_add" => embedded_curve_add(args, return_type, location, pedantic_solving),
"multi_scalar_mul" => multi_scalar_mul(args, return_type, location, pedantic_solving),
Expand Down Expand Up @@ -90,7 +90,7 @@
let output = acvm::blackbox_solver::aes128_encrypt(&inputs, iv, key)
.map_err(|e| InterpreterError::BlackBoxError(e, location))?;

Ok(to_byte_vector(&output))
Ok(to_byte_array(&output))
}

/// Run one of the Blake hash functions.
Expand Down
23 changes: 23 additions & 0 deletions compiler/noirc_frontend/src/tests/metaprogramming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1169,3 +1169,26 @@ fn varargs_on_function_without_last_vector_parameter() {
";
check_errors(src);
}

#[test]
fn unify_comptime_block_expression_with_target_type() {
let src = r#"
fn main() {
let _: u8 = comptime { 1 };
}
"#;
assert_no_errors(src);
}

#[test]
fn unify_comptime_block_statement_with_target_type() {
let src = r#"
fn main() {
}

pub fn foo() -> u8 {
comptime { 1 }
}
"#;
assert_no_errors(src);
}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fn main() {
// format strings are lowered as normal strings
let (s1, s2): (str<39>, str<4>) = comptime {
// We need `as_quoted_str!()` to go from a `fmtstr` to a `str`
let (s1, s2) = comptime {
let x: u32 = 4;
let y: u32 = 5;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ mod test_as_typed_expr_4 {
let bar_q = quote {
bar
};
foo(bar_q.as_expr().unwrap().resolve(Option::none()))
foo!(bar_q.as_expr().unwrap().resolve(Option::none()))
};
x
}
Expand Down

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading