Skip to content

Commit 932943a

Browse files
jfecherkevaundray
andauthored
fix: operators issuing type errors when used with matching integer types arising from generic code (#789)
Reorder match cases Co-authored-by: kevaundray <kevtheappdev@gmail.com>
1 parent 59ff9e8 commit 932943a

File tree

1 file changed

+54
-51
lines changed
  • crates/noirc_frontend/src/hir/type_check

1 file changed

+54
-51
lines changed

crates/noirc_frontend/src/hir/type_check/expr.rs

+54-51
Original file line numberDiff line numberDiff line change
@@ -513,19 +513,8 @@ pub fn infix_operand_type_rules(
513513

514514
use Type::*;
515515
match (lhs_type, rhs_type) {
516-
(Integer(comptime_x, sign_x, bit_width_x), Integer(comptime_y, sign_y, bit_width_y)) => {
517-
if sign_x != sign_y {
518-
return Err(make_error(format!("Integers must have the same signedness LHS is {sign_x:?}, RHS is {sign_y:?} ")))
519-
}
520-
if bit_width_x != bit_width_y {
521-
return Err(make_error(format!("Integers must have the same bit width LHS is {bit_width_x}, RHS is {bit_width_y} ")))
522-
}
523-
let comptime = comptime_x.and(comptime_y, op.location.span);
524-
Ok(Integer(comptime, *sign_x, *bit_width_x))
525-
}
526-
(Integer(..), FieldElement(..)) | (FieldElement(..), Integer(..)) => {
527-
Err(make_error("Cannot use an integer and a Field in a binary operation, try converting the Field into an integer".to_string()))
528-
}
516+
// Matches on PolymorphicInteger and TypeVariable must be first so that we follow any type
517+
// bindings.
529518
(PolymorphicInteger(comptime, int), other)
530519
| (other, PolymorphicInteger(comptime, int)) => {
531520
if let TypeBinding::Bound(binding) = &*int.borrow() {
@@ -555,6 +544,32 @@ pub fn infix_operand_type_rules(
555544
Err(make_error(format!("Types in a binary operation should match, but found {lhs_type} and {rhs_type}")))
556545
}
557546
}
547+
(TypeVariable(var), other)
548+
| (other, TypeVariable(var)) => {
549+
if let TypeBinding::Bound(binding) = &*var.borrow() {
550+
return infix_operand_type_rules(binding, op, other, span, interner, errors);
551+
}
552+
553+
let comptime = CompTime::No(None);
554+
if other.try_bind_to_polymorphic_int(var, &comptime, true, op.location.span).is_ok() || other == &Type::Error {
555+
Ok(other.clone())
556+
} else {
557+
Err(make_error(format!("Types in a binary operation should match, but found {lhs_type} and {rhs_type}")))
558+
}
559+
}
560+
(Integer(comptime_x, sign_x, bit_width_x), Integer(comptime_y, sign_y, bit_width_y)) => {
561+
if sign_x != sign_y {
562+
return Err(make_error(format!("Integers must have the same signedness LHS is {sign_x:?}, RHS is {sign_y:?} ")))
563+
}
564+
if bit_width_x != bit_width_y {
565+
return Err(make_error(format!("Integers must have the same bit width LHS is {bit_width_x}, RHS is {bit_width_y} ")))
566+
}
567+
let comptime = comptime_x.and(comptime_y, op.location.span);
568+
Ok(Integer(comptime, *sign_x, *bit_width_x))
569+
}
570+
(Integer(..), FieldElement(..)) | (FieldElement(..), Integer(..)) => {
571+
Err(make_error("Cannot use an integer and a Field in a binary operation, try converting the Field into an integer".to_string()))
572+
}
558573
(Integer(..), typ) | (typ,Integer(..)) => {
559574
Err(make_error(format!("Integer cannot be used with type {typ}")))
560575
}
@@ -578,20 +593,6 @@ pub fn infix_operand_type_rules(
578593

579594
(Bool(comptime_x), Bool(comptime_y)) => Ok(Bool(comptime_x.and(comptime_y, op.location.span))),
580595

581-
(TypeVariable(var), other)
582-
| (other, TypeVariable(var)) => {
583-
if let TypeBinding::Bound(binding) = &*var.borrow() {
584-
return infix_operand_type_rules(binding, op, other, span, interner, errors);
585-
}
586-
587-
let comptime = CompTime::No(None);
588-
if other.try_bind_to_polymorphic_int(var, &comptime, true, op.location.span).is_ok() || other == &Type::Error {
589-
Ok(other.clone())
590-
} else {
591-
Err(make_error(format!("Types in a binary operation should match, but found {lhs_type} and {rhs_type}")))
592-
}
593-
}
594-
595596
(lhs, rhs) => Err(make_error(format!("Unsupported types for binary operation: {lhs} and {rhs}"))),
596597
}
597598
}
@@ -722,6 +723,32 @@ pub fn comparator_operand_type_rules(
722723
use crate::BinaryOpKind::{Equal, NotEqual};
723724
use Type::*;
724725
match (lhs_type, rhs_type) {
726+
// Matches on PolymorphicInteger and TypeVariable must be first to follow any type
727+
// bindings.
728+
(PolymorphicInteger(comptime, int), other)
729+
| (other, PolymorphicInteger(comptime, int)) => {
730+
if let TypeBinding::Bound(binding) = &*int.borrow() {
731+
return comparator_operand_type_rules(other, binding, op, errors);
732+
}
733+
if other.try_bind_to_polymorphic_int(int, comptime, true, op.location.span).is_ok() || other == &Type::Error {
734+
Ok(Bool(comptime.clone()))
735+
} else {
736+
Err(format!("Types in a binary operation should match, but found {lhs_type} and {rhs_type}"))
737+
}
738+
}
739+
(TypeVariable(var), other)
740+
| (other, TypeVariable(var)) => {
741+
if let TypeBinding::Bound(binding) = &*var.borrow() {
742+
return comparator_operand_type_rules(binding, other, op, errors);
743+
}
744+
745+
let comptime = CompTime::No(None);
746+
if other.try_bind_to_polymorphic_int(var, &comptime, true, op.location.span).is_ok() || other == &Type::Error {
747+
Ok(other.clone())
748+
} else {
749+
Err(format!("Types in a binary operation should match, but found {lhs_type} and {rhs_type}"))
750+
}
751+
}
725752
(Integer(comptime_x, sign_x, bit_width_x), Integer(comptime_y, sign_y, bit_width_y)) => {
726753
if sign_x != sign_y {
727754
return Err(format!("Integers must have the same signedness LHS is {sign_x:?}, RHS is {sign_y:?} "))
@@ -735,17 +762,6 @@ pub fn comparator_operand_type_rules(
735762
(Integer(..), FieldElement(..)) | ( FieldElement(..), Integer(..) ) => {
736763
Err("Cannot use an integer and a Field in a binary operation, try converting the Field into an integer first".to_string())
737764
}
738-
(PolymorphicInteger(comptime, int), other)
739-
| (other, PolymorphicInteger(comptime, int)) => {
740-
if let TypeBinding::Bound(binding) = &*int.borrow() {
741-
return comparator_operand_type_rules(other, binding, op, errors);
742-
}
743-
if other.try_bind_to_polymorphic_int(int, comptime, true, op.location.span).is_ok() || other == &Type::Error {
744-
Ok(Bool(comptime.clone()))
745-
} else {
746-
Err(format!("Types in a binary operation should match, but found {lhs_type} and {rhs_type}"))
747-
}
748-
}
749765
(Integer(..), typ) | (typ,Integer(..)) => {
750766
Err(format!("Integer cannot be used with type {typ}"))
751767
}
@@ -795,19 +811,6 @@ pub fn comparator_operand_type_rules(
795811
}
796812
Err(format!("Unsupported types for comparison: {name_a} and {name_b}"))
797813
}
798-
(TypeVariable(var), other)
799-
| (other, TypeVariable(var)) => {
800-
if let TypeBinding::Bound(binding) = &*var.borrow() {
801-
return comparator_operand_type_rules(binding, other, op, errors);
802-
}
803-
804-
let comptime = CompTime::No(None);
805-
if other.try_bind_to_polymorphic_int(var, &comptime, true, op.location.span).is_ok() || other == &Type::Error {
806-
Ok(other.clone())
807-
} else {
808-
Err(format!("Types in a binary operation should match, but found {lhs_type} and {rhs_type}"))
809-
}
810-
}
811814
(String(x_size), String(y_size)) => {
812815
x_size.unify(y_size, op.location.span, errors, || {
813816
TypeCheckError::Unstructured {

0 commit comments

Comments
 (0)