shithub: mc

Download patch

ref: 90e26e0f687da28530b3b967df0cedf20407c071
parent: 94448201527e0c47c2924219bf1a8d0c0c2406b7
author: Ori Bernstein <[email protected]>
date: Mon Jan 1 16:09:50 EST 2018

Move to new trait syntax.

--- a/lib/bio/bio.myr
+++ b/lib/bio/bio.myr
@@ -283,7 +283,7 @@
   writes a single integer-like value to the output stream, in
   little endian format
 */
-generic putle = {f, v : @a::(numeric,integral)
+generic putle = {f, v : @a :: numeric,integral @a
 	for var i = 0; i < sizeof(@a); i++
 		putb(f, (v & 0xff : byte))
 		v >>= 8
@@ -295,7 +295,7 @@
   writes a single integer-like value to the output stream, in
   big endian format
 */
-generic putbe = {f, v : @a::(numeric,integral)
+generic putbe = {f, v : @a :: numeric,integral @a
 	for var i = sizeof(@a); i != 0; i--
 		putb(f, ((v >> ((i-1)*8)) & 0xff : byte))
 	;;
--- a/lib/bio/geti.myr
+++ b/lib/bio/geti.myr
@@ -5,16 +5,16 @@
 
 pkg bio =
 	/* unsigned big endian */
-	generic getbe8	: (f : file# -> std.result(@a::(numeric,integral), err))
-	generic getbe16	: (f : file# -> std.result(@a::(numeric,integral), err))
-	generic getbe32	: (f : file# -> std.result(@a::(numeric,integral), err))
-	generic getbe64	: (f : file# -> std.result(@a::(numeric,integral), err))
+	generic getbe8	: (f : file# -> std.result(@a, err)) :: numeric,integral @a
+	generic getbe16	: (f : file# -> std.result(@a, err)) :: numeric,integral @a
+	generic getbe32	: (f : file# -> std.result(@a, err)) :: numeric,integral @a
+	generic getbe64	: (f : file# -> std.result(@a, err)) :: numeric,integral @a
 
 	/* signed big endian */
-	generic getle8	: (f : file# -> std.result(@a::(numeric,integral), err))
-	generic getle16	: (f : file# -> std.result(@a::(numeric,integral), err))
-	generic getle32	: (f : file# -> std.result(@a::(numeric,integral), err))
-	generic getle64	: (f : file# -> std.result(@a::(numeric,integral), err))
+	generic getle8	: (f : file# -> std.result(@a, err)) :: numeric,integral @a
+	generic getle16	: (f : file# -> std.result(@a, err)) :: numeric,integral @a
+	generic getle32	: (f : file# -> std.result(@a, err)) :: numeric,integral @a
+	generic getle64	: (f : file# -> std.result(@a, err)) :: numeric,integral @a
 ;;
 
 /*
@@ -21,7 +21,7 @@
   reads a single integer-like value to the output stream, in
   little endian format
 */
-generic getle = {f, n -> std.result(@a::(numeric,integral), err)
+generic getle = {f, n -> std.result(@a, err) :: numeric,integral @a
 	match ensureread(f, n)
 	| `std.Err e :	-> `std.Err e
 	| `std.Ok _:
@@ -29,7 +29,7 @@
 		for var i = 0; i < n; i++
 			v |= (f.rbuf[f.rstart++] : uint64) << (8*(i : uint64))
 		;;
-		-> `std.Ok (v : @a::(numeric,integral))
+		-> `std.Ok (v : @a)
 	;;
 }
 
@@ -37,7 +37,7 @@
   reads a single integer-like value to the output stream, in
   big endian format
 */
-generic getbe = {f, n -> std.result(@a::(numeric,integral), err)
+generic getbe = {f, n -> std.result(@a, err) :: numeric,integral @a
 	match ensureread(f, n)
 	| `std.Err e :	-> `std.Err e
 	| `std.Ok _:
@@ -46,7 +46,7 @@
 			v <<= 8
 			v |= (f.rbuf[f.rstart++] : uint64)
 		;;
-		-> `std.Ok (v : @a::(numeric,integral))
+		-> `std.Ok (v : @a)
 	;;
 }
 
--- a/lib/bio/puti.myr
+++ b/lib/bio/puti.myr
@@ -5,16 +5,16 @@
 
 pkg bio =
 	/* unsigned big endian */
-	generic putbe8	: (f : file#, v : @a::(numeric,integral) -> std.result(std.size, err))
-	generic putbe16	: (f : file#, v : @a::(numeric,integral) -> std.result(std.size, err))
-	generic putbe32	: (f : file#, v : @a::(numeric,integral) -> std.result(std.size, err))
-	generic putbe64	: (f : file#, v : @a::(numeric,integral) -> std.result(std.size, err))
+	generic putbe8	: (f : file#, v : @a -> std.result(std.size, err)) :: numeric,integral @a
+	generic putbe16	: (f : file#, v : @a -> std.result(std.size, err)) :: numeric,integral @a
+	generic putbe32	: (f : file#, v : @a -> std.result(std.size, err)) :: numeric,integral @a
+	generic putbe64	: (f : file#, v : @a -> std.result(std.size, err)) :: numeric,integral @a
 
 	/* unsigned little endian */
-	generic putle8	: (f : file#, v : @a::(numeric,integral) -> std.result(std.size, err))
-	generic putle16	: (f : file#, v : @a::(numeric,integral) -> std.result(std.size, err))
-	generic putle32	: (f : file#, v : @a::(numeric,integral) -> std.result(std.size, err))
-	generic putle64	: (f : file#, v : @a::(numeric,integral) -> std.result(std.size, err))
+	generic putle8	: (f : file#, v : @a -> std.result(std.size, err)) :: numeric,integral @a
+	generic putle16	: (f : file#, v : @a -> std.result(std.size, err)) :: numeric,integral @a
+	generic putle32	: (f : file#, v : @a -> std.result(std.size, err)) :: numeric,integral @a
+	generic putle64	: (f : file#, v : @a -> std.result(std.size, err)) :: numeric,integral @a
 ;;
 
 generic putbe8  = {f, v; -> putbe(f, (v : uint64), 1)}
--- a/lib/crypto/rand.myr
+++ b/lib/crypto/rand.myr
@@ -8,8 +8,8 @@
 pkg crypto =
 	/* designed to mirror std.rand() */
 	const randbytes	: (buf : byte[:] -> void)
-	generic rand	: (lo : @a::(integral,numeric), hi : @a::(integral,numeric) -> @a::(numeric,integral))
-	generic randnum	: (-> @a::(numeric,integral))
+	generic rand	: (lo : @a, hi : @a -> @a) ::numeric,integral @a
+	generic randnum	: (-> @a) :: numeric,integral @a
 ;;
 
 const Stirinterval = 16*std.MiB
--- a/lib/date/parse.myr
+++ b/lib/date/parse.myr
@@ -239,9 +239,8 @@
 		-> s
 	;;
 }
-generic intval = {dst : @a::(numeric,integral)#, s : byte[:], \
-		min : @a::(numeric,integral), max : @a::(numeric,integral), \
-		err : std.option(parsefail)# -> byte[:]
+
+generic intval = {dst : @a#, s : byte[:], min : @a, max : @a, err : std.option(parsefail)# -> byte[:] :: numeric,integral @a
 	var i, c, num
 
 	num = s
--- a/lib/std/bigint.myr
+++ b/lib/std/bigint.myr
@@ -22,7 +22,7 @@
 	;;
 
 	/* administrivia */
-	generic mkbigint	: (v : @a::(numeric,integral) -> bigint#)
+	generic mkbigint	: (v : @a -> bigint#) :: numeric,integral @a
 	const bigfrombytes	: (isneg : bool, v : byte[:] -> bigint#)
 	const bigfree	: (a : bigint# -> void)
 	const bigdup	: (a : bigint# -> bigint#)
@@ -40,7 +40,7 @@
 	const bigiszero	: (a : bigint# -> bool)
 	const bigiseven	: (a : bigint# -> bool)
 	const bigcmp	: (a : bigint#, b : bigint# -> order)
-	generic bigcmpi	: (a : bigint#, b : @a::(numeric,integral) -> order)
+	generic bigcmpi	: (a : bigint#, b : @a -> order) :: numeric,integral @a
 
 	/* shorthand for comparisons */
 	const bigeq	: (a : bigint#, b : bigint# -> bool)
@@ -48,11 +48,11 @@
 	const bigle	: (a : bigint#, b : bigint# -> bool)
 	const biggt	: (a : bigint#, b : bigint# -> bool)
 	const bigge	: (a : bigint#, b : bigint# -> bool)
-	generic bigeqi	: (a : bigint#, b : @a::(numeric,integral) -> bool)
-	generic biglti	: (a : bigint#, b : @a::(numeric,integral) -> bool)
-	generic biglei	: (a : bigint#, b : @a::(numeric,integral) -> bool)
-	generic biggti	: (a : bigint#, b : @a::(numeric,integral) -> bool)
-	generic biggei	: (a : bigint#, b : @a::(numeric,integral) -> bool)
+	generic bigeqi	: (a : bigint#, b : @a -> bool) :: numeric,integral @a
+	generic biglti	: (a : bigint#, b : @a -> bool) :: numeric,integral @a
+	generic biglei	: (a : bigint#, b : @a -> bool) :: numeric,integral @a
+	generic biggti	: (a : bigint#, b : @a -> bool) :: numeric,integral @a
+	generic biggei	: (a : bigint#, b : @a -> bool) :: numeric,integral @a
 
 	/* bigint*bigint -> bigint ops */
 	const bigadd	: (a : bigint#, b : bigint# -> bigint#)
@@ -71,15 +71,15 @@
 
 
 	/* bigint*int -> bigint ops */
-	generic bigaddi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
-	generic bigsubi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
-	generic bigmuli	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
-	generic bigdivi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
-	generic bigmodi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
-	generic bigshli	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
-	generic bigshri	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
-	generic bigandi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
-	generic bigori	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+	generic bigaddi	: (a : bigint#, b : @a -> bigint#) :: integral,numeric @a
+	generic bigsubi	: (a : bigint#, b : @a -> bigint#) :: integral,numeric @a
+	generic bigmuli	: (a : bigint#, b : @a -> bigint#) :: integral,numeric @a
+	generic bigdivi	: (a : bigint#, b : @a -> bigint#) :: integral,numeric @a
+	generic bigmodi	: (a : bigint#, b : @a -> bigint#) :: integral,numeric @a
+	generic bigshli	: (a : bigint#, b : @a -> bigint#) :: integral,numeric @a
+	generic bigshri	: (a : bigint#, b : @a -> bigint#) :: integral,numeric @a
+	generic bigandi	: (a : bigint#, b : @a -> bigint#) :: integral,numeric @a
+	generic bigori	: (a : bigint#, b : @a -> bigint#) :: integral,numeric @a
 
 	//const bigpowi	: (a : bigint#, b : uint64 -> bigint#)
 	//const bigmodpowi	: (b : bigint#, e : bigint#, m : bigint# -> bigint#)
@@ -93,7 +93,7 @@
 
 const Base = 0x100000000ul
 
-generic mkbigint = {v : @a::(integral,numeric)
+generic mkbigint = {v : @a :: integral,numeric @a
 	var a
 	var val
 
@@ -771,7 +771,7 @@
 	-> a
 }
 
-generic bigsubi = {a, b : @a::(numeric,integral)
+generic bigsubi = {a, b : @a :: numeric,integral @a
 	var bigb : bigint
 	var dig : uint32[2]
 
@@ -811,7 +811,7 @@
   a << s, with integer arg.
   logical left shift. any other type would be illogical.
  */
-generic bigshli = {a, s : @a::(numeric,integral)
+generic bigshli = {a, s : @a :: numeric,integral @a
 	var off, shift
 	var t, carry
 
--- a/lib/std/bitset.myr
+++ b/lib/std/bitset.myr
@@ -22,9 +22,9 @@
 	const bsmax	: (a : bitset# -> size)
 	const bscount	: (a : bitset# -> size)
 
-	generic bsput	: (bs : bitset#, v : @a::(integral,numeric) -> bool)
-	generic bsdel	: (bs : bitset#, v : @a::(integral,numeric) -> bool)
-	generic bshas	: (bs : bitset#, v : @a::(integral,numeric) -> bool)
+	generic bsput	: (bs : bitset#, v : @a -> bool) :: integral,numeric @a
+	generic bsdel	: (bs : bitset#, v : @a -> bool) :: integral,numeric @a
+	generic bshas	: (bs : bitset#, v : @a -> bool) :: integral,numeric @a
 
 	const bsdiff	: (a : bitset#, b : bitset# -> void)
 	const bsintersect	: (a : bitset#, b : bitset# -> void)
--- a/lib/std/chartype.myr
+++ b/lib/std/chartype.myr
@@ -25,7 +25,7 @@
 	const toupper	: (c : char -> char)
 	const totitle	: (c : char -> char)
 
-	generic charval : (c : char, base : int -> @a::(integral,numeric))
+	generic charval : (c : char, base : int -> @a) :: integral,numeric @a
 
 	const cellwidth	: (c : char -> int)
 ;;
@@ -1670,18 +1670,18 @@
 	-> c
 }
 
-generic charval = {c, base -> @a::(numeric,integral)
+generic charval = {c, base -> @a :: numeric,integral @a
 	var v = -1
 
 	if c >= '0' && c <= '9'
-		v =  (c - '0' : @a::(integral,numeric))
+		v =  (c - '0' : @a)
 	elif c >= 'a' && c <= 'z'
-		v =  (c - 'a' + 10 : @a::(integral,numeric))
+		v =  (c - 'a' + 10 : @a)
 	elif c >= 'A' && c <= 'Z'
-		v =  (c - 'A' + 10 : @a::(integral,numeric))
+		v =  (c - 'A' + 10 : @a)
 	;;
 
-	if v < 0 || v >= (base : @a::(integral,numeric))
+	if v < 0 || v >= (base : @a)
 		-> -1
 	;;
 	-> v
--- a/lib/std/endian.myr
+++ b/lib/std/endian.myr
@@ -1,16 +1,16 @@
 pkg std =
-	generic hosttonet	: (v : @a::(integral,numeric) -> @a::(integral,numeric))
-	generic nettohost	: (v : @a::(integral,numeric) -> @a::(integral,numeric))
+	generic hosttonet	: (v : @a -> @a) :: integral,numeric @a
+	generic nettohost	: (v : @a -> @a) :: integral,numeric @a
 ;;
 
 /* FIXME: we only support little endian platforms right now,
    so we assume a little endian machine. FIX THIS. */
-generic hosttonet = {v : @a::(integral,numeric)
+generic hosttonet = {v : @a :: integral,numeric @a
 	var i
 	var ret
 
 	ret = 0
-	for i = 0; i < sizeof(@a::(integral,numeric)); i++
+	for i = 0; i < sizeof(@a); i++
 		ret <<= 8
 		ret |= v & 0xff 
 		v >>= 8
@@ -18,12 +18,12 @@
 	-> ret
 }
 
-generic nettohost = {v : @a::(integral,numeric)
+generic nettohost = {v : @a :: integral,numeric @a
 	var i
 	var ret
 
 	ret = 0
-	for i = 0; i < sizeof(@a::(integral,numeric)); i++
+	for i = 0; i < sizeof(@a); i++
 		ret <<= 8
 		ret |= v & 0xff 
 		v >>= 8
--- a/lib/std/extremum.myr
+++ b/lib/std/extremum.myr
@@ -1,8 +1,8 @@
 pkg std =
-	generic min	: (a : @a::numeric, b : @a::numeric  -> @a::numeric)
-	generic max	: (a : @a::numeric, b : @a::numeric  -> @a::numeric)
-	generic clamp	: (a : @a::numeric, min : @a::numeric, max : @a::numeric -> @a::numeric)
-	generic abs	: (a : @a::numeric -> @a::numeric)
+	generic min	: (a : @a, b : @a -> @a)		:: numeric @a
+	generic max	: (a : @a, b : @a -> @a)		:: numeric @a
+	generic clamp	: (a : @a, min : @a, max : @a -> @a)	:: numeric @a
+	generic abs	: (a : @a -> @a)			:: numeric @a
 ;;
 
 generic min = {a, b
@@ -31,8 +31,8 @@
 	;;
 }
 
-generic abs = {a : @a::numeric
-	if a < (0 : @a::numeric)
+generic abs = {a : @a :: numeric @a
+	if a < (0 : @a)
 		-> -a
 	else
 		-> a
--- a/lib/std/fltbits.myr
+++ b/lib/std/fltbits.myr
@@ -6,7 +6,7 @@
 	const flt32inf	: (-> flt32)
 	const flt32nan	: (-> flt32)
 
-	generic isnan	: (f : @a::floating -> bool)
+	generic isnan		: (f : @a -> bool) ::floating @a
 	const flt64frombits	: (bits : uint64 -> flt64)
 	const flt32frombits	: (bits : uint32 -> flt32)
 	const flt64explode	: (flt : flt64 -> (bool, int64, int64))
--- a/lib/std/fmt.myr
+++ b/lib/std/fmt.myr
@@ -537,7 +537,7 @@
 	'5','6','7','8','9',
 	'a','b','c','d','e','f'
 ]
-generic intfmt = {sb, opts, signed, bits : @a::(integral,numeric)
+generic intfmt = {sb, opts, signed, bits : @a :: integral,numeric @a
 	var isneg
 	var sval, val
 	var b : char[32]
@@ -557,7 +557,7 @@
 		;;
 	else
 		val = (bits : uint64)
-		val &= ~0 >> (8*(sizeof(uint64)-sizeof(@a::(integral,numeric))))
+		val &= ~0 >> (8*(sizeof(uint64)-sizeof(@a)))
 		isneg = false
 	;;
 
--- a/lib/std/fndup.myr
+++ b/lib/std/fndup.myr
@@ -5,10 +5,10 @@
 use "types"
 
 pkg std =
-	generic fnenvsz	: (fn : @fn::function -> size)
-	generic fndup	: (fn : @fn::function -> @fn::function)
-	generic fnbdup	: (fn : @fn::function, buf : byte[:] -> @fn::function)
-	generic fnfree	: (fn : @fn::function -> void)
+	generic fnenvsz	: (fn : @fn -> size)	:: function @fn
+	generic fndup	: (fn : @fn -> @fn)	:: function @fn
+	generic fnbdup	: (fn : @fn, buf : byte[:] -> @fn)	:: function @fn
+	generic fnfree	: (fn : @fn -> void)	:: function @fn
 ;;
 
 generic fndup = {fn
@@ -27,7 +27,7 @@
 
 extern const put : (fmt : byte[:], args : ... -> int64)
 
-generic fnbdup = {fn, buf
+generic fnbdup = {fn : @fn, buf	:: function @fn
 	var repr : intptr[2]
 	var env
 
@@ -35,7 +35,7 @@
 	env = envslice(repr[0])
 	slcp(buf[:env.len], env)
 	repr[0] = (buf : intptr)
-	-> (&repr : @fn::function#)#
+	-> (&repr : @fn#)#
 }
 
 generic fnfree = {fn
--- a/lib/std/getint.myr
+++ b/lib/std/getint.myr
@@ -2,95 +2,95 @@
 use "memops"
 
 pkg std =
-	generic gethost64	: (buf : byte[:]	-> @a::(numeric,integral))
-	generic getle64		: (buf : byte[:]	-> @a::(numeric,integral))
-	generic getbe64		: (buf : byte[:]	-> @a::(numeric,integral))
-	generic gethost32	: (buf : byte[:]	-> @a::(numeric,integral))
-	generic getle32		: (buf : byte[:]	-> @a::(numeric,integral))
-	generic getbe32		: (buf : byte[:]	-> @a::(numeric,integral))
-	generic gethost16	: (buf : byte[:]	-> @a::(numeric,integral))
-	generic getle16		: (buf : byte[:]	-> @a::(numeric,integral))
-	generic getbe16		: (buf : byte[:]	-> @a::(numeric,integral))
-	generic gethost8	: (buf : byte[:]	-> @a::(numeric,integral))
-	generic getle8		: (buf : byte[:]	-> @a::(numeric,integral))
-	generic getbe8		: (buf : byte[:]	-> @a::(numeric,integral))
+	generic gethost64	: (buf : byte[:]	-> @a) :: numeric,integral @a
+	generic getle64		: (buf : byte[:]	-> @a) :: numeric,integral @a
+	generic getbe64		: (buf : byte[:]	-> @a) :: numeric,integral @a
+	generic gethost32	: (buf : byte[:]	-> @a) :: numeric,integral @a
+	generic getle32		: (buf : byte[:]	-> @a) :: numeric,integral @a
+	generic getbe32		: (buf : byte[:]	-> @a) :: numeric,integral @a
+	generic gethost16	: (buf : byte[:]	-> @a) :: numeric,integral @a
+	generic getle16		: (buf : byte[:]	-> @a) :: numeric,integral @a
+	generic getbe16		: (buf : byte[:]	-> @a) :: numeric,integral @a
+	generic gethost8	: (buf : byte[:]	-> @a) :: numeric,integral @a
+	generic getle8		: (buf : byte[:]	-> @a) :: numeric,integral @a
+	generic getbe8		: (buf : byte[:]	-> @a) :: numeric,integral @a
 ;;
 
-generic gethost64 = {buf -> @a::(numeric,integral)
+generic gethost64 = {buf -> @a :: numeric,integral @a
 	var val : int64
 	iassert(buf.len >= 8, "gethost64: index out of bounds")
 	memblit((&val : byte#), (buf : byte#), 8)
-	-> (val : @a::(numeric,integral))
+	-> (val : @a)
 }
 
-generic getbe64 = {buf -> @a::(numeric,integral)
-	-> ((buf[0] : @a::(numeric,integral)) << 56) | \
-		((buf[1] : @a::(numeric,integral)) << 48) | \
-		((buf[2] : @a::(numeric,integral)) << 40) | \
-		((buf[3] : @a::(numeric,integral)) << 32) | \
-		((buf[4] : @a::(numeric,integral)) << 24) | \
-		((buf[5] : @a::(numeric,integral)) << 16) | \
-		((buf[6] : @a::(numeric,integral)) << 8) | \
-		((buf[7] : @a::(numeric,integral)) << 0)
+generic getbe64 = {buf -> @a :: numeric,integral @a
+	->	((buf[0] : @a) << 56) | \
+		((buf[1] : @a) << 48) | \
+		((buf[2] : @a) << 40) | \
+		((buf[3] : @a) << 32) | \
+		((buf[4] : @a) << 24) | \
+		((buf[5] : @a) << 16) | \
+		((buf[6] : @a) << 8) | \
+		((buf[7] : @a) << 0)
 }
 
 generic getle64 = {buf
-	-> ((buf[0] : @a::(numeric,integral))  << 0) | \
-		((buf[1] : @a::(numeric,integral))  << 8) | \
-		((buf[2] : @a::(numeric,integral))  << 16) | \
-		((buf[3] : @a::(numeric,integral))  << 24) | \
-		((buf[4] : @a::(numeric,integral))  << 32) | \
-		((buf[5] : @a::(numeric,integral))  << 40) | \
-		((buf[6] : @a::(numeric,integral))  << 48) | \
-		((buf[7] : @a::(numeric,integral))  << 56)
+	->	((buf[0] : @a)  << 0) | \
+		((buf[1] : @a)  << 8) | \
+		((buf[2] : @a)  << 16) | \
+		((buf[3] : @a)  << 24) | \
+		((buf[4] : @a)  << 32) | \
+		((buf[5] : @a)  << 40) | \
+		((buf[6] : @a)  << 48) | \
+		((buf[7] : @a)  << 56)
 }
 
-generic gethost32 = {buf -> @a::(numeric,integral)
+generic gethost32 = {buf -> @a :: numeric,integral @a
 	var val : int32
 	iassert(buf.len >= 4, "gethost32: index out of bounds")
 	memblit((&val : byte#), (buf : byte#), 4)
-	-> (val : @a::(numeric,integral))
+	-> (val : @a)
 }
 
-generic getbe32 = {buf
-	-> ((buf[0] : @a::(numeric,integral)) << 24) | \
-		((buf[1] : @a::(numeric,integral)) << 16) | \
-		((buf[2] : @a::(numeric,integral)) << 8) | \
-		((buf[3] : @a::(numeric,integral)) << 0)
+generic getbe32 = {buf -> @a :: numeric, integral @a
+	->	((buf[0] : @a) << 24) | \
+		((buf[1] : @a) << 16) | \
+		((buf[2] : @a) << 8) | \
+		((buf[3] : @a) << 0)
 }
 
-generic getle32 = {buf
-	-> ((buf[0] : @a::(numeric,integral)) << 0) | \
-		((buf[1] : @a::(numeric,integral)) << 8) | \
-		((buf[2] : @a::(numeric,integral)) << 16) | \
-		((buf[3] : @a::(numeric,integral)) << 24)
+generic getle32 = {buf -> @a :: numeric, integral @a
+	-> ((buf[0] : @a) << 0) | \
+		((buf[1] : @a) << 8) | \
+		((buf[2] : @a) << 16) | \
+		((buf[3] : @a) << 24)
 }
 
-generic gethost16 = {buf -> @a::(numeric,integral)
+generic gethost16 = {buf -> @a :: numeric,integral @a
 	var val : int16
 	iassert(buf.len >= 2, "gethost16: index out of bounds")
 	memblit((&val : byte#), (buf : byte#), 4)
-	-> (val : @a::(numeric,integral))
+	-> (val : @a)
 }
 
-generic getbe16 = {buf
-	-> ((buf[0] : @a::(numeric,integral)) << 8) | \
-		((buf[1] : @a::(numeric,integral)) << 0)
+generic getbe16 = {buf -> @a :: numeric,integral @a
+	-> ((buf[0] : @a) << 8) | \
+		((buf[1] : @a) << 0)
 }
 
-generic getle16 = {buf
-	-> ((buf[0] : @a::(numeric,integral)) << 0) | \
-		((buf[1] : @a::(numeric,integral)) << 8)
+generic getle16 = {buf -> @a :: numeric,integral @a
+	-> ((buf[0] : @a) << 0) | \
+		((buf[1] : @a) << 8)
 }
 
-generic gethost8 = {buf
-	-> (buf[0] : @a::(numeric,integral)) << 0
+generic gethost8 = {buf -> @a :: numeric,integral @a
+	-> (buf[0] : @a) << 0
 }
 
-generic getbe8 = {buf
-	-> (buf[0] : @a::(numeric,integral)) << 0
+generic getbe8 = {buf -> @a :: numeric,integral @a
+	-> (buf[0] : @a) << 0
 }
 
-generic getle8 = {buf
-	-> (buf[0] : @a::(numeric,integral)) << 0
+generic getle8 = {buf -> @a :: numeric,integral @a
+	-> (buf[0] : @a) << 0
 }
--- a/lib/std/hashfuncs.myr
+++ b/lib/std/hashfuncs.myr
@@ -23,13 +23,13 @@
 		}
 	;;
 
-	impl equatable @a::(integral,numeric) =
+	impl equatable @a :: integral,numeric @a =
 		eq = {a, b
 			-> a == b
 		}
 	;;
 
-	impl hashable @a::(integral,numeric) =
+	impl hashable @a :: integral,numeric @a =
 		hash = {a
 			-> siphash24((&a : byte#)[:sizeof(@a)], Seed)
 		}
--- a/lib/std/intparse.myr
+++ b/lib/std/intparse.myr
@@ -7,8 +7,8 @@
 use "utf"
 
 pkg std =
-	generic intparsebase	: (s : byte[:], base : int -> option(@a::(integral,numeric)))
-	generic intparse	: (s : byte[:]	-> option(@a::(integral,numeric)))
+	generic intparsebase	: (s : byte[:], base : int -> option(@a)) :: integral,numeric @a
+	generic intparse	: (s : byte[:]	-> option(@a)) ::  integral,numeric @a
 ;;
 
 generic intparse = {s
@@ -47,7 +47,7 @@
 	-> doparse(s, isneg, base)
 }
 
-generic doparse = {s, isneg, base ->  option(@a::(integral,numeric))
+generic doparse = {s, isneg, base ->  option(@a) :: integral,numeric @a
 	var v
 	var cv : int32
 	
@@ -58,8 +58,8 @@
 		;;
 		cv = charval(c, base)
 		if cv >= 0
-			v *= (base : @a::(integral,numeric))
-			v += (cv : @a::(integral,numeric))
+			v *= (base : @a)
+			v += (cv : @a)
 		else
 			-> `None
 		;;
--- a/lib/std/ipparse.myr
+++ b/lib/std/ipparse.myr
@@ -116,7 +116,7 @@
 	;;
 }
 
-generic num = {ip, lo, hi, base, sep, ok -> (@a::(numeric,integral), byte[:], bool)
+generic num = {ip, lo, hi, base, sep, ok -> (@a, byte[:], bool) :: numeric,integral @a
 	var len
 
 	if !ok
@@ -133,7 +133,7 @@
 		if v < lo || v > hi
 			-> (0, "", false)
 		;;
-		-> ((v : @a::(numeric,integral)), ip[len:], true)
+		-> ((v : @a), ip[len:], true)
 	| `std.None:
 		-> (0, "", false)
 	;;
--- a/lib/std/putint.myr
+++ b/lib/std/putint.myr
@@ -3,21 +3,21 @@
 use "types"
 
 pkg std =
-	generic puthost64	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
-	generic putle64		: (buf : byte[:], v :  @a::(numeric,integral) -> size)
-	generic putbe64		: (buf : byte[:], v :  @a::(numeric,integral) -> size)
-	generic puthost32	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
-	generic putle32		: (buf : byte[:], v :  @a::(numeric,integral) -> size)
-	generic putbe32		: (buf : byte[:], v :  @a::(numeric,integral) -> size)
-	generic puthost16	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
-	generic putle16		: (buf : byte[:], v :  @a::(numeric,integral) -> size)
-	generic putbe16		: (buf : byte[:], v :  @a::(numeric,integral) -> size)
-	generic puthost8	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
-	generic putle8		: (buf : byte[:], v :  @a::(numeric,integral) -> size)
-	generic putbe8		: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+	generic puthost64	: (buf : byte[:], v :  @a -> size) :: numeric,integral @a
+	generic putle64		: (buf : byte[:], v :  @a -> size) :: numeric,integral @a
+	generic putbe64		: (buf : byte[:], v :  @a -> size) :: numeric,integral @a
+	generic puthost32	: (buf : byte[:], v :  @a -> size) :: numeric,integral @a
+	generic putle32		: (buf : byte[:], v :  @a -> size) :: numeric,integral @a
+	generic putbe32		: (buf : byte[:], v :  @a -> size) :: numeric,integral @a
+	generic puthost16	: (buf : byte[:], v :  @a -> size) :: numeric,integral @a
+	generic putle16		: (buf : byte[:], v :  @a -> size) :: numeric,integral @a
+	generic putbe16		: (buf : byte[:], v :  @a -> size) :: numeric,integral @a
+	generic puthost8	: (buf : byte[:], v :  @a -> size) :: numeric,integral @a
+	generic putle8		: (buf : byte[:], v :  @a -> size) :: numeric,integral @a
+	generic putbe8		: (buf : byte[:], v :  @a -> size) :: numeric,integral @a
 ;;
 
-generic puthost = {buf, val : @a::(integral, numeric)
+generic puthost = {buf, val : @a :: integral, numeric @a
 	iassert(buf.len >= sizeof(@a), "buffer too small")
 	memblit((buf : byte#), (&val : byte#), sizeof(@a))
 	-> sizeof(@a)
--- a/lib/std/rand.myr
+++ b/lib/std/rand.myr
@@ -13,12 +13,12 @@
 	const mksrng	: (seed : uint32 -> rng#)
 	const freerng	: (rng : rng# -> void)
 
-	generic rand	: (lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral))
-	generic randnum	: (-> @a::(numeric,integral))
+	generic rand	: (lo : @a, hi : @a -> @a) :: numeric,integral @a
+	generic randnum	: (-> @a) :: numeric,integral @a
 	const randbytes	: (buf : byte[:] -> void)
 
-	generic rngrand	: (rng : rng#, lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral))
-	generic rngrandnum	: (rng : rng# -> @a::(numeric,integral))
+	generic rngrand	: (rng : rng#, lo : @a, hi : @a -> @a) ::numeric,integral @a
+	generic rngrandnum	: (rng : rng# -> @a) :: numeric,integral @a
 	const rngrandbytes	: (rng : rng#, buf : byte[:] -> void)
 ;;
 
@@ -90,7 +90,7 @@
 
 See http://xoroshiro.di.unimi.it/ for details.
 */
-generic rngrandnum = {rng -> @a::(numeric,integral)
+generic rngrandnum = {rng -> @a :: numeric,integral @a
 	var s0, s1, r
 
 	s0 = rng.s0
@@ -101,5 +101,5 @@
 
 	rng.s0 = (s0 << 55 | s0 >> 9) ^ s1 ^ (s1 << 14)
 	rng.s1 = (s1 << 36 | s1 >> 28)
-	-> (r : @a::(numeric,integral))
+	-> (r : @a)
 }
--- a/lib/std/search.myr
+++ b/lib/std/search.myr
@@ -3,8 +3,8 @@
 use "types"
 
 pkg std =
-	generic lsearch	: (sl : @t[:], key : @k, cmp : (v : @t, k : @k -> order) -> option(@idx::(integral,numeric)))
-	generic bsearch	: (sl : @t[:], key : @k, cmp : (v : @t, k : @k -> order) -> option(@idx::(integral,numeric)))
+	generic lsearch	: (sl : @t[:], key : @k, cmp : (v : @t, k : @k -> order) -> option(@idx)) :: integral,numeric @idx
+	generic bsearch	: (sl : @t[:], key : @k, cmp : (v : @t, k : @k -> order) -> option(@idx)) :: integral,numeric @idx
 ;;
 
 /* linear search over a list of values */
--- a/lib/std/syswrap+posixy.myr
+++ b/lib/std/syswrap+posixy.myr
@@ -179,7 +179,7 @@
 	;;
 }
 
-generic check = {e : @a::(integral, numeric) -> result(@b, errno)
+generic check = {e : @a -> result(@b, errno) :: integral,numeric @a
 	if e < 0
 		-> `Err (e : errno)
 	else
--- a/lib/std/units.myr
+++ b/lib/std/units.myr
@@ -2,14 +2,14 @@
 
 pkg std =
 	/* JEDEC 100B.1 memory sizes */
-	generic KiB	: @a::(integral,numeric)	= 1024 
-	generic MiB	: @a::(integral,numeric)	= KiB*1024
-	generic GiB	: @a::(integral,numeric)	= MiB*1024
-	generic TiB	: @a::(integral,numeric)	= GiB*1024
-	generic PiB	: @a::(integral,numeric)	= TiB*1024
-	generic EiB	: @a::(integral,numeric)	= PiB*1024
-	generic ZiB	: @a::(integral,numeric)	= EiB*1024
-	generic YiB	: @a::(integral,numeric)	= ZiB*1024
+	generic KiB	: @a	= 1024 		:: integral,numeric @a
+	generic MiB	: @a	= KiB*1024      :: integral,numeric @a
+	generic GiB	: @a	= MiB*1024      :: integral,numeric @a
+	generic TiB	: @a	= GiB*1024      :: integral,numeric @a
+	generic PiB	: @a	= TiB*1024      :: integral,numeric @a
+	generic EiB	: @a	= PiB*1024      :: integral,numeric @a
+	generic ZiB	: @a	= EiB*1024      :: integral,numeric @a
+	generic YiB	: @a	= ZiB*1024      :: integral,numeric @a
 
 	generic Sec	: time	= 1_000_000
 	generic Msec	: time	= 1_000
--- a/lib/thread/atomic.myr
+++ b/lib/thread/atomic.myr
@@ -1,7 +1,7 @@
 use std
 
 pkg thread =
-	trait atomic @a::(integral,numeric) =
+	trait atomic @a :: integral,numeric @a =
 		xget	: (p : @a# -> @a)
 		xset	: (p : @a#, v : @a -> void)
 		xadd	: (p : @a#, v : @a -> @a)
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -18,10 +18,11 @@
 #include "parse.h"
 
 
-Stab *curscope;
 #define LBLSTKSZ 64
 static Node **lbls[LBLSTKSZ];
 static size_t nlbls[LBLSTKSZ];
+Stab *curscope;
+
 /* the first time we see a label, we increment to 0 */
 static int lbldepth = -1;
 
@@ -32,6 +33,7 @@
 static Node *mkpseudodecl(Srcloc l, Type *t);
 static void installucons(Stab *st, Type *t);
 static void setattrs(Node *dcl, char **attrs, size_t nattrs);
+static void setwith(Type *ty, Traitspec **spec, size_t nspec);
 static void setupinit(Node *n);
 
 %}
@@ -132,7 +134,9 @@
 %type <ty> type structdef uniondef tupledef compoundtype functype funcsig
 %type <ty> generictype
 %type <tylist> typelist typarams optauxtypes
-%type <nodelist> typaramlist
+%type <traitspecs> traitspec traits
+%type <traitspec> traitvar
+%type <nodelist> traitlist
 
 %type <tok> asnop cmpop addop mulop shiftop optident obrace
 
@@ -207,6 +211,11 @@
 		Type **params;
 		size_t nparams;
 	} tydef;
+	struct {
+		Traitspec **spec;
+		size_t nspec;
+	} traitspecs;
+	Traitspec *traitspec;
 	Trait *trait;
 	Node *node;
 	Tok  *tok;
@@ -254,7 +263,7 @@
 	| /* empty */
 	;
 
-decl	: attrs Tvar decllist {
+decl	: attrs Tvar decllist traitspec {
 		size_t i;
 
 		for (i = 0; i < $3.nn; i++)
@@ -261,7 +270,7 @@
 			setattrs($3.nl[i], $1.str, $1.nstr);
 		$$ = $3;
 	}
-	| attrs Tconst decllist {
+	| attrs Tconst decllist traitspec {
 		size_t i;
 		for (i = 0; i < $3.nn; i++) {
 			setattrs($3.nl[i], $1.str, $1.nstr);
@@ -269,11 +278,12 @@
 		}
 		$$ = $3;
 	}
-	| attrs Tgeneric decllist {
+	| attrs Tgeneric decllist traitspec {
 		size_t i;
 
 		for (i = 0; i < $3.nn; i++) {
 			setattrs($3.nl[i], $1.str, $1.nstr);
+			setwith($3.nl[i]->decl.type, $4.spec, $4.nspec);
 			$3.nl[i]->decl.isconst = 1;
 			$3.nl[i]->decl.isgeneric = 1;
 		}
@@ -288,6 +298,50 @@
 	}
 	;
 
+traitspec
+	: Twith traits	{$$ = $2;}
+	| /* nothing */ {$$.nspec = 0;}
+	;
+
+traits	: traitvar {
+       		$$.spec = NULL;
+       		$$.nspec = 0;
+		lappend(&$$.spec, &$$.nspec, $1);
+	}
+	| traits listsep traitvar {
+		$$ = $1;
+		lappend(&$$.spec, &$$.nspec, $3);
+	}
+	;
+
+traitvar
+	: traitlist generictype {
+		$$ = calloc(sizeof(Traitspec), 1);
+		$$->traits = $1.nl;
+		$$->ntraits = $1.nn;
+		$$->param = $2;
+		$$->aux = NULL;
+	}
+	| traitlist generictype Tret type {
+		$$ = calloc(sizeof(Traitspec), 1);
+		$$->traits = $1.nl;
+		$$->ntraits = $1.nn;
+		$$->param = $2;
+		$$->aux = $4;
+	}
+	;
+
+traitlist
+	: name {
+		$$.nl = 0;
+		$$.nn = 0;
+		lappend(&$$.nl, &$$.nn, $1);
+	}
+	| traitlist listsep name {
+		lappend(&$$.nl, &$$.nn, $3);
+	}
+	;
+
 decllist: declbody {
 		$$.loc = $1->loc; $$.nl = NULL; $$.nn = 0;
 		lappend(&$$.nl, &$$.nn, $1);
@@ -388,12 +442,22 @@
 	;
 
 implstmt
-	: Timpl name type optauxtypes {
+	: Timpl name type optauxtypes traitspec {
+		size_t i;
+
 		$$ = mkimplstmt($1->loc, $2, $3, $4.types, $4.ntypes, NULL, 0);
 		$$->impl.isproto = 1;
+		setwith($3, $5.spec, $5.nspec);
+		for (i = 0; i < $4.ntypes; i++)
+			setwith($4.types[i], $5.spec, $5.nspec);
 	}
-	| Timpl name type optauxtypes Tasn Tendln implbody Tendblk {
-		$$ = mkimplstmt($1->loc, $2, $3, $4.types, $4.ntypes, $7.nl, $7.nn);
+	| Timpl name type optauxtypes traitspec Tasn Tendln implbody Tendblk {
+		size_t i;
+
+		$$ = mkimplstmt($1->loc, $2, $3, $4.types, $4.ntypes, $8.nl, $8.nn);
+		setwith($3, $5.spec, $5.nspec);
+		for (i = 0; i < $4.ntypes; i++)
+			setwith($4.types[i], $5.spec, $5.nspec);
 	}
 	;
 
@@ -411,25 +475,32 @@
 	;
 
 traitdef
-	: Ttrait Tident generictype optauxtypes { /* trait prototype */
+	: Ttrait Tident generictype optauxtypes traitspec { /* trait prototype */
+		size_t i;
 		$$ = mktrait($1->loc,
 			mkname($2->loc, $2->id), $3,
 			$4.types, $4.ntypes,
 			NULL, 0,
 			1);
+		setwith($3, $5.spec, $5.nspec);
+		for (i = 0; i < $4.ntypes; i++)
+			setwith($4.types[i], $5.spec, $5.nspec);
 	}
-	| Ttrait Tident generictype optauxtypes Tasn traitbody Tendblk /* trait definition */ {
+	| Ttrait Tident generictype optauxtypes traitspec Tasn traitbody Tendblk /* trait definition */ {
 		size_t i;
 		$$ = mktrait($1->loc,
 			mkname($2->loc, $2->id), $3,
 			$4.types, $4.ntypes,
-			$6.nl, $6.nn,
+			$7.nl, $7.nn,
 			0);
-		for (i = 0; i < $6.nn; i++) {
-			$6.nl[i]->decl.trait = $$;
-			$6.nl[i]->decl.impls = mkht(tyhash, tyeq);
-			$6.nl[i]->decl.isgeneric = 1;
+		for (i = 0; i < $7.nn; i++) {
+			$7.nl[i]->decl.trait = $$;
+			$7.nl[i]->decl.impls = mkht(tyhash, tyeq);
+			$7.nl[i]->decl.isgeneric = 1;
 		}
+		setwith($3, $5.spec, $5.nspec);
+		for (i = 0; i < $4.ntypes; i++)
+			setwith($4.types[i], $5.spec, $5.nspec);
 	}
 	;
 
@@ -452,14 +523,14 @@
 	;
 
 
-tydef	: Ttype typeid {$$ = $2;}
-	| Ttype typeid Tasn type {
+tydef	: Ttype typeid traitspec {$$ = $2;}
+	| Ttype typeid traitspec Tasn type {
 		$$ = $2;
-		if ($$.nparams == 0) {
-			$$.type = mktyname($2.loc, mkname($2.loc, $2.name), $4);
-		} else {
-			$$.type = mktygeneric($2.loc, mkname($2.loc, $2.name), $2.params, $2.nparams, $4);
-		}
+		if ($$.nparams == 0)
+			$$.type = mktyname($2.loc, mkname($2.loc, $2.name), $5);
+		else
+			$$.type = mktygeneric($2.loc, mkname($2.loc, $2.name), $2.params, $2.nparams, $5);
+		setwith($$.type, $3.spec, $3.nspec);
 	}
 	;
 
@@ -498,35 +569,17 @@
 
 generictype
 	: Ttyparam {$$ = mktyparam($1->loc, $1->id);}
-	| Ttyparam Twith name {
-		$$ = mktyparam($1->loc, $1->id);
-		lappend(&$$->traits, &$$->ntraits, $3);
-	}
-	| Ttyparam Twith Toparen typaramlist Tcparen {
-		size_t i;
-		$$ = mktyparam($1->loc, $1->id);
-		for (i = 0; i < $4.nn; i++)
-			lappend(&$$->traits, &$$->ntraits, $4.nl[i]);
-	}
 	;
 
-typaramlist
-	: name {
-		$$.nl = NULL; $$.nn = 0;
-		lappend(&$$.nl, &$$.nn, $1);
-	}
-	| typaramlist listsep name {lappend(&$$.nl, &$$.nn, $3);}
-	;
-
 compoundtype
-	: functype   {$$ = $1;}
-	| type Tosqbrac Tcolon Tcsqbrac {$$ = mktyslice($2->loc, $1);}
-	| type Tosqbrac expr Tcsqbrac {$$ = mktyarray($2->loc, $1, $3);}
-	| type Tosqbrac Tellipsis Tcsqbrac {$$ = mktyarray($2->loc, $1, NULL);}
-	| name Toparen typelist Tcparen {$$ = mktyunres($1->loc, $1, $3.types, $3.ntypes);}
-	| type Tderef	{$$ = mktyptr($2->loc, $1);}
-	| Tvoidlit	{$$ = mktyunres($1->loc, mkname($1->loc, $1->id), NULL, 0);}
-	| name	{$$ = mktyunres($1->loc, $1, NULL, 0);}
+	: functype   				{$$ = $1;}
+	| type Tosqbrac Tcolon Tcsqbrac		{$$ = mktyslice($2->loc, $1);}
+	| type Tosqbrac expr Tcsqbrac		{$$ = mktyarray($2->loc, $1, $3);}
+	| type Tosqbrac Tellipsis Tcsqbrac 	{$$ = mktyarray($2->loc, $1, NULL);}
+	| name Toparen typelist Tcparen 	{$$ = mktyunres($1->loc, $1, $3.types, $3.ntypes);}
+	| type Tderef				{$$ = mktyptr($2->loc, $1);}
+	| Tvoidlit				{$$ = mktyunres($1->loc, mkname($1->loc, $1->id), NULL, 0);}
+	| name					{$$ = mktyunres($1->loc, $1, NULL, 0);}
 	;
 
 functype: Toparen funcsig Tcparen {$$ = $2;}
@@ -826,11 +879,13 @@
 	}
 	;
 
-funclit : obrace params Tendln blkbody Tcbrace {
+funclit : obrace params traitspec Tendln blkbody Tcbrace {
 		size_t i;
 		Node *fn, *lit;
 
-		$$ = mkfunc($1->loc, $2.nl, $2.nn, mktyvar($3->loc), $4);
+		for (i = 0; i < $2.nn; i++)
+			setwith($2.nl[i]->decl.type, $3.spec, $3.nspec);
+		$$ = mkfunc($1->loc, $2.nl, $2.nn, mktyvar($4->loc), $5);
 		fn = $$->lit.fnval;
 		for (i = 0; i < nlbls[lbldepth]; i++) {
 			lit = lbls[lbldepth][i]->expr.args[0];
@@ -840,11 +895,14 @@
 		assert(lbldepth >= 0);
 		lbldepth--;
 	}
-	| obrace params Tret type Tendln blkbody Tcbrace {
+	| obrace params Tret type traitspec Tendln blkbody Tcbrace {
 		size_t i;
 		Node *fn, *lit;
 
-		$$ = mkfunc($1->loc, $2.nl, $2.nn, $4, $6);
+		setwith($4, $5.spec, $5.nspec);
+		for (i = 0; i < $2.nn; i++)
+			setwith($2.nl[i]->decl.type, $5.spec, $5.nspec);
+		$$ = mkfunc($1->loc, $2.nl, $2.nn, $4, $7);
 		fn = $$->lit.fnval;
 		for (i = 0; i < nlbls[lbldepth]; i++) {
 			lit = lbls[lbldepth][i]->expr.args[0];
@@ -1098,6 +1156,48 @@
 			dcl->decl.isnoret = 1;
 		else if (!strcmp(attrs[i], "pkglocal"))
 			dcl->decl.ispkglocal = 1;
+	}
+}
+
+static void setwith(Type *ty, Traitspec **ts, size_t nts)
+{
+	size_t i, j;
+
+	if (!ty)
+		return;
+	for (i = 0; i < nts; i++) {
+		switch (ty->type) {
+		case Typaram:
+			if (tyeq(ty, ts[i]->param))
+				lappend(&ty->spec, &ty->nspec, ts[i]);
+
+			break;
+		case Tyname:
+		case Tyunres:
+			for (j = 0; j < ty->ngparam; j++)
+				setwith(ty->gparam[j], ts, nts);
+			for (j = 0; j < ty->narg; j++)
+				setwith(ty->arg[j], ts, nts);
+			break;
+		case Tystruct:
+			for (j = 0; j < ty->nmemb; j++)
+				setwith(ty->sdecls[j]->decl.type, ts, nts);
+			break;
+		case Tyunion:
+			for (j = 0; j < ty->nmemb; j++)
+				setwith(ty->udecls[j]->etype, ts, nts);
+			break;
+		case Typtr:
+		case Tyarray:
+		case Tyslice:
+		case Tyfunc:
+		case Tytuple:
+			for (j = 0; j < ty->nsub; j++)
+				setwith(ty->sub[j], ts, nts);
+			break;
+		default:
+			break;
+		}
 	}
 }
 
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -66,7 +66,6 @@
 static size_t nspecializations;
 static Stab **specializationscope;
 static size_t nspecializationscope;
-static Htab *seqbase;
 static Traitmap *traitmap;
 
 static void
@@ -482,7 +481,7 @@
 static void
 tyresolve(Type *t)
 {
-	size_t i;
+	size_t i, j;
 	Trait *tr;
 
 	if (t->resolved)
@@ -526,13 +525,15 @@
 		break;
 	}
 
-	for (i = 0; i < t->ntraits; i++) {
-		tr = gettrait(curstab(), t->traits[i]);
-		if (!tr)
-			lfatal(t->loc, "trait %s does not exist", ctxstr(t->traits[i]));
-		if (!t->trneed)
-			t->trneed = mkbs();
-		bsput(t->trneed, tr->uid);
+	for (i = 0; i < t->nspec; i++) {
+		for (j = 0; j < t->spec[i]->ntraits; j++) {
+			tr = gettrait(curstab(), t->spec[i]->traits[j]);
+			if (!tr)
+				lfatal(t->loc, "trait %s does not exist", ctxstr(t->spec[i]->traits[j]));
+			if (!t->trneed)
+				t->trneed = mkbs();
+			bsput(t->trneed, tr->uid);
+		}
 	}
 
 	for (i = 0; i < t->nsub; i++) {
@@ -2898,7 +2899,6 @@
 infer(void)
 {
 	delayed = mkht(tyhash, tyeq);
-	seqbase = mkht(tyhash, tyeq);
 	loaduses();
 	initimpl();
 
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -2,6 +2,7 @@
 
 typedef struct Srcloc Srcloc;
 typedef struct Tysubst Tysubst;
+typedef struct Traitspec Traitspec;
 
 typedef struct Tok Tok;
 typedef struct Node Node;
@@ -118,6 +119,13 @@
 	Htab *tab;
 };
 
+struct Traitspec {
+	Node **traits;
+	size_t ntraits;
+	Type *param;
+	Type *aux;
+};
+
 struct Type {
 	Ty type;
 	uint32_t tid;
@@ -125,8 +133,10 @@
 	Vis vis;
 
 
-	Node **traits;		/* trait list */
-	size_t ntraits;		/* trait list size */
+	Traitspec **spec;
+	size_t nspec;
+	//Node **traits;		/* trait list */
+	//size_t ntraits;		/* trait list size */
 
 	Type **gparam;		/* Tygeneric: type parameters that match the type args */
 	size_t ngparam;		/* Tygeneric: count of type parameters */
@@ -350,6 +360,7 @@
 };
 
 /* globals */
+extern Htab *seqbase;
 extern Srcloc curloc;
 extern char *filename;
 extern Tok *curtok;	/* the last token we tokenized */
--- a/parse/type.c
+++ b/parse/type.c
@@ -24,6 +24,7 @@
 Node **impltab;
 size_t nimpltab;
 Htab *eqcache;
+Htab *seqbase;
 
 struct Typair {
 	uint32_t atid;
@@ -1083,6 +1084,7 @@
 	Type *ty;
 	Trait *tr;
 
+	seqbase = mkht(tyhash, tyeq);
 	eqcache = mkht(typairhash, typaireq);
 	tydeduptab = mkht(tyhash, tystricteq);
 	/* this must be done after all the types are created, otherwise we will
--- a/test/emptytrait.myr
+++ b/test/emptytrait.myr
@@ -6,7 +6,7 @@
 impl fooable int =
 ;;
 
-generic foo = {x : @a::fooable
+generic foo = {x : @a::fooable @a
 	-> x
 }
 
--- a/test/generictype.myr
+++ b/test/generictype.myr
@@ -1,8 +1,8 @@
 use std
 
 /* checks that parameterized types work. exits with 0. */
-type option(@a::(integral,numeric)) = union
-	`Some @a::(integral,numeric)
+type option(@a) :: integral,numeric @a = union
+	`Some @a
 	`None
 ;;
 
--- a/test/genericval.myr
+++ b/test/genericval.myr
@@ -1,6 +1,6 @@
 use std
 
-generic Foo : @a::(integral,numeric) = 42
+generic Foo : @a = 42 :: integral,numeric @a
 
 const main = {
 	std.exit(Foo)
--- a/test/gtrait.myr
+++ b/test/gtrait.myr
@@ -4,7 +4,7 @@
 	cmp	: (a : @a, b : @a -> std.order)
 ;;
 
-impl comparable @a::numeric =
+impl comparable @a :: numeric @a =
 	cmp = {a, b
 		-> std.numcmp(a, b)
 	}
--- a/test/recgeneric.myr
+++ b/test/recgeneric.myr
@@ -1,6 +1,6 @@
 use std
 
-type o(@a::integral) = union
+type o(@a) :: integral @a = union
 	`S @a
 ;;
 
--- a/test/trait-builtin.myr
+++ b/test/trait-builtin.myr
@@ -7,7 +7,7 @@
 exits with 42.
 */
 
-generic max = {a:@a::numeric, b:@a::numeric
+generic max = {a : @a, b : @a :: numeric @a
 	if a > b
 		-> a
 	else
@@ -15,7 +15,7 @@
 	;;
 }
 
-generic intlike_is42 = {a : @a::(numeric,integral)
+generic intlike_is42 = {a : @a :: numeric,integral @a
 	-> a == 42
 }
 
--- a/test/traitimpl.myr
+++ b/test/traitimpl.myr
@@ -22,7 +22,7 @@
 	}
 ;;
 
-generic foo = {x : @a::frobable
+generic foo = {x : @a :: frobable @a
 	-> frob(x)
 }