flix / flix

The Flix Programming Language
https://flix.dev/
Other
2.08k stars 150 forks source link

Regions: Monomorph crash on `String.unfold` #3749

Closed jaschdoc closed 2 years ago

jaschdoc commented 2 years ago

The Str.unfold function seems crash the compiler when the test function is run.

opaque type StringBuilder1[_: Region] = ##java.lang.StringBuilder

instance Newable[StringBuilder1] {
    pub def new(r: Region[r]): StringBuilder1[r] \ Write(r) = StringBuilder1.new(r)
}

namespace StringBuilder1 {
    ///
    /// Returns a new mutable StringBuilder.
    ///
    pub def new(_: Region[r]): StringBuilder1[r] \ Write(r) =
        import new java.lang.StringBuilder(): ##java.lang.StringBuilder & r as newStringBuilder;
        StringBuilder1(newStringBuilder())

    ///
    /// Append `x` to the StringBuilder `sb`.
    ///
    pub def append!(x: a, sb: StringBuilder1[r]): Unit \ Write(r) with ToString[a] =
        let s = ToString.toString(x);
        s `appendString!` sb;
        ()

    ///
    /// Append the String `s` to the StringBuilder `sb`.
    ///
    pub def appendString!(s: String, sb: StringBuilder1[r]): Unit \ Write(r) =
        import java.lang.StringBuilder.append(String): ##java.lang.StringBuilder & r;
        let StringBuilder1(msb) = sb;
        msb `append` s;
        ()

    ///
    /// Convert the StringBuilder `sb` to a string.
    ///
    pub def toString(sb: StringBuilder1[r]): String \ Read(r) =
        import java.lang.StringBuilder.toString(): String & r;
        let StringBuilder1(msb) = sb;
        toString(msb)
}

namespace Str {
    pub def unfold(f: b -> Option[(Char, b)] & ef, x: b): String & ef = region r {
        let sb = new StringBuilder1(r);
        def loop(a) = {
            let a1 = f(a);
            match a1 {
                case None         => StringBuilder1.toString(sb)
                case Some(c, st1) => {
                    StringBuilder1.append!(c, sb);
                    loop(st1)
                }
            }
        };
        loop(x)
    }
}

namespace TestStr {

@test
def unfold01(): Bool =
    Str.unfold(x -> if (x < 5) Some('a', x+1) else None, 0) == "aaaaa"
}

Error

#                                                                               
# An unexpected error has been detected by the Flix compiler:
#
#   Unable to unify: '(t50098 -> Option[(Char, t50098)] & (b579012 and b8411!) or (b579014 and ((not (b579668 and b579012 and b8411!)) or (not b8411!)))) -> (t50098 -> String & b579012 and b8411!)' and '(Int32 -> Option[(Char, Int32)]) -> (Int32 -> String)'.
#
# This is a bug in the Flix compiler. Please report it here:
#
# https://github.com/flix/flix/issues
#
# -- Flix Compiler --
#
# Flix Version : v0.28.0
#   incremental: All
#
# -- Java Virtual Machine --
#
# JVM Version  : 17.0.1 (2021-10-19)
# JVM Vendor   : Oracle Corporation
# JAVA_HOME    : /home/jaschn/.sdkman/candidates/java/17.0.1-open
# System       : Linux (5.17.6-200.fc35.x86_64)
#
# -- Stack Trace --
ca.uwaterloo.flix.util.InternalCompilerException: Unable to unify: '(t50098 -> Option[(Char, t50098)] & (b579012 and b8411!) or (b579014 and ((not (b579668 and b579012 and b8411!)) or (not b8411!)))) -> (t50098 -> String & b579012 and b8411!)' and '(Int32 -> Option[(Char, Int32)]) -> (Int32 -> String)'.
        at ca.uwaterloo.flix.language.phase.Monomorph$.infallibleUnify(Monomorph.scala:929)
        at ca.uwaterloo.flix.language.phase.Monomorph$.specializeDef(Monomorph.scala:748)
        at ca.uwaterloo.flix.language.phase.Monomorph$.specializeDefSym(Monomorph.scala:695)
        at ca.uwaterloo.flix.language.phase.Monomorph$.visitExp$1(Monomorph.scala:267)
        at ca.uwaterloo.flix.language.phase.Monomorph$.visitExp$1(Monomorph.scala:332)
        at ca.uwaterloo.flix.language.phase.Monomorph$.$anonfun$specialize$1(Monomorph.scala:333)
        at scala.collection.immutable.List.map(List.scala:246)
        at ca.uwaterloo.flix.language.phase.Monomorph$.visitExp$1(Monomorph.scala:333)
        at ca.uwaterloo.flix.language.phase.Monomorph$.specialize(Monomorph.scala:678)
        at ca.uwaterloo.flix.language.phase.Monomorph$.$anonfun$run$4(Monomorph.scala:200)
        at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:563)
        at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:561)
        at scala.collection.AbstractIterable.foreach(Iterable.scala:919)
        at scala.collection.IterableOps$WithFilter.foreach(Iterable.scala:889)
        at ca.uwaterloo.flix.language.phase.Monomorph$.$anonfun$run$1(Monomorph.scala:191)
        at ca.uwaterloo.flix.api.Flix.phase(Flix.scala:566)
        at ca.uwaterloo.flix.language.phase.Monomorph$.run(Monomorph.scala:167)
        at ca.uwaterloo.flix.api.Flix.$anonfun$codeGen$2(Flix.scala:519)
        at ca.uwaterloo.flix.util.Validation.flatMap(Validation.scala:50)
        at ca.uwaterloo.flix.util.Validation.flatMap$(Validation.scala:49)
        at ca.uwaterloo.flix.util.Validation$Success.flatMap(Validation.scala:74)
        at ca.uwaterloo.flix.api.Flix.$anonfun$codeGen$1(Flix.scala:518)
        at ca.uwaterloo.flix.util.Validation.flatMap(Validation.scala:50)
        at ca.uwaterloo.flix.util.Validation.flatMap$(Validation.scala:49)
        at ca.uwaterloo.flix.util.Validation$Success.flatMap(Validation.scala:74)
        at ca.uwaterloo.flix.api.Flix.codeGen(Flix.scala:517)
        at ca.uwaterloo.flix.api.Flix.$anonfun$compile$1(Flix.scala:551)
        at ca.uwaterloo.flix.util.Validation$.flatMapN(Validation.scala:252)
        at ca.uwaterloo.flix.api.Flix.compile(Flix.scala:551)
        at ca.uwaterloo.flix.tools.Packager$.build(Packager.scala:199)
        at ca.uwaterloo.flix.tools.Packager$.test(Packager.scala:360)
        at ca.uwaterloo.flix.Main$.main(Main.scala:149)
        at ca.uwaterloo.flix.Main.main(Main.scala)

Unable to unify: '(t50098 -> Option[(Char, t50098)] & (b579012 and b8411!) or (b579014 and ((not (b579668 and b579012 and b8411!)) or (not b8411!)))) -> (t50098 -> String & b579012 and b8411!)' and '(Int32 -> Option[(Char, Int32)]) -> (Int32 -> String)'.
magnus-madsen commented 2 years ago

@mlutze Interestingly this is a rigidity issue.

If I change l925 in Monomorph to:

    Unification.unifyTypes(tpe1.map(_.withRigidity(Rigidity.Flexible)), tpe2) match {

then it no longer crashes.

magnus-madsen commented 2 years ago

Presumably #3644 would help, but it probably does not solve all these crashes.

We probably really need to do two things: Introduce the rigidity env and to force all type params to be rigid in the initial subst.

magnus-madsen commented 2 years ago

@jaschdoc Can you confirm that #3755 helps?

jaschdoc commented 2 years ago

Affirmative. It does not crash anymore