From 242af6c43803ebbf95e5f0b0912826e9f464db4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Je=C4=8Dmen?= Date: Thu, 7 Dec 2023 15:44:16 +0100 Subject: [PATCH 1/5] output bug: bottom and nothing are different types --- Project/src/main/java/prlprg/GenDB.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Project/src/main/java/prlprg/GenDB.java b/Project/src/main/java/prlprg/GenDB.java index 88539f1..3a28305 100644 --- a/Project/src/main/java/prlprg/GenDB.java +++ b/Project/src/main/java/prlprg/GenDB.java @@ -112,8 +112,9 @@ public Ty fixUp(List bounds) { switch (nm()) { case "typeof": // typeof is a special case return new TyCon(toString()); - case "Nothing": - return Ty.None; + // TODO: Core.TypeofBottom and Nothing are different! + // case "Nothing": + // return Ty.None; default: if (!pre_tydb.containsKey(nm)) { System.err.println("Warning: " + nm + " not found in type database, patching"); From 986a686b8b852e0fa3ad29df00f76e40be0bcc00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Je=C4=8Dmen?= Date: Thu, 7 Dec 2023 15:46:52 +0100 Subject: [PATCH 2/5] test case generation --- Project/src/main/java/prlprg/Generator.java | 57 +++++++++++++++++++-- StabilityChecker/shenv.jl | 12 +++++ StabilityChecker/test.jl | 53 +++++++++++++++++++ 3 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 StabilityChecker/shenv.jl create mode 100644 StabilityChecker/test.jl diff --git a/Project/src/main/java/prlprg/Generator.java b/Project/src/main/java/prlprg/Generator.java index 2ea3ddd..727ce31 100644 --- a/Project/src/main/java/prlprg/Generator.java +++ b/Project/src/main/java/prlprg/Generator.java @@ -265,6 +265,37 @@ boolean isGround() { public String toString() { return "function " + nm + " " + ty; } + + public void add_pkgs(HashSet pkgs) { + if (nm.contains(".")) { + pkgs.add(nm.split("\\.", 2)[0]); + } + if (ty instanceof Tuple t) { + for (var typ : t.tys) { + // TODO: recurse into other kinds of type + if (typ instanceof Inst inst) { + if (inst.nm().contains(".")) { + pkgs.add(inst.nm().split("\\.", 2)[0]); + } + } + } + } + } + + public String juliaName() { + // FileWatching.| + // Pkg.Artifacts.var#verify_artifact#1 + // Base.GMP.MPQ.// + var parts = nm.split("\\."); + var name = parts[parts.length - 1]; + if (name.startsWith("var#")) { + name = name.substring(0, 3) + "\"" + name.substring(3) + "\""; + } else if (!Character.isLetter(name.charAt(0)) && name.charAt(0) != '_') { + name = ":(" + name + ")"; + } + parts[parts.length - 1] = name; + return String.join(".", parts); + } } GenDB db; // our database of types and signatures -- these are still not complete @@ -310,17 +341,35 @@ public void gen() { } try { - var w = new BufferedWriter(new FileWriter("test.jl")); + HashSet pkgs = new HashSet<>(); + var w = new BufferedWriter(new FileWriter("tests.jl")); for (var b : sigs.values()) { for (var s : b) { if (s.isGround()) { System.err.println("Ground: " + s); - var str = ((Tuple) s.ty).tys.stream().map(Type::toString).collect(Collectors.joining(",")); - var content = "code_warntype(" + s.nm + ",[" + str + "])\n"; - w.write(content); + + s.add_pkgs(pkgs); + + w.write("isstablecall("); + w.write(s.juliaName()); + w.write(", ["); + w.write(((Tuple) s.ty).tys.stream().map(Type::toString).collect(Collectors.joining(", "))); + w.write("])\n"); } } } + w.close(); + + pkgs.remove("Base"); + pkgs.remove("Core"); + var pkgsf = new BufferedWriter(new FileWriter("pkgs.txt")); + var importsf = new BufferedWriter(new FileWriter("imports.jl")); + for (var p : pkgs) { + pkgsf.write(p + "\n"); + importsf.write("import " + p + "\n"); + } + pkgsf.close(); + importsf.close(); } catch (IOException e) { throw new Error(e); } diff --git a/StabilityChecker/shenv.jl b/StabilityChecker/shenv.jl new file mode 100644 index 0000000..2a3bab6 --- /dev/null +++ b/StabilityChecker/shenv.jl @@ -0,0 +1,12 @@ +pkgs = isempty(ARGS) ? error("Required argument: path of pkgs.txt") : joinpath(pwd(), popfirst!(ARGS)) + +const env = "JuliaGenerable" + +using Pkg + +Pkg.activate(env; shared=true) +Pkg.add(split(strip(read(pkgs, String)), "\n")) +Pkg.instantiate() + +@info "Shared environment `@$env' at `$(joinpath(Pkg.envdir(), env))':" +Pkg.status() diff --git a/StabilityChecker/test.jl b/StabilityChecker/test.jl new file mode 100644 index 0000000..e3e6f18 --- /dev/null +++ b/StabilityChecker/test.jl @@ -0,0 +1,53 @@ +imports = isempty(ARGS) ? error("Required argument: path of imports.jl") : joinpath(pwd(), popfirst!(ARGS)) +tests = isempty(ARGS) ? error("Required argument: path of tests.jl") : joinpath(pwd(), popfirst!(ARGS)) + +const env = "JuliaGenerable" + +import Pkg + +Pkg.activate(env; shared=true) + +mutable struct Stats + ok::Int + fail::Int + stable::Int + unstable::Int +end +Stats() = Stats(0, 0, 0, 0) +Base.show(io::IO, stats::Stats) = begin + total = stats.ok + stats.fail + println(io, "Passed $(stats.ok / total * 100.0)% of $total tests") + println(io, " PASSED: $(stats.ok)") + println(io, " FAILED: $(stats.fail)") + println(io, " STABLE: $(stats.stable)") + println(io, " UNSTABLE: $(stats.unstable)") +end +const stats = Stats() + +isstablecall(@nospecialize(f::Function), @nospecialize(ts::Vector)) = begin + try + ct = code_typed(f, (ts...,), optimize=false) + length(ct) == 1 || return false + (_, t) = first(ct) + res = isconcretetype(t) + global stats.ok += 1 + if res + global stats.stable += 1 + else + global stats.unstable += 1 + end + return res + catch e + println("ERROR:"); + showerror(stdout, e); + println(); + global stats.fail += 1; + end +end + +include(imports) + +println("Running tests from `$tests'") +include(tests) + +println("Results: $stats") From f59786c9ea88b57f8e189f5e4e37518d965343bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Je=C4=8Dmen?= Date: Thu, 7 Dec 2023 15:47:54 +0100 Subject: [PATCH 3/5] fix bug in type discovery: defining method in other module --- TypeDiscover.jl/src/TypeDiscover.jl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/TypeDiscover.jl/src/TypeDiscover.jl b/TypeDiscover.jl/src/TypeDiscover.jl index 7720cf6..be94b94 100644 --- a/TypeDiscover.jl/src/TypeDiscover.jl +++ b/TypeDiscover.jl/src/TypeDiscover.jl @@ -235,12 +235,17 @@ end baseShowMethodCustom(io::IO, m::Method, kind::String) = begin tv, decls, file, line = Base.arg_decl_parts(m) sig = Base.unwrap_unionall(m.sig) + mod = try + first(sig.parameters).name.module + catch _ + m.module + end if sig === Tuple # Builtin - print(io, m.module, ".", m.name, "(...) [", kind, "]") + print(io, mod, ".", m.name, "(...) [", kind, "]") return end - print(io, m.module, ".", decls[1][2], "(") + print(io, mod, ".", decls[1][2], "(") join( io, String[isempty(d[2]) ? d[1] : string(d[1], "::", d[2]) for d in decls[2:end]], @@ -356,8 +361,8 @@ typediscover(mods::AbstractVector{Module}=Base.loaded_modules_array(); typefile=nothing, skip_macros=true, skip_lambdas=true, - skip_constructors=false, - skip_callable=false, + skip_constructors=true, + skip_callable=true, skip_builtins=true, skip_intrinsics=true, skip_generics=false, From 2f4fb75eac8fafd9405fa7b768ad64777e6dbb3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Je=C4=8Dmen?= Date: Thu, 7 Dec 2023 15:50:06 +0100 Subject: [PATCH 4/5] add readme --- README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..32ab304 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +In the root of this repo (e.g. `~/Projects/JuliaGenerable`): + +Generate function and type records + + julia --project=./TypeDiscover.jl -e 'using TypeDiscover; typediscover(; funcfile="./Inputs/stdf.jlg", typefile="./Inputs/stdt.jlg")' + +Build the Java project + + mvn -f ./Project/pom.xml package + +Generate the test cases + + java -cp ./Project/target/JuliaGenerable2-1.0-SNAPSHOT.jar prlprg.App -c=NONE -r=./Inputs/ -f=stdf.jlg -t=stdt.jlg -h=FALSE -s=FALSE + +Install dependencies in a shared Julia environment (this stays between runs and can be reused) + + julia ./StabilityChecker/shenv.jl ./pkgs.txt + +And run the tests + + julia ./StabilityChecker/test.jl ./imports.jl ./tests.jl + +If all goes well, you should see results such as + + Results: Passed 100.0% of 1771 tests + PASSED: 1771 + FAILED: 0 + STABLE: 1446 + UNSTABLE: 325 + +> TODO: there's a bug and some modules make it into the tests, eg. `isstablecall(Base, [])`. For now, these need to be commented out manually. From 59f587d6005cf19093fae1e96e0b220d43dcedfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Je=C4=8Dmen?= Date: Tue, 12 Dec 2023 16:03:34 +0100 Subject: [PATCH 5/5] update bug list --- README.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 32ab304..5ada02d 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,19 @@ And run the tests If all goes well, you should see results such as - Results: Passed 100.0% of 1771 tests - PASSED: 1771 + Results: Passed 100.0% of 5473 tests + PASSED: 5473 FAILED: 0 - STABLE: 1446 - UNSTABLE: 325 - -> TODO: there's a bug and some modules make it into the tests, eg. `isstablecall(Base, [])`. For now, these need to be commented out manually. + STABLE: 3608 + UNSTABLE: 1865 + +> TODO: there are some bugs in the generated tests: +> +> `isstablecall(Base, [])` +> `isstablecall(Core.Compiler, [])` +> `isstablecall(Core.Compiler.merge, [NamedTuple, NamedTuple{EOF}])` and such should replace EOFs with `()` +> `isstablecall(Base.iterate, [Base.Iterators.ProductIterator{()}])` should take `Tuple{}` not `()` +> `isstablecall(Core.Compiler.iterate, [Core.Compiler.Iterators.ProductIterator{()}])` same +> `isstablecall(Core.Compiler.lift_comparison!, [typeof(===), Core.Compiler.IncrementalCompact, Int64, Expr, Core.Compiler.IdDict{Pair{[Core.Compiler.NewSSAValue|Core.Compiler.OldSSAValue|Core.SSAValue],Any},[Core.Compiler.NewSSAValue|Core.Compiler.OldSSAValue|Core.SSAValue]}])` and such printing unions +> +> For now, these need to be commented out manually.