hkuplg/fcore

Class name too long error

zonyitoo opened this issue · 20 comments

Once the lines of code hits 1000+, the compiler will generate inner classes which makes javac generates the file name of .class too long.

Inner classes are generated because of multiple argument functions (one argument one inner class as per the formalization), I don't think lambda lifting can help much.

there would the same number of inner classes, but their names would be shorter after lifting, no? may not work with applyopt though

@tomtau I don't think lambda lifting will solve this problem.

In practice, I saw dozens of Lets nested into other Lets, and also some datas nested in Lets, which should be an error in generating module. Because no one will write so much nested lets in one let. And I am sure that I haven't write any datas nested in lets.

@bixuanzju Also, if inner classes will be generated because of multiple argument functions, then why it generates a inner class in level 10+?

For example:

./F2j_parser$.java:15069: 错误: 写入Fun12500时出错: ./F2j_parser$$1Let181$1Let214$1Let275$1Let519$1Let570$1Let653$1Let704$1Let776$1Let837$1Let952$1Let1119$1Let1148$1Let2667$1Let2938$1Let4231$1Let5025$1Let5106$1Datatype15368$1Let5344$1Let6291$1Let8384$1Let8647$1Let9144$1Fun12312$1Fun12399$1Fun12494$1Fun12500.class (File name too long)
                                                                                                            class Fun12500 extends f2j.Closure
                                                                                                            ^
1 个错误
错误: 找不到或无法加载主类 F2j_parser$

@zhiyuanshi A simple example:

let rec fun1 (a : Int) (b : Int) : Int = a + 1;
let rec fun2 (a : Int) (b: Int): Int = a + 2;
fun1 1 4

would generate

Test$$1Let1$1Fun11$1Fun14.class
Test$$1Let1$1Fun11.class
Test$$1Let1$1Let18$1Fun28$1Fun31.class
Test$$1Let1$1Let18$1Fun28.class
Test$$1Let1$1Let18.class
Test$$1Let1.class
Test$.class

Those long nested Let classes are generated because we transform all recursive functions to LetRec instead of Fix in the front-end. Could you revert that change?

@bixuanzju I don't think that'll solve the problem. Besides, if I revert that change, a more serious bug will arise.

@zhiyuanshi So now Fix constructor will never be used, right? BTW, in the backend, LetRec will be translated to Let classes, initially designed for mutually recursive functions. But now, self recursive function would also be wrapped into Let classes. If you insist this is needed in the front-end, I could add a transformation in the partial evaluator, that if a letrec has only one binding, change it to fix.

@bixuanzju I think the fix will work but won't solve the very issue once and for all. In the end, people will write very large programs with letrec holding a great many of bindings.

This has nothing to do with how many bindings. Nested classes are generated only for multiple argument functions (if you write a function with 10+ arguments, it would of course has 10+ nested classes, we can do nothing about that). However, the problem now is the way backend deals with LetRec:

  • Using Letrec for every recursive functions:
let rec fun1 = ... fun1 ...;
let rec fun2 = ... fun2 ...;

generates

class Let1 {
  class Fun1 {
  ...
  }
 class Let2 {
   class Fun2 {
    ...
   }
 }
}

Notice Fun2 are embedded inside two Let classes.

  • However, fun1 and fun2 could use Fix (they only recur on themselves), then
class Fun1 {
...
}
class Fun2 {
...
}

No unnecessary Let classes.

  • If you write
let rec fun1 = ... fun2 ...
and fun2 = ... fun1...;

generates

class Let1 {
   Obejct fun1;
   Object fun2;
   class Fun1 {
    ...
   }
   class Fun2 {
    ...
   }
}

As seen, Let classes are there for mutual recursive functions.

@tomtau Tomas may have some thoughts on this?

@bixuanzju The second one make senses!!

@bixuanzju looks good

@zonyitoo the names that cause you problems are generally dominated by the nested Lets?

@tomtau It seems yes. Actually I have already mentioned that in Slack with you.

I don't know much detail about the backend. If you need my co-operation, please contact me. ;)

@zonyitoo Could you try 5e3dc9d?

@bixuanzju

f2j: lib/PartialEvaluator.hs:(36,17)-(38,19): Irrefutable pattern failed for pattern Core.Lam _ _ body

@zonyitoo Can you give an example?

@bixuanzju It is hard to give you an example. I just want to compile my parser, and it crash. I don't know where and why this problem happens.

@zonyitoo Alright! I will revert that commit, but I can't investigate any further unless you give me an example.

Ref 1b99bf8 as a temporary solution.