flix icon indicating copy to clipboard operation
flix copied to clipboard

Potential problem with java method invocation

Open dghosef opened this issue 1 year ago • 5 comments

In main/src/library/String.flix, if I modify the split function from

    pub def split(regex: {regex = String}, s: String): List[String] = region rc {
        import java.lang.String.split(String): Array[String, rc] \ rc;
        let _ = rc; // This avoids a redundancy error.
        Array.toList(split(s, regex#regex))
    }

to

    pub def split(regex: {regex = String}, s: String): List[String] = region rc {
        let _ = rc; // This avoids a redundancy error.
        unsafe Array.toList(s.split(regex#regex))
    }

I get the following error:

#
# An unexpected error has been detected by the Flix compiler:
#
#   Unexpected type: 'split'.
#
# This is a bug in the Flix compiler. Please report it here:
#
# https://github.com/flix/flix/issues
#
# -- Flix Compiler --
#
# Flix Version : 0.48.0
#   incremental: All
#
# -- Java Virtual Machine --
#
# JVM Version  : 21.0.2 (2024-01-16)
# JVM Vendor   : Homebrew
# JAVA_HOME    : /opt/homebrew/Cellar/openjdk/21.0.2/libexec/openjdk.jdk/Contents/Home
# System       : Mac OS X (14.2.1)
#
# -- Stack Trace --
ca.uwaterloo.flix.util.InternalCompilerException: Unexpected type: 'split'.
	at ca.uwaterloo.flix.language.phase.Simplifier$.visitType(Simplifier.scala:341)
	at ca.uwaterloo.flix.language.phase.Simplifier$.$anonfun$visitType$1(Simplifier.scala:227)
	at scala.collection.immutable.List.map(List.scala:247)
	at ca.uwaterloo.flix.language.phase.Simplifier$.visitType(Simplifier.scala:227)
	at ca.uwaterloo.flix.language.phase.Simplifier$.visitExp(Simplifier.scala:129)
	at ca.uwaterloo.flix.language.phase.Simplifier$.$anonfun$visitExp$1(Simplifier.scala:78)
	at scala.collection.immutable.List.map(List.scala:247)
	at ca.uwaterloo.flix.language.phase.Simplifier$.visitExp(Simplifier.scala:78)
	at ca.uwaterloo.flix.language.phase.Simplifier$.visitExp(Simplifier.scala:183)
	at ca.uwaterloo.flix.language.phase.Simplifier$.$anonfun$patternMatchWithLabels$3(Simplifier.scala:481)
	at scala.collection.immutable.List.map(List.scala:247)
	at ca.uwaterloo.flix.language.phase.Simplifier$.patternMatchWithLabels(Simplifier.scala:473)
	at ca.uwaterloo.flix.language.phase.Simplifier$.visitExp(Simplifier.scala:159)
	at ca.uwaterloo.flix.language.phase.Simplifier$.visitExp(Simplifier.scala:156)
	at ca.uwaterloo.flix.language.phase.Simplifier$.visitDef(Simplifier.scala:44)
	at ca.uwaterloo.flix.language.phase.Simplifier$.$anonfun$run$2(Simplifier.scala:34)
	at ca.uwaterloo.flix.util.ParOps$.$anonfun$parMapValues$1(ParOps.scala:90)
	at ca.uwaterloo.flix.util.ParOps$.$anonfun$parMap$2(ParOps.scala:64)
	at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1423)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188)

dghosef avatar Jul 31 '24 07:07 dghosef

Not sure if this is the same thing, but in Regex.flix if I change

pub def unmatchable(): Regex =
    try {
        import static java.util.regex.Pattern.compile(String): ##java.util.regex.Pattern \ {};
        compile("^\\b$")
    } catch {
        case _: ##java.lang.Exception => unreachable!()
    }

to

pub def unmatchable(): Regex =
    try {
        unsafe "^\\b$".compile()
    } catch {
        case _: ##java.lang.Exception => unreachable!()
    }

I get

ca.uwaterloo.flix.util.InternalCompilerException: Unexpected error expression near
	at ca.uwaterloo.flix.language.phase.Lowering$.visitExp(Lowering.scala:800)
	at ca.uwaterloo.flix.language.phase.Lowering$.visitExp(Lowering.scala:563)
	at ca.uwaterloo.flix.language.phase.Lowering$.visitExp(Lowering.scala:575)
	at ca.uwaterloo.flix.language.phase.Lowering$.visitDef(Lowering.scala:177)
	at ca.uwaterloo.flix.language.phase.Lowering$.$anonfun$run$2(Lowering.scala:151)
	at ca.uwaterloo.flix.util.ParOps$.$anonfun$parMapValues$1(ParOps.scala:90)
	at ca.uwaterloo.flix.util.ParOps$.$anonfun$parMap$2(ParOps.scala:64)
	at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1423)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188

I actually don't think this is correct code, so there should be an error, but not sure if it should be an InternalCompilerException

dghosef avatar Jul 31 '24 08:07 dghosef

The following function:

    pub def replace(src: {src = String}, dst: {dst = String}, s: String): String =
        unsafe s.replace(checked_cast(src#src), checked_cast(dst#dst))

fails to compile with the error:

Unable to compile. Failed with: 1 errors.

-- Type Error -------------------------------------------------- String.flix

>> Unable to unify the types: 'j0' and 't0'.

815 |         unsafe s.replace(checked_cast(src#src), checked_cast(dst#dst))
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                     mismatched types.

Type One: j0
Type Two: t0

It works without the checked cast. I'm not sure why the checked cast is there - it was there in the old version without the dot syntax, so I'd imagine it should work with the dot syntax too, but I might be wrong about that.

A similar error occurs in Test.Exp.Jvm.NewObject.flix

@test
def testImplementInterface01(): Bool \ IO =
    let anon = checked_cast(implementSerializable());
    anon.toString() |> String.startsWith(prefix = "Anon")

In general, it seems that the new import syntax doesn't work with checked casts. I guess this makes sense because when you have a checked_cast, overload resolution becomes a lot harder/impossible?

dghosef avatar Jul 31 '24 09:07 dghosef

In regards to checked_cast, since @chanattan added subtyping checks the cast is not needed anymore, it should be good automatically. By having checked_cast the java resolution breaks since its not proper two-way inference

JonathanStarup avatar Jul 31 '24 12:07 JonathanStarup

For the first isse, with import java.lang.String.split(String): Array[String, rc] \ rc; I guess the "auto-import" is import java.lang.String.split(String): Array[String, split] \ IO; (which seems weird) but we discussed that when the import uses regions, we should write def split(s1, s2)= unched_cast (s1.split(s2) as Array[String, rc] \ rc)

JonathanStarup avatar Jul 31 '24 12:07 JonathanStarup

This program now works:

pub def replace(src: {src = String}, dst: {dst = String}, s: String): String =
    unsafe s.replace(src#src, dst#dst)

Does that mean we can close the issue?

magnus-madsen avatar Aug 01 '24 13:08 magnus-madsen