@@ -367,6 +367,44 @@ unit_tlet_self_capture = do
367367 r <- evalFullTest mempty mempty Syn expr
368368 r @?= Right expected
369369
370+ -- tlet a = C in (tlet v = a in v)
371+ -- ==>
372+ -- C
373+ --
374+ -- The RHS of a type-level @tlet@ must be reduced before it is bound, just as at
375+ -- every other binding site in the interpreter. The inner binding @v = a@ has the
376+ -- in-scope variable @a@ as its RHS; binding it unreduced makes the lookup of @v@
377+ -- return @a@ verbatim, leaving a dangling @TVar "a"@ in the result -- @a@ is out
378+ -- of scope once both @tlet@s have been consumed.
379+ -- https://github.com/hackworthltd/primer/issues/1439
380+ unit_tlet_reduce_rhs :: Assertion
381+ unit_tlet_reduce_rhs =
382+ let (expr, expected) = create2 $ do
383+ e0 <- ann emptyHole $ tlet " a" (tcon' [" M" ] " C" ) $ tlet " v" (tvar " a" ) $ tvar " v"
384+ e1 <- ann emptyHole $ tcon' [" M" ] " C"
385+ pure (e0, e1)
386+ in do
387+ r <- evalFullTest mempty mempty Syn expr
388+ r @?= Right expected
389+
390+ -- tlet v = (tlet w = C in w) in (v -> v)
391+ -- ==>
392+ -- C -> C
393+ --
394+ -- A second witness: when the RHS is itself reducible (here another @tlet@),
395+ -- binding it unreduced leaves residual @tlet@s in the result instead of a
396+ -- normal form.
397+ -- https://github.com/hackworthltd/primer/issues/1439
398+ unit_tlet_reduce_rhs_let :: Assertion
399+ unit_tlet_reduce_rhs_let =
400+ let (expr, expected) = create2 $ do
401+ e0 <- ann emptyHole $ tlet " v" (tlet " w" (tcon' [" M" ] " C" ) $ tvar " w" ) $ tfun (tvar " v" ) (tvar " v" )
402+ e1 <- ann emptyHole $ tfun (tcon' [" M" ] " C" ) (tcon' [" M" ] " C" )
403+ pure (e0, e1)
404+ in do
405+ r <- evalFullTest mempty mempty Syn expr
406+ r @?= Right expected
407+
370408-- This test is mainly for the step evaluator, but we check it here as
371409-- well just for completeness.
372410unit_closed_let_beta :: Assertion
0 commit comments