Skip to content

Commit

Permalink
Merge branch 'master' into doc-generator
Browse files Browse the repository at this point in the history
  • Loading branch information
Sakapoi authored Nov 15, 2023
2 parents bf7be71 + fd836cb commit e872287
Show file tree
Hide file tree
Showing 56 changed files with 576 additions and 295 deletions.
3 changes: 0 additions & 3 deletions compiler/noirc_driver/build.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
const GIT_COMMIT: &&str = &"GIT_COMMIT";

fn main() {
// Rebuild if the tests have changed
println!("cargo:rerun-if-changed=tests");

// Only use build_data if the environment variable isn't set
// The environment variable is always set when working via Nix
if std::env::var(GIT_COMMIT).is_err() {
Expand Down
123 changes: 62 additions & 61 deletions compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,75 +658,76 @@ impl Context {
store_value: Option<ValueId>,
) -> Result<bool, RuntimeError> {
let index_const = dfg.get_numeric_constant(index);
match dfg.type_of_value(array) {
Type::Array(_, _) => {
match self.convert_value(array, dfg) {
AcirValue::Var(acir_var, _) => {
return Err(RuntimeError::InternalError(InternalError::UnExpected {
expected: "an array value".to_string(),
found: format!("{acir_var:?}"),
call_stack: self.acir_context.get_call_stack(),
}))
}
AcirValue::Array(array) => {
if let Some(index_const) = index_const {
let array_size = array.len();
let index = match index_const.try_to_u64() {
Some(index_const) => index_const as usize,
None => {
let call_stack = self.acir_context.get_call_stack();
return Err(RuntimeError::TypeConversion {
from: "array index".to_string(),
into: "u64".to_string(),
call_stack,
});
let value_type = dfg.type_of_value(array);
let (Type::Array(element_types, _) | Type::Slice(element_types)) = &value_type else {
unreachable!("ICE: expected array or slice type");

};

// TODO(#3188): Need to be able to handle constant index for slices to seriously reduce
// constraint sizes of nested slices
// This can only be done if we accurately flatten nested slices as otherwise we will reach
// index out of bounds errors. If the slice is already flat then we can treat them similarly to arrays.
if matches!(value_type, Type::Slice(_))
&& element_types.iter().any(|element| element.contains_slice_element())
{
return Ok(false);
}

match self.convert_value(array, dfg) {
AcirValue::Var(acir_var, _) => {
return Err(RuntimeError::InternalError(InternalError::UnExpected {
expected: "an array value".to_string(),
found: format!("{acir_var:?}"),
call_stack: self.acir_context.get_call_stack(),
}))
}
AcirValue::Array(array) => {
if let Some(index_const) = index_const {
let array_size = array.len();
let index = match index_const.try_to_u64() {
Some(index_const) => index_const as usize,
None => {
let call_stack = self.acir_context.get_call_stack();
return Err(RuntimeError::TypeConversion {
from: "array index".to_string(),
into: "u64".to_string(),
call_stack,
});
}
};
if self.acir_context.is_constant_one(&self.current_side_effects_enabled_var) {
// Report the error if side effects are enabled.
if index >= array_size {
let call_stack = self.acir_context.get_call_stack();
return Err(RuntimeError::IndexOutOfBounds {
index,
array_size,
call_stack,
});
} else {
let value = match store_value {
Some(store_value) => {
let store_value = self.convert_value(store_value, dfg);
AcirValue::Array(array.update(index, store_value))
}
None => array[index].clone(),
};
if self
.acir_context
.is_constant_one(&self.current_side_effects_enabled_var)
{
// Report the error if side effects are enabled.
if index >= array_size {
let call_stack = self.acir_context.get_call_stack();
return Err(RuntimeError::IndexOutOfBounds {
index,
array_size,
call_stack,
});
} else {
let value = match store_value {
Some(store_value) => {
let store_value = self.convert_value(store_value, dfg);
AcirValue::Array(array.update(index, store_value))
}
None => array[index].clone(),
};

self.define_result(dfg, instruction, value);
return Ok(true);
}
}
// If there is a predicate and the index is not out of range, we can directly perform the read
else if index < array_size && store_value.is_none() {
self.define_result(dfg, instruction, array[index].clone());
return Ok(true);
}
self.define_result(dfg, instruction, value);
return Ok(true);
}
}
AcirValue::DynamicArray(_) => (),
// If there is a predicate and the index is not out of range, we can directly perform the read
else if index < array_size && store_value.is_none() {
self.define_result(dfg, instruction, array[index].clone());
return Ok(true);
}
}
}
Type::Slice(_) => {
// TODO(#3188): Need to be able to handle constant index for slices to seriously reduce
// constraint sizes of nested slices
// This can only be done if we accurately flatten nested slices as other we will reach
// index out of bounds errors.
AcirValue::DynamicArray(_) => (),
};

// Do nothing we only want dynamic checks for slices
}
_ => unreachable!("ICE: expected array or slice type"),
}
Ok(false)
}

Expand Down
28 changes: 20 additions & 8 deletions compiler/noirc_frontend/src/hir/resolution/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::hir::def_map::{LocalModuleId, ModuleDefId, TryFromModuleDefId, MAIN_F
use crate::hir_def::stmt::{HirAssignStatement, HirForStatement, HirLValue, HirPattern};
use crate::node_interner::{
DefinitionId, DefinitionKind, ExprId, FuncId, NodeInterner, StmtId, StructId, TraitId,
TraitImplId,
TraitImplId, TraitImplKind,
};
use crate::{
hir::{def_map::CrateDefMap, resolution::path_resolver::PathResolver},
Expand Down Expand Up @@ -1207,8 +1207,12 @@ impl<'a> Resolver<'a> {
Literal::Unit => HirLiteral::Unit,
}),
ExpressionKind::Variable(path) => {
if let Some(expr) = self.resolve_trait_generic_path(&path) {
expr
if let Some((hir_expr, object_type)) = self.resolve_trait_generic_path(&path) {
let expr_id = self.interner.push_expr(hir_expr);
self.interner.push_expr_location(expr_id, expr.span, self.file);
self.interner
.select_impl_for_ident(expr_id, TraitImplKind::Assumed { object_type });
return expr_id;
} else {
// If the Path is being used as an Expression, then it is referring to a global from a separate module
// Otherwise, then it is referring to an Identifier
Expand Down Expand Up @@ -1370,6 +1374,8 @@ impl<'a> Resolver<'a> {
ExpressionKind::Parenthesized(sub_expr) => return self.resolve_expression(*sub_expr),
};

// If these lines are ever changed, make sure to change the early return
// in the ExpressionKind::Variable case as well
let expr_id = self.interner.push_expr(hir_expr);
self.interner.push_expr_location(expr_id, expr.span, self.file);
expr_id
Expand Down Expand Up @@ -1576,7 +1582,10 @@ impl<'a> Resolver<'a> {
}

// this resolves Self::some_static_method, inside an impl block (where we don't have a concrete self_type)
fn resolve_trait_static_method_by_self(&mut self, path: &Path) -> Option<HirExpression> {
fn resolve_trait_static_method_by_self(
&mut self,
path: &Path,
) -> Option<(HirExpression, Type)> {
if let Some(trait_id) = self.trait_id {
if path.kind == PathKind::Plain && path.segments.len() == 2 {
let name = &path.segments[0].0.contents;
Expand All @@ -1590,7 +1599,7 @@ impl<'a> Resolver<'a> {
the_trait.self_type_typevar,
crate::TypeVariableKind::Normal,
);
return Some(HirExpression::TraitMethodReference(self_type, method));
return Some((HirExpression::TraitMethodReference(method), self_type));
}
}
}
Expand All @@ -1599,7 +1608,10 @@ impl<'a> Resolver<'a> {
}

// this resolves a static trait method T::trait_method by iterating over the where clause
fn resolve_trait_method_by_named_generic(&mut self, path: &Path) -> Option<HirExpression> {
fn resolve_trait_method_by_named_generic(
&mut self,
path: &Path,
) -> Option<(HirExpression, Type)> {
if path.segments.len() != 2 {
return None;
}
Expand All @@ -1621,15 +1633,15 @@ impl<'a> Resolver<'a> {
the_trait.find_method(path.segments.last().unwrap().clone())
{
let self_type = self.resolve_type(typ.clone());
return Some(HirExpression::TraitMethodReference(self_type, method));
return Some((HirExpression::TraitMethodReference(method), self_type));
}
}
}
}
None
}

fn resolve_trait_generic_path(&mut self, path: &Path) -> Option<HirExpression> {
fn resolve_trait_generic_path(&mut self, path: &Path) -> Option<(HirExpression, Type)> {
self.resolve_trait_static_method_by_self(path)
.or_else(|| self.resolve_trait_method_by_named_generic(path))
}
Expand Down
6 changes: 6 additions & 0 deletions compiler/noirc_frontend/src/hir/type_check/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ pub enum TypeCheckError {
},
#[error("No matching impl found")]
NoMatchingImplFound { constraints: Vec<(Type, String)>, span: Span },
#[error("Constraint for `{typ}: {trait_name}` is not needed, another matching impl is already in scope")]
UnneededTraitConstraint { trait_name: String, typ: Type, span: Span },
}

impl TypeCheckError {
Expand Down Expand Up @@ -269,6 +271,10 @@ impl From<TypeCheckError> for Diagnostic {

diagnostic
}
TypeCheckError::UnneededTraitConstraint { trait_name, typ, span } => {
let msg = format!("Constraint for `{typ}: {trait_name}` is not needed, another matching impl is already in scope");
Diagnostic::simple_warning(msg, "Unnecessary trait constraint in where clause".into(), span)
}
}
}
}
Loading

0 comments on commit e872287

Please sign in to comment.