Ok I'm way too sleepy to think about this rn
3 files changed, 59 insertions(+), 4 deletions(-)

M fml/tests/main.rs
M fml/tests/test_module1.gt
A => fml/tests/test_module2.gt
M fml/tests/main.rs +6 -0
@@ 150,3 150,9 @@ fn test_module1() {
     let src = include_str!("test_module1.gt");
     let _output = fml::compile("test_module1.gt", src);
 }
+
+#[test]
+fn test_module2() {
+    let src = include_str!("test_module2.gt");
+    let _output = fml::compile("test_module2.gt", src);
+}

          
M fml/tests/test_module1.gt +6 -4
@@ 1,19 1,21 @@ 
-
 -- A hasher that only accepts basic integers and always returns an
 -- integer.  Implements a particular hash algorithm, with optional
 -- state in it.
 -- Analogous to Rust's std::hash::Hasher
 -- We don't have mutation yet, so this just returns a new state.
-type Hasher(@Self) = struct
+--
+-- No associated types either, so we just make it a type param for now,
+-- which surprisingly appears to work.
+type Hasher(@Self, @Out) = struct
     write: fn(@Self, I32): @Self,
-    finish: fn(@Self): I32,
+    finish: fn(@Self): @Out,
 end
 
 type DumbHashState = I32
 
 
 fn main(): I32 =
-    let dumbhasher = $Hasher(DumbHashState) {
+    let dumbhasher = $Hasher(DumbHashState, I32) {
         .write = fn(s: DumbHashState, i: I32): DumbHashState = $DumbHashState i end,
         .finish = fn(s: DumbHashState): I32 = 3 end
     }

          
A => fml/tests/test_module2.gt +47 -0
@@ 0,0 1,47 @@ 
+-- A hasher that only accepts basic integers and always returns an
+-- integer.  Implements a particular hash algorithm, with optional
+-- state in it.
+-- Analogous to Rust's std::hash::Hasher
+-- We don't have mutation yet, so this just returns a new state.
+--
+-- No associated types either, so we just make it a type param for now,
+-- which surprisingly appears to work.
+type Hasher(@Self, @Out) = struct
+    write: fn(@Self, I32): @Self,
+    finish: fn(@Self): @Out,
+end
+
+type DumbHashState = I32
+
+-- Ok now we have to imagine associated types so we can pass an
+-- implementation of a particular type to this...
+type Hash(@Self) = struct
+    hasher_impl: Hasher(@Self, I32),
+    hash: fn(@Self, Hasher_impl): Hasher_impl,
+end
+
+
+fn main(): I32 =
+    let dumbhasher = $Hasher(DumbHashState, I32) {
+        .write = fn(s: DumbHashState, i: I32): DumbHashState = $DumbHashState i end,
+        .finish = fn(s: DumbHashState): I32 = 3 end
+    }
+    let hash_state = $DumbHashState 1
+    let updated_state = dumbhasher.write(hash_state, 12)
+    let hash = dumbhasher.finish(updated_state)
+
+    -- Try implementing our Hash "trait" for {I32, I32}
+    let hash_impl = $Hash({I32, I32}) {
+        .hasher_impl = dumbhasher,
+        .hash = fn(self: {I32, I32}, state: DumbHasher): DumbHasher =
+            -- Pretend we're destructuring the tuple here
+            let fst = 1
+            let snd = 2
+            let s0 = $DumbHashState 1
+            let s1 = state.write(s0, fst)
+            let s2 = state.write(s1, snd)
+            s2
+        end,
+    }
+    3
+end