@@ -442,6 +442,10 @@ pub enum TypeVariableKind {
442442 /// type annotations on each integer literal.
443443 IntegerOrField ,
444444
445+ /// A generic integer type. This is a more specific kind of TypeVariable
446+ /// that can only be bound to Type::Integer, or other polymorphic integers.
447+ Integer ,
448+
445449 /// A potentially constant array size. This will only bind to itself, Type::NotConstant, or
446450 /// Type::Constant(n) with a matching size. This defaults to Type::Constant(n) if still unbound
447451 /// during monomorphization.
@@ -747,6 +751,13 @@ impl std::fmt::Display for Type {
747751 Signedness :: Unsigned => write ! ( f, "u{num_bits}" ) ,
748752 } ,
749753 Type :: TypeVariable ( var, TypeVariableKind :: Normal ) => write ! ( f, "{}" , var. borrow( ) ) ,
754+ Type :: TypeVariable ( binding, TypeVariableKind :: Integer ) => {
755+ if let TypeBinding :: Unbound ( _) = & * binding. borrow ( ) {
756+ write ! ( f, "{}" , TypeVariableKind :: Integer . default_type( ) )
757+ } else {
758+ write ! ( f, "{}" , binding. borrow( ) )
759+ }
760+ }
750761 Type :: TypeVariable ( binding, TypeVariableKind :: IntegerOrField ) => {
751762 if let TypeBinding :: Unbound ( _) = & * binding. borrow ( ) {
752763 // Show a Field by default if this TypeVariableKind::IntegerOrField is unbound, since that is
@@ -911,6 +922,7 @@ impl Type {
911922 Ok ( ( ) )
912923 }
913924 TypeVariableKind :: IntegerOrField => Err ( UnificationError ) ,
925+ TypeVariableKind :: Integer => Err ( UnificationError ) ,
914926 } ,
915927 }
916928 }
@@ -925,6 +937,7 @@ impl Type {
925937 & self ,
926938 var : & TypeVariable ,
927939 bindings : & mut TypeBindings ,
940+ only_integer : bool ,
928941 ) -> Result < ( ) , UnificationError > {
929942 let target_id = match & * var. borrow ( ) {
930943 TypeBinding :: Bound ( _) => unreachable ! ( ) ,
@@ -940,7 +953,30 @@ impl Type {
940953 Type :: TypeVariable ( self_var, TypeVariableKind :: IntegerOrField ) => {
941954 let borrow = self_var. borrow ( ) ;
942955 match & * borrow {
943- TypeBinding :: Bound ( typ) => typ. try_bind_to_polymorphic_int ( var, bindings) ,
956+ TypeBinding :: Bound ( typ) => {
957+ typ. try_bind_to_polymorphic_int ( var, bindings, only_integer)
958+ }
959+ // Avoid infinitely recursive bindings
960+ TypeBinding :: Unbound ( id) if * id == target_id => Ok ( ( ) ) ,
961+ TypeBinding :: Unbound ( new_target_id) => {
962+ if only_integer {
963+ // Integer is more specific than IntegerOrField so we bind the type
964+ // variable to Integer instead.
965+ let clone = Type :: TypeVariable ( var. clone ( ) , TypeVariableKind :: Integer ) ;
966+ bindings. insert ( * new_target_id, ( self_var. clone ( ) , clone) ) ;
967+ } else {
968+ bindings. insert ( target_id, ( var. clone ( ) , this. clone ( ) ) ) ;
969+ }
970+ Ok ( ( ) )
971+ }
972+ }
973+ }
974+ Type :: TypeVariable ( self_var, TypeVariableKind :: Integer ) => {
975+ let borrow = self_var. borrow ( ) ;
976+ match & * borrow {
977+ TypeBinding :: Bound ( typ) => {
978+ typ. try_bind_to_polymorphic_int ( var, bindings, only_integer)
979+ }
944980 // Avoid infinitely recursive bindings
945981 TypeBinding :: Unbound ( id) if * id == target_id => Ok ( ( ) ) ,
946982 TypeBinding :: Unbound ( _) => {
@@ -949,18 +985,23 @@ impl Type {
949985 }
950986 }
951987 }
952- Type :: TypeVariable ( binding , TypeVariableKind :: Normal ) => {
953- let borrow = binding . borrow ( ) ;
988+ Type :: TypeVariable ( self_var , TypeVariableKind :: Normal ) => {
989+ let borrow = self_var . borrow ( ) ;
954990 match & * borrow {
955- TypeBinding :: Bound ( typ) => typ. try_bind_to_polymorphic_int ( var, bindings) ,
991+ TypeBinding :: Bound ( typ) => {
992+ typ. try_bind_to_polymorphic_int ( var, bindings, only_integer)
993+ }
956994 // Avoid infinitely recursive bindings
957995 TypeBinding :: Unbound ( id) if * id == target_id => Ok ( ( ) ) ,
958996 TypeBinding :: Unbound ( new_target_id) => {
959- // IntegerOrField is more specific than TypeVariable so we bind the type
960- // variable to IntegerOrField instead.
961- let clone =
962- Type :: TypeVariable ( var. clone ( ) , TypeVariableKind :: IntegerOrField ) ;
963- bindings. insert ( * new_target_id, ( binding. clone ( ) , clone) ) ;
997+ // Bind to the most specific type variable kind
998+ let clone_kind = if only_integer {
999+ TypeVariableKind :: Integer
1000+ } else {
1001+ TypeVariableKind :: IntegerOrField
1002+ } ;
1003+ let clone = Type :: TypeVariable ( var. clone ( ) , clone_kind) ;
1004+ bindings. insert ( * new_target_id, ( self_var. clone ( ) , clone) ) ;
9641005 Ok ( ( ) )
9651006 }
9661007 }
@@ -1050,7 +1091,16 @@ impl Type {
10501091 ( TypeVariable ( var, Kind :: IntegerOrField ) , other)
10511092 | ( other, TypeVariable ( var, Kind :: IntegerOrField ) ) => {
10521093 other. try_unify_to_type_variable ( var, bindings, |bindings| {
1053- other. try_bind_to_polymorphic_int ( var, bindings)
1094+ let only_integer = false ;
1095+ other. try_bind_to_polymorphic_int ( var, bindings, only_integer)
1096+ } )
1097+ }
1098+
1099+ ( TypeVariable ( var, Kind :: Integer ) , other)
1100+ | ( other, TypeVariable ( var, Kind :: Integer ) ) => {
1101+ other. try_unify_to_type_variable ( var, bindings, |bindings| {
1102+ let only_integer = true ;
1103+ other. try_bind_to_polymorphic_int ( var, bindings, only_integer)
10541104 } )
10551105 }
10561106
@@ -1599,6 +1649,7 @@ impl TypeVariableKind {
15991649 pub ( crate ) fn default_type ( & self ) -> Type {
16001650 match self {
16011651 TypeVariableKind :: IntegerOrField | TypeVariableKind :: Normal => Type :: default_int_type ( ) ,
1652+ TypeVariableKind :: Integer => Type :: default_range_loop_type ( ) ,
16021653 TypeVariableKind :: Constant ( length) => Type :: Constant ( * length) ,
16031654 }
16041655 }
@@ -1627,6 +1678,10 @@ impl From<&Type> for PrintableType {
16271678 }
16281679 Signedness :: Signed => PrintableType :: SignedInteger { width : ( * bit_width) . into ( ) } ,
16291680 } ,
1681+ Type :: TypeVariable ( binding, TypeVariableKind :: Integer ) => match & * binding. borrow ( ) {
1682+ TypeBinding :: Bound ( typ) => typ. into ( ) ,
1683+ TypeBinding :: Unbound ( _) => Type :: default_range_loop_type ( ) . into ( ) ,
1684+ } ,
16301685 Type :: TypeVariable ( binding, TypeVariableKind :: IntegerOrField ) => {
16311686 match & * binding. borrow ( ) {
16321687 TypeBinding :: Bound ( typ) => typ. into ( ) ,
@@ -1685,6 +1740,9 @@ impl std::fmt::Debug for Type {
16851740 Type :: TypeVariable ( binding, TypeVariableKind :: IntegerOrField ) => {
16861741 write ! ( f, "IntOrField{:?}" , binding)
16871742 }
1743+ Type :: TypeVariable ( binding, TypeVariableKind :: Integer ) => {
1744+ write ! ( f, "Int{:?}" , binding)
1745+ }
16881746 Type :: TypeVariable ( binding, TypeVariableKind :: Constant ( n) ) => {
16891747 write ! ( f, "{}{:?}" , n, binding)
16901748 }
0 commit comments