purescript-lua icon indicating copy to clipboard operation
purescript-lua copied to clipboard

Stack overflow in Prelude generic tests

Open UnrelatedString opened this issue 8 months ago • 5 comments

As the title says. I tried to get tests working for the Prelude, and I was mostly successful, with the caveat that the inclusion of the Generic tests causes a stack overflow in the definition of eqList. This seems more plausibly to be a bug with the backend's implementation of derive instance Generic than an issue with the Prelude itself.

Specifically,

data List a = Nil | Cons { head :: a, tail :: List a }

cons :: forall a. a -> List a -> List a
cons head tail = Cons { head, tail }

derive instance genericList :: G.Generic (List a) _

instance eqList :: Eq a => Eq (List a) where
  eq x y = GEq.genericEq x y

results in the offending definitions

M.Test_Data_Generic_Rep_eqList = function(dictEq)
  return {
    eq = M.Data_Eq_Generic_genericEq
      (M.Test_Data_Generic_Rep_genericList)  
      (M.Test_Data_Generic_Rep_genericEqSum(
        M.Data_Eq_Generic_genericEqConstructor(
          M.Data_Eq_Generic_genericEqArgument(
            M.Test_Data_Generic_Rep_eqRec(
              M.Data_Eq_eqRowCons(
                M.Test_Data_Generic_Rep_eqRowCons
                  (M.Test_Data_Generic_Rep_tailIsSymbol)
                  (M.Test_Data_Generic_Rep_eqList(dictEq))
                )
                ()
                (M.Test_Data_Generic_Rep_headIsSymbol)
                (dictEq)
              )
            )
          )
        )
      )
  }
end
M.Test_Data_Generic_Rep_eqList1 = M.Test_Data_Generic_Rep_eqList(M.Data_Eq_eqInt)

(indents added for clarity.)

UnrelatedString avatar Mar 26 '25 02:03 UnrelatedString

Thank you for the report, I will look into it this week.

Unisay avatar Mar 26 '25 09:03 Unisay

@UnrelatedString I couldn't reproduce the problem - list equality works, check this PR out.

Unisay avatar Mar 30 '25 17:03 Unisay

Very strange... I repro'd on a CI runner fine just now. Looking at the Golden Test, it appears that it uses an eta-expanded definition eq x y = GEq.genericEq x y, where eq = GEq.genericEq might cause issues with eager circular references in a way known and accepted even for the JS backend... and I thought I remembered the test in the Prelude repo itself being the former, but it's defined precisely the same way.

...I only now realized that just because the error message in the generated Lua points to the definition doesn't mean the definition itself causes the error 😭😭😭 Turns out, it's specifically testing that cons 1 (cons 2 Nil) == cons 1 (cons 2 Nil) which causes the stack overflow--the non-equality test case doesn't have this issue, and I was able to repro even more minimally with (Nil :: List Int) == Nil.

UnrelatedString avatar Mar 30 '25 19:03 UnrelatedString

Incidentally, it seems that derived Functor instances may also be faulty? Trying to map over an Either errors trying to index a function.

UnrelatedString avatar Apr 29 '25 06:04 UnrelatedString

...and a long enough do block stack overflows just by the scale of the nested bind calls ;_;

UnrelatedString avatar Apr 29 '25 06:04 UnrelatedString