From 8e2e0c0d5fb530b81b095e45e4f3955f9f326846 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 4 Jan 2024 00:53:52 +0800 Subject: [PATCH 01/43] WIP: constraints solving for function overloading --- .../scala/mlscript/ConstraintSolver.scala | 5 +- .../main/scala/mlscript/TyperDatatypes.scala | 85 ++++++++++++++++++- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index e509a48579..9cd4908357 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -620,7 +620,9 @@ class ConstraintSolver extends NormalForms { self: Typer => rec(b.inner.ub, ar.inner.ub, false) case (LhsRefined(S(b: ArrayBase), ts, r, _), _) => reportError() case (LhsRefined(S(ov: Overload), ts, r, trs), _) => - annoying(Nil, LhsRefined(S(ov.approximatePos), ts, r, trs), Nil, done_rs) // TODO remove approx. with ambiguous constraints + val t = TupleSetConstraints.mk(ov) + annoying(Nil, LhsRefined(S(t), ts, r, trs), Nil, done_rs) + // annoying(Nil, LhsRefined(S(ov.approximatePos), ts, r, trs), Nil, done_rs) // TODO remove approx. with ambiguous constraints case (LhsRefined(S(Without(b, ns)), ts, r, _), RhsBases(pts, N | S(L(_)), _)) => rec(b, done_rs.toType(), true) case (_, RhsBases(pts, S(L(Without(base, ns))), _)) => @@ -818,6 +820,7 @@ class ConstraintSolver extends NormalForms { self: Typer => val newBound = (cctx._1 ::: cctx._2.reverse).foldRight(rhs)((c, ty) => if (c.prov is noProv) ty else mkProxy(ty, c.prov)) lhs.upperBounds ::= newBound // update the bound + lhs.tsc.foreach { case (tsc, i) => tsc.filterUB(i, rhs) } lhs.lowerBounds.foreach(rec(_, rhs, true)) // propagate from the bound case (lhs, rhs: TypeVariable) if lhs.level <= rhs.level => diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 5fc80392a6..4fe22c5d62 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -534,6 +534,8 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => require(value.forall(_.level <= level)) _assignedTo = value } + + var tsc: Opt[(TupleSetConstraints, Int)] = N // * Bounds should always be disregarded when `equatedTo` is defined, as they are then irrelevant: def lowerBounds: List[SimpleType] = { require(assignedTo.isEmpty, this); _lowerBounds } @@ -646,5 +648,86 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => lazy val underlying: SimpleType = tt.neg() val prov = noProv } - + + class TupleSetConstraints(val constraints: MutSet[Ls[ST]], var tvs: Ls[TV])(val prov: TypeProvenance) { + def filterUB(index: Int, ub: ST)(implicit raise: Raise, ctx: Ctx): Unit = { + def go(ub: ST): Unit = ub match { + case ub: TV => + ub.upperBounds.foreach(go) + ub.tsc = S(this, index) + case _ => + constraints.filterInPlace { constrs => + val ty = constrs(index) + val dnf = DNF.mk(MaxLevel, Nil, ty & ub.neg(), true) + dnf.isBot + } + } + go(ub) + println(s"TSC filterUB: $tvs in $constraints") + if (constraints.sizeCompare(1) === 0) { + constraints.head.zip(tvs).foreach { + case (ty, tv) => + tv.tsc = N + constrain(tv, ty)(raise, prov, ctx) + constrain(ty, tv)(raise, prov, ctx) + } + } + } + } + object TupleSetConstraints { + def lcgField(a: FieldType, b: FieldType) + (implicit prov: TypeProvenance, lvl: Level) + : (FieldType, Ls[TV], Ls[Ls[ST]]) = { + val (ub, tvs, constrs) = lcg(a.ub, b.ub) + if (a.lb.isEmpty && b.lb.isEmpty) { + (FieldType(N, ub)(prov), tvs, constrs) + } else { + val (lb, ltvs, lconstrs) = lcg(a.lb.getOrElse(BotType), b.lb.getOrElse(BotType)) + (FieldType(S(lb), ub)(prov), tvs ++ ltvs, constrs ++ lconstrs) + } + } + def lcg(a: ST, b: ST) + (implicit prov: TypeProvenance, lvl: Level) + : (ST, Ls[TV], Ls[Ls[ST]]) = (a, b) match { + case (_, b: ProvType) => lcg(a, b.underlying) + case (a: ProvType, _) => lcg(a.underlying, b) + case (a: FT, b: FT) => lcgFunction(a, b) + case (a: ArrayType, b: ArrayType) => + val (t, tvs, constrs) = lcgField(a.inner, b.inner) + (ArrayType(t)(prov), tvs, constrs) + case (a: TupleType, b: TupleType) if a.fields.sizeCompare(b.fields.size) === 0 => + val (fts, tvss, constrss) = a.fields.map(_._2).zip(b.fields.map(_._2)).map { + case (a, b) => lcgField(a, b) + }.unzip3 + (TupleType(fts.map(N -> _))(prov), tvss.flatten, constrss.flatten) + case (a: TR, b: TR) if a.defn === b.defn && a.targs.sizeCompare(b.targs.size) === 0 => + val (ts, tvss, constrss) = a.targs.zip(b.targs).map { + case (a, b) => lcg(a, b) + }.unzip3 + (TypeRef(a.defn, ts)(prov), tvss.flatten, constrss.flatten) + case (a: TV, b: TV) if a.compare(b) === 0 => (a, Nil, Nil) + case (a: ExtrType, b: ExtrType) if a.pol === b.pol => (a, Nil, Nil) + case _ => + val tv = freshVar(prov, N) + (tv, List(tv), List(List(a, b))) + } + def lcgFunction(a: FT, b: FT) + (implicit prov: TypeProvenance, lvl: Level) + : (FT, Ls[TV], Ls[Ls[ST]]) = { + val (lhs, ltvs, lconstrs) = lcg(a.lhs, b.lhs) + val (rhs, rtvs, rconstrs) = lcg(a.rhs, b.rhs) + (FunctionType(lhs, rhs)(prov), ltvs ++ rtvs, lconstrs ++ rconstrs) + } + def mk(ov: Overload)(implicit lvl: Level): FunctionType = { + val (t, tvs, constrs) = + ov.alts.tail.foldLeft((ov.alts.head, Nil: Ls[TV], Nil: Ls[Ls[ST]])) { + case ((a, tvs, constrs), b) => lcgFunction(a, b)(ov.prov, lvl) + } + // val (t, tvs, constrs) = lcgFunction(ov.alts.head, ov.alts.tail)(ov.prov, lvl) + val tsc = new TupleSetConstraints(MutSet.empty ++ constrs.transpose, tvs)(ov.prov) + tvs.zipWithIndex.foreach { case (tv, i) => tv.tsc = S((tsc, i)) } + println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") + t + } + } } From 3ad402f6ace362fd9bbd589378dc6122390c8c2b Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 4 Jan 2024 01:01:35 +0800 Subject: [PATCH 02/43] fix type variables being filtered out --- shared/src/main/scala/mlscript/TyperDatatypes.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 4fe22c5d62..648cc5f8e1 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -659,7 +659,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => constraints.filterInPlace { constrs => val ty = constrs(index) val dnf = DNF.mk(MaxLevel, Nil, ty & ub.neg(), true) - dnf.isBot + dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty)) } } go(ub) From d40c9b7d76c1db0d6a028110c66d5274dae61d98 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sun, 14 Jan 2024 18:03:35 +0800 Subject: [PATCH 03/43] fix lcg and add constraints filtering by lowerbound --- .../scala/mlscript/ConstraintSolver.scala | 11 ++- .../main/scala/mlscript/TypeSimplifier.scala | 1 - .../main/scala/mlscript/TyperDatatypes.scala | 97 ++++++++++++------- .../main/scala/mlscript/TyperHelpers.scala | 19 +++- shared/src/test/diff/nu/HeungTung.mls | 62 ++++++++---- 5 files changed, 130 insertions(+), 60 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 9cd4908357..37b3a5441f 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -820,7 +820,11 @@ class ConstraintSolver extends NormalForms { self: Typer => val newBound = (cctx._1 ::: cctx._2.reverse).foldRight(rhs)((c, ty) => if (c.prov is noProv) ty else mkProxy(ty, c.prov)) lhs.upperBounds ::= newBound // update the bound - lhs.tsc.foreach { case (tsc, i) => tsc.filterUB(i, rhs) } + lhs.lbtsc.foreach { + case (tsc, i) => + tsc.filterUB(i, rhs) + if (tsc.constraints.isEmpty) reportError() + } lhs.lowerBounds.foreach(rec(_, rhs, true)) // propagate from the bound case (lhs, rhs: TypeVariable) if lhs.level <= rhs.level => @@ -828,6 +832,11 @@ class ConstraintSolver extends NormalForms { self: Typer => val newBound = (cctx._1 ::: cctx._2.reverse).foldLeft(lhs)((ty, c) => if (c.prov is noProv) ty else mkProxy(ty, c.prov)) rhs.lowerBounds ::= newBound // update the bound + rhs.ubtsc.foreach { + case (tsc, i) => + tsc.filterLB(i, lhs) + if (tsc.constraints.isEmpty) reportError() + } rhs.upperBounds.foreach(rec(lhs, _, true)) // propagate from the bound diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index f2a4b297bf..0e688fe8e3 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -76,7 +76,6 @@ trait TypeSimplifier { self: Typer => .reduceOption(_ &- _).filterNot(_.isTop).toList else Nil } - nv case ComposedType(true, l, r) => diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 648cc5f8e1..c9d3c4efa7 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -535,7 +535,8 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => _assignedTo = value } - var tsc: Opt[(TupleSetConstraints, Int)] = N + var lbtsc: Opt[(TupleSetConstraints, Int)] = N + var ubtsc: Opt[(TupleSetConstraints, Int)] = N // * Bounds should always be disregarded when `equatedTo` is defined, as they are then irrelevant: def lowerBounds: List[SimpleType] = { require(assignedTo.isEmpty, this); _lowerBounds } @@ -654,7 +655,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => def go(ub: ST): Unit = ub match { case ub: TV => ub.upperBounds.foreach(go) - ub.tsc = S(this, index) + ub.lbtsc = S(this, index) case _ => constraints.filterInPlace { constrs => val ty = constrs(index) @@ -667,7 +668,25 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => if (constraints.sizeCompare(1) === 0) { constraints.head.zip(tvs).foreach { case (ty, tv) => - tv.tsc = N + tv.lbtsc = N + tv.ubtsc = N + constrain(tv, ty)(raise, prov, ctx) + constrain(ty, tv)(raise, prov, ctx) + } + } + } + def filterLB(index: Int, lb: ST)(implicit raise: Raise, ctx: Ctx): Unit = { + constraints.filterInPlace { constrs => + val ty = constrs(index) + val dnf = DNF.mk(MaxLevel, Nil, lb & ty.neg(), true) + dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty)) + } + println(s"TSC filterLB: $tvs in $constraints") + if (constraints.sizeCompare(1) === 0) { + constraints.head.zip(tvs).foreach { + case (ty, tv) => + tv.lbtsc = N + tv.ubtsc = N constrain(tv, ty)(raise, prov, ctx) constrain(ty, tv)(raise, prov, ctx) } @@ -675,57 +694,63 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } } object TupleSetConstraints { - def lcgField(a: FieldType, b: FieldType) + def lcgField(first: FieldType, rest: Ls[FieldType]) (implicit prov: TypeProvenance, lvl: Level) : (FieldType, Ls[TV], Ls[Ls[ST]]) = { - val (ub, tvs, constrs) = lcg(a.ub, b.ub) - if (a.lb.isEmpty && b.lb.isEmpty) { + val (ub, tvs, constrs) = lcg(first.ub, rest.map(_.ub)) + if (first.lb.isEmpty && rest.forall(_.lb.isEmpty)) { (FieldType(N, ub)(prov), tvs, constrs) } else { - val (lb, ltvs, lconstrs) = lcg(a.lb.getOrElse(BotType), b.lb.getOrElse(BotType)) + val (lb, ltvs, lconstrs) = lcg(first.lb.getOrElse(BotType), rest.map(_.lb.getOrElse(BotType))) (FieldType(S(lb), ub)(prov), tvs ++ ltvs, constrs ++ lconstrs) } } - def lcg(a: ST, b: ST) + def lcg(first: ST, rest: Ls[ST]) (implicit prov: TypeProvenance, lvl: Level) - : (ST, Ls[TV], Ls[Ls[ST]]) = (a, b) match { - case (_, b: ProvType) => lcg(a, b.underlying) - case (a: ProvType, _) => lcg(a.underlying, b) - case (a: FT, b: FT) => lcgFunction(a, b) - case (a: ArrayType, b: ArrayType) => - val (t, tvs, constrs) = lcgField(a.inner, b.inner) + : (ST, Ls[TV], Ls[Ls[ST]]) = first match { + case a: FunctionType if rest.forall(_.isInstanceOf[FunctionType]) => + val (lhss, rhss) = rest.collect { + case FunctionType(lhs, rhs) => lhs -> rhs + }.unzip + val (lhs, ltvs, lconstrs) = lcg(a.lhs, lhss) + val (rhs, rtvs, rconstrs) = lcg(a.rhs, rhss) + (FunctionType(lhs, rhs)(prov), ltvs ++ rtvs, lconstrs ++ rconstrs) + case a: ArrayType if rest.forall(_.isInstanceOf[ArrayType]) => + val inners = rest.collect { case b: ArrayType => b.inner } + val (t, tvs, constrs) = lcgField(a.inner, inners) (ArrayType(t)(prov), tvs, constrs) - case (a: TupleType, b: TupleType) if a.fields.sizeCompare(b.fields.size) === 0 => - val (fts, tvss, constrss) = a.fields.map(_._2).zip(b.fields.map(_._2)).map { - case (a, b) => lcgField(a, b) - }.unzip3 + case a: TupleType if rest.forall { case b: TupleType => a.fields.sizeCompare(b.fields.size) === 0; case _ => false } => + val fields = rest.collect { case TupleType(fields) => fields.map(_._2) } + val (fts, tvss, constrss) = a.fields.map(_._2).zip(fields.transpose).map { case (a, bs) => lcgField(a, bs) }.unzip3 (TupleType(fts.map(N -> _))(prov), tvss.flatten, constrss.flatten) - case (a: TR, b: TR) if a.defn === b.defn && a.targs.sizeCompare(b.targs.size) === 0 => - val (ts, tvss, constrss) = a.targs.zip(b.targs).map { - case (a, b) => lcg(a, b) - }.unzip3 + case a: TR if rest.forall { case b: TR => a.defn === b.defn && a.targs.sizeCompare(b.targs.size) === 0; case _ => false } => + val targs = rest.collect { case b: TR => b.targs } + val (ts, tvss, constrss) = a.targs.zip(targs.transpose).map { case (a, bs) => lcg(a, bs) }.unzip3 (TypeRef(a.defn, ts)(prov), tvss.flatten, constrss.flatten) - case (a: TV, b: TV) if a.compare(b) === 0 => (a, Nil, Nil) - case (a: ExtrType, b: ExtrType) if a.pol === b.pol => (a, Nil, Nil) + case a: TV if rest.forall { case b: TV => a.compare(b) === 0; case _ => false } => (a, Nil, Nil) + case a if rest.forall(_ === a) => (a, Nil, Nil) case _ => val tv = freshVar(prov, N) - (tv, List(tv), List(List(a, b))) + (tv, List(tv), List(first :: rest)) } - def lcgFunction(a: FT, b: FT) - (implicit prov: TypeProvenance, lvl: Level) - : (FT, Ls[TV], Ls[Ls[ST]]) = { - val (lhs, ltvs, lconstrs) = lcg(a.lhs, b.lhs) - val (rhs, rtvs, rconstrs) = lcg(a.rhs, b.rhs) + def lcgFunction(first: FunctionType, rest: Ls[FunctionType])(implicit prov: TypeProvenance, lvl: Level) + : (FunctionType, Ls[TV], Ls[Ls[ST]]) = { + val (lhss, rhss) = rest.map { + case FunctionType(lhs, rhs) => lhs -> rhs + }.unzip + val (lhs, ltvs, lconstrs) = lcg(first.lhs, lhss) + val (rhs, rtvs, rconstrs) = lcg(first.rhs, rhss) (FunctionType(lhs, rhs)(prov), ltvs ++ rtvs, lconstrs ++ rconstrs) } def mk(ov: Overload)(implicit lvl: Level): FunctionType = { - val (t, tvs, constrs) = - ov.alts.tail.foldLeft((ov.alts.head, Nil: Ls[TV], Nil: Ls[Ls[ST]])) { - case ((a, tvs, constrs), b) => lcgFunction(a, b)(ov.prov, lvl) - } - // val (t, tvs, constrs) = lcgFunction(ov.alts.head, ov.alts.tail)(ov.prov, lvl) + def unwrap(t: ST): ST = t.map(unwrap) + val f = ov.mapAlts(unwrap)(unwrap) + val (t, tvs, constrs) = lcgFunction(f.alts.head, f.alts.tail)(ov.prov, lvl) val tsc = new TupleSetConstraints(MutSet.empty ++ constrs.transpose, tvs)(ov.prov) - tvs.zipWithIndex.foreach { case (tv, i) => tv.tsc = S((tsc, i)) } + tvs.zipWithIndex.foreach { case (tv, i) => + tv.lbtsc = S((tsc, i)) + tv.ubtsc = S((tsc, i)) + } println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") t } diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 727b0001c7..4c5d1414db 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -983,13 +983,24 @@ abstract class TyperHelpers { Typer: Typer => def getVars: SortedSet[TypeVariable] = getVarsImpl(includeBounds = true) def showBounds: String = - getVars.iterator.filter(tv => tv.assignedTo.nonEmpty || (tv.upperBounds ++ tv.lowerBounds).nonEmpty).map { + getVars.iterator.filter(tv => tv.assignedTo.nonEmpty || (tv.upperBounds ++ tv.lowerBounds).nonEmpty || (tv.lbtsc.fold(false)(!_._1.tvs.contains(tv)))).map { case tv @ AssignedVariable(ty) => "\n\t\t" + tv.toString + " := " + ty case tv => ("\n\t\t" + tv.toString + (if (tv.lowerBounds.isEmpty) "" else " :> " + tv.lowerBounds.mkString(" | ")) - + (if (tv.upperBounds.isEmpty) "" else " <: " + tv.upperBounds.mkString(" & "))) - }.mkString - + + (if (tv.upperBounds.isEmpty) "" else " <: " + tv.upperBounds.mkString(" & ")) + + tv.lbtsc.fold(""){ case (tsc, i) => " :> " + tsc.tvs(i) } ) + }.mkString + { + val visited: MutSet[TV] = MutSet.empty + getVars.iterator.filter(tv => tv.lbtsc.fold(false)(_._1.tvs.contains(tv))).map { + case tv if visited.contains(tv) => "" + case tv => + visited ++= tv.lbtsc.fold(Nil: Ls[TV])(_._1.tvs) + tv.lbtsc.fold("") { case (tsc, _) => ("\n\t\t[ " + + tsc.tvs.mkString(", ") + + " ] in { " + tsc.constraints.mkString(", ") + " }") + } + }.mkString + } } diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 51f4efad8b..c810a3122b 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -66,8 +66,16 @@ fun g = h //│ fun g: (Bool | Int) -> (Int | false | true) // * In one step +:e // TODO: argument of union type fun g: (Int | Bool) -> (Int | Bool) fun g = f +//│ ╔══[ERROR] Type mismatch in definition: +//│ ║ l.71: fun g = f +//│ ║ ^^^^^ +//│ ╟── expression of type `Int | false | true` does not match type `?a` +//│ ╟── Note: constraint arises from function type: +//│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) +//│ ╙── ^^^^^^^^^^^^^^ //│ fun g: Int -> Int & Bool -> Bool //│ fun g: (Bool | Int) -> (Int | false | true) @@ -88,9 +96,11 @@ fun j = i fun j: (Int & Bool) -> (Int & Bool) fun j = f //│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.89: fun j = f +//│ ║ l.97: fun j = f //│ ║ ^^^^^ -//│ ╙── expression of type `Int` does not match type `nothing` +//│ ╟── type `?a` does not match type `nothing` +//│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) +//│ ╙── ^^^^^^^^^^^^^^ //│ fun j: Int -> Int & Bool -> Bool //│ fun j: nothing -> nothing @@ -106,7 +116,7 @@ fun g = f // * With match-type-based constraint solving, we could return Int here f(0) -//│ Int | false | true +//│ Int //│ res //│ = 0 @@ -114,15 +124,22 @@ f(0) x => f(x) -//│ (Bool | Int) -> (Int | false | true) +//│ anything -> nothing //│ res //│ = [Function: res] // : forall 'a: 'a -> case 'a of { Int => Int; Bool => Bool } where 'a <: Int | Bool - +:e f(if true then 0 else false) -//│ Int | false | true +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.134: f(if true then 0 else false) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `0 | false` does not match type `?a` +//│ ╟── Note: constraint arises from function type: +//│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) +//│ ╙── ^^^^^^^^^^^^^^ +//│ error //│ res //│ = 0 @@ -132,12 +149,21 @@ f(if true then 0 else false) :w f(refined if true then 0 else false) // this one can be precise again! //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.133: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.150: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.133: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.150: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^ -//│ Int | false | true +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.150: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `error` does not match type `?a` +//│ ║ l.150: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from function type: +//│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) +//│ ╙── ^^^^^^^^^^^^^^ +//│ error //│ Code generation encountered an error: //│ unresolved symbol refined @@ -193,7 +219,7 @@ type T = List[Int] :e // TODO application types type Res = M(T) //│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 -//│ ║ l.194: type Res = M(T) +//│ ║ l.220: type Res = M(T) //│ ╙── ^^^^ //│ type Res = M @@ -216,7 +242,7 @@ fun f: Int -> Int fun f: Bool -> Bool fun f = id //│ ╔══[ERROR] A type signature for 'f' was already given -//│ ║ l.216: fun f: Bool -> Bool +//│ ║ l.242: fun f: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun f: forall 'a. 'a -> 'a //│ fun f: Int -> Int @@ -224,13 +250,13 @@ fun f = id :e // TODO support f: (Int -> Int) & (Bool -> Bool) //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.225: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.251: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^ //│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.225: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.251: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.215: fun f: Int -> Int +//│ ║ l.241: fun f: Int -> Int //│ ╙── ^^^ //│ Int -> Int & Bool -> Bool //│ res @@ -297,14 +323,14 @@ fun test(x) = refined if x is A then 0 B then 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.296: fun test(x) = refined if x is +//│ ║ l.322: fun test(x) = refined if x is //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.297: A then 0 +//│ ║ l.323: A then 0 //│ ║ ^^^^^^^^^^ -//│ ║ l.298: B then 1 +//│ ║ l.324: B then 1 //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.296: fun test(x) = refined if x is +//│ ║ l.322: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ fun test: (A | B) -> error //│ Code generation encountered an error: From 4aa30acda82adb3d071ee7155c4dcfc5cae13a08 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Mon, 15 Jan 2024 13:19:10 +0800 Subject: [PATCH 04/43] fix test: single function in overload --- .../main/scala/mlscript/TyperDatatypes.scala | 18 +++++++------ .../main/scala/mlscript/TyperHelpers.scala | 4 +-- shared/src/test/diff/nu/ArrayProg.mls | 2 +- shared/src/test/diff/nu/WeirdUnions.mls | 26 +++++++++++++------ 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index c9d3c4efa7..e94cd179c8 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -744,15 +744,17 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } def mk(ov: Overload)(implicit lvl: Level): FunctionType = { def unwrap(t: ST): ST = t.map(unwrap) - val f = ov.mapAlts(unwrap)(unwrap) - val (t, tvs, constrs) = lcgFunction(f.alts.head, f.alts.tail)(ov.prov, lvl) - val tsc = new TupleSetConstraints(MutSet.empty ++ constrs.transpose, tvs)(ov.prov) - tvs.zipWithIndex.foreach { case (tv, i) => - tv.lbtsc = S((tsc, i)) - tv.ubtsc = S((tsc, i)) + if (ov.alts.tail.isEmpty) ov.alts.head else { + val f = ov.mapAlts(unwrap)(unwrap) + val (t, tvs, constrs) = lcgFunction(f.alts.head, f.alts.tail)(ov.prov, lvl) + val tsc = new TupleSetConstraints(MutSet.empty ++ constrs.transpose, tvs)(ov.prov) + tvs.zipWithIndex.foreach { case (tv, i) => + tv.lbtsc = S((tsc, i)) + tv.ubtsc = S((tsc, i)) + } + println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") + t } - println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") - t } } } diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 4c5d1414db..2e20b650c8 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -983,7 +983,7 @@ abstract class TyperHelpers { Typer: Typer => def getVars: SortedSet[TypeVariable] = getVarsImpl(includeBounds = true) def showBounds: String = - getVars.iterator.filter(tv => tv.assignedTo.nonEmpty || (tv.upperBounds ++ tv.lowerBounds).nonEmpty || (tv.lbtsc.fold(false)(!_._1.tvs.contains(tv)))).map { + getVars.iterator.filter(tv => tv.assignedTo.nonEmpty || (tv.upperBounds ++ tv.lowerBounds).nonEmpty || (tv.lbtsc.isDefined && tv.ubtsc.isEmpty)).map { case tv @ AssignedVariable(ty) => "\n\t\t" + tv.toString + " := " + ty case tv => ("\n\t\t" + tv.toString + (if (tv.lowerBounds.isEmpty) "" else " :> " + tv.lowerBounds.mkString(" | ")) @@ -991,7 +991,7 @@ abstract class TyperHelpers { Typer: Typer => + tv.lbtsc.fold(""){ case (tsc, i) => " :> " + tsc.tvs(i) } ) }.mkString + { val visited: MutSet[TV] = MutSet.empty - getVars.iterator.filter(tv => tv.lbtsc.fold(false)(_._1.tvs.contains(tv))).map { + getVars.iterator.filter(tv => tv.ubtsc.isDefined).map { case tv if visited.contains(tv) => "" case tv => visited ++= tv.lbtsc.fold(Nil: Ls[TV])(_._1.tvs) diff --git a/shared/src/test/diff/nu/ArrayProg.mls b/shared/src/test/diff/nu/ArrayProg.mls index 857ee4e3ac..c5243ca638 100644 --- a/shared/src/test/diff/nu/ArrayProg.mls +++ b/shared/src/test/diff/nu/ArrayProg.mls @@ -155,7 +155,7 @@ module A { //│ } A.g(0) -//│ Int | Str +//│ Int //│ res //│ = 0 diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index 03ab69c023..e92c6ca504 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -47,14 +47,24 @@ fun f: (Str => Str) & ((Str, Int) => Int) //│ fun f: Str -> Str & (Str, Int) -> Int // * ...resulting in approximation at call sites (we don't handle overloading) +:e // TODO f("abc", "abc") -//│ Int | Str +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.51: f("abc", "abc") +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── argument list of type `["abc", "abc"]` does not match type `?a` +//│ ║ l.51: f("abc", "abc") +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from function type: +//│ ║ l.46: fun f: (Str => Str) & ((Str, Int) => Int) +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ error //│ res //│ = //│ f is not implemented f("abcabc") -//│ Int | Str +//│ Str //│ res //│ = //│ f is not implemented @@ -71,19 +81,19 @@ let r = if true then id else (x, y) => [y, x] r(error) r(error, error) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.71: r(error) +//│ ║ l.81: r(error) //│ ║ ^^^^^^^^ //│ ╟── argument of type `[nothing]` does not match type `[?a, ?b]` -//│ ║ l.71: r(error) +//│ ║ l.81: r(error) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.65: let r = if true then id else (x, y) => [y, x] +//│ ║ l.75: let r = if true then id else (x, y) => [y, x] //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.72: r(error, error) +//│ ║ l.82: r(error, error) //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── argument list of type `[nothing, nothing]` does not match type `[?a]` -//│ ║ l.72: r(error, error) +//│ ║ l.82: r(error, error) //│ ╙── ^^^^^^^^^^^^^^ //│ error | [nothing, nothing] //│ res @@ -106,7 +116,7 @@ r of [0, 1] // Also currently parses the same: let r = if true then id else [x, y] => [y, x] -//│ let r: forall 'a 'b 'c. (['b, 'c] & 'a) -> (['c, 'b] | 'a) +//│ let r: forall 'a 'b 'c. (['a, 'b] & 'c) -> (['b, 'a] | 'c) //│ r //│ = [Function: id] From fcc772f0c1d96ca990f34b417a7bde9dcd492e1f Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 29 Jan 2024 17:11:29 +0800 Subject: [PATCH 05/43] Update tests & remove obsolete function --- .../main/scala/mlscript/TyperHelpers.scala | 30 ----------- shared/src/test/diff/basics/Intersections.fun | 51 ++++++------------- .../diff/ecoop23/SimpleRegionDSL_annot.mls | 2 +- shared/src/test/diff/fcp/Overloads.mls | 25 +++++---- shared/src/test/diff/mlscript/BadPolym.mls | 4 +- 5 files changed, 34 insertions(+), 78 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 2e20b650c8..a97e69832a 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -693,36 +693,6 @@ abstract class TyperHelpers { Typer: Typer => case _ => this :: Nil } - def childrenPol(pol: Opt[Bool])(implicit ctx: Ctx): List[Opt[Bool] -> SimpleType] = { - def childrenPolField(fld: FieldType): List[Opt[Bool] -> SimpleType] = - fld.lb.map(pol.map(!_) -> _).toList ::: pol -> fld.ub :: Nil - this match { - case tv @ AssignedVariable(ty) => - pol -> ty :: Nil - case tv: TypeVariable => - (if (pol =/= S(false)) tv.lowerBounds.map(S(true) -> _) else Nil) ::: - (if (pol =/= S(true)) tv.upperBounds.map(S(false) -> _) else Nil) - case FunctionType(l, r) => pol.map(!_) -> l :: pol -> r :: Nil - case Overload(as) => as.map(pol -> _) - case ComposedType(_, l, r) => pol -> l :: pol -> r :: Nil - case RecordType(fs) => fs.unzip._2.flatMap(childrenPolField) - case TupleType(fs) => fs.unzip._2.flatMap(childrenPolField) - case ArrayType(fld) => childrenPolField(fld) - case SpliceType(elems) => elems flatMap {case L(l) => pol -> l :: Nil case R(r) => childrenPolField(r)} - case NegType(n) => pol.map(!_) -> n :: Nil - case ExtrType(_) => Nil - case ProxyType(und) => pol -> und :: Nil - // case _: TypeTag => Nil - case _: ObjectTag | _: Extruded => Nil - case SkolemTag(id) => pol -> id :: Nil - case tr: TypeRef => tr.mapTargs(pol)(_ -> _) - case Without(b, ns) => pol -> b :: Nil - case TypeBounds(lb, ub) => S(false) -> lb :: S(true) -> ub :: Nil - case PolymorphicType(_, und) => pol -> und :: Nil - case ConstrainedType(cs, bod) => - cs.flatMap(vbs => S(true) -> vbs._1 :: S(false) -> vbs._2 :: Nil) ::: pol -> bod :: Nil - }} - /** (exclusive, inclusive) */ def varsBetween(lb: Level, ub: Level): Set[TV] = { val res = MutSet.empty[TypeVariable] diff --git a/shared/src/test/diff/basics/Intersections.fun b/shared/src/test/diff/basics/Intersections.fun index 4bbdaa0f74..385b6a89fe 100644 --- a/shared/src/test/diff/basics/Intersections.fun +++ b/shared/src/test/diff/basics/Intersections.fun @@ -26,84 +26,65 @@ succ / foo(1) let foo = (Int => Int) & (Bool => Bool) //│ foo: int -> int & bool -> bool -:e foo(1) // returns int & bool, equivalent to nothing succ / foo(1) foo(true) not / foo(true) -//│ res: bool | int -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.31: succ / foo(1) -//│ ║ ^^^^^^^^^^^^^ -//│ ╟── reference of type `bool` is not an instance of type `int` -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ║ ^^^^ -//│ ╟── but it flows into application with expected type `int` -//│ ║ l.31: succ / foo(1) -//│ ╙── ^^^^^^ -//│ res: error | int -//│ res: bool | int -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.33: not / foo(true) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── reference of type `int` is not an instance of type `bool` -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ║ ^^^ -//│ ╟── but it flows into application with expected type `bool` -//│ ║ l.33: not / foo(true) -//│ ╙── ^^^^^^^^^ -//│ res: bool | error +//│ res: int +//│ res: int +//│ res: bool +//│ res: bool :e not / foo(1) foo(1) as Nothing //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.58: not / foo(1) +//│ ║ l.39: not / foo(1) //│ ║ ^^^^^^^^^^^^ //│ ╟── reference of type `int` is not an instance of type `bool` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^ //│ ╟── but it flows into application with expected type `bool` -//│ ║ l.58: not / foo(1) +//│ ║ l.39: not / foo(1) //│ ╙── ^^^^^^ //│ res: bool | error //│ ╔══[ERROR] Type mismatch in 'as' binding: -//│ ║ l.59: foo(1) as Nothing +//│ ║ l.40: foo(1) as Nothing //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `int` does not match type `nothing` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^ //│ ╟── but it flows into application with expected type `nothing` -//│ ║ l.59: foo(1) as Nothing +//│ ║ l.40: foo(1) as Nothing //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.59: foo(1) as Nothing +//│ ║ l.40: foo(1) as Nothing //│ ╙── ^^^^^^^ //│ res: nothing :e foo as Nothing //│ ╔══[ERROR] Type mismatch in 'as' binding: -//│ ║ l.85: foo as Nothing +//│ ║ l.66: foo as Nothing //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type intersection of type `int -> int & bool -> bool` does not match type `nothing` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `nothing` -//│ ║ l.85: foo as Nothing +//│ ║ l.66: foo as Nothing //│ ║ ^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.85: foo as Nothing +//│ ║ l.66: foo as Nothing //│ ╙── ^^^^^^^ //│ res: nothing :e let oops = (&) //│ ╔══[ERROR] Illegal use of reserved operator: & -//│ ║ l.101: let oops = (&) -//│ ╙── ^^^ +//│ ║ l.82: let oops = (&) +//│ ╙── ^^^ //│ ╔══[ERROR] identifier not found: & -//│ ║ l.101: let oops = (&) -//│ ╙── ^^^ +//│ ║ l.82: let oops = (&) +//│ ╙── ^^^ //│ oops: error diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls index ae9192d9df..d2b54c6799 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls @@ -348,7 +348,7 @@ fun mk(n) = if n is _ then Scale(Vector(0, 0), mk(n)) //│ fun mk: forall 'a. Object -> 'a //│ where -//│ 'a :> Outside['a] | Translate['a] | Scale['a] | Union['a] | Intersect['a] +//│ 'a :> Outside['a] | Scale['a] | Union['a] | Intersect['a] | Translate['a] :re TestElim.eliminate(mk(100)) diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 71a328bb55..b0e8c58dcb 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -44,9 +44,12 @@ IISS : BBNN //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.43: IISS : BBNN //│ ║ ^^^^ -//│ ╟── type `bool` does not match type `int | string` +//│ ╟── type `bool` does not match type `?a` //│ ║ l.6: type BBNN = bool -> bool & number -> number -//│ ╙── ^^^^ +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from function type: +//│ ║ l.12: def IISS: int -> int & string -> string +//│ ╙── ^^^^^^^^^^^^^^^^ //│ res: BBNN @@ -59,19 +62,20 @@ IISS : (0 | 1) -> number //│ res: (0 | 1) -> number IISS : 'a -> 'a -//│ res: ('a & (int | string)) -> (int | string | 'a) +//│ res: 'a -> 'a IISS 0 -//│ res: int | string +//│ res: int (IISS : int -> int) 0 //│ res: int (if true then IISS else BBNN) 0 -//│ res: bool | number | string +//│ res: number +// * TODO: update type simplifier fun x -> (if true then IISS else BBNN) x -//│ res: int -> (bool | number | string) +//│ res: anything -> nothing if true then IISS else BBNN //│ res: bool -> bool & number -> number | int -> int & string -> string @@ -85,11 +89,12 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.86: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.90: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `true` does not match type `int | string` -//│ ║ l.86: (if true then IISS else BBNN) : (0 | 1 | true) -> number -//│ ╙── ^^^^ +//│ ╟── expression of type `0 | 1 | true` does not match type `?a` +//│ ╟── Note: constraint arises from function type: +//│ ║ l.12: def IISS: int -> int & string -> string +//│ ╙── ^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/mlscript/BadPolym.mls b/shared/src/test/diff/mlscript/BadPolym.mls index d8695bb76e..ced0b225e8 100644 --- a/shared/src/test/diff/mlscript/BadPolym.mls +++ b/shared/src/test/diff/mlscript/BadPolym.mls @@ -40,11 +40,11 @@ fooImpl id fooImpl2 (f: int -> int & string -> string) = f 1 -//│ fooImpl2: (int -> int & string -> string) -> (int | string) +//│ fooImpl2: (int -> int & string -> string) -> int //│ = [Function: fooImpl2] fooImpl2 id -//│ res: int | string +//│ res: int //│ = 1 :e From badd1ef4ce2c614f0da2793f4312ed4a20c9a2a5 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 15 Feb 2024 00:29:13 +0800 Subject: [PATCH 06/43] Extend Constrained with field to hold constraints --- .../scala/mlscript/ConstraintSolver.scala | 6 +++-- .../main/scala/mlscript/TypeSimplifier.scala | 27 ++++++++++++++++++- shared/src/main/scala/mlscript/Typer.scala | 27 +++++++++++++++---- .../main/scala/mlscript/TyperDatatypes.scala | 16 +++++------ .../main/scala/mlscript/TyperHelpers.scala | 12 ++++----- .../codegen/typescript/TsTypegen.scala | 2 +- shared/src/main/scala/mlscript/helpers.scala | 11 +++++--- shared/src/main/scala/mlscript/syntax.scala | 2 +- .../src/test/scala/mlscript/DiffTests.scala | 2 +- 9 files changed, 75 insertions(+), 30 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 37b3a5441f..ce32eb81e4 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -820,7 +820,7 @@ class ConstraintSolver extends NormalForms { self: Typer => val newBound = (cctx._1 ::: cctx._2.reverse).foldRight(rhs)((c, ty) => if (c.prov is noProv) ty else mkProxy(ty, c.prov)) lhs.upperBounds ::= newBound // update the bound - lhs.lbtsc.foreach { + lhs.tsc.foreach { case (tsc, i) => tsc.filterUB(i, rhs) if (tsc.constraints.isEmpty) reportError() @@ -832,7 +832,7 @@ class ConstraintSolver extends NormalForms { self: Typer => val newBound = (cctx._1 ::: cctx._2.reverse).foldLeft(lhs)((ty, c) => if (c.prov is noProv) ty else mkProxy(ty, c.prov)) rhs.lowerBounds ::= newBound // update the bound - rhs.ubtsc.foreach { + rhs.tsc.foreach { case (tsc, i) => tsc.filterLB(i, lhs) if (tsc.constraints.isEmpty) reportError() @@ -1562,6 +1562,8 @@ class ConstraintSolver extends NormalForms { self: Typer => freshened += tv -> v v.lowerBounds = tv.lowerBounds.mapConserve(freshen) v.upperBounds = tv.upperBounds.mapConserve(freshen) + v.tsc = tv.tsc + v.tsc.foreach { case (tsc, i) => tsc.tvs = tsc.tvs.mapConserve(x => freshen(x).asInstanceOf[TV]) } v } diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 0e688fe8e3..ac43a4ea92 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -75,6 +75,17 @@ trait TypeSimplifier { self: Typer => tv.upperBounds.reverseIterator.map(process(_, S(false -> tv))) .reduceOption(_ &- _).filterNot(_.isTop).toList else Nil + nv.tsc = tv.tsc.map { + case (tsc, i) => + tsc.tvs.flatMap(x => renewed.get(x).flatMap(_.tsc)).headOption + .fold(new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov), i) { + tsc => (tsc._1, i) + } + } + nv.tsc.foreach { case (tsc, i) => + val (l, r) = tsc.tvs.splitAt(i-1) + l ++ (nv :: r.drop(1)) + } } nv @@ -520,6 +531,7 @@ trait TypeSimplifier { self: Typer => override def apply(pol: PolMap)(st: ST): Unit = trace(s"analyze1[${(pol)}] $st") { st match { case tv: TV => + println(s"analyzing 1: $tv, ${pol(tv)}") pol(tv) match { case S(pol) => occNums(pol -> tv) += 1 @@ -543,7 +555,9 @@ trait TypeSimplifier { self: Typer => analyzed1.setAndIfUnset(tv -> pol(tv).getOrElse(false)) { apply(pol)(ty) } case N => if (pol(tv) =/= S(false)) - analyzed1.setAndIfUnset(tv -> true) { tv.lowerBounds.foreach(apply(pol.at(tv.level, true))) } + analyzed1.setAndIfUnset(tv -> true) { + tv.lowerBounds.foreach(apply(pol.at(tv.level, true))) + } if (pol(tv) =/= S(true)) analyzed1.setAndIfUnset(tv -> false) { tv.upperBounds.foreach(apply(pol.at(tv.level, false))) } } @@ -1011,6 +1025,17 @@ trait TypeSimplifier { self: Typer => res.lowerBounds = tv.lowerBounds.map(transform(_, pol.at(tv.level, true), Set.single(tv))) if (occNums.contains(false -> tv)) res.upperBounds = tv.upperBounds.map(transform(_, pol.at(tv.level, false), Set.single(tv))) + res.tsc = tv.tsc.map { + case (tsc, i) => + tsc.tvs.flatMap(x => renewals.get(x).flatMap(_.tsc)).headOption + .fold(new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov), i) { + tsc => (tsc._1, i) + } + } + res.tsc.foreach { case (tsc, i) => + val (l, r) = tsc.tvs.splitAt(i-1) + l ++ (res :: r.drop(1)) + } } res }() diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 3a3e5d15d4..5892bdfa1a 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -578,7 +578,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne tv.assignedTo = S(bod) tv case Rem(base, fs) => Without(rec(base), fs.toSortedSet)(tyTp(ty.toLoc, "field removal type")) - case Constrained(base, tvbs, where) => + case Constrained(base, tvbs, where, tscs) => val res = rec(base match { case ty: Type => ty case _ => die @@ -591,6 +591,11 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne constrain(rec(lo), rec(hi))(raise, tp(mergeOptions(lo.toLoc, hi.toLoc)(_ ++ _), "constraint specifiation"), ctx) } + tscs.foreach { case (typevars, constrs) => + val tvs = typevars.map(recVars) + val tsc = new TupleSetConstraints(MutSet.empty ++ constrs.map(_.map(rec)), tvs)(res.prov) + tvs.zipWithIndex.foreach { case (tv, i) => tv.tsc = S((tsc, i)) } + } res case PolyType(vars, ty) => val oldLvl = ctx.lvl @@ -1674,6 +1679,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne val expandType = () var bounds: Ls[TypeVar -> Bounds] = Nil + var tscs: Ls[Ls[TypeVar] -> Ls[Ls[Type]]] = Nil val seenVars = mutable.Set.empty[TV] @@ -1783,6 +1789,14 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne if (l =/= Bot || u =/= Top) bounds ::= nv -> Bounds(l, u) } + tv.tsc.foreach { + case (tsc, i) => + if (tsc.tvs.forall(v => !seenVars(v) || v === tv)) { + val tvs = tsc.tvs.map(_.asTypeVar) + val constrs = tsc.constraints.toList.map(_.map(go)) + tscs ::= tvs -> constrs + } + } } nv }) @@ -1832,17 +1846,20 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne case Overload(as) => as.map(go).reduce(Inter) case PolymorphicType(lvl, bod) => val boundsSize = bounds.size + val tscsSize = tscs.size val b = go(bod) // This is not completely correct: if we've already traversed TVs as part of a previous sibling PolymorphicType, // the bounds of these TVs won't be registered again... // FIXME in principle we'd want to compute a transitive closure... val newBounds = bounds.reverseIterator.drop(boundsSize).toBuffer + val newTscs = tscs.reverseIterator.drop(tscsSize).toBuffer val qvars = bod.varsBetween(lvl, MaxLevel).iterator val ftvs = b.freeTypeVariables ++ newBounds.iterator.map(_._1) ++ - newBounds.iterator.flatMap(_._2.freeTypeVariables) + newBounds.iterator.flatMap(_._2.freeTypeVariables) ++ + newTscs.iterator.flatMap(_._1) val fvars = qvars.filter(tv => ftvs.contains(tv.asTypeVar)) if (fvars.isEmpty) b else PolyType(fvars.map(_.asTypeVar pipe (R(_))).toList, b) @@ -1851,7 +1868,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne val lbs = others1.mapValues(_.head).groupMap(_._2)(_._1).toList val bounds = (ubs.mapValues(_.reduce(_ &- _)) ++ lbs.mapValues(_.reduce(_ | _)).map(_.swap)) val procesased = bounds.map { case (lo, hi) => Bounds(go(lo), go(hi)) } - Constrained(go(bod), Nil, procesased) + Constrained(go(bod), Nil, procesased, Nil) // case DeclType(lvl, info) => @@ -1859,8 +1876,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne // }(r => s"~> $r") val res = goLike(st)(new ExpCtx(Map.empty)) - if (bounds.isEmpty) res - else Constrained(res, bounds, Nil) + if (bounds.isEmpty && tscs.isEmpty) res + else Constrained(res, bounds, Nil, tscs) // goLike(st) } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index e94cd179c8..a5bd47e7c1 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -535,8 +535,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => _assignedTo = value } - var lbtsc: Opt[(TupleSetConstraints, Int)] = N - var ubtsc: Opt[(TupleSetConstraints, Int)] = N + var tsc: Opt[(TupleSetConstraints, Int)] = N // * Bounds should always be disregarded when `equatedTo` is defined, as they are then irrelevant: def lowerBounds: List[SimpleType] = { require(assignedTo.isEmpty, this); _lowerBounds } @@ -655,7 +654,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => def go(ub: ST): Unit = ub match { case ub: TV => ub.upperBounds.foreach(go) - ub.lbtsc = S(this, index) + ub.lowerBounds ::= tvs(index) case _ => constraints.filterInPlace { constrs => val ty = constrs(index) @@ -668,8 +667,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => if (constraints.sizeCompare(1) === 0) { constraints.head.zip(tvs).foreach { case (ty, tv) => - tv.lbtsc = N - tv.ubtsc = N + tv.tsc = N constrain(tv, ty)(raise, prov, ctx) constrain(ty, tv)(raise, prov, ctx) } @@ -685,8 +683,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => if (constraints.sizeCompare(1) === 0) { constraints.head.zip(tvs).foreach { case (ty, tv) => - tv.lbtsc = N - tv.ubtsc = N + tv.tsc = N constrain(tv, ty)(raise, prov, ctx) constrain(ty, tv)(raise, prov, ctx) } @@ -743,14 +740,13 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => (FunctionType(lhs, rhs)(prov), ltvs ++ rtvs, lconstrs ++ rconstrs) } def mk(ov: Overload)(implicit lvl: Level): FunctionType = { - def unwrap(t: ST): ST = t.map(unwrap) + def unwrap(t: ST): ST = t.unwrapProxies.map(unwrap) if (ov.alts.tail.isEmpty) ov.alts.head else { val f = ov.mapAlts(unwrap)(unwrap) val (t, tvs, constrs) = lcgFunction(f.alts.head, f.alts.tail)(ov.prov, lvl) val tsc = new TupleSetConstraints(MutSet.empty ++ constrs.transpose, tvs)(ov.prov) tvs.zipWithIndex.foreach { case (tv, i) => - tv.lbtsc = S((tsc, i)) - tv.ubtsc = S((tsc, i)) + tv.tsc = S((tsc, i)) } println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") t diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index a97e69832a..3d8aed5443 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -953,19 +953,19 @@ abstract class TyperHelpers { Typer: Typer => def getVars: SortedSet[TypeVariable] = getVarsImpl(includeBounds = true) def showBounds: String = - getVars.iterator.filter(tv => tv.assignedTo.nonEmpty || (tv.upperBounds ++ tv.lowerBounds).nonEmpty || (tv.lbtsc.isDefined && tv.ubtsc.isEmpty)).map { + getVars.iterator.filter(tv => (tv.assignedTo.nonEmpty || (tv.upperBounds ++ tv.lowerBounds).nonEmpty) && tv.tsc.isEmpty).map { case tv @ AssignedVariable(ty) => "\n\t\t" + tv.toString + " := " + ty case tv => ("\n\t\t" + tv.toString + (if (tv.lowerBounds.isEmpty) "" else " :> " + tv.lowerBounds.mkString(" | ")) + (if (tv.upperBounds.isEmpty) "" else " <: " + tv.upperBounds.mkString(" & ")) - + tv.lbtsc.fold(""){ case (tsc, i) => " :> " + tsc.tvs(i) } ) + ) }.mkString + { val visited: MutSet[TV] = MutSet.empty - getVars.iterator.filter(tv => tv.ubtsc.isDefined).map { + getVars.iterator.filter(tv => tv.tsc.isDefined).map { case tv if visited.contains(tv) => "" case tv => - visited ++= tv.lbtsc.fold(Nil: Ls[TV])(_._1.tvs) - tv.lbtsc.fold("") { case (tsc, _) => ("\n\t\t[ " + visited ++= tv.tsc.fold(Nil: Ls[TV])(_._1.tvs) + tv.tsc.fold("") { case (tsc, _) => ("\n\t\t[ " + tsc.tvs.mkString(", ") + " ] in { " + tsc.constraints.mkString(", ") + " }") } @@ -1398,7 +1398,7 @@ abstract class TyperHelpers { Typer: Typer => private val lvl = 0 def apply(lvl: Level): Pol def quantifPolarity(lvl: Level): PolMap - final def apply(tv: TV): Pol = apply(tv.level) + final def apply(tv: TV): Pol = if (tv.tsc.isEmpty) apply(tv.level) else N def enter(polymLvl: Level): PolMap = new PolMap(base) { def apply(lvl: Level): Pol = diff --git a/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala b/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala index 51a41cfa35..c75f8025e8 100644 --- a/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala +++ b/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala @@ -572,7 +572,7 @@ final class TsTypegenCodeBuilder { typeScope.getTypeAliasSymbol(tvarName).map { taliasInfo => SourceCode(taliasInfo.lexicalName) ++ SourceCode.paramList(taliasInfo.params.map(SourceCode(_))) }.getOrElse(SourceCode(tvarName)) - case Constrained(base, tvbs, where) => + case Constrained(base, tvbs, where, _) => throw CodeGenError(s"Cannot generate type for `where` clause $tvbs $where") case _: Splice | _: TypeTag | _: PolyType | _: Selection => throw CodeGenError(s"Cannot yet generate type for: $mlType") diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index b6154bd409..61fb516f9b 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -113,7 +113,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => .mkString("forall ", " ", ".")} ${body.showIn(ctx, 0)}", outerPrec > 1 // or 0? ) - case Constrained(b, bs, ws) => + case Constrained(b, bs, ws, tscs) => val oldCtx = ctx val bStr = b.showIn(ctx, 0).stripSuffix("\n") val multiline = bStr.contains('\n') @@ -136,6 +136,11 @@ trait TypeLikeImpl extends Located { self: TypeLike => }.mkString }${ws.map{ case Bounds(lo, hi) => s"\n${ctx.indStr}${lo.showIn(ctx, 0)} <: ${hi.showIn(ctx, 0)}" // TODO print differently from bs? + }.mkString + }${tscs.map{ + case (tvs, constrs) => + s"\n${ctx.indStr}${tvs.map(_.showIn(ctx, 0)).mkString("[", ", ", "]")}" + + s" in ${constrs.map(_.map(_.showIn(ctx, 0)).mkString("[", ", ", "]")).mkString("{", ", ", "}")}" }.mkString}" }, outerPrec > 0) case fd @ NuFunDef(isLetRec, nme, snme, targs, rhs) => @@ -205,7 +210,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => case WithExtension(b, r) => b :: r :: Nil case PolyType(targs, body) => targs.map(_.fold(identity, identity)) :+ body case Splice(fs) => fs.flatMap{ case L(l) => l :: Nil case R(r) => r.in.toList ++ (r.out :: Nil) } - case Constrained(b, bs, ws) => b :: bs.flatMap(c => c._1 :: c._2 :: Nil) ::: ws.flatMap(c => c.lb :: c.ub :: Nil) + case Constrained(b, bs, ws, tscs) => b :: bs.flatMap(c => c._1 :: c._2 :: Nil) ::: ws.flatMap(c => c.lb :: c.ub :: Nil) ::: tscs.flatMap(tsc => tsc._1 ::: tsc._2.flatten) case Signature(xs, res) => xs ::: res.toList case NuFunDef(isLetRec, nme, snme, targs, rhs) => targs ::: rhs.toOption.toList case NuTypeDef(kind, nme, tparams, params, ctor, sig, parents, sup, ths, body) => @@ -671,7 +676,7 @@ trait TermImpl extends StatementImpl { self: Term => Constrained(body.toType_!, Nil, where.map { case Asc(l, r) => Bounds(l.toType_!, r) case s => throw new NotAType(s) - }) + }, Nil) case Forall(ps, bod) => PolyType(ps.map(R(_)), bod.toType_!) // diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index d3d3b05c4d..6242ecf878 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -156,7 +156,7 @@ final case class Rem(base: Type, names: Ls[Var]) extends Type final case class Bounds(lb: Type, ub: Type) extends Type final case class WithExtension(base: Type, rcd: Record) extends Type final case class Splice(fields: Ls[Either[Type, Field]]) extends Type -final case class Constrained(base: TypeLike, tvBounds: Ls[TypeVar -> Bounds], where: Ls[Bounds]) extends Type +final case class Constrained(base: TypeLike, tvBounds: Ls[TypeVar -> Bounds], where: Ls[Bounds], tscs: Ls[Ls[TypeVar] -> Ls[Ls[Type]]]) extends Type // final case class FirstClassDefn(defn: NuTypeDef) extends Type // TODO // final case class Refinement(base: Type, decls: TypingUnit) extends Type // TODO diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index b5772437fd..a787c71038 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -507,7 +507,7 @@ class DiffTests exp match { // * Strip top-level implicitly-quantified type variables case pt: PolyType => stripPoly(pt) - case Constrained(pt: PolyType, bs, cs) => Constrained(stripPoly(pt), bs, cs) + case Constrained(pt: PolyType, bs, cs, tscs) => Constrained(stripPoly(pt), bs, cs, tscs) case ty => ty } } From 63eb50072f1612d20f38c2613ee1c67cc07d95f1 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 15 Feb 2024 22:15:54 +0800 Subject: [PATCH 07/43] update tests --- .../main/scala/mlscript/TypeSimplifier.scala | 9 +- shared/src/test/diff/basics/Intersections.fun | 8 +- shared/src/test/diff/fcp/Overloads.mls | 11 ++- shared/src/test/diff/nu/HeungTung.mls | 88 +++++++++++++++---- shared/src/test/diff/nu/WeirdUnions.mls | 14 +-- 5 files changed, 95 insertions(+), 35 deletions(-) diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index ac43a4ea92..eb035608c7 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -83,8 +83,8 @@ trait TypeSimplifier { self: Typer => } } nv.tsc.foreach { case (tsc, i) => - val (l, r) = tsc.tvs.splitAt(i-1) - l ++ (nv :: r.drop(1)) + val (l, r) = tsc.tvs.splitAt(i) + tsc.tvs = l ++ (nv :: r.drop(1)) } } nv @@ -531,7 +531,6 @@ trait TypeSimplifier { self: Typer => override def apply(pol: PolMap)(st: ST): Unit = trace(s"analyze1[${(pol)}] $st") { st match { case tv: TV => - println(s"analyzing 1: $tv, ${pol(tv)}") pol(tv) match { case S(pol) => occNums(pol -> tv) += 1 @@ -1033,8 +1032,8 @@ trait TypeSimplifier { self: Typer => } } res.tsc.foreach { case (tsc, i) => - val (l, r) = tsc.tvs.splitAt(i-1) - l ++ (res :: r.drop(1)) + val (l, r) = tsc.tvs.splitAt(i) + tsc.tvs = l ++ (res :: r.drop(1)) } } res diff --git a/shared/src/test/diff/basics/Intersections.fun b/shared/src/test/diff/basics/Intersections.fun index 385b6a89fe..b6e97890fb 100644 --- a/shared/src/test/diff/basics/Intersections.fun +++ b/shared/src/test/diff/basics/Intersections.fun @@ -41,9 +41,9 @@ foo(1) as Nothing //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.39: not / foo(1) //│ ║ ^^^^^^^^^^^^ -//│ ╟── reference of type `int` is not an instance of type `bool` +//│ ╟── function of type `int` is not an instance of type `bool` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ║ ^^^ +//│ ║ ^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `bool` //│ ║ l.39: not / foo(1) //│ ╙── ^^^^^^ @@ -51,9 +51,9 @@ foo(1) as Nothing //│ ╔══[ERROR] Type mismatch in 'as' binding: //│ ║ l.40: foo(1) as Nothing //│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── reference of type `int` does not match type `nothing` +//│ ╟── function of type `int` does not match type `nothing` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ║ ^^^ +//│ ║ ^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `nothing` //│ ║ l.40: foo(1) as Nothing //│ ║ ^^^^^^ diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index b0e8c58dcb..505669f81a 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -62,7 +62,9 @@ IISS : (0 | 1) -> number //│ res: (0 | 1) -> number IISS : 'a -> 'a -//│ res: 'a -> 'a +//│ res: ('a & 'b) -> ('a | 'c) +//│ where +//│ ['b, 'c] in {[string, string], [int, int]} IISS 0 //│ res: int @@ -75,7 +77,10 @@ IISS 0 // * TODO: update type simplifier fun x -> (if true then IISS else BBNN) x -//│ res: anything -> nothing +//│ res: ('a & 'b) -> ('c | 'd) +//│ where +//│ ['b, 'd] in {[bool, bool], [number, number]} +//│ ['a, 'c] in {[string, string], [int, int]} if true then IISS else BBNN //│ res: bool -> bool & number -> number | int -> int & string -> string @@ -89,7 +94,7 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.90: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.95: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `0 | 1 | true` does not match type `?a` //│ ╟── Note: constraint arises from function type: diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index c810a3122b..f0f47adc28 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -124,7 +124,9 @@ f(0) x => f(x) -//│ anything -> nothing +//│ forall 'a 'b. 'a -> 'b +//│ where +//│ ['a, 'b] in {[Bool, Bool], [Int, Int]} //│ res //│ = [Function: res] @@ -133,13 +135,15 @@ x => f(x) :e f(if true then 0 else false) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.134: f(if true then 0 else false) +//│ ║ l.136: f(if true then 0 else false) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `0 | false` does not match type `?a` //│ ╟── Note: constraint arises from function type: //│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) //│ ╙── ^^^^^^^^^^^^^^ -//│ error +//│ error | 'a +//│ where +//│ ['b, 'a] in {} //│ res //│ = 0 @@ -149,21 +153,23 @@ f(if true then 0 else false) :w f(refined if true then 0 else false) // this one can be precise again! //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.150: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.154: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.150: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.154: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.150: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.154: f(refined if true then 0 else false) // this one can be precise again! //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `error` does not match type `?a` -//│ ║ l.150: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.154: f(refined if true then 0 else false) // this one can be precise again! //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from function type: //│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) //│ ╙── ^^^^^^^^^^^^^^ -//│ error +//│ error | 'a +//│ where +//│ ['b, 'a] in {} //│ Code generation encountered an error: //│ unresolved symbol refined @@ -219,7 +225,7 @@ type T = List[Int] :e // TODO application types type Res = M(T) //│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 -//│ ║ l.220: type Res = M(T) +//│ ║ l.226: type Res = M(T) //│ ╙── ^^^^ //│ type Res = M @@ -242,7 +248,7 @@ fun f: Int -> Int fun f: Bool -> Bool fun f = id //│ ╔══[ERROR] A type signature for 'f' was already given -//│ ║ l.242: fun f: Bool -> Bool +//│ ║ l.248: fun f: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun f: forall 'a. 'a -> 'a //│ fun f: Int -> Int @@ -250,13 +256,13 @@ fun f = id :e // TODO support f: (Int -> Int) & (Bool -> Bool) //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.251: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.257: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^ //│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.251: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.257: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.241: fun f: Int -> Int +//│ ║ l.247: fun f: Int -> Int //│ ╙── ^^^ //│ Int -> Int & Bool -> Bool //│ res @@ -323,14 +329,14 @@ fun test(x) = refined if x is A then 0 B then 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.322: fun test(x) = refined if x is +//│ ║ l.328: fun test(x) = refined if x is //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.323: A then 0 +//│ ║ l.329: A then 0 //│ ║ ^^^^^^^^^^ -//│ ║ l.324: B then 1 +//│ ║ l.330: B then 1 //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.322: fun test(x) = refined if x is +//│ ║ l.328: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ fun test: (A | B) -> error //│ Code generation encountered an error: @@ -340,3 +346,51 @@ fun test(x) = refined if x is +fun q: (0|1) -> true & (1|2) -> false +//│ fun q: (0 | 1) -> true & (1 | 2) -> false + +q(0) +//│ true +//│ res +//│ = +//│ q is not implemented + +q(1) +//│ 'a +//│ where +//│ ['b, 'a] in {[0 | 1, true], [1 | 2, false]} +//│ res +//│ = +//│ q is not implemented + +x => q(x): true +//│ (0 | 1) -> true +//│ res +//│ = +//│ q is not implemented + +x => q(x) +//│ forall 'a 'b. 'a -> 'b +//│ where +//│ ['a, 'b] in {[0 | 1, true], [1 | 2, false]} +//│ res +//│ = +//│ q is not implemented + +fun w = x => q(x) +//│ fun w: forall 'a 'b. 'a -> 'b +//│ where +//│ ['a, 'b] in {[0 | 1, true], [1 | 2, false]} + +w(0) +//│ forall 'a. 'a +//│ where +//│ ['b, 'a] in {[0 | 1, true]} +//│ res +//│ = +//│ w and q are not implemented + +x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 +//│ Int -> (f: (0, Int) -> Int & (1, Str) -> [Int]) -> Int +//│ res +//│ = [Function: res] diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index e92c6ca504..504096afa9 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -58,7 +58,9 @@ f("abc", "abc") //│ ╟── Note: constraint arises from function type: //│ ║ l.46: fun f: (Str => Str) & ((Str, Int) => Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ error +//│ error | 'a +//│ where +//│ ['b, 'a] in {} //│ res //│ = //│ f is not implemented @@ -81,19 +83,19 @@ let r = if true then id else (x, y) => [y, x] r(error) r(error, error) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.81: r(error) +//│ ║ l.83: r(error) //│ ║ ^^^^^^^^ //│ ╟── argument of type `[nothing]` does not match type `[?a, ?b]` -//│ ║ l.81: r(error) +//│ ║ l.83: r(error) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.75: let r = if true then id else (x, y) => [y, x] +//│ ║ l.77: let r = if true then id else (x, y) => [y, x] //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.82: r(error, error) +//│ ║ l.84: r(error, error) //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── argument list of type `[nothing, nothing]` does not match type `[?a]` -//│ ║ l.82: r(error, error) +//│ ║ l.84: r(error, error) //│ ╙── ^^^^^^^^^^^^^^ //│ error | [nothing, nothing] //│ res From 3ed1981d1e562281edd22e4d727fd96131e77a29 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Mon, 4 Mar 2024 05:50:50 +0800 Subject: [PATCH 08/43] wip: constraints on ST and add polarity --- .../scala/mlscript/ConstraintSolver.scala | 21 +- .../main/scala/mlscript/TypeSimplifier.scala | 47 +- shared/src/main/scala/mlscript/Typer.scala | 15 +- .../main/scala/mlscript/TyperDatatypes.scala | 185 +-- .../main/scala/mlscript/TyperHelpers.scala | 6 +- shared/src/main/scala/mlscript/helpers.scala | 4 +- shared/src/main/scala/mlscript/syntax.scala | 2 +- shared/src/test/diff/basics/Intersections.fun | 20 +- .../diff/ecoop23/SimpleRegionDSL_annot.mls | 1003 ++++++++++++++++- shared/src/test/diff/fcp/Overloads.mls | 66 +- shared/src/test/diff/nu/ArrayProg.mls | 24 +- shared/src/test/diff/nu/HeungTung.mls | 166 ++- shared/src/test/diff/nu/WeirdUnions.mls | 28 +- 13 files changed, 1305 insertions(+), 282 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index ce32eb81e4..2169fedcf6 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -619,10 +619,13 @@ class ConstraintSolver extends NormalForms { self: Typer => recLb(ar.inner, b.inner) rec(b.inner.ub, ar.inner.ub, false) case (LhsRefined(S(b: ArrayBase), ts, r, _), _) => reportError() + case (LhsRefined(S(ov: Overload), ts, r, trs), RhsBases(_, S(L(f: FunctionType)), _)) => + val tsc = TupleSetConstraints.mk(ov, f) + if (tsc.constraints.isEmpty) reportError() + // val t = TupleSetConstraints.mk(ov) + // annoying(Nil, LhsRefined(S(t), ts, r, trs), Nil, done_rs) case (LhsRefined(S(ov: Overload), ts, r, trs), _) => - val t = TupleSetConstraints.mk(ov) - annoying(Nil, LhsRefined(S(t), ts, r, trs), Nil, done_rs) - // annoying(Nil, LhsRefined(S(ov.approximatePos), ts, r, trs), Nil, done_rs) // TODO remove approx. with ambiguous constraints + annoying(Nil, LhsRefined(S(ov.approximatePos), ts, r, trs), Nil, done_rs) // TODO remove approx. with ambiguous constraints case (LhsRefined(S(Without(b, ns)), ts, r, _), RhsBases(pts, N | S(L(_)), _)) => rec(b, done_rs.toType(), true) case (_, RhsBases(pts, S(L(Without(base, ns))), _)) => @@ -820,9 +823,9 @@ class ConstraintSolver extends NormalForms { self: Typer => val newBound = (cctx._1 ::: cctx._2.reverse).foldRight(rhs)((c, ty) => if (c.prov is noProv) ty else mkProxy(ty, c.prov)) lhs.upperBounds ::= newBound // update the bound - lhs.tsc.foreach { + lhs.tsc.foreachEntry { case (tsc, i) => - tsc.filterUB(i, rhs) + tsc.updateOn(i, rhs) if (tsc.constraints.isEmpty) reportError() } lhs.lowerBounds.foreach(rec(_, rhs, true)) // propagate from the bound @@ -832,9 +835,9 @@ class ConstraintSolver extends NormalForms { self: Typer => val newBound = (cctx._1 ::: cctx._2.reverse).foldLeft(lhs)((ty, c) => if (c.prov is noProv) ty else mkProxy(ty, c.prov)) rhs.lowerBounds ::= newBound // update the bound - rhs.tsc.foreach { + rhs.tsc.foreachEntry { case (tsc, i) => - tsc.filterLB(i, lhs) + tsc.updateOn(i, lhs) if (tsc.constraints.isEmpty) reportError() } rhs.upperBounds.foreach(rec(lhs, _, true)) // propagate from the bound @@ -1562,8 +1565,8 @@ class ConstraintSolver extends NormalForms { self: Typer => freshened += tv -> v v.lowerBounds = tv.lowerBounds.mapConserve(freshen) v.upperBounds = tv.upperBounds.mapConserve(freshen) - v.tsc = tv.tsc - v.tsc.foreach { case (tsc, i) => tsc.tvs = tsc.tvs.mapConserve(x => freshen(x).asInstanceOf[TV]) } + v.tsc = tv.tsc // fixme + v.tsc.foreachEntry { case (tsc, i) => tsc.tvs = tsc.tvs.mapConserve(x => (x._1, freshen(x._2))) } v } diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index eb035608c7..e5ca2111cb 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -75,17 +75,19 @@ trait TypeSimplifier { self: Typer => tv.upperBounds.reverseIterator.map(process(_, S(false -> tv))) .reduceOption(_ &- _).filterNot(_.isTop).toList else Nil - nv.tsc = tv.tsc.map { - case (tsc, i) => - tsc.tvs.flatMap(x => renewed.get(x).flatMap(_.tsc)).headOption - .fold(new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov), i) { - tsc => (tsc._1, i) - } - } - nv.tsc.foreach { case (tsc, i) => - val (l, r) = tsc.tvs.splitAt(i) - tsc.tvs = l ++ (nv :: r.drop(1)) - } + // fixme + // nv.tsc = tv.tsc.map { + // case (tsc, i) => + // tsc.tvs.collect { case (_, x: TV) => renewed.get(x).flatMap(_.tsc) } + // .flatten.headOption + // .fold(new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov), i) { + // tsc => (tsc._1, i) + // } + // } + // nv.tsc.foreach { case (tsc, i) => + // val (l, r) = tsc.tvs.splitAt(i) + // tsc.tvs = l ++ ((r.head._1, nv) :: r.drop(1)) + // } } nv @@ -1024,17 +1026,18 @@ trait TypeSimplifier { self: Typer => res.lowerBounds = tv.lowerBounds.map(transform(_, pol.at(tv.level, true), Set.single(tv))) if (occNums.contains(false -> tv)) res.upperBounds = tv.upperBounds.map(transform(_, pol.at(tv.level, false), Set.single(tv))) - res.tsc = tv.tsc.map { - case (tsc, i) => - tsc.tvs.flatMap(x => renewals.get(x).flatMap(_.tsc)).headOption - .fold(new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov), i) { - tsc => (tsc._1, i) - } - } - res.tsc.foreach { case (tsc, i) => - val (l, r) = tsc.tvs.splitAt(i) - tsc.tvs = l ++ (res :: r.drop(1)) - } + // TODO + // res.tsc = tv.tsc.map { + // case (tsc, i) => + // tsc.tvs.collect { case (_, x: TV) => renewals.get(x).flatMap(_.tsc)}.flatten.headOption + // .fold(new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov), i) { + // tsc => (tsc._1, i) + // } + // } + // res.tsc.foreach { case (tsc, i) => + // val (l, r) = tsc.tvs.splitAt(i) + // tsc.tvs = l ++ ((r.head._1, res) :: r.drop(1)) + // } } res }() diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 5892bdfa1a..ef9a0a1392 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -592,9 +592,12 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne tp(mergeOptions(lo.toLoc, hi.toLoc)(_ ++ _), "constraint specifiation"), ctx) } tscs.foreach { case (typevars, constrs) => - val tvs = typevars.map(recVars) + val tvs = typevars.map(x => (x._1, rec(x._2))) val tsc = new TupleSetConstraints(MutSet.empty ++ constrs.map(_.map(rec)), tvs)(res.prov) - tvs.zipWithIndex.foreach { case (tv, i) => tv.tsc = S((tsc, i)) } + tvs.zipWithIndex.foreach { + case ((_, tv: TV), i) => tv.tsc += tsc -> i + case _ => () + } } res case PolyType(vars, ty) => @@ -1679,7 +1682,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne val expandType = () var bounds: Ls[TypeVar -> Bounds] = Nil - var tscs: Ls[Ls[TypeVar] -> Ls[Ls[Type]]] = Nil + var tscs: Ls[Ls[(Opt[Bool], Type)] -> Ls[Ls[Type]]] = Nil val seenVars = mutable.Set.empty[TV] @@ -1789,10 +1792,10 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne if (l =/= Bot || u =/= Top) bounds ::= nv -> Bounds(l, u) } - tv.tsc.foreach { + tv.tsc.foreachEntry { case (tsc, i) => - if (tsc.tvs.forall(v => !seenVars(v) || v === tv)) { - val tvs = tsc.tvs.map(_.asTypeVar) + if (tsc.tvs.forall { case (_, v: TV) => !seenVars(v) || v === tv; case _ => true }) { + val tvs = tsc.tvs.map(x => (x._1, go(x._2))) val constrs = tsc.constraints.toList.map(_.map(go)) tscs ::= tvs -> constrs } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index a5bd47e7c1..7f99e48998 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -535,7 +535,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => _assignedTo = value } - var tsc: Opt[(TupleSetConstraints, Int)] = N + var tsc: MutMap[TupleSetConstraints, Int] = MutMap.empty // * Bounds should always be disregarded when `equatedTo` is defined, as they are then irrelevant: def lowerBounds: List[SimpleType] = { require(assignedTo.isEmpty, this); _lowerBounds } @@ -649,108 +649,145 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => val prov = noProv } - class TupleSetConstraints(val constraints: MutSet[Ls[ST]], var tvs: Ls[TV])(val prov: TypeProvenance) { - def filterUB(index: Int, ub: ST)(implicit raise: Raise, ctx: Ctx): Unit = { - def go(ub: ST): Unit = ub match { - case ub: TV => - ub.upperBounds.foreach(go) - ub.lowerBounds ::= tvs(index) - case _ => - constraints.filterInPlace { constrs => - val ty = constrs(index) - val dnf = DNF.mk(MaxLevel, Nil, ty & ub.neg(), true) - dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty)) - } + class TupleSetConstraints(val constraints: MutSet[Ls[ST]], var tvs: Ls[(Opt[Bool], ST)])(val prov: TypeProvenance) { + def updateImpl(index: Int, bound: ST)(implicit raise: Raise, ctx: Ctx) : Unit = { + val (_, tvs0, cs) = TupleSetConstraints.lcg(tvs(index)._1, bound, constraints.toList.map(x => S(x(index))))(prov, ctx) + val cs0 = tvs0.zip(cs).map { + case ((_, v: TV), c) => c + case ((S(true), lb), c) => c.map(_.flatMap { ty => + val dnf = DNF.mk(MaxLevel, Nil, lb & ty.neg(), true) + if (dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) + S(ty) + else N + }) + case ((S(false), ub), c) => c.map(_.flatMap { ty => + val dnf = DNF.mk(MaxLevel, Nil, ty & ub.neg(), true) + if (dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) + S(ty) + else N + }) + case ((N, b), c) => c.map(_.flatMap { ty => + val dnf = DNF.mk(MaxLevel, Nil, ty & b.neg(), true) + val dnf0 = DNF.mk(MaxLevel, Nil, b & ty.neg(), true) + if ((dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) + && (dnf0.isBot || dnf0.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty)))) + S(ty) + else N + }) } - go(ub) - println(s"TSC filterUB: $tvs in $constraints") - if (constraints.sizeCompare(1) === 0) { - constraints.head.zip(tvs).foreach { - case (ty, tv) => - tv.tsc = N - constrain(tv, ty)(raise, prov, ctx) - constrain(ty, tv)(raise, prov, ctx) - } + val ncs = constraints.toList.zip(cs0.transpose).map { + case (u, v) => if (v.exists(_.isEmpty)) Nil else u ++ v.flatten + }.filter(_.nonEmpty) + constraints.clear() + constraints ++= ncs + tvs ++= tvs0 + tvs.zipWithIndex.foreach { + case ((pol, tv: TV), i) => tv.tsc.update(this, i) + case _ => () } } - def filterLB(index: Int, lb: ST)(implicit raise: Raise, ctx: Ctx): Unit = { - constraints.filterInPlace { constrs => - val ty = constrs(index) - val dnf = DNF.mk(MaxLevel, Nil, lb & ty.neg(), true) - dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty)) - } - println(s"TSC filterLB: $tvs in $constraints") + def updateOn(index: Int, bound: ST)(implicit raise: Raise, ctx: Ctx) : Unit = { + println(s"TSC update: $tvs in $constraints") + updateImpl(index, bound) + println(s"TSC update: $tvs in $constraints") if (constraints.sizeCompare(1) === 0) { + tvs.foreach { + case (pol, tv: TV) => tv.tsc.clear() + case _ => () + } constraints.head.zip(tvs).foreach { - case (ty, tv) => - tv.tsc = N - constrain(tv, ty)(raise, prov, ctx) - constrain(ty, tv)(raise, prov, ctx) + case (c, (pol, t)) => + if (pol =/= S(true)) constrain(c, t)(raise, prov, ctx) + if (pol =/= S(false)) constrain(t, c)(raise, prov, ctx) } } } } object TupleSetConstraints { - def lcgField(first: FieldType, rest: Ls[FieldType]) - (implicit prov: TypeProvenance, lvl: Level) - : (FieldType, Ls[TV], Ls[Ls[ST]]) = { - val (ub, tvs, constrs) = lcg(first.ub, rest.map(_.ub)) - if (first.lb.isEmpty && rest.forall(_.lb.isEmpty)) { + def lcgField(pol: Opt[Bool], first: FieldType, rest: Ls[Opt[FieldType]]) + (implicit prov: TypeProvenance, ctx: Ctx) + : (FieldType, Ls[(Opt[Bool], ST)], Ls[Ls[Opt[ST]]]) = { + val (ub, tvs, constrs) = lcg(pol, first.ub, rest.map(_.map(_.ub))) + if (first.lb.isEmpty && rest.flatten.forall(_.lb.isEmpty)) { (FieldType(N, ub)(prov), tvs, constrs) } else { - val (lb, ltvs, lconstrs) = lcg(first.lb.getOrElse(BotType), rest.map(_.lb.getOrElse(BotType))) + val (lb, ltvs, lconstrs) = lcg(pol.map(!_), first.lb.getOrElse(BotType), rest.map(_.map(_.lb.getOrElse(BotType)))) (FieldType(S(lb), ub)(prov), tvs ++ ltvs, constrs ++ lconstrs) } } - def lcg(first: ST, rest: Ls[ST]) - (implicit prov: TypeProvenance, lvl: Level) - : (ST, Ls[TV], Ls[Ls[ST]]) = first match { - case a: FunctionType if rest.forall(_.isInstanceOf[FunctionType]) => - val (lhss, rhss) = rest.collect { - case FunctionType(lhs, rhs) => lhs -> rhs + def lcg(pol: Opt[Bool], first: ST, rest: Ls[Opt[ST]]) + (implicit prov: TypeProvenance, ctx: Ctx) + : (ST, Ls[(Opt[Bool], ST)], Ls[Ls[Opt[ST]]]) = first match { + case a: FunctionType => + val (lhss, rhss) = rest.map { + case S(FunctionType(lhs, rhs)) => S(lhs) -> S(rhs) + case _ => (N, N) }.unzip - val (lhs, ltvs, lconstrs) = lcg(a.lhs, lhss) - val (rhs, rtvs, rconstrs) = lcg(a.rhs, rhss) + val (lhs, ltvs, lconstrs) = lcg(pol.map(!_), a.lhs, lhss) + val (rhs, rtvs, rconstrs) = lcg(pol, a.rhs, rhss) (FunctionType(lhs, rhs)(prov), ltvs ++ rtvs, lconstrs ++ rconstrs) - case a: ArrayType if rest.forall(_.isInstanceOf[ArrayType]) => - val inners = rest.collect { case b: ArrayType => b.inner } - val (t, tvs, constrs) = lcgField(a.inner, inners) + case a: ArrayType => + val inners = rest.map { + case S(b: ArrayType) => S(b.inner) + case _ => N + } + val (t, tvs, constrs) = lcgField(pol, a.inner, inners) (ArrayType(t)(prov), tvs, constrs) - case a: TupleType if rest.forall { case b: TupleType => a.fields.sizeCompare(b.fields.size) === 0; case _ => false } => - val fields = rest.collect { case TupleType(fields) => fields.map(_._2) } - val (fts, tvss, constrss) = a.fields.map(_._2).zip(fields.transpose).map { case (a, bs) => lcgField(a, bs) }.unzip3 + case a: TupleType => + val fields = rest.map { + case S(TupleType(fs)) if a.fields.sizeCompare(fs.size) === 0 => + fs.map(x => S(x._2)) + case _ => a.fields.map(_ => N) + } + val (fts, tvss, constrss) = a.fields.map(_._2).zip(fields.transpose).map { case (a, bs) => lcgField(pol, a, bs) }.unzip3 (TupleType(fts.map(N -> _))(prov), tvss.flatten, constrss.flatten) - case a: TR if rest.forall { case b: TR => a.defn === b.defn && a.targs.sizeCompare(b.targs.size) === 0; case _ => false } => - val targs = rest.collect { case b: TR => b.targs } - val (ts, tvss, constrss) = a.targs.zip(targs.transpose).map { case (a, bs) => lcg(a, bs) }.unzip3 + case a: TR if rest.flatten.forall { case b: TR => a.defn === b.defn && a.targs.sizeCompare(b.targs.size) === 0; case _ => false } => + val targs = rest.map { + case S(b: TR) => b.targs.map(S(_)) + case _ => a.targs.map(_ => N) + } + val (ts, tvss, constrss) = a.targs.zip(targs.transpose).map { case (a, bs) => lcg(pol, a, bs) }.unzip3 (TypeRef(a.defn, ts)(prov), tvss.flatten, constrss.flatten) - case a: TV if rest.forall { case b: TV => a.compare(b) === 0; case _ => false } => (a, Nil, Nil) - case a if rest.forall(_ === a) => (a, Nil, Nil) + case a: TV if rest.flatten.forall { case b: TV => a.compare(b) === 0; case _ => false } => (a, Nil, Nil) + case a if rest.flatten.forall(_ === a) => (a, Nil, Nil) case _ => - val tv = freshVar(prov, N) - (tv, List(tv), List(first :: rest)) + (first, List((pol, first)), List(rest)) + // val tv = freshVar(prov, N) + // (tv, List(tv), List(first :: rest)) } - def lcgFunction(first: FunctionType, rest: Ls[FunctionType])(implicit prov: TypeProvenance, lvl: Level) - : (FunctionType, Ls[TV], Ls[Ls[ST]]) = { + def lcgFunction(pol: Opt[Bool], first: FT, rest: Ls[FunctionType])(implicit prov: TypeProvenance, ctx: Ctx) + : (FT, Ls[(Opt[Bool], ST)], Ls[Ls[Opt[ST]]]) = { val (lhss, rhss) = rest.map { - case FunctionType(lhs, rhs) => lhs -> rhs + case FunctionType(lhs, rhs) => S(lhs) -> S(rhs) }.unzip - val (lhs, ltvs, lconstrs) = lcg(first.lhs, lhss) - val (rhs, rtvs, rconstrs) = lcg(first.rhs, rhss) + val (lhs, ltvs, lconstrs) = lcg(pol.map(!_), first.lhs, lhss) + val (rhs, rtvs, rconstrs) = lcg(pol, first.rhs, rhss) (FunctionType(lhs, rhs)(prov), ltvs ++ rtvs, lconstrs ++ rconstrs) } - def mk(ov: Overload)(implicit lvl: Level): FunctionType = { + def mk(ov: Overload, f: FT)(implicit raise: Raise, ctx: Ctx): TupleSetConstraints = { def unwrap(t: ST): ST = t.unwrapProxies.map(unwrap) - if (ov.alts.tail.isEmpty) ov.alts.head else { - val f = ov.mapAlts(unwrap)(unwrap) - val (t, tvs, constrs) = lcgFunction(f.alts.head, f.alts.tail)(ov.prov, lvl) - val tsc = new TupleSetConstraints(MutSet.empty ++ constrs.transpose, tvs)(ov.prov) - tvs.zipWithIndex.foreach { case (tv, i) => - tv.tsc = S((tsc, i)) + // if (ov.alts.tail.isEmpty) ov.alts.head else { + val ovf = ov.mapAlts(unwrap)(unwrap) + val (t, tvs, constrs) = lcgFunction(S(false), f, ovf.alts)(ov.prov, ctx) + val tsc = new TupleSetConstraints(MutSet.empty ++ constrs.transpose.filter(_.forall(_.isDefined)).map(_.flatten), tvs)(ov.prov) + println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") + tvs.zipWithIndex.foreach { + case ((pol, tv: TV), i) => tv.tsc.update(tsc, i) + case ((_, ty), i) => tsc.updateImpl(i, ty) + } + if (tsc.constraints.sizeCompare(1) === 0) { + tvs.foreach { + case (pol, tv: TV) => tv.tsc.clear() + case _ => () + } + tsc.constraints.head.zip(tvs).foreach { + case (c, (pol, t)) => + if (pol =/= S(true)) constrain(c, t)(raise, ov.prov, ctx) + if (pol =/= S(false)) constrain(t, c)(raise, ov.prov, ctx) } - println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") - t } + println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") + tsc } } } diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 3d8aed5443..26dede6e96 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -961,11 +961,11 @@ abstract class TyperHelpers { Typer: Typer => ) }.mkString + { val visited: MutSet[TV] = MutSet.empty - getVars.iterator.filter(tv => tv.tsc.isDefined).map { + getVars.iterator.filter(tv => tv.tsc.nonEmpty).map { case tv if visited.contains(tv) => "" case tv => - visited ++= tv.tsc.fold(Nil: Ls[TV])(_._1.tvs) - tv.tsc.fold("") { case (tsc, _) => ("\n\t\t[ " + visited ++= tv.tsc.map(_._1.tvs.collect { case (_, v: TV) => v }).flatten + tv.tsc.map { case (tsc, _) => ("\n\t\t[ " + tsc.tvs.mkString(", ") + " ] in { " + tsc.constraints.mkString(", ") + " }") } diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 61fb516f9b..c59bee3829 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -139,7 +139,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => }.mkString }${tscs.map{ case (tvs, constrs) => - s"\n${ctx.indStr}${tvs.map(_.showIn(ctx, 0)).mkString("[", ", ", "]")}" + + s"\n${ctx.indStr}${tvs.map(_._2.showIn(ctx, 0)).mkString("[", ", ", "]")}" + s" in ${constrs.map(_.map(_.showIn(ctx, 0)).mkString("[", ", ", "]")).mkString("{", ", ", "}")}" }.mkString}" }, outerPrec > 0) @@ -210,7 +210,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => case WithExtension(b, r) => b :: r :: Nil case PolyType(targs, body) => targs.map(_.fold(identity, identity)) :+ body case Splice(fs) => fs.flatMap{ case L(l) => l :: Nil case R(r) => r.in.toList ++ (r.out :: Nil) } - case Constrained(b, bs, ws, tscs) => b :: bs.flatMap(c => c._1 :: c._2 :: Nil) ::: ws.flatMap(c => c.lb :: c.ub :: Nil) ::: tscs.flatMap(tsc => tsc._1 ::: tsc._2.flatten) + case Constrained(b, bs, ws, tscs) => b :: bs.flatMap(c => c._1 :: c._2 :: Nil) ::: ws.flatMap(c => c.lb :: c.ub :: Nil) ::: tscs.flatMap(tsc => tsc._1.map(_._2) ::: tsc._2.flatten) case Signature(xs, res) => xs ::: res.toList case NuFunDef(isLetRec, nme, snme, targs, rhs) => targs ::: rhs.toOption.toList case NuTypeDef(kind, nme, tparams, params, ctor, sig, parents, sup, ths, body) => diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 6242ecf878..767727ea47 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -156,7 +156,7 @@ final case class Rem(base: Type, names: Ls[Var]) extends Type final case class Bounds(lb: Type, ub: Type) extends Type final case class WithExtension(base: Type, rcd: Record) extends Type final case class Splice(fields: Ls[Either[Type, Field]]) extends Type -final case class Constrained(base: TypeLike, tvBounds: Ls[TypeVar -> Bounds], where: Ls[Bounds], tscs: Ls[Ls[TypeVar] -> Ls[Ls[Type]]]) extends Type +final case class Constrained(base: TypeLike, tvBounds: Ls[TypeVar -> Bounds], where: Ls[Bounds], tscs: Ls[Ls[(Opt[Bool], Type)] -> Ls[Ls[Type]]]) extends Type // final case class FirstClassDefn(defn: NuTypeDef) extends Type // TODO // final case class Refinement(base: Type, decls: TypingUnit) extends Type // TODO diff --git a/shared/src/test/diff/basics/Intersections.fun b/shared/src/test/diff/basics/Intersections.fun index b6e97890fb..d39f38d083 100644 --- a/shared/src/test/diff/basics/Intersections.fun +++ b/shared/src/test/diff/basics/Intersections.fun @@ -41,20 +41,14 @@ foo(1) as Nothing //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.39: not / foo(1) //│ ║ ^^^^^^^^^^^^ -//│ ╟── function of type `int` is not an instance of type `bool` -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ║ ^^^^^^^^^^^^ -//│ ╟── but it flows into application with expected type `bool` +//│ ╟── application of type `int` is not an instance of type `bool` //│ ║ l.39: not / foo(1) //│ ╙── ^^^^^^ //│ res: bool | error //│ ╔══[ERROR] Type mismatch in 'as' binding: //│ ║ l.40: foo(1) as Nothing //│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `int` does not match type `nothing` -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ║ ^^^^^^^^^^^^ -//│ ╟── but it flows into application with expected type `nothing` +//│ ╟── application of type `int` does not match type `nothing` //│ ║ l.40: foo(1) as Nothing //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from reference: @@ -65,26 +59,26 @@ foo(1) as Nothing :e foo as Nothing //│ ╔══[ERROR] Type mismatch in 'as' binding: -//│ ║ l.66: foo as Nothing +//│ ║ l.60: foo as Nothing //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type intersection of type `int -> int & bool -> bool` does not match type `nothing` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `nothing` -//│ ║ l.66: foo as Nothing +//│ ║ l.60: foo as Nothing //│ ║ ^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.66: foo as Nothing +//│ ║ l.60: foo as Nothing //│ ╙── ^^^^^^^ //│ res: nothing :e let oops = (&) //│ ╔══[ERROR] Illegal use of reserved operator: & -//│ ║ l.82: let oops = (&) +//│ ║ l.76: let oops = (&) //│ ╙── ^^^ //│ ╔══[ERROR] identifier not found: & -//│ ║ l.82: let oops = (&) +//│ ║ l.76: let oops = (&) //│ ╙── ^^^ //│ oops: error diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls index d2b54c6799..9bc7361f83 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls @@ -91,6 +91,104 @@ type RegionLang = BaseLang[RegionLang] | ExtLang[RegionLang] module TestSize extends SizeBase, SizeExt { fun size: RegionLang -> Int } +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.91: module TestSize extends SizeBase, SizeExt { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.92: fun size: RegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.93: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.79: Scale(_, b) then this.size(b) + 1 +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.79: Scale(_, b) then this.size(b) + 1 +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.91: module TestSize extends SizeBase, SizeExt { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.92: fun size: RegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.93: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.33: Translate(_, a) then this.size(a) + 1 +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.33: Translate(_, a) then this.size(a) + 1 +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.91: module TestSize extends SizeBase, SizeExt { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.92: fun size: RegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.93: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.91: module TestSize extends SizeBase, SizeExt { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.92: fun size: RegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.93: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.91: module TestSize extends SizeBase, SizeExt { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.92: fun size: RegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.93: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.91: module TestSize extends SizeBase, SizeExt { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.92: fun size: RegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.93: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.91: module TestSize extends SizeBase, SizeExt { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.92: fun size: RegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.93: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.30: Outside(a) then this.size(a) + 1 +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.30: Outside(a) then this.size(a) + 1 +//│ ╙── ^^^^^^^^^ //│ module TestSize { //│ fun size: RegionLang -> Int //│ } @@ -137,6 +235,90 @@ type BaseRegionLang = BaseLang[BaseRegionLang] module TestContains extends Contains { fun contains: (BaseRegionLang, Vector) -> Bool } +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.235: module TestContains extends Contains { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.236: fun contains: (BaseRegionLang, Vector) -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.237: } +//│ ║ ^ +//│ ╟── expression of type `(BaseRegionLang, Vector) -> Bool & (?a, ?b) -> (?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.225: Translate(v, a) then this.contains(a, Vector(p.x - v.x, p.y - v.y)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.225: Translate(v, a) then this.contains(a, Vector(p.x - v.x, p.y - v.y)) +//│ ╙── ^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.235: module TestContains extends Contains { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.236: fun contains: (BaseRegionLang, Vector) -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.237: } +//│ ║ ^ +//│ ╟── expression of type `(BaseRegionLang, Vector) -> Bool & (?a, ?b) -> (?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.224: Intersect(lhs, rhs) then this.contains(lhs, p) && this.contains(rhs, p) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.224: Intersect(lhs, rhs) then this.contains(lhs, p) && this.contains(rhs, p) +//│ ╙── ^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.235: module TestContains extends Contains { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.236: fun contains: (BaseRegionLang, Vector) -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.237: } +//│ ║ ^ +//│ ╟── expression of type `(BaseRegionLang, Vector) -> Bool & (?a, ?b) -> (?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.224: Intersect(lhs, rhs) then this.contains(lhs, p) && this.contains(rhs, p) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.224: Intersect(lhs, rhs) then this.contains(lhs, p) && this.contains(rhs, p) +//│ ╙── ^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.235: module TestContains extends Contains { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.236: fun contains: (BaseRegionLang, Vector) -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.237: } +//│ ║ ^ +//│ ╟── expression of type `(BaseRegionLang, Vector) -> Bool & (?a, ?b) -> (?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.223: Union(lhs, rhs) then this.contains(lhs, p) || this.contains(rhs, p) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.223: Union(lhs, rhs) then this.contains(lhs, p) || this.contains(rhs, p) +//│ ╙── ^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.235: module TestContains extends Contains { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.236: fun contains: (BaseRegionLang, Vector) -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.237: } +//│ ║ ^ +//│ ╟── expression of type `(BaseRegionLang, Vector) -> Bool & (?a, ?b) -> (?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.223: Union(lhs, rhs) then this.contains(lhs, p) || this.contains(rhs, p) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.223: Union(lhs, rhs) then this.contains(lhs, p) || this.contains(rhs, p) +//│ ╙── ^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.235: module TestContains extends Contains { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.236: fun contains: (BaseRegionLang, Vector) -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.237: } +//│ ║ ^ +//│ ╟── expression of type `(BaseRegionLang, Vector) -> Bool & (?a, ?b) -> (?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.222: Outside(a) then not (this.contains(a, p)) +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.222: Outside(a) then not (this.contains(a, p)) +//│ ╙── ^^^^^^^^^^^^^ //│ module TestContains { //│ fun contains: (BaseRegionLang, Vector) -> Bool //│ } @@ -180,16 +362,16 @@ mixin Text { :e module SizeText extends Text //│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` -//│ ║ l.173: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ l.355: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` -//│ ║ l.172: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ l.354: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` -//│ ║ l.171: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ l.353: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` -//│ ║ l.170: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ l.352: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ //│ module SizeText { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> Str @@ -200,6 +382,166 @@ module SizeText extends SizeBase, Text { fun size: BaseRegionLang -> Int fun text: BaseRegionLang -> Str } +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.381: module SizeText extends SizeBase, Text { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.382: fun size: BaseRegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.383: fun text: BaseRegionLang -> Str +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.384: } +//│ ║ ^ +//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.355: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.355: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.381: module SizeText extends SizeBase, Text { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.382: fun size: BaseRegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.383: fun text: BaseRegionLang -> Str +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.384: } +//│ ║ ^ +//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.354: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.354: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.381: module SizeText extends SizeBase, Text { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.382: fun size: BaseRegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.383: fun text: BaseRegionLang -> Str +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.384: } +//│ ║ ^ +//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.353: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.353: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.381: module SizeText extends SizeBase, Text { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.382: fun size: BaseRegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.383: fun text: BaseRegionLang -> Str +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.384: } +//│ ║ ^ +//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.352: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.352: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.381: module SizeText extends SizeBase, Text { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.382: fun size: BaseRegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.383: fun text: BaseRegionLang -> Str +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.384: } +//│ ║ ^ +//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.33: Translate(_, a) then this.size(a) + 1 +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.33: Translate(_, a) then this.size(a) + 1 +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.381: module SizeText extends SizeBase, Text { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.382: fun size: BaseRegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.383: fun text: BaseRegionLang -> Str +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.384: } +//│ ║ ^ +//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.381: module SizeText extends SizeBase, Text { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.382: fun size: BaseRegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.383: fun text: BaseRegionLang -> Str +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.384: } +//│ ║ ^ +//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.381: module SizeText extends SizeBase, Text { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.382: fun size: BaseRegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.383: fun text: BaseRegionLang -> Str +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.384: } +//│ ║ ^ +//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.381: module SizeText extends SizeBase, Text { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.382: fun size: BaseRegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.383: fun text: BaseRegionLang -> Str +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.384: } +//│ ║ ^ +//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.381: module SizeText extends SizeBase, Text { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.382: fun size: BaseRegionLang -> Int +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.383: fun text: BaseRegionLang -> Str +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.384: } +//│ ║ ^ +//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.30: Outside(a) then this.size(a) + 1 +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.30: Outside(a) then this.size(a) + 1 +//│ ╙── ^^^^^^^^^ //│ module SizeText { //│ fun size: BaseRegionLang -> Int //│ fun text: BaseRegionLang -> Str @@ -261,6 +603,230 @@ module IsUnivIsEmpty extends IsUniv, IsEmpty { fun isEmpty: RegionLang -> Bool fun isUniv: RegionLang -> Bool } +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.594: Scale(_, a) then this.isEmpty(a) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.594: Scale(_, a) then this.isEmpty(a) +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.593: Translate(_, a) then this.isEmpty(a) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.593: Translate(_, a) then this.isEmpty(a) +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.590: Outside(a) then this.isUniv(a) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.590: Outside(a) then this.isUniv(a) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.578: Scale(_, a) then this.isUniv(a) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.578: Scale(_, a) then this.isUniv(a) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.577: Translate(_, a) then this.isUniv(a) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.577: Translate(_, a) then this.isUniv(a) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.603: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.604: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.605: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.574: Outside(a) then this.isEmpty(a) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.574: Outside(a) then this.isEmpty(a) +//│ ╙── ^^^^^^^^^^^^ //│ module IsUnivIsEmpty { //│ fun isEmpty: RegionLang -> Bool //│ fun isUniv: RegionLang -> Bool @@ -270,6 +836,230 @@ module IsUnivIsEmpty extends IsEmpty, IsUniv { fun isEmpty: RegionLang -> Bool fun isUniv: RegionLang -> Bool } +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.578: Scale(_, a) then this.isUniv(a) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.578: Scale(_, a) then this.isUniv(a) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.577: Translate(_, a) then this.isUniv(a) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.577: Translate(_, a) then this.isUniv(a) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.574: Outside(a) then this.isEmpty(a) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.574: Outside(a) then this.isEmpty(a) +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.594: Scale(_, a) then this.isEmpty(a) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.594: Scale(_, a) then this.isEmpty(a) +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.593: Translate(_, a) then this.isEmpty(a) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.593: Translate(_, a) then this.isEmpty(a) +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.836: fun isEmpty: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.837: fun isUniv: RegionLang -> Bool +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.838: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.590: Outside(a) then this.isUniv(a) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.590: Outside(a) then this.isUniv(a) +//│ ╙── ^^^^^^^^^^^ //│ module IsUnivIsEmpty { //│ fun isEmpty: RegionLang -> Bool //│ fun isUniv: RegionLang -> Bool @@ -289,11 +1079,11 @@ IsUnivIsEmpty.isEmpty(circles) class Foo() IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.290: IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1080: IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Foo` does not match type `BaseLang[RegionLang] | ExtLang[RegionLang]` -//│ ║ l.290: IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) -//│ ║ ^^^^^ +//│ ║ l.1080: IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) +//│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.88: type RegionLang = BaseLang[RegionLang] | ExtLang[RegionLang] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -326,6 +1116,118 @@ mixin Eliminate { module TestElim extends Eliminate { fun eliminate: RegionLang -> RegionLang } +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.1116: module TestElim extends Eliminate { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1118: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.1106: Scale(v, a) then Scale(v, this.eliminate(a)) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.1106: Scale(v, a) then Scale(v, this.eliminate(a)) +//│ ╙── ^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.1116: module TestElim extends Eliminate { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1118: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.1105: Translate(v, a) then Translate(v, this.eliminate(a)) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.1105: Translate(v, a) then Translate(v, this.eliminate(a)) +//│ ╙── ^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.1116: module TestElim extends Eliminate { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1118: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.1104: Intersect(a, b) then Intersect(this.eliminate(a), this.eliminate(b)) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.1104: Intersect(a, b) then Intersect(this.eliminate(a), this.eliminate(b)) +//│ ╙── ^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.1116: module TestElim extends Eliminate { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1118: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.1104: Intersect(a, b) then Intersect(this.eliminate(a), this.eliminate(b)) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.1104: Intersect(a, b) then Intersect(this.eliminate(a), this.eliminate(b)) +//│ ╙── ^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.1116: module TestElim extends Eliminate { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1118: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.1103: Union(a, b) then Union(this.eliminate(a), this.eliminate(b)) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.1103: Union(a, b) then Union(this.eliminate(a), this.eliminate(b)) +//│ ╙── ^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.1116: module TestElim extends Eliminate { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1118: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.1103: Union(a, b) then Union(this.eliminate(a), this.eliminate(b)) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.1103: Union(a, b) then Union(this.eliminate(a), this.eliminate(b)) +//│ ╙── ^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.1116: module TestElim extends Eliminate { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1118: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.1102: Outside(a) then Outside(this.eliminate(a)) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.1102: Outside(a) then Outside(this.eliminate(a)) +//│ ╙── ^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.1116: module TestElim extends Eliminate { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1118: } +//│ ║ ^ +//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function +//│ ╟── Note: constraint arises from application: +//│ ║ l.1101: Outside(Outside(a)) then this.eliminate(a) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── from field selection: +//│ ║ l.1101: Outside(Outside(a)) then this.eliminate(a) +//│ ╙── ^^^^^^^^^^^^^^ //│ module TestElim { //│ fun eliminate: RegionLang -> RegionLang //│ } @@ -348,7 +1250,7 @@ fun mk(n) = if n is _ then Scale(Vector(0, 0), mk(n)) //│ fun mk: forall 'a. Object -> 'a //│ where -//│ 'a :> Outside['a] | Scale['a] | Union['a] | Intersect['a] | Translate['a] +//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] :re TestElim.eliminate(mk(100)) @@ -367,109 +1269,96 @@ module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminat fun size: RegionLang -> Int fun text: BaseRegionLang -> Str } -//│ module Lang { -//│ fun contains: (BaseRegionLang, Vector) -> Bool -//│ fun eliminate: RegionLang -> RegionLang -//│ fun isEmpty: RegionLang -> Bool -//│ fun isUniv: RegionLang -> Bool -//│ fun size: RegionLang -> Int -//│ fun text: BaseRegionLang -> Str -//│ } +//│ /!!!\ Uncaught error: java.lang.StackOverflowError Lang.size(circles) //│ Int -//│ res -//│ = 13 +//│ Code generation encountered an error: +//│ unresolved symbol Lang Lang.contains(circles, Vector(0, 0)) //│ Bool -//│ res -//│ = false +//│ Code generation encountered an error: +//│ unresolved symbol Lang Lang.text(circles) //│ Str -//│ res -//│ = 'the union of two regions of size ' +//│ Code generation encountered an error: +//│ unresolved symbol Lang Lang.isUniv(circles) //│ Bool -//│ res -//│ = false +//│ Code generation encountered an error: +//│ unresolved symbol Lang Lang.isEmpty(circles) //│ Bool -//│ res -//│ = false +//│ Code generation encountered an error: +//│ unresolved symbol Lang Lang.size(Lang.eliminate(circles)) //│ Int -//│ res -//│ = 13 +//│ Code generation encountered an error: +//│ unresolved symbol Lang :re Lang.size(mk(100)) //│ Int -//│ res -//│ Runtime error: -//│ RangeError: Maximum call stack size exceeded +//│ Code generation encountered an error: +//│ unresolved symbol Lang :e :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.418: Lang.contains(mk(100), Vector(0, 0)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1312: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[BaseRegionLang] | Outside[BaseRegionLang] | Translate[BaseRegionLang] | Union[BaseRegionLang]` -//│ ║ l.348: _ then Scale(Vector(0, 0), mk(n)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1250: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.23: type BaseLang[T] = Circle | Intersect[T] | Union[T] | Outside[T] | Translate[T] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── from type reference: -//│ ║ l.134: type BaseRegionLang = BaseLang[BaseRegionLang] +//│ ║ l.232: type BaseRegionLang = BaseLang[BaseRegionLang] //│ ╙── ^^^^^^^^^^^^^^ //│ error | false | true -//│ res -//│ Runtime error: -//│ RangeError: Maximum call stack size exceeded +//│ Code generation encountered an error: +//│ unresolved symbol Lang :e :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.438: Lang.text(mk(100)) -//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.1331: Lang.text(mk(100)) +//│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[BaseRegionLang] | Outside[BaseRegionLang] | Translate[BaseRegionLang] | Union[BaseRegionLang]` -//│ ║ l.348: _ then Scale(Vector(0, 0), mk(n)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.1250: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.23: type BaseLang[T] = Circle | Intersect[T] | Union[T] | Outside[T] | Translate[T] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── from type reference: -//│ ║ l.134: type BaseRegionLang = BaseLang[BaseRegionLang] +//│ ║ l.232: type BaseRegionLang = BaseLang[BaseRegionLang] //│ ╙── ^^^^^^^^^^^^^^ //│ Str | error -//│ res -//│ Runtime error: -//│ RangeError: Maximum call stack size exceeded +//│ Code generation encountered an error: +//│ unresolved symbol Lang :re Lang.isUniv(mk(100)) //│ Bool -//│ res -//│ Runtime error: -//│ RangeError: Maximum call stack size exceeded +//│ Code generation encountered an error: +//│ unresolved symbol Lang :re Lang.isEmpty(mk(100)) //│ Bool -//│ res -//│ Runtime error: -//│ RangeError: Maximum call stack size exceeded +//│ Code generation encountered an error: +//│ unresolved symbol Lang :re Lang.size(Lang.eliminate(mk(100))) //│ Int -//│ res -//│ Runtime error: -//│ RangeError: Maximum call stack size exceeded +//│ Code generation encountered an error: +//│ unresolved symbol Lang diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 505669f81a..f71247df0d 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -31,25 +31,37 @@ IISS : ZZII //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.30: IISS : ZZII //│ ║ ^^^^ -//│ ╟── type `int` does not match type `0` +//│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string -//│ ║ ^^^ -//│ ╟── Note: constraint arises from literal type: +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `0 -> 0` +//│ ║ l.30: IISS : ZZII +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from function type: //│ ║ l.7: type ZZII = 0 -> 0 & int -> int -//│ ╙── ^ +//│ ║ ^^^^^^ +//│ ╟── from type reference: +//│ ║ l.30: IISS : ZZII +//│ ╙── ^^^^ //│ res: ZZII :e IISS : BBNN //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.43: IISS : BBNN +//│ ║ l.49: IISS : BBNN //│ ║ ^^^^ -//│ ╟── type `bool` does not match type `?a` -//│ ║ l.6: type BBNN = bool -> bool & number -> number -//│ ║ ^^^^ -//│ ╟── Note: constraint arises from function type: +//│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string -//│ ╙── ^^^^^^^^^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `bool -> bool` +//│ ║ l.49: IISS : BBNN +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from function type: +//│ ║ l.6: type BBNN = bool -> bool & number -> number +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from type reference: +//│ ║ l.49: IISS : BBNN +//│ ╙── ^^^^ //│ res: BBNN @@ -62,9 +74,7 @@ IISS : (0 | 1) -> number //│ res: (0 | 1) -> number IISS : 'a -> 'a -//│ res: ('a & 'b) -> ('a | 'c) -//│ where -//│ ['b, 'c] in {[string, string], [int, int]} +//│ res: 'a -> 'a IISS 0 //│ res: int @@ -76,11 +86,18 @@ IISS 0 //│ res: number // * TODO: update type simplifier +:e fun x -> (if true then IISS else BBNN) x -//│ res: ('a & 'b) -> ('c | 'd) -//│ where -//│ ['b, 'd] in {[bool, bool], [number, number]} -//│ ['a, 'c] in {[string, string], [int, int]} +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.90: fun x -> (if true then IISS else BBNN) x +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `int -> int & string -> string` is not a function +//│ ║ l.12: def IISS: int -> int & string -> string +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `?a -> ?b` +//│ ║ l.90: fun x -> (if true then IISS else BBNN) x +//│ ╙── ^^^^ +//│ res: anything -> error if true then IISS else BBNN //│ res: bool -> bool & number -> number | int -> int & string -> string @@ -94,12 +111,17 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.95: (if true then IISS else BBNN) : (0 | 1 | true) -> number -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `0 | 1 | true` does not match type `?a` -//│ ╟── Note: constraint arises from function type: +//│ ║ l.112: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string -//│ ╙── ^^^^^^^^^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` +//│ ║ l.112: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from function type: +//│ ║ l.112: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/nu/ArrayProg.mls b/shared/src/test/diff/nu/ArrayProg.mls index c5243ca638..649b30320b 100644 --- a/shared/src/test/diff/nu/ArrayProg.mls +++ b/shared/src/test/diff/nu/ArrayProg.mls @@ -137,8 +137,18 @@ fun s: ([Numbr,Numbr] -> Int) & ([Vectr,Vectr] -> Int) //│ fun s: (Numbr | Vectr, Numbr | Vectr) -> Int +:e s(Vectr([]),Vectr([])) -//│ Int +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.141: s(Vectr([]),Vectr([])) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `(Numbr | Vectr, Numbr | Vectr) -> Int` is not a function +//│ ║ l.136: fun s: ([Numbr,Numbr] -> Int) & ([Vectr,Vectr] -> Int) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `(?a, ?b) -> ?c` +//│ ║ l.141: s(Vectr([]),Vectr([])) +//│ ╙── ^ +//│ error //│ res //│ = //│ s is not implemented @@ -174,13 +184,13 @@ s([Numbr(0),Numbr(0)]) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.+1: s([Numbr(0),Numbr(0)]) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── argument of type `[[?a, ?b]]` does not match type `[Numbr | Vectr, Numbr | Vectr]` -//│ ║ l.+1: s([Numbr(0),Numbr(0)]) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── Note: constraint arises from tuple type: +//│ ╟── type `(Numbr | Vectr, Numbr | Vectr) -> Int` is not a function //│ ║ l.136: fun s: ([Numbr,Numbr] -> Int) & ([Vectr,Vectr] -> Int) -//│ ╙── ^^^^^^^^^^^^^ -//│ Int | error +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `([?a, ?b]) -> ?c` +//│ ║ l.+1: s([Numbr(0),Numbr(0)]) +//│ ╙── ^ +//│ error // g <: 0 -> 'a :e diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index f0f47adc28..ae5b41b647 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -72,10 +72,15 @@ fun g = f //│ ╔══[ERROR] Type mismatch in definition: //│ ║ l.71: fun g = f //│ ║ ^^^^^ -//│ ╟── expression of type `Int | false | true` does not match type `?a` -//│ ╟── Note: constraint arises from function type: +//│ ╟── type `Int -> Int & Bool -> Bool` is not a function //│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) -//│ ╙── ^^^^^^^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `(Int | false | true) -> (Bool | Int)` +//│ ║ l.71: fun g = f +//│ ║ ^ +//│ ╟── Note: constraint arises from function type: +//│ ║ l.70: fun g: (Int | Bool) -> (Int | Bool) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ fun g: Int -> Int & Bool -> Bool //│ fun g: (Bool | Int) -> (Int | false | true) @@ -96,11 +101,17 @@ fun j = i fun j: (Int & Bool) -> (Int & Bool) fun j = f //│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.97: fun j = f -//│ ║ ^^^^^ -//│ ╟── type `?a` does not match type `nothing` +//│ ║ l.102: fun j = f +//│ ║ ^^^^^ +//│ ╟── type `Int -> Int & Bool -> Bool` is not a function //│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) -//│ ╙── ^^^^^^^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `nothing -> nothing` +//│ ║ l.102: fun j = f +//│ ║ ^ +//│ ╟── Note: constraint arises from function type: +//│ ║ l.101: fun j: (Int & Bool) -> (Int & Bool) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ fun j: Int -> Int & Bool -> Bool //│ fun j: nothing -> nothing @@ -123,10 +134,18 @@ f(0) // f(0) : case 0 of { Int => Int; Bool => Bool } == Int +:e x => f(x) -//│ forall 'a 'b. 'a -> 'b -//│ where -//│ ['a, 'b] in {[Bool, Bool], [Int, Int]} +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.138: x => f(x) +//│ ║ ^^^^ +//│ ╟── type `Int -> Int & Bool -> Bool` is not a function +//│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `?a -> ?b` +//│ ║ l.138: x => f(x) +//│ ╙── ^ +//│ anything -> error //│ res //│ = [Function: res] @@ -135,15 +154,15 @@ x => f(x) :e f(if true then 0 else false) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.136: f(if true then 0 else false) +//│ ║ l.155: f(if true then 0 else false) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `0 | false` does not match type `?a` -//│ ╟── Note: constraint arises from function type: +//│ ╟── type `Int -> Int & Bool -> Bool` is not a function //│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) -//│ ╙── ^^^^^^^^^^^^^^ -//│ error | 'a -//│ where -//│ ['b, 'a] in {} +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `(0 | false) -> ?a` +//│ ║ l.155: f(if true then 0 else false) +//│ ╙── ^ +//│ error //│ res //│ = 0 @@ -153,23 +172,21 @@ f(if true then 0 else false) :w f(refined if true then 0 else false) // this one can be precise again! //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.154: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.173: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.154: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.173: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.154: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.173: f(refined if true then 0 else false) // this one can be precise again! //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `error` does not match type `?a` -//│ ║ l.154: f(refined if true then 0 else false) // this one can be precise again! -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── Note: constraint arises from function type: +//│ ╟── type `Int -> Int & Bool -> Bool` is not a function //│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) -//│ ╙── ^^^^^^^^^^^^^^ -//│ error | 'a -//│ where -//│ ['b, 'a] in {} +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `?a -> ?b` +//│ ║ l.173: f(refined if true then 0 else false) // this one can be precise again! +//│ ╙── ^ +//│ error //│ Code generation encountered an error: //│ unresolved symbol refined @@ -225,7 +242,7 @@ type T = List[Int] :e // TODO application types type Res = M(T) //│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 -//│ ║ l.226: type Res = M(T) +//│ ║ l.243: type Res = M(T) //│ ╙── ^^^^ //│ type Res = M @@ -248,7 +265,7 @@ fun f: Int -> Int fun f: Bool -> Bool fun f = id //│ ╔══[ERROR] A type signature for 'f' was already given -//│ ║ l.248: fun f: Bool -> Bool +//│ ║ l.265: fun f: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun f: forall 'a. 'a -> 'a //│ fun f: Int -> Int @@ -256,13 +273,13 @@ fun f = id :e // TODO support f: (Int -> Int) & (Bool -> Bool) //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.257: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.274: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^ //│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.257: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.274: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.247: fun f: Int -> Int +//│ ║ l.264: fun f: Int -> Int //│ ╙── ^^^ //│ Int -> Int & Bool -> Bool //│ res @@ -329,14 +346,14 @@ fun test(x) = refined if x is A then 0 B then 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.328: fun test(x) = refined if x is +//│ ║ l.345: fun test(x) = refined if x is //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.329: A then 0 +//│ ║ l.346: A then 0 //│ ║ ^^^^^^^^^^ -//│ ║ l.330: B then 1 +//│ ║ l.347: B then 1 //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.328: fun test(x) = refined if x is +//│ ║ l.345: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ fun test: (A | B) -> error //│ Code generation encountered an error: @@ -356,41 +373,88 @@ q(0) //│ q is not implemented q(1) -//│ 'a -//│ where -//│ ['b, 'a] in {[0 | 1, true], [1 | 2, false]} +//│ nothing //│ res //│ = //│ q is not implemented +// FIXME +:e x => q(x): true -//│ (0 | 1) -> true +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.383: x => q(x): true +//│ ║ ^^^^ +//│ ╟── type `(0 | 1) -> true & (1 | 2) -> false` is not a function +//│ ║ l.366: fun q: (0|1) -> true & (1|2) -> false +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `?a -> ?b` +//│ ║ l.383: x => q(x): true +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.383: x => q(x): true +//│ ║ ^^^^ +//│ ╟── application of type `?a` does not match type `true` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.383: x => q(x): true +//│ ╙── ^^^^ +//│ anything -> true //│ res //│ = //│ q is not implemented + +:e x => q(x) -//│ forall 'a 'b. 'a -> 'b -//│ where -//│ ['a, 'b] in {[0 | 1, true], [1 | 2, false]} +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.407: x => q(x) +//│ ║ ^^^^ +//│ ╟── type `(0 | 1) -> true & (1 | 2) -> false` is not a function +//│ ║ l.366: fun q: (0|1) -> true & (1|2) -> false +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `?a -> ?b` +//│ ║ l.407: x => q(x) +//│ ╙── ^ +//│ anything -> error //│ res //│ = //│ q is not implemented +:e fun w = x => q(x) -//│ fun w: forall 'a 'b. 'a -> 'b -//│ where -//│ ['a, 'b] in {[0 | 1, true], [1 | 2, false]} +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.423: fun w = x => q(x) +//│ ║ ^^^^ +//│ ╟── type `(0 | 1) -> true & (1 | 2) -> false` is not a function +//│ ║ l.366: fun q: (0|1) -> true & (1|2) -> false +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `?a -> ?b` +//│ ║ l.423: fun w = x => q(x) +//│ ╙── ^ +//│ fun w: anything -> error w(0) -//│ forall 'a. 'a -//│ where -//│ ['b, 'a] in {[0 | 1, true]} +//│ error //│ res //│ = //│ w and q are not implemented +:e x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 -//│ Int -> (f: (0, Int) -> Int & (1, Str) -> [Int]) -> Int +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.442: x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 +//│ ║ ^^^^^^^ +//│ ╟── type `(0, Int) -> 'a & (1, Str) -> ['a]` is not a function +//│ ║ l.442: x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `(0, ?a) -> ?b` +//│ ║ l.442: x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.442: x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 +//│ ║ ^^^^^^^^^^^ +//│ ╟── application of type `?a` does not match type `Int` +//│ ║ l.442: x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 +//│ ╙── ^^^^^^^ +//│ anything -> (f: (0, Int) -> anything & (1, Str) -> [anything]) -> (Int | error) //│ res //│ = [Function: res] diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index 504096afa9..159ed20232 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -47,20 +47,18 @@ fun f: (Str => Str) & ((Str, Int) => Int) //│ fun f: Str -> Str & (Str, Int) -> Int // * ...resulting in approximation at call sites (we don't handle overloading) -:e // TODO +:e f("abc", "abc") //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.51: f("abc", "abc") //│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── argument list of type `["abc", "abc"]` does not match type `?a` -//│ ║ l.51: f("abc", "abc") -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── Note: constraint arises from function type: +//│ ╟── type `Str -> Str & (Str, Int) -> Int` is not a function //│ ║ l.46: fun f: (Str => Str) & ((Str, Int) => Int) -//│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ error | 'a -//│ where -//│ ['b, 'a] in {} +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `("abc", "abc") -> ?a` +//│ ║ l.51: f("abc", "abc") +//│ ╙── ^ +//│ error //│ res //│ = //│ f is not implemented @@ -83,19 +81,19 @@ let r = if true then id else (x, y) => [y, x] r(error) r(error, error) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.83: r(error) +//│ ║ l.81: r(error) //│ ║ ^^^^^^^^ //│ ╟── argument of type `[nothing]` does not match type `[?a, ?b]` -//│ ║ l.83: r(error) +//│ ║ l.81: r(error) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.77: let r = if true then id else (x, y) => [y, x] +//│ ║ l.75: let r = if true then id else (x, y) => [y, x] //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.84: r(error, error) +//│ ║ l.82: r(error, error) //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── argument list of type `[nothing, nothing]` does not match type `[?a]` -//│ ║ l.84: r(error, error) +//│ ║ l.82: r(error, error) //│ ╙── ^^^^^^^^^^^^^^ //│ error | [nothing, nothing] //│ res @@ -118,7 +116,7 @@ r of [0, 1] // Also currently parses the same: let r = if true then id else [x, y] => [y, x] -//│ let r: forall 'a 'b 'c. (['a, 'b] & 'c) -> (['b, 'a] | 'c) +//│ let r: forall 'a 'b 'c. (['c, 'a] & 'b) -> (['a, 'c] | 'b) //│ r //│ = [Function: id] From 96156464448e96854cf65e47e727eb615ce16229 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sat, 9 Mar 2024 23:41:22 +0800 Subject: [PATCH 09/43] fix prov --- .../main/scala/mlscript/TyperDatatypes.scala | 31 +- .../diff/ecoop23/SimpleRegionDSL_annot.mls | 938 +----------------- shared/src/test/diff/fcp/Overloads.mls | 18 +- shared/src/test/diff/nu/ArrayProg.mls | 24 +- shared/src/test/diff/nu/HeungTung.mls | 113 +-- 5 files changed, 58 insertions(+), 1066 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 7f99e48998..bf255dc283 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -717,41 +717,41 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } def lcg(pol: Opt[Bool], first: ST, rest: Ls[Opt[ST]]) (implicit prov: TypeProvenance, ctx: Ctx) - : (ST, Ls[(Opt[Bool], ST)], Ls[Ls[Opt[ST]]]) = first match { + : (ST, Ls[(Opt[Bool], ST)], Ls[Ls[Opt[ST]]]) = first.unwrapProxies match { case a: FunctionType => - val (lhss, rhss) = rest.map { + val (lhss, rhss) = rest.map(_.map(_.unwrapProxies) match { case S(FunctionType(lhs, rhs)) => S(lhs) -> S(rhs) case _ => (N, N) - }.unzip + }).unzip val (lhs, ltvs, lconstrs) = lcg(pol.map(!_), a.lhs, lhss) val (rhs, rtvs, rconstrs) = lcg(pol, a.rhs, rhss) (FunctionType(lhs, rhs)(prov), ltvs ++ rtvs, lconstrs ++ rconstrs) case a: ArrayType => - val inners = rest.map { + val inners = rest.map(_.map(_.unwrapProxies) match { case S(b: ArrayType) => S(b.inner) case _ => N - } + }) val (t, tvs, constrs) = lcgField(pol, a.inner, inners) (ArrayType(t)(prov), tvs, constrs) case a: TupleType => - val fields = rest.map { + val fields = rest.map(_.map(_.unwrapProxies) match { case S(TupleType(fs)) if a.fields.sizeCompare(fs.size) === 0 => fs.map(x => S(x._2)) case _ => a.fields.map(_ => N) - } + }) val (fts, tvss, constrss) = a.fields.map(_._2).zip(fields.transpose).map { case (a, bs) => lcgField(pol, a, bs) }.unzip3 (TupleType(fts.map(N -> _))(prov), tvss.flatten, constrss.flatten) - case a: TR if rest.flatten.forall { case b: TR => a.defn === b.defn && a.targs.sizeCompare(b.targs.size) === 0; case _ => false } => - val targs = rest.map { + case a: TR if rest.flatten.map(_.unwrapProxies).forall { case b: TR => a.defn === b.defn && a.targs.sizeCompare(b.targs.size) === 0; case _ => false } => + val targs = rest.map(_.map(_.unwrapProxies) match { case S(b: TR) => b.targs.map(S(_)) case _ => a.targs.map(_ => N) - } + }) val (ts, tvss, constrss) = a.targs.zip(targs.transpose).map { case (a, bs) => lcg(pol, a, bs) }.unzip3 (TypeRef(a.defn, ts)(prov), tvss.flatten, constrss.flatten) - case a: TV if rest.flatten.forall { case b: TV => a.compare(b) === 0; case _ => false } => (a, Nil, Nil) - case a if rest.flatten.forall(_ === a) => (a, Nil, Nil) + case a: TV if rest.flatten.map(_.unwrapProxies).forall { case b: TV => a.compare(b) === 0; case _ => false } => (a, Nil, Nil) + case a if rest.flatten.forall(_.unwrapProxies === a) => (a, Nil, Nil) case _ => - (first, List((pol, first)), List(rest)) + (first, List((pol, first)), List(rest.map(_.map(_.unwrapProxies)))) // val tv = freshVar(prov, N) // (tv, List(tv), List(first :: rest)) } @@ -765,10 +765,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => (FunctionType(lhs, rhs)(prov), ltvs ++ rtvs, lconstrs ++ rconstrs) } def mk(ov: Overload, f: FT)(implicit raise: Raise, ctx: Ctx): TupleSetConstraints = { - def unwrap(t: ST): ST = t.unwrapProxies.map(unwrap) - // if (ov.alts.tail.isEmpty) ov.alts.head else { - val ovf = ov.mapAlts(unwrap)(unwrap) - val (t, tvs, constrs) = lcgFunction(S(false), f, ovf.alts)(ov.prov, ctx) + val (t, tvs, constrs) = lcgFunction(S(false), f, ov.alts)(ov.prov, ctx) val tsc = new TupleSetConstraints(MutSet.empty ++ constrs.transpose.filter(_.forall(_.isDefined)).map(_.flatten), tvs)(ov.prov) println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") tvs.zipWithIndex.foreach { diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls index 9bc7361f83..4b03e7543b 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls @@ -91,104 +91,6 @@ type RegionLang = BaseLang[RegionLang] | ExtLang[RegionLang] module TestSize extends SizeBase, SizeExt { fun size: RegionLang -> Int } -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.91: module TestSize extends SizeBase, SizeExt { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.92: fun size: RegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.93: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.79: Scale(_, b) then this.size(b) + 1 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.79: Scale(_, b) then this.size(b) + 1 -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.91: module TestSize extends SizeBase, SizeExt { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.92: fun size: RegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.93: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.33: Translate(_, a) then this.size(a) + 1 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.33: Translate(_, a) then this.size(a) + 1 -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.91: module TestSize extends SizeBase, SizeExt { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.92: fun size: RegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.93: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.91: module TestSize extends SizeBase, SizeExt { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.92: fun size: RegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.93: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.91: module TestSize extends SizeBase, SizeExt { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.92: fun size: RegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.93: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.91: module TestSize extends SizeBase, SizeExt { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.92: fun size: RegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.93: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.91: module TestSize extends SizeBase, SizeExt { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.92: fun size: RegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.93: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Int & ?a -> (?b | ?c)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.30: Outside(a) then this.size(a) + 1 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.30: Outside(a) then this.size(a) + 1 -//│ ╙── ^^^^^^^^^ //│ module TestSize { //│ fun size: RegionLang -> Int //│ } @@ -235,90 +137,6 @@ type BaseRegionLang = BaseLang[BaseRegionLang] module TestContains extends Contains { fun contains: (BaseRegionLang, Vector) -> Bool } -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.235: module TestContains extends Contains { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.236: fun contains: (BaseRegionLang, Vector) -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.237: } -//│ ║ ^ -//│ ╟── expression of type `(BaseRegionLang, Vector) -> Bool & (?a, ?b) -> (?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.225: Translate(v, a) then this.contains(a, Vector(p.x - v.x, p.y - v.y)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.225: Translate(v, a) then this.contains(a, Vector(p.x - v.x, p.y - v.y)) -//│ ╙── ^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.235: module TestContains extends Contains { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.236: fun contains: (BaseRegionLang, Vector) -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.237: } -//│ ║ ^ -//│ ╟── expression of type `(BaseRegionLang, Vector) -> Bool & (?a, ?b) -> (?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.224: Intersect(lhs, rhs) then this.contains(lhs, p) && this.contains(rhs, p) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.224: Intersect(lhs, rhs) then this.contains(lhs, p) && this.contains(rhs, p) -//│ ╙── ^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.235: module TestContains extends Contains { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.236: fun contains: (BaseRegionLang, Vector) -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.237: } -//│ ║ ^ -//│ ╟── expression of type `(BaseRegionLang, Vector) -> Bool & (?a, ?b) -> (?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.224: Intersect(lhs, rhs) then this.contains(lhs, p) && this.contains(rhs, p) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.224: Intersect(lhs, rhs) then this.contains(lhs, p) && this.contains(rhs, p) -//│ ╙── ^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.235: module TestContains extends Contains { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.236: fun contains: (BaseRegionLang, Vector) -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.237: } -//│ ║ ^ -//│ ╟── expression of type `(BaseRegionLang, Vector) -> Bool & (?a, ?b) -> (?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.223: Union(lhs, rhs) then this.contains(lhs, p) || this.contains(rhs, p) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.223: Union(lhs, rhs) then this.contains(lhs, p) || this.contains(rhs, p) -//│ ╙── ^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.235: module TestContains extends Contains { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.236: fun contains: (BaseRegionLang, Vector) -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.237: } -//│ ║ ^ -//│ ╟── expression of type `(BaseRegionLang, Vector) -> Bool & (?a, ?b) -> (?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.223: Union(lhs, rhs) then this.contains(lhs, p) || this.contains(rhs, p) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.223: Union(lhs, rhs) then this.contains(lhs, p) || this.contains(rhs, p) -//│ ╙── ^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.235: module TestContains extends Contains { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.236: fun contains: (BaseRegionLang, Vector) -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.237: } -//│ ║ ^ -//│ ╟── expression of type `(BaseRegionLang, Vector) -> Bool & (?a, ?b) -> (?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.222: Outside(a) then not (this.contains(a, p)) -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.222: Outside(a) then not (this.contains(a, p)) -//│ ╙── ^^^^^^^^^^^^^ //│ module TestContains { //│ fun contains: (BaseRegionLang, Vector) -> Bool //│ } @@ -362,16 +180,16 @@ mixin Text { :e module SizeText extends Text //│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` -//│ ║ l.355: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ l.173: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` -//│ ║ l.354: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ l.172: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` -//│ ║ l.353: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ l.171: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` -//│ ║ l.352: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ l.170: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ //│ module SizeText { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> Str @@ -382,166 +200,6 @@ module SizeText extends SizeBase, Text { fun size: BaseRegionLang -> Int fun text: BaseRegionLang -> Str } -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.381: module SizeText extends SizeBase, Text { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.382: fun size: BaseRegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.383: fun text: BaseRegionLang -> Str -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.384: } -//│ ║ ^ -//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.355: Translate then concat("a translated region of size ", toString(this.size(e))) -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.355: Translate then concat("a translated region of size ", toString(this.size(e))) -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.381: module SizeText extends SizeBase, Text { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.382: fun size: BaseRegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.383: fun text: BaseRegionLang -> Str -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.384: } -//│ ║ ^ -//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.354: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.354: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.381: module SizeText extends SizeBase, Text { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.382: fun size: BaseRegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.383: fun text: BaseRegionLang -> Str -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.384: } -//│ ║ ^ -//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.353: Union then concat("the union of two regions of size ", toString(this.size(e))) -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.353: Union then concat("the union of two regions of size ", toString(this.size(e))) -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.381: module SizeText extends SizeBase, Text { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.382: fun size: BaseRegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.383: fun text: BaseRegionLang -> Str -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.384: } -//│ ║ ^ -//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.352: Outside(a) then concat("outside a region of size ", toString(this.size(a))) -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.352: Outside(a) then concat("outside a region of size ", toString(this.size(a))) -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.381: module SizeText extends SizeBase, Text { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.382: fun size: BaseRegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.383: fun text: BaseRegionLang -> Str -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.384: } -//│ ║ ^ -//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.33: Translate(_, a) then this.size(a) + 1 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.33: Translate(_, a) then this.size(a) + 1 -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.381: module SizeText extends SizeBase, Text { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.382: fun size: BaseRegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.383: fun text: BaseRegionLang -> Str -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.384: } -//│ ║ ^ -//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.381: module SizeText extends SizeBase, Text { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.382: fun size: BaseRegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.383: fun text: BaseRegionLang -> Str -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.384: } -//│ ║ ^ -//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.32: Intersect(a, b) then this.size(a) + this.size(b) + 1 -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.381: module SizeText extends SizeBase, Text { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.382: fun size: BaseRegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.383: fun text: BaseRegionLang -> Str -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.384: } -//│ ║ ^ -//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.381: module SizeText extends SizeBase, Text { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.382: fun size: BaseRegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.383: fun text: BaseRegionLang -> Str -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.384: } -//│ ║ ^ -//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.31: Union(a, b) then this.size(a) + this.size(b) + 1 -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.381: module SizeText extends SizeBase, Text { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.382: fun size: BaseRegionLang -> Int -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.383: fun text: BaseRegionLang -> Str -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.384: } -//│ ║ ^ -//│ ╟── expression of type `BaseRegionLang -> Int & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.30: Outside(a) then this.size(a) + 1 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.30: Outside(a) then this.size(a) + 1 -//│ ╙── ^^^^^^^^^ //│ module SizeText { //│ fun size: BaseRegionLang -> Int //│ fun text: BaseRegionLang -> Str @@ -603,230 +261,6 @@ module IsUnivIsEmpty extends IsUniv, IsEmpty { fun isEmpty: RegionLang -> Bool fun isUniv: RegionLang -> Bool } -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.594: Scale(_, a) then this.isEmpty(a) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.594: Scale(_, a) then this.isEmpty(a) -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.593: Translate(_, a) then this.isEmpty(a) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.593: Translate(_, a) then this.isEmpty(a) -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.590: Outside(a) then this.isUniv(a) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.590: Outside(a) then this.isUniv(a) -//│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.578: Scale(_, a) then this.isUniv(a) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.578: Scale(_, a) then this.isUniv(a) -//│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.577: Translate(_, a) then this.isUniv(a) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.577: Translate(_, a) then this.isUniv(a) -//│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) -//│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) -//│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) -//│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) -//│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.602: module IsUnivIsEmpty extends IsUniv, IsEmpty { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.603: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.604: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.605: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.574: Outside(a) then this.isEmpty(a) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.574: Outside(a) then this.isEmpty(a) -//│ ╙── ^^^^^^^^^^^^ //│ module IsUnivIsEmpty { //│ fun isEmpty: RegionLang -> Bool //│ fun isUniv: RegionLang -> Bool @@ -836,230 +270,6 @@ module IsUnivIsEmpty extends IsEmpty, IsUniv { fun isEmpty: RegionLang -> Bool fun isUniv: RegionLang -> Bool } -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.578: Scale(_, a) then this.isUniv(a) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.578: Scale(_, a) then this.isUniv(a) -//│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.577: Translate(_, a) then this.isUniv(a) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.577: Translate(_, a) then this.isUniv(a) -//│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) -//│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.576: Intersect(a, b) then this.isUniv(a) && this.isUniv(b) -//│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) -//│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.575: Union(a, b) then this.isUniv(a) || this.isUniv(b) -//│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.574: Outside(a) then this.isEmpty(a) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.574: Outside(a) then this.isEmpty(a) -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.594: Scale(_, a) then this.isEmpty(a) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.594: Scale(_, a) then this.isEmpty(a) -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.593: Translate(_, a) then this.isEmpty(a) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.593: Translate(_, a) then this.isEmpty(a) -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.592: Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.591: Union(a, b) then this.isEmpty(a) || this.isEmpty(b) -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.835: module IsUnivIsEmpty extends IsEmpty, IsUniv { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.836: fun isEmpty: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.837: fun isUniv: RegionLang -> Bool -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.838: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> Bool & ?a -> (?b | ?c | ?d | ?e | ?f)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.590: Outside(a) then this.isUniv(a) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.590: Outside(a) then this.isUniv(a) -//│ ╙── ^^^^^^^^^^^ //│ module IsUnivIsEmpty { //│ fun isEmpty: RegionLang -> Bool //│ fun isUniv: RegionLang -> Bool @@ -1079,11 +289,11 @@ IsUnivIsEmpty.isEmpty(circles) class Foo() IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.1080: IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.290: IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Foo` does not match type `BaseLang[RegionLang] | ExtLang[RegionLang]` -//│ ║ l.1080: IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) -//│ ║ ^^^^^ +//│ ║ l.290: IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) +//│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.88: type RegionLang = BaseLang[RegionLang] | ExtLang[RegionLang] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1116,118 +326,6 @@ mixin Eliminate { module TestElim extends Eliminate { fun eliminate: RegionLang -> RegionLang } -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.1116: module TestElim extends Eliminate { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1118: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.1106: Scale(v, a) then Scale(v, this.eliminate(a)) -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.1106: Scale(v, a) then Scale(v, this.eliminate(a)) -//│ ╙── ^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.1116: module TestElim extends Eliminate { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1118: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.1105: Translate(v, a) then Translate(v, this.eliminate(a)) -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.1105: Translate(v, a) then Translate(v, this.eliminate(a)) -//│ ╙── ^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.1116: module TestElim extends Eliminate { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1118: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.1104: Intersect(a, b) then Intersect(this.eliminate(a), this.eliminate(b)) -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.1104: Intersect(a, b) then Intersect(this.eliminate(a), this.eliminate(b)) -//│ ╙── ^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.1116: module TestElim extends Eliminate { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1118: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.1104: Intersect(a, b) then Intersect(this.eliminate(a), this.eliminate(b)) -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.1104: Intersect(a, b) then Intersect(this.eliminate(a), this.eliminate(b)) -//│ ╙── ^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.1116: module TestElim extends Eliminate { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1118: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.1103: Union(a, b) then Union(this.eliminate(a), this.eliminate(b)) -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.1103: Union(a, b) then Union(this.eliminate(a), this.eliminate(b)) -//│ ╙── ^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.1116: module TestElim extends Eliminate { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1118: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.1103: Union(a, b) then Union(this.eliminate(a), this.eliminate(b)) -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.1103: Union(a, b) then Union(this.eliminate(a), this.eliminate(b)) -//│ ╙── ^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.1116: module TestElim extends Eliminate { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1118: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.1102: Outside(a) then Outside(this.eliminate(a)) -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.1102: Outside(a) then Outside(this.eliminate(a)) -//│ ╙── ^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.1116: module TestElim extends Eliminate { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1117: fun eliminate: RegionLang -> RegionLang -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.1118: } -//│ ║ ^ -//│ ╟── expression of type `RegionLang -> RegionLang & ?a -> (?b | ?c | ?d | ?e | ?f | ?g)` is not a function -//│ ╟── Note: constraint arises from application: -//│ ║ l.1101: Outside(Outside(a)) then this.eliminate(a) -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── from field selection: -//│ ║ l.1101: Outside(Outside(a)) then this.eliminate(a) -//│ ╙── ^^^^^^^^^^^^^^ //│ module TestElim { //│ fun eliminate: RegionLang -> RegionLang //│ } @@ -1311,16 +409,16 @@ Lang.size(mk(100)) :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.1312: Lang.contains(mk(100), Vector(0, 0)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.410: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[BaseRegionLang] | Outside[BaseRegionLang] | Translate[BaseRegionLang] | Union[BaseRegionLang]` -//│ ║ l.1250: _ then Scale(Vector(0, 0), mk(n)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.348: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.23: type BaseLang[T] = Circle | Intersect[T] | Union[T] | Outside[T] | Translate[T] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── from type reference: -//│ ║ l.232: type BaseRegionLang = BaseLang[BaseRegionLang] +//│ ║ l.134: type BaseRegionLang = BaseLang[BaseRegionLang] //│ ╙── ^^^^^^^^^^^^^^ //│ error | false | true //│ Code generation encountered an error: @@ -1330,16 +428,16 @@ Lang.contains(mk(100), Vector(0, 0)) :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.1331: Lang.text(mk(100)) -//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.429: Lang.text(mk(100)) +//│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[BaseRegionLang] | Outside[BaseRegionLang] | Translate[BaseRegionLang] | Union[BaseRegionLang]` -//│ ║ l.1250: _ then Scale(Vector(0, 0), mk(n)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.348: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.23: type BaseLang[T] = Circle | Intersect[T] | Union[T] | Outside[T] | Translate[T] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── from type reference: -//│ ║ l.232: type BaseRegionLang = BaseLang[BaseRegionLang] +//│ ║ l.134: type BaseRegionLang = BaseLang[BaseRegionLang] //│ ╙── ^^^^^^^^^^^^^^ //│ Str | error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index f71247df0d..6f15e7eebf 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -86,18 +86,8 @@ IISS 0 //│ res: number // * TODO: update type simplifier -:e fun x -> (if true then IISS else BBNN) x -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.90: fun x -> (if true then IISS else BBNN) x -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `int -> int & string -> string` is not a function -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `?a -> ?b` -//│ ║ l.90: fun x -> (if true then IISS else BBNN) x -//│ ╙── ^^^^ -//│ res: anything -> error +//│ res: anything -> nothing if true then IISS else BBNN //│ res: bool -> bool & number -> number | int -> int & string -> string @@ -111,16 +101,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.112: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.102: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.112: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.102: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.112: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.102: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/nu/ArrayProg.mls b/shared/src/test/diff/nu/ArrayProg.mls index 649b30320b..92d2ae5599 100644 --- a/shared/src/test/diff/nu/ArrayProg.mls +++ b/shared/src/test/diff/nu/ArrayProg.mls @@ -137,18 +137,8 @@ fun s: ([Numbr,Numbr] -> Int) & ([Vectr,Vectr] -> Int) //│ fun s: (Numbr | Vectr, Numbr | Vectr) -> Int -:e s(Vectr([]),Vectr([])) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.141: s(Vectr([]),Vectr([])) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `(Numbr | Vectr, Numbr | Vectr) -> Int` is not a function -//│ ║ l.136: fun s: ([Numbr,Numbr] -> Int) & ([Vectr,Vectr] -> Int) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `(?a, ?b) -> ?c` -//│ ║ l.141: s(Vectr([]),Vectr([])) -//│ ╙── ^ -//│ error +//│ Int //│ res //│ = //│ s is not implemented @@ -179,18 +169,8 @@ A.g(0) :AllowTypeErrors -:e s([Numbr(0),Numbr(0)]) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.+1: s([Numbr(0),Numbr(0)]) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `(Numbr | Vectr, Numbr | Vectr) -> Int` is not a function -//│ ║ l.136: fun s: ([Numbr,Numbr] -> Int) & ([Vectr,Vectr] -> Int) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `([?a, ?b]) -> ?c` -//│ ║ l.+1: s([Numbr(0),Numbr(0)]) -//│ ╙── ^ -//│ error +//│ Int // g <: 0 -> 'a :e diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index ae5b41b647..556083e0bd 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -134,18 +134,8 @@ f(0) // f(0) : case 0 of { Int => Int; Bool => Bool } == Int -:e x => f(x) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.138: x => f(x) -//│ ║ ^^^^ -//│ ╟── type `Int -> Int & Bool -> Bool` is not a function -//│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `?a -> ?b` -//│ ║ l.138: x => f(x) -//│ ╙── ^ -//│ anything -> error +//│ anything -> nothing //│ res //│ = [Function: res] @@ -154,13 +144,13 @@ x => f(x) :e f(if true then 0 else false) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.155: f(if true then 0 else false) +//│ ║ l.145: f(if true then 0 else false) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `Int -> Int & Bool -> Bool` is not a function //│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | false) -> ?a` -//│ ║ l.155: f(if true then 0 else false) +//│ ║ l.145: f(if true then 0 else false) //│ ╙── ^ //│ error //│ res @@ -172,21 +162,12 @@ f(if true then 0 else false) :w f(refined if true then 0 else false) // this one can be precise again! //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.173: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.163: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.173: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.163: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.173: f(refined if true then 0 else false) // this one can be precise again! -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `Int -> Int & Bool -> Bool` is not a function -//│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `?a -> ?b` -//│ ║ l.173: f(refined if true then 0 else false) // this one can be precise again! -//│ ╙── ^ -//│ error +//│ nothing //│ Code generation encountered an error: //│ unresolved symbol refined @@ -242,7 +223,7 @@ type T = List[Int] :e // TODO application types type Res = M(T) //│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 -//│ ║ l.243: type Res = M(T) +//│ ║ l.224: type Res = M(T) //│ ╙── ^^^^ //│ type Res = M @@ -265,7 +246,7 @@ fun f: Int -> Int fun f: Bool -> Bool fun f = id //│ ╔══[ERROR] A type signature for 'f' was already given -//│ ║ l.265: fun f: Bool -> Bool +//│ ║ l.246: fun f: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun f: forall 'a. 'a -> 'a //│ fun f: Int -> Int @@ -273,13 +254,13 @@ fun f = id :e // TODO support f: (Int -> Int) & (Bool -> Bool) //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.274: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.255: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^ //│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.274: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.255: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.264: fun f: Int -> Int +//│ ║ l.245: fun f: Int -> Int //│ ╙── ^^^ //│ Int -> Int & Bool -> Bool //│ res @@ -346,14 +327,14 @@ fun test(x) = refined if x is A then 0 B then 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.345: fun test(x) = refined if x is +//│ ║ l.326: fun test(x) = refined if x is //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.346: A then 0 +//│ ║ l.327: A then 0 //│ ║ ^^^^^^^^^^ -//│ ║ l.347: B then 1 +//│ ║ l.328: B then 1 //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.345: fun test(x) = refined if x is +//│ ║ l.326: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ fun test: (A | B) -> error //│ Code generation encountered an error: @@ -378,83 +359,29 @@ q(1) //│ = //│ q is not implemented -// FIXME -:e x => q(x): true -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.383: x => q(x): true -//│ ║ ^^^^ -//│ ╟── type `(0 | 1) -> true & (1 | 2) -> false` is not a function -//│ ║ l.366: fun q: (0|1) -> true & (1|2) -> false -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `?a -> ?b` -//│ ║ l.383: x => q(x): true -//│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.383: x => q(x): true -//│ ║ ^^^^ -//│ ╟── application of type `?a` does not match type `true` -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.383: x => q(x): true -//│ ╙── ^^^^ -//│ anything -> true +//│ (0 | 1) -> true //│ res //│ = //│ q is not implemented -:e x => q(x) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.407: x => q(x) -//│ ║ ^^^^ -//│ ╟── type `(0 | 1) -> true & (1 | 2) -> false` is not a function -//│ ║ l.366: fun q: (0|1) -> true & (1|2) -> false -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `?a -> ?b` -//│ ║ l.407: x => q(x) -//│ ╙── ^ -//│ anything -> error +//│ anything -> nothing //│ res //│ = //│ q is not implemented -:e fun w = x => q(x) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.423: fun w = x => q(x) -//│ ║ ^^^^ -//│ ╟── type `(0 | 1) -> true & (1 | 2) -> false` is not a function -//│ ║ l.366: fun q: (0|1) -> true & (1|2) -> false -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `?a -> ?b` -//│ ║ l.423: fun w = x => q(x) -//│ ╙── ^ -//│ fun w: anything -> error +//│ fun w: anything -> nothing w(0) -//│ error +//│ nothing //│ res //│ = //│ w and q are not implemented -:e x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.442: x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 -//│ ║ ^^^^^^^ -//│ ╟── type `(0, Int) -> 'a & (1, Str) -> ['a]` is not a function -//│ ║ l.442: x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `(0, ?a) -> ?b` -//│ ║ l.442: x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 -//│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.442: x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 -//│ ║ ^^^^^^^^^^^ -//│ ╟── application of type `?a` does not match type `Int` -//│ ║ l.442: x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 -//│ ╙── ^^^^^^^ -//│ anything -> (f: (0, Int) -> anything & (1, Str) -> [anything]) -> (Int | error) +//│ Int -> (f: (0, Int) -> Int & (1, Str) -> [Int]) -> Int //│ res //│ = [Function: res] From fe6ed2f5f4e893fac79fc59b7991deeace95b9a1 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Mon, 11 Mar 2024 00:10:57 +0800 Subject: [PATCH 10/43] modify type simplifier --- .../main/scala/mlscript/TypeSimplifier.scala | 45 ++++++------ shared/src/main/scala/mlscript/Typer.scala | 8 ++- .../main/scala/mlscript/TyperDatatypes.scala | 4 +- shared/src/test/diff/fcp/Overloads.mls | 17 +++-- shared/src/test/diff/nu/HeungTung.mls | 70 +++++++++++++------ shared/src/test/diff/nu/WeirdUnions.mls | 17 +++-- 6 files changed, 102 insertions(+), 59 deletions(-) diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index e5ca2111cb..8f1a757ef4 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -26,6 +26,7 @@ trait TypeSimplifier { self: Typer => println(s"allVarPols: ${printPols(allVarPols)}") val renewed = MutMap.empty[TypeVariable, TypeVariable] + val renewedtsc = MutMap.empty[TupleSetConstraints, TupleSetConstraints] def renew(tv: TypeVariable): TypeVariable = renewed.getOrElseUpdate(tv, @@ -75,19 +76,15 @@ trait TypeSimplifier { self: Typer => tv.upperBounds.reverseIterator.map(process(_, S(false -> tv))) .reduceOption(_ &- _).filterNot(_.isTop).toList else Nil - // fixme - // nv.tsc = tv.tsc.map { - // case (tsc, i) => - // tsc.tvs.collect { case (_, x: TV) => renewed.get(x).flatMap(_.tsc) } - // .flatten.headOption - // .fold(new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov), i) { - // tsc => (tsc._1, i) - // } - // } - // nv.tsc.foreach { case (tsc, i) => - // val (l, r) = tsc.tvs.splitAt(i) - // tsc.tvs = l ++ ((r.head._1, nv) :: r.drop(1)) - // } + nv.tsc = tv.tsc.map { case (tsc, i) => + (renewedtsc.getOrElseUpdate(tsc, + new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov)), + i) + } + nv.tsc.foreachEntry { case (tsc, i) => + val (l, r) = tsc.tvs.splitAt(i) + tsc.tvs = l ++ ((r.head._1, nv) :: r.drop(1)) + } } nv @@ -932,6 +929,7 @@ trait TypeSimplifier { self: Typer => println(s"[rec] ${recVars}") val renewals = MutMap.empty[TypeVariable, TypeVariable] + val renewaltsc = MutMap.empty[TupleSetConstraints, TupleSetConstraints] val semp = Set.empty[TV] @@ -1026,18 +1024,15 @@ trait TypeSimplifier { self: Typer => res.lowerBounds = tv.lowerBounds.map(transform(_, pol.at(tv.level, true), Set.single(tv))) if (occNums.contains(false -> tv)) res.upperBounds = tv.upperBounds.map(transform(_, pol.at(tv.level, false), Set.single(tv))) - // TODO - // res.tsc = tv.tsc.map { - // case (tsc, i) => - // tsc.tvs.collect { case (_, x: TV) => renewals.get(x).flatMap(_.tsc)}.flatten.headOption - // .fold(new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov), i) { - // tsc => (tsc._1, i) - // } - // } - // res.tsc.foreach { case (tsc, i) => - // val (l, r) = tsc.tvs.splitAt(i) - // tsc.tvs = l ++ ((r.head._1, res) :: r.drop(1)) - // } + res.tsc = tv.tsc.map { case (tsc, i) => + (renewaltsc.getOrElseUpdate(tsc, + new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov)), + i) + } + res.tsc.foreachEntry { case (tsc, i) => + val (l, r) = tsc.tvs.splitAt(i) + tsc.tvs = l ++ ((r.head._1, res) :: r.drop(1)) + } } res }() diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index ef9a0a1392..91bfcb0d4c 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -112,7 +112,13 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne assert(b.level > lvl) if (p) (b, tv) else (tv, b) } }.toList, innerTy) - + + val ambiguous: Bool = innerTy.getVars.toList.flatMap(_.tsc) + .flatMap(_._1.tvs.map(_._2)) + .collect { case x: TV => x } + .exists(_.tsc.sizeIs > 1) + if (ambiguous) raise(ErrorReport(Ls(fromStr("ambiguous") -> N), true)) + println(s"Inferred poly constr: $cty —— where ${cty.showBounds}") val cty_fresh = diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index bf255dc283..c1202df6d9 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -750,8 +750,8 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => (TypeRef(a.defn, ts)(prov), tvss.flatten, constrss.flatten) case a: TV if rest.flatten.map(_.unwrapProxies).forall { case b: TV => a.compare(b) === 0; case _ => false } => (a, Nil, Nil) case a if rest.flatten.forall(_.unwrapProxies === a) => (a, Nil, Nil) - case _ => - (first, List((pol, first)), List(rest.map(_.map(_.unwrapProxies)))) + case a => + (a, List((pol, a)), List(rest.map(_.map(_.unwrapProxies)))) // val tv = freshVar(prov, N) // (tv, List(tv), List(first :: rest)) } diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 6f15e7eebf..a540a48bae 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -75,6 +75,9 @@ IISS : (0 | 1) -> number IISS : 'a -> 'a //│ res: 'a -> 'a +//│ where +//│ ['a0, 'a] in {[string, string], [int, int]} +//│ ['a0, 'a0] in {[string, string], [int, int]} IISS 0 //│ res: int @@ -86,8 +89,14 @@ IISS 0 //│ res: number // * TODO: update type simplifier +// fixme +:e fun x -> (if true then IISS else BBNN) x -//│ res: anything -> nothing +//│ ╔══[ERROR] ambiguous +//│ ╙── +//│ res: 'a -> 'b +//│ where +//│ ['a, 'b] in {[string, string], [int, int]} if true then IISS else BBNN //│ res: bool -> bool & number -> number | int -> int & string -> string @@ -101,16 +110,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.102: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.111: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.102: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.111: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.102: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.111: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 556083e0bd..9f10b32c1b 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -135,7 +135,9 @@ f(0) x => f(x) -//│ anything -> nothing +//│ forall 'a 'b. 'a -> 'b +//│ where +//│ ['a, 'b] in {[Bool, Bool], [Int, Int]} //│ res //│ = [Function: res] @@ -144,15 +146,18 @@ x => f(x) :e f(if true then 0 else false) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.145: f(if true then 0 else false) +//│ ║ l.147: f(if true then 0 else false) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `Int -> Int & Bool -> Bool` is not a function //│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | false) -> ?a` -//│ ║ l.145: f(if true then 0 else false) +//│ ║ l.147: f(if true then 0 else false) //│ ╙── ^ -//│ error +//│ 'a +//│ where +//│ 'a :> error +//│ [0 | false, 'a, 0 | false] in {} //│ res //│ = 0 @@ -162,12 +167,16 @@ f(if true then 0 else false) :w f(refined if true then 0 else false) // this one can be precise again! //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.163: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.168: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.163: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.168: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^ -//│ nothing +//│ 'a +//│ where +//│ 'b :> error +//│ ['b, 'a] in {[Bool, Bool], [Int, Int]} +//│ ['b, 'c] in {[Bool, Bool], [Int, Int]} //│ Code generation encountered an error: //│ unresolved symbol refined @@ -223,7 +232,7 @@ type T = List[Int] :e // TODO application types type Res = M(T) //│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 -//│ ║ l.224: type Res = M(T) +//│ ║ l.233: type Res = M(T) //│ ╙── ^^^^ //│ type Res = M @@ -246,7 +255,7 @@ fun f: Int -> Int fun f: Bool -> Bool fun f = id //│ ╔══[ERROR] A type signature for 'f' was already given -//│ ║ l.246: fun f: Bool -> Bool +//│ ║ l.255: fun f: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun f: forall 'a. 'a -> 'a //│ fun f: Int -> Int @@ -254,13 +263,13 @@ fun f = id :e // TODO support f: (Int -> Int) & (Bool -> Bool) //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.255: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.264: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^ //│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.255: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.264: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.245: fun f: Int -> Int +//│ ║ l.254: fun f: Int -> Int //│ ╙── ^^^ //│ Int -> Int & Bool -> Bool //│ res @@ -327,14 +336,14 @@ fun test(x) = refined if x is A then 0 B then 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.326: fun test(x) = refined if x is +//│ ║ l.335: fun test(x) = refined if x is //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.327: A then 0 +//│ ║ l.336: A then 0 //│ ║ ^^^^^^^^^^ -//│ ║ l.328: B then 1 +//│ ║ l.337: B then 1 //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.326: fun test(x) = refined if x is +//│ ║ l.335: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ fun test: (A | B) -> error //│ Code generation encountered an error: @@ -354,7 +363,9 @@ q(0) //│ q is not implemented q(1) -//│ nothing +//│ 'a +//│ where +//│ [1, 'a, 1] in {[1 | 2, false, 1 | 2], [0 | 1, true, 0 | 1]} //│ res //│ = //│ q is not implemented @@ -365,15 +376,18 @@ x => q(x): true //│ = //│ q is not implemented - x => q(x) -//│ anything -> nothing +//│ forall 'a 'b. 'a -> 'b +//│ where +//│ ['a, 'b] in {[0 | 1, true], [1 | 2, false]} //│ res //│ = //│ q is not implemented fun w = x => q(x) -//│ fun w: anything -> nothing +//│ fun w: forall 'a 'b. 'a -> 'b +//│ where +//│ ['a, 'b] in {[0 | 1, true], [1 | 2, false]} w(0) //│ nothing @@ -385,3 +399,19 @@ x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 //│ Int -> (f: (0, Int) -> Int & (1, Str) -> [Int]) -> Int //│ res //│ = [Function: res] + +fun r: Int -> Int & Bool -> Bool +//│ fun r: Int -> Int & Bool -> Bool + +:e +x => r(r(x)) +//│ ╔══[ERROR] ambiguous +//│ ╙── +//│ forall 'a 'b. 'a -> 'b +//│ where +//│ ['a, 'c] in {[Bool, Bool], [Int, Int]} +//│ ['c, 'd] in {[Bool, Bool], [Int, Int]} +//│ ['e, 'c] in {[Bool, Bool], [Int, Int]} +//│ res +//│ = +//│ r is not implemented diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index 159ed20232..6167f9535b 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -58,7 +58,10 @@ f("abc", "abc") //│ ╟── but it flows into reference with expected type `("abc", "abc") -> ?a` //│ ║ l.51: f("abc", "abc") //│ ╙── ^ -//│ error +//│ 'a +//│ where +//│ 'a :> error +//│ ["abc", "abc", 'a, "abc", "abc"] in {} //│ res //│ = //│ f is not implemented @@ -81,19 +84,19 @@ let r = if true then id else (x, y) => [y, x] r(error) r(error, error) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.81: r(error) +//│ ║ l.84: r(error) //│ ║ ^^^^^^^^ //│ ╟── argument of type `[nothing]` does not match type `[?a, ?b]` -//│ ║ l.81: r(error) +//│ ║ l.84: r(error) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.75: let r = if true then id else (x, y) => [y, x] +//│ ║ l.78: let r = if true then id else (x, y) => [y, x] //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.82: r(error, error) +//│ ║ l.85: r(error, error) //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── argument list of type `[nothing, nothing]` does not match type `[?a]` -//│ ║ l.82: r(error, error) +//│ ║ l.85: r(error, error) //│ ╙── ^^^^^^^^^^^^^^ //│ error | [nothing, nothing] //│ res @@ -116,7 +119,7 @@ r of [0, 1] // Also currently parses the same: let r = if true then id else [x, y] => [y, x] -//│ let r: forall 'a 'b 'c. (['c, 'a] & 'b) -> (['a, 'c] | 'b) +//│ let r: forall 'a 'b 'c. (['a, 'b] & 'c) -> (['b, 'a] | 'c) //│ r //│ = [Function: id] From 74ba3f0d6013d71fea6010b30141982ea3cbb1a3 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 11 Mar 2024 16:19:42 +0800 Subject: [PATCH 11/43] WIP Changes from meeting --- shared/src/main/scala/mlscript/Typer.scala | 2 ++ shared/src/main/scala/mlscript/TyperHelpers.scala | 1 + shared/src/test/diff/fcp/Overloads.mls | 7 ++++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 91bfcb0d4c..e73be5a217 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1691,6 +1691,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne var tscs: Ls[Ls[(Opt[Bool], Type)] -> Ls[Ls[Type]]] = Nil val seenVars = mutable.Set.empty[TV] + val seenTscs = mutable.Set.empty[TupleSetConstraints] def field(ft: FieldType)(implicit ectx: ExpCtx): Field = ft match { case FieldType(S(l: TV), u: TV) if l === u => @@ -1801,6 +1802,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne tv.tsc.foreachEntry { case (tsc, i) => if (tsc.tvs.forall { case (_, v: TV) => !seenVars(v) || v === tv; case _ => true }) { + if (seenTscs.add(tsc)) { val tvs = tsc.tvs.map(x => (x._1, go(x._2))) val constrs = tsc.constraints.toList.map(_.map(go)) tscs ::= tvs -> constrs diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 26dede6e96..96ec70c44f 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -964,6 +964,7 @@ abstract class TyperHelpers { Typer: Typer => getVars.iterator.filter(tv => tv.tsc.nonEmpty).map { case tv if visited.contains(tv) => "" case tv => + // FIXME nonsense: just keep a set of visited TSCs visited ++= tv.tsc.map(_._1.tvs.collect { case (_, v: TV) => v }).flatten tv.tsc.map { case (tsc, _) => ("\n\t\t[ " + tsc.tvs.mkString(", ") diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index a540a48bae..7caddbf1ab 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -96,6 +96,7 @@ fun x -> (if true then IISS else BBNN) x //│ ╙── //│ res: 'a -> 'b //│ where +//│ ['a, 'b] in {[bool, bool], [number, number]} //│ ['a, 'b] in {[string, string], [int, int]} if true then IISS else BBNN @@ -110,16 +111,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.111: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.252: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.111: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.252: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.111: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.252: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number From f41cc1b14236b53b98e3d2195ce1cf0cad36a068 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Tue, 12 Mar 2024 23:43:01 +0800 Subject: [PATCH 12/43] use LinkedHashMap preserve insertion order --- shared/src/main/scala/mlscript/Typer.scala | 1 - shared/src/main/scala/mlscript/TyperDatatypes.scala | 4 ++-- shared/src/main/scala/mlscript/TyperHelpers.scala | 13 +++++-------- shared/src/test/diff/fcp/Overloads.mls | 8 ++++---- shared/src/test/diff/nu/HeungTung.mls | 2 ++ 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index e73be5a217..ba851f2f29 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1801,7 +1801,6 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne } tv.tsc.foreachEntry { case (tsc, i) => - if (tsc.tvs.forall { case (_, v: TV) => !seenVars(v) || v === tv; case _ => true }) { if (seenTscs.add(tsc)) { val tvs = tsc.tvs.map(x => (x._1, go(x._2))) val constrs = tsc.constraints.toList.map(_.map(go)) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index c1202df6d9..dc1f46e166 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -1,7 +1,7 @@ package mlscript import scala.collection.mutable -import scala.collection.mutable.{Map => MutMap, Set => MutSet, Buffer} +import scala.collection.mutable.{Map => MutMap, Set => MutSet, Buffer, LinkedHashMap} import scala.collection.immutable.{SortedSet, SortedMap} import scala.util.chaining._ import scala.annotation.tailrec @@ -535,7 +535,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => _assignedTo = value } - var tsc: MutMap[TupleSetConstraints, Int] = MutMap.empty + var tsc: LinkedHashMap[TupleSetConstraints, Int] = LinkedHashMap.empty // * Bounds should always be disregarded when `equatedTo` is defined, as they are then irrelevant: def lowerBounds: List[SimpleType] = { require(assignedTo.isEmpty, this); _lowerBounds } diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 96ec70c44f..820f6f1310 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -960,16 +960,13 @@ abstract class TyperHelpers { Typer: Typer => + (if (tv.upperBounds.isEmpty) "" else " <: " + tv.upperBounds.mkString(" & ")) ) }.mkString + { - val visited: MutSet[TV] = MutSet.empty - getVars.iterator.filter(tv => tv.tsc.nonEmpty).map { - case tv if visited.contains(tv) => "" - case tv => - // FIXME nonsense: just keep a set of visited TSCs - visited ++= tv.tsc.map(_._1.tvs.collect { case (_, v: TV) => v }).flatten - tv.tsc.map { case (tsc, _) => ("\n\t\t[ " + val visited: MutSet[TupleSetConstraints] = MutSet.empty + getVars.iterator.flatMap(_.tsc).map { case (tsc, i) => + if (visited.add(tsc)) + ("\n\t\t[ " + tsc.tvs.mkString(", ") + " ] in { " + tsc.constraints.mkString(", ") + " }") - } + else "" }.mkString } } diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 7caddbf1ab..69a9ddf860 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -96,8 +96,8 @@ fun x -> (if true then IISS else BBNN) x //│ ╙── //│ res: 'a -> 'b //│ where -//│ ['a, 'b] in {[bool, bool], [number, number]} //│ ['a, 'b] in {[string, string], [int, int]} +//│ ['a, 'b] in {[bool, bool], [number, number]} if true then IISS else BBNN //│ res: bool -> bool & number -> number | int -> int & string -> string @@ -111,16 +111,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.252: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.112: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.252: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.112: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.252: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.112: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 9f10b32c1b..5c80a7f25d 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -403,12 +403,14 @@ x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 fun r: Int -> Int & Bool -> Bool //│ fun r: Int -> Int & Bool -> Bool +// fixme: multiple occurence :e x => r(r(x)) //│ ╔══[ERROR] ambiguous //│ ╙── //│ forall 'a 'b. 'a -> 'b //│ where +//│ ['c, 'b] in {[Bool, Bool], [Int, Int]} //│ ['a, 'c] in {[Bool, Bool], [Int, Int]} //│ ['c, 'd] in {[Bool, Bool], [Int, Int]} //│ ['e, 'c] in {[Bool, Bool], [Int, Int]} From c8c35dfa841ae877dbd9b253ca42b8183da03f75 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 14 Mar 2024 00:20:36 +0800 Subject: [PATCH 13/43] fix duplicate occurence --- .../scala/mlscript/ConstraintSolver.scala | 11 ++- .../main/scala/mlscript/TypeSimplifier.scala | 35 +++++----- shared/src/main/scala/mlscript/Typer.scala | 5 +- .../main/scala/mlscript/TyperDatatypes.scala | 2 +- .../main/scala/mlscript/TyperHelpers.scala | 3 +- .../diff/ecoop23/SimpleRegionDSL_annot.mls | 67 +++++++++++-------- shared/src/test/diff/fcp/Overloads.mls | 11 ++- shared/src/test/diff/nu/HeungTung.mls | 27 ++++---- 8 files changed, 90 insertions(+), 71 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 2169fedcf6..35197de041 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -1487,6 +1487,7 @@ class ConstraintSolver extends NormalForms { self: Typer => (implicit ctx: Ctx, freshened: MutMap[TV, ST]) : SimpleType = { + val freshenedTsc: MutMap[TupleSetConstraints, TupleSetConstraints] = MutMap.empty def freshenImpl(ty: SimpleType, below: Level): SimpleType = // (trace(s"${lvl}. FRESHEN $ty || $above .. $below ${ty.level} ${ty.level <= above}") { @@ -1565,8 +1566,14 @@ class ConstraintSolver extends NormalForms { self: Typer => freshened += tv -> v v.lowerBounds = tv.lowerBounds.mapConserve(freshen) v.upperBounds = tv.upperBounds.mapConserve(freshen) - v.tsc = tv.tsc // fixme - v.tsc.foreachEntry { case (tsc, i) => tsc.tvs = tsc.tvs.mapConserve(x => (x._1, freshen(x._2))) } + v.tsc ++= tv.tsc.map { case (tsc, i) => freshenedTsc.get(tsc) match { + case S(tsc) => (tsc, i) + case N => + val t = new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov) + freshenedTsc += tsc -> t + t.tvs = t.tvs.map(x => (x._1, freshen(x._2))) + (t, i) + }} v } diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 8f1a757ef4..469014a70e 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -76,15 +76,15 @@ trait TypeSimplifier { self: Typer => tv.upperBounds.reverseIterator.map(process(_, S(false -> tv))) .reduceOption(_ &- _).filterNot(_.isTop).toList else Nil - nv.tsc = tv.tsc.map { case (tsc, i) => - (renewedtsc.getOrElseUpdate(tsc, - new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov)), - i) - } - nv.tsc.foreachEntry { case (tsc, i) => - val (l, r) = tsc.tvs.splitAt(i) - tsc.tvs = l ++ ((r.head._1, nv) :: r.drop(1)) - } + nv.tsc ++= tv.tsc.map { case (tsc, i) => renewedtsc.get(tsc) match { + case S(tsc) => (tsc, i) + case N if inPlace => (tsc, i) + case N => + val t = new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov) + renewedtsc += tsc -> t + t.tvs = t.tvs.map(x => (x._1, process(x._2, N))) + (t, i) + }} } nv @@ -1024,15 +1024,14 @@ trait TypeSimplifier { self: Typer => res.lowerBounds = tv.lowerBounds.map(transform(_, pol.at(tv.level, true), Set.single(tv))) if (occNums.contains(false -> tv)) res.upperBounds = tv.upperBounds.map(transform(_, pol.at(tv.level, false), Set.single(tv))) - res.tsc = tv.tsc.map { case (tsc, i) => - (renewaltsc.getOrElseUpdate(tsc, - new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov)), - i) - } - res.tsc.foreachEntry { case (tsc, i) => - val (l, r) = tsc.tvs.splitAt(i) - tsc.tvs = l ++ ((r.head._1, res) :: r.drop(1)) - } + res.tsc ++= tv.tsc.map { case (tsc, i) => renewaltsc.get(tsc) match { + case S(tsc) => (tsc, i) + case N => + val t = new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov) + renewaltsc += tsc -> t + t.tvs = t.tvs.map(x => (x._1, transform(x._2, PolMap.neu, Set.empty))) + (t, i) + }} } res }() diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index ba851f2f29..7cb5ddb688 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1802,7 +1802,10 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne tv.tsc.foreachEntry { case (tsc, i) => if (seenTscs.add(tsc)) { - val tvs = tsc.tvs.map(x => (x._1, go(x._2))) + val tvs = tsc.tvs.map { + case (pol, tv: TV) => (pol, tv.asTypeVar) + case (pol, t) => (pol, go(t)) + } val constrs = tsc.constraints.toList.map(_.map(go)) tscs ::= tvs -> constrs } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index dc1f46e166..75c76c990f 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -535,7 +535,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => _assignedTo = value } - var tsc: LinkedHashMap[TupleSetConstraints, Int] = LinkedHashMap.empty + val tsc: LinkedHashMap[TupleSetConstraints, Int] = LinkedHashMap.empty // * Bounds should always be disregarded when `equatedTo` is defined, as they are then irrelevant: def lowerBounds: List[SimpleType] = { require(assignedTo.isEmpty, this); _lowerBounds } diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 820f6f1310..4b24e0ebc6 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -757,7 +757,8 @@ abstract class TyperHelpers { Typer: Typer => case tv: TypeVariable => val poltv = pol(tv) (if (poltv =/= S(false)) tv.lowerBounds.map(pol.at(tv.level, true) -> _) else Nil) ::: - (if (poltv =/= S(true)) tv.upperBounds.map(pol.at(tv.level, false) -> _) else Nil) + (if (poltv =/= S(true)) tv.upperBounds.map(pol.at(tv.level, false) -> _) else Nil) ::: + (tv.tsc.toList.flatMap { case (tsc, i) => (tsc.tvs.take(i) ++ tsc.tvs.drop(i+1)).map(PolMap.neu -> _._2) }) case FunctionType(l, r) => pol.contravar -> l :: pol.covar -> r :: Nil case Overload(as) => as.map(pol -> _) case ComposedType(_, l, r) => pol -> l :: pol -> r :: Nil diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls index 4b03e7543b..c634f7c8dc 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls @@ -367,49 +367,57 @@ module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminat fun size: RegionLang -> Int fun text: BaseRegionLang -> Str } -//│ /!!!\ Uncaught error: java.lang.StackOverflowError +//│ module Lang { +//│ fun contains: (BaseRegionLang, Vector) -> Bool +//│ fun eliminate: RegionLang -> RegionLang +//│ fun isEmpty: RegionLang -> Bool +//│ fun isUniv: RegionLang -> Bool +//│ fun size: RegionLang -> Int +//│ fun text: BaseRegionLang -> Str +//│ } Lang.size(circles) //│ Int -//│ Code generation encountered an error: -//│ unresolved symbol Lang +//│ res +//│ = 13 Lang.contains(circles, Vector(0, 0)) //│ Bool -//│ Code generation encountered an error: -//│ unresolved symbol Lang +//│ res +//│ = false Lang.text(circles) //│ Str -//│ Code generation encountered an error: -//│ unresolved symbol Lang +//│ res +//│ = 'the union of two regions of size ' Lang.isUniv(circles) //│ Bool -//│ Code generation encountered an error: -//│ unresolved symbol Lang +//│ res +//│ = false Lang.isEmpty(circles) //│ Bool -//│ Code generation encountered an error: -//│ unresolved symbol Lang +//│ res +//│ = false Lang.size(Lang.eliminate(circles)) //│ Int -//│ Code generation encountered an error: -//│ unresolved symbol Lang +//│ res +//│ = 13 :re Lang.size(mk(100)) //│ Int -//│ Code generation encountered an error: -//│ unresolved symbol Lang +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded :e :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.410: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.418: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[BaseRegionLang] | Outside[BaseRegionLang] | Translate[BaseRegionLang] | Union[BaseRegionLang]` //│ ║ l.348: _ then Scale(Vector(0, 0), mk(n)) @@ -421,14 +429,15 @@ Lang.contains(mk(100), Vector(0, 0)) //│ ║ l.134: type BaseRegionLang = BaseLang[BaseRegionLang] //│ ╙── ^^^^^^^^^^^^^^ //│ error | false | true -//│ Code generation encountered an error: -//│ unresolved symbol Lang +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded :e :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.429: Lang.text(mk(100)) +//│ ║ l.438: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[BaseRegionLang] | Outside[BaseRegionLang] | Translate[BaseRegionLang] | Union[BaseRegionLang]` //│ ║ l.348: _ then Scale(Vector(0, 0), mk(n)) @@ -440,23 +449,27 @@ Lang.text(mk(100)) //│ ║ l.134: type BaseRegionLang = BaseLang[BaseRegionLang] //│ ╙── ^^^^^^^^^^^^^^ //│ Str | error -//│ Code generation encountered an error: -//│ unresolved symbol Lang +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded :re Lang.isUniv(mk(100)) //│ Bool -//│ Code generation encountered an error: -//│ unresolved symbol Lang +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded :re Lang.isEmpty(mk(100)) //│ Bool -//│ Code generation encountered an error: -//│ unresolved symbol Lang +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded :re Lang.size(Lang.eliminate(mk(100))) //│ Int -//│ Code generation encountered an error: -//│ unresolved symbol Lang +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 69a9ddf860..04dab4e81a 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -76,8 +76,7 @@ IISS : (0 | 1) -> number IISS : 'a -> 'a //│ res: 'a -> 'a //│ where -//│ ['a0, 'a] in {[string, string], [int, int]} -//│ ['a0, 'a0] in {[string, string], [int, int]} +//│ ['a, 'a] in {[string, string], [int, int]} IISS 0 //│ res: int @@ -96,8 +95,8 @@ fun x -> (if true then IISS else BBNN) x //│ ╙── //│ res: 'a -> 'b //│ where -//│ ['a, 'b] in {[string, string], [int, int]} //│ ['a, 'b] in {[bool, bool], [number, number]} +//│ ['a, 'b] in {[string, string], [int, int]} if true then IISS else BBNN //│ res: bool -> bool & number -> number | int -> int & string -> string @@ -111,16 +110,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.112: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.111: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.112: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.111: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.112: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.111: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 5c80a7f25d..fbdb57b4cd 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -174,9 +174,7 @@ f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^ //│ 'a //│ where -//│ 'b :> error //│ ['b, 'a] in {[Bool, Bool], [Int, Int]} -//│ ['b, 'c] in {[Bool, Bool], [Int, Int]} //│ Code generation encountered an error: //│ unresolved symbol refined @@ -232,7 +230,7 @@ type T = List[Int] :e // TODO application types type Res = M(T) //│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 -//│ ║ l.233: type Res = M(T) +//│ ║ l.231: type Res = M(T) //│ ╙── ^^^^ //│ type Res = M @@ -255,7 +253,7 @@ fun f: Int -> Int fun f: Bool -> Bool fun f = id //│ ╔══[ERROR] A type signature for 'f' was already given -//│ ║ l.255: fun f: Bool -> Bool +//│ ║ l.253: fun f: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun f: forall 'a. 'a -> 'a //│ fun f: Int -> Int @@ -263,13 +261,13 @@ fun f = id :e // TODO support f: (Int -> Int) & (Bool -> Bool) //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.264: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.262: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^ //│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.264: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.262: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.254: fun f: Int -> Int +//│ ║ l.252: fun f: Int -> Int //│ ╙── ^^^ //│ Int -> Int & Bool -> Bool //│ res @@ -336,14 +334,14 @@ fun test(x) = refined if x is A then 0 B then 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.335: fun test(x) = refined if x is +//│ ║ l.333: fun test(x) = refined if x is //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.336: A then 0 +//│ ║ l.334: A then 0 //│ ║ ^^^^^^^^^^ -//│ ║ l.337: B then 1 +//│ ║ l.335: B then 1 //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.335: fun test(x) = refined if x is +//│ ║ l.333: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ fun test: (A | B) -> error //│ Code generation encountered an error: @@ -390,7 +388,9 @@ fun w = x => q(x) //│ ['a, 'b] in {[0 | 1, true], [1 | 2, false]} w(0) -//│ nothing +//│ forall 'a. 'a +//│ where +//│ ['b, 'a] in {[0 | 1, true, 0 | 1]} //│ res //│ = //│ w and q are not implemented @@ -403,7 +403,6 @@ x => (f: forall a: ((0, Int) -> 'a & (1, Str) -> ['a])) => f(0, x) + 1 fun r: Int -> Int & Bool -> Bool //│ fun r: Int -> Int & Bool -> Bool -// fixme: multiple occurence :e x => r(r(x)) //│ ╔══[ERROR] ambiguous @@ -412,8 +411,6 @@ x => r(r(x)) //│ where //│ ['c, 'b] in {[Bool, Bool], [Int, Int]} //│ ['a, 'c] in {[Bool, Bool], [Int, Int]} -//│ ['c, 'd] in {[Bool, Bool], [Int, Int]} -//│ ['e, 'c] in {[Bool, Bool], [Int, Int]} //│ res //│ = //│ r is not implemented From a4760d0662d71bfae40f8cff85104db15718b950 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sun, 24 Mar 2024 04:08:43 +0800 Subject: [PATCH 14/43] modify lcg --- .../scala/mlscript/ConstraintSolver.scala | 6 +- .../main/scala/mlscript/TyperDatatypes.scala | 192 ++++++++++-------- shared/src/test/diff/nu/ArrayProg.mls | 12 +- shared/src/test/diff/nu/WeirdUnions.mls | 2 +- 4 files changed, 119 insertions(+), 93 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 35197de041..8201e2d7e5 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -620,8 +620,10 @@ class ConstraintSolver extends NormalForms { self: Typer => rec(b.inner.ub, ar.inner.ub, false) case (LhsRefined(S(b: ArrayBase), ts, r, _), _) => reportError() case (LhsRefined(S(ov: Overload), ts, r, trs), RhsBases(_, S(L(f: FunctionType)), _)) => - val tsc = TupleSetConstraints.mk(ov, f) - if (tsc.constraints.isEmpty) reportError() + TupleSetConstraints.mk(ov, f) match { + case S(tsc) => if (!tsc.tvs.isEmpty && tsc.constraints.isEmpty) reportError() + case N => reportError() + } // val t = TupleSetConstraints.mk(ov) // annoying(Nil, LhsRefined(S(t), ts, r, trs), Nil, done_rs) case (LhsRefined(S(ov: Overload), ts, r, trs), _) => diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 75c76c990f..bdaaf54769 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -651,39 +651,53 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => class TupleSetConstraints(val constraints: MutSet[Ls[ST]], var tvs: Ls[(Opt[Bool], ST)])(val prov: TypeProvenance) { def updateImpl(index: Int, bound: ST)(implicit raise: Raise, ctx: Ctx) : Unit = { - val (_, tvs0, cs) = TupleSetConstraints.lcg(tvs(index)._1, bound, constraints.toList.map(x => S(x(index))))(prov, ctx) - val cs0 = tvs0.zip(cs).map { - case ((_, v: TV), c) => c - case ((S(true), lb), c) => c.map(_.flatMap { ty => - val dnf = DNF.mk(MaxLevel, Nil, lb & ty.neg(), true) - if (dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) - S(ty) - else N - }) - case ((S(false), ub), c) => c.map(_.flatMap { ty => - val dnf = DNF.mk(MaxLevel, Nil, ty & ub.neg(), true) - if (dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) - S(ty) - else N - }) - case ((N, b), c) => c.map(_.flatMap { ty => - val dnf = DNF.mk(MaxLevel, Nil, ty & b.neg(), true) - val dnf0 = DNF.mk(MaxLevel, Nil, b & ty.neg(), true) - if ((dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) - && (dnf0.isBot || dnf0.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty)))) - S(ty) - else N - }) - } - val ncs = constraints.toList.zip(cs0.transpose).map { - case (u, v) => if (v.exists(_.isEmpty)) Nil else u ++ v.flatten + val u = constraints.toList.map(_(index)).map(TupleSetConstraints.lcg(tvs(index)._1, bound, _)(prov, ctx)) + val ncs0 = constraints.toList.zip(u).map { + case (u, v) => if (v.isEmpty) Nil else u }.filter(_.nonEmpty) constraints.clear() - constraints ++= ncs - tvs ++= tvs0 - tvs.zipWithIndex.foreach { - case ((pol, tv: TV), i) => tv.tsc.update(this, i) - case _ => () + constraints ++= ncs0 + if (!constraints.isEmpty) { + val (tvs0, m) = u.flatten + .reduce[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] { + case ((xl, xm), (yl, ym)) => + val l = (xl.filter(ym.contains(_)) ++ yl.filter(xm.contains(_))).distinct + (l, l.map(t => (t, xm(t) ++ ym(t))).toMap) + } + val cs = tvs0.map(m(_)) + val cs0 = tvs0.zip(cs).map { + case ((_, v: TV), c) => c.map(S(_)) + case ((S(true), lb), c) => c.map { ty => + val dnf = DNF.mk(MaxLevel, Nil, lb & ty.neg(), true) + if (dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) + S(ty) + else N + } + case ((S(false), ub), c) => c.map { ty => + val dnf = DNF.mk(MaxLevel, Nil, ty & ub.neg(), true) + if (dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) + S(ty) + else N + } + case ((N, b), c) => c.map { ty => + val dnf = DNF.mk(MaxLevel, Nil, ty & b.neg(), true) + val dnf0 = DNF.mk(MaxLevel, Nil, b & ty.neg(), true) + if ((dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) + && (dnf0.isBot || dnf0.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty)))) + S(ty) + else N + } + } + val ncs = ncs0.zip(cs0.transpose).map { + case (u, v) => if (v.exists(_.isEmpty)) Nil else u ++ v.flatten + }.filter(_.nonEmpty) + constraints.clear() + constraints ++= ncs + tvs ++= tvs0 + tvs.zipWithIndex.foreach { + case ((pol, tv: TV), i) => tv.tsc.update(this, i) + case _ => () + } } } def updateOn(index: Int, bound: ST)(implicit raise: Raise, ctx: Ctx) : Unit = { @@ -704,69 +718,69 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } } object TupleSetConstraints { - def lcgField(pol: Opt[Bool], first: FieldType, rest: Ls[Opt[FieldType]]) + def lcgField(pol: Opt[Bool], first: FieldType, rest: FieldType) (implicit prov: TypeProvenance, ctx: Ctx) - : (FieldType, Ls[(Opt[Bool], ST)], Ls[Ls[Opt[ST]]]) = { - val (ub, tvs, constrs) = lcg(pol, first.ub, rest.map(_.map(_.ub))) - if (first.lb.isEmpty && rest.flatten.forall(_.lb.isEmpty)) { - (FieldType(N, ub)(prov), tvs, constrs) - } else { - val (lb, ltvs, lconstrs) = lcg(pol.map(!_), first.lb.getOrElse(BotType), rest.map(_.map(_.lb.getOrElse(BotType)))) - (FieldType(S(lb), ub)(prov), tvs ++ ltvs, constrs ++ lconstrs) + : Opt[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] = { + for { + (ubl, ubm) <- lcg(pol, first.ub, rest.ub) + (lbl, lbm) <- { + if (first.lb.isEmpty && rest.lb.isEmpty) + S(Nil, Map()) + else + lcg(pol.map(!_), first.lb.getOrElse(BotType), rest.lb.getOrElse(BotType)) + } + } yield { + (ubl ++ lbl, ubm ++ lbm) } } - def lcg(pol: Opt[Bool], first: ST, rest: Ls[Opt[ST]]) + def lcg(pol: Opt[Bool], first: ST, rest: ST) (implicit prov: TypeProvenance, ctx: Ctx) - : (ST, Ls[(Opt[Bool], ST)], Ls[Ls[Opt[ST]]]) = first.unwrapProxies match { - case a: FunctionType => - val (lhss, rhss) = rest.map(_.map(_.unwrapProxies) match { - case S(FunctionType(lhs, rhs)) => S(lhs) -> S(rhs) - case _ => (N, N) - }).unzip - val (lhs, ltvs, lconstrs) = lcg(pol.map(!_), a.lhs, lhss) - val (rhs, rtvs, rconstrs) = lcg(pol, a.rhs, rhss) - (FunctionType(lhs, rhs)(prov), ltvs ++ rtvs, lconstrs ++ rconstrs) - case a: ArrayType => - val inners = rest.map(_.map(_.unwrapProxies) match { - case S(b: ArrayType) => S(b.inner) - case _ => N - }) - val (t, tvs, constrs) = lcgField(pol, a.inner, inners) - (ArrayType(t)(prov), tvs, constrs) - case a: TupleType => - val fields = rest.map(_.map(_.unwrapProxies) match { - case S(TupleType(fs)) if a.fields.sizeCompare(fs.size) === 0 => - fs.map(x => S(x._2)) - case _ => a.fields.map(_ => N) - }) - val (fts, tvss, constrss) = a.fields.map(_._2).zip(fields.transpose).map { case (a, bs) => lcgField(pol, a, bs) }.unzip3 - (TupleType(fts.map(N -> _))(prov), tvss.flatten, constrss.flatten) - case a: TR if rest.flatten.map(_.unwrapProxies).forall { case b: TR => a.defn === b.defn && a.targs.sizeCompare(b.targs.size) === 0; case _ => false } => - val targs = rest.map(_.map(_.unwrapProxies) match { - case S(b: TR) => b.targs.map(S(_)) - case _ => a.targs.map(_ => N) - }) - val (ts, tvss, constrss) = a.targs.zip(targs.transpose).map { case (a, bs) => lcg(pol, a, bs) }.unzip3 - (TypeRef(a.defn, ts)(prov), tvss.flatten, constrss.flatten) - case a: TV if rest.flatten.map(_.unwrapProxies).forall { case b: TV => a.compare(b) === 0; case _ => false } => (a, Nil, Nil) - case a if rest.flatten.forall(_.unwrapProxies === a) => (a, Nil, Nil) - case a => - (a, List((pol, a)), List(rest.map(_.map(_.unwrapProxies)))) - // val tv = freshVar(prov, N) - // (tv, List(tv), List(first :: rest)) + : Opt[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] = (first.unwrapProxies, rest.unwrapProxies) match { + case (a: TV, b: TV) if a.compare(b) === 0 => S(Nil, Map()) + case (a: TV, b) => S(List((pol, a)), Map((pol, a) -> List(b))) + case (a, b: TV) => S(List((pol, a)), Map((pol, a) -> List(b))) + case (a: ComposedType, b) => S(List((pol, a)), Map((pol, a) -> List(b))) + case (a, b: ComposedType) => S(List((pol, a)), Map((pol, a) -> List(b))) + case (a: FT, b: FT) => lcgFunction(pol, a, b) + case (a: FT, b) => N + case (a: ArrayType, b: ArrayType) => + for { (l, m) <- lcgField(pol, a.inner, b.inner) } yield { + (l, m + ((pol, a) -> List(b))) + } + case (a: ArrayType, b) => N + case (a: TupleType, b: TupleType) if a.fields.sizeCompare(b.fields) === 0 => + val fs = a.fields.map(_._2).zip(b.fields.map(_._2)).map(u => lcgField(pol, u._1, u._2)) + if (fs.contains(N)) + N + else { + val (l, m) = fs.flatten.reduce[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] { + case ((xl, xm), (yl, ym)) => (xl ++ yl, xm ++ ym) + } + S(l, m + ((pol, a) -> List(b))) + } + case (a: TupleType, b) => N + case (a, b) if a === b => S(Nil, Map((pol, a) -> List(b))) + case (a, b) => S(List((pol, a)), Map((pol, a) -> List(b))) } - def lcgFunction(pol: Opt[Bool], first: FT, rest: Ls[FunctionType])(implicit prov: TypeProvenance, ctx: Ctx) - : (FT, Ls[(Opt[Bool], ST)], Ls[Ls[Opt[ST]]]) = { - val (lhss, rhss) = rest.map { - case FunctionType(lhs, rhs) => S(lhs) -> S(rhs) - }.unzip - val (lhs, ltvs, lconstrs) = lcg(pol.map(!_), first.lhs, lhss) - val (rhs, rtvs, rconstrs) = lcg(pol, first.rhs, rhss) - (FunctionType(lhs, rhs)(prov), ltvs ++ rtvs, lconstrs ++ rconstrs) + def lcgFunction(pol: Opt[Bool], first: FT, rest: FT) + (implicit prov: TypeProvenance, ctx: Ctx) + : Opt[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] = { + for { + (ll, lm) <- lcg(pol.map(!_), first.lhs, rest.lhs) + (rl, rm) <- lcg(pol, first.rhs, rest.rhs) + } yield { + (ll ++ rl,lm ++ rm + ((pol, first) -> List(rest))) + } } - def mk(ov: Overload, f: FT)(implicit raise: Raise, ctx: Ctx): TupleSetConstraints = { - val (t, tvs, constrs) = lcgFunction(S(false), f, ov.alts)(ov.prov, ctx) - val tsc = new TupleSetConstraints(MutSet.empty ++ constrs.transpose.filter(_.forall(_.isDefined)).map(_.flatten), tvs)(ov.prov) + def mk(ov: Overload, f: FT)(implicit raise: Raise, ctx: Ctx): Opt[TupleSetConstraints] = { + val u = ov.alts.map(lcgFunction(S(false), f, _)(ov.prov, ctx)).flatten + if (u.isEmpty) { return N } + val (tvs, m) = u.reduce[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] { + case ((xl, xm), (yl, ym)) => + val l = (xl.filter(ym.contains(_)) ++ yl.filter(xm.contains(_))).distinct + (l, l.map(t => (t, xm(t) ++ ym(t))).toMap) + } + val tsc = new TupleSetConstraints(MutSet.empty ++ tvs.map(m(_)).transpose, tvs)(ov.prov) println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") tvs.zipWithIndex.foreach { case ((pol, tv: TV), i) => tv.tsc.update(tsc, i) @@ -784,7 +798,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } } println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") - tsc + S(tsc) } } } diff --git a/shared/src/test/diff/nu/ArrayProg.mls b/shared/src/test/diff/nu/ArrayProg.mls index 92d2ae5599..66d7371294 100644 --- a/shared/src/test/diff/nu/ArrayProg.mls +++ b/shared/src/test/diff/nu/ArrayProg.mls @@ -169,8 +169,18 @@ A.g(0) :AllowTypeErrors +:e s([Numbr(0),Numbr(0)]) -//│ Int +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.+1: s([Numbr(0),Numbr(0)]) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `(Numbr | Vectr, Numbr | Vectr) -> Int` is not a function +//│ ║ l.136: fun s: ([Numbr,Numbr] -> Int) & ([Vectr,Vectr] -> Int) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `([?a, ?b]) -> ?c` +//│ ║ l.+1: s([Numbr(0),Numbr(0)]) +//│ ╙── ^ +//│ error // g <: 0 -> 'a :e diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index 6167f9535b..4fb2f775e2 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -61,7 +61,7 @@ f("abc", "abc") //│ 'a //│ where //│ 'a :> error -//│ ["abc", "abc", 'a, "abc", "abc"] in {} +//│ ["abc", "abc", 'a, "abc"] in {} //│ res //│ = //│ f is not implemented From 9f84c57880abedd1edf7753adc03a73f634ca722 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sun, 24 Mar 2024 17:18:14 +0800 Subject: [PATCH 15/43] print pol --- .../src/main/scala/mlscript/TyperHelpers.scala | 2 +- shared/src/main/scala/mlscript/helpers.scala | 8 ++++++-- shared/src/test/diff/fcp/Overloads.mls | 6 +++--- shared/src/test/diff/nu/HeungTung.mls | 18 +++++++++--------- shared/src/test/diff/nu/WeirdUnions.mls | 2 +- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 4b24e0ebc6..41bdf61795 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -965,7 +965,7 @@ abstract class TyperHelpers { Typer: Typer => getVars.iterator.flatMap(_.tsc).map { case (tsc, i) => if (visited.add(tsc)) ("\n\t\t[ " - + tsc.tvs.mkString(", ") + + tsc.tvs.map(t => s"${printPol(t._1)}${t._2}").mkString(", ") + " ] in { " + tsc.constraints.mkString(", ") + " }") else "" }.mkString diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index c59bee3829..c2f9ecf98f 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -1,5 +1,4 @@ package mlscript - import scala.util.chaining._ import scala.collection.mutable.{Map => MutMap, SortedMap => SortedMutMap, Set => MutSet, Buffer} @@ -139,7 +138,12 @@ trait TypeLikeImpl extends Located { self: TypeLike => }.mkString }${tscs.map{ case (tvs, constrs) => - s"\n${ctx.indStr}${tvs.map(_._2.showIn(ctx, 0)).mkString("[", ", ", "]")}" + + val s = tvs.map { + case (S(true), t) => "+" ++ t.showIn(ctx, 0) + case (S(false), t) => "-" ++ t.showIn(ctx, 0) + case (N, t) => "=" ++ t.showIn(ctx, 0) + }.mkString("[", ", ", "]") + s"\n${ctx.indStr}" + s + s" in ${constrs.map(_.map(_.showIn(ctx, 0)).mkString("[", ", ", "]")).mkString("{", ", ", "}")}" }.mkString}" }, outerPrec > 0) diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 04dab4e81a..d7c0f00df5 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -76,7 +76,7 @@ IISS : (0 | 1) -> number IISS : 'a -> 'a //│ res: 'a -> 'a //│ where -//│ ['a, 'a] in {[string, string], [int, int]} +//│ [+'a, -'a] in {[string, string], [int, int]} IISS 0 //│ res: int @@ -95,8 +95,8 @@ fun x -> (if true then IISS else BBNN) x //│ ╙── //│ res: 'a -> 'b //│ where -//│ ['a, 'b] in {[bool, bool], [number, number]} -//│ ['a, 'b] in {[string, string], [int, int]} +//│ [+'a, -'b] in {[bool, bool], [number, number]} +//│ [+'a, -'b] in {[string, string], [int, int]} if true then IISS else BBNN //│ res: bool -> bool & number -> number | int -> int & string -> string diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index fbdb57b4cd..b419136fb2 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -137,7 +137,7 @@ f(0) x => f(x) //│ forall 'a 'b. 'a -> 'b //│ where -//│ ['a, 'b] in {[Bool, Bool], [Int, Int]} +//│ [+'a, -'b] in {[Bool, Bool], [Int, Int]} //│ res //│ = [Function: res] @@ -157,7 +157,7 @@ f(if true then 0 else false) //│ 'a //│ where //│ 'a :> error -//│ [0 | false, 'a, 0 | false] in {} +//│ [+0 | false, -'a, +0 | false] in {} //│ res //│ = 0 @@ -174,7 +174,7 @@ f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^ //│ 'a //│ where -//│ ['b, 'a] in {[Bool, Bool], [Int, Int]} +//│ [+'b, -'a] in {[Bool, Bool], [Int, Int]} //│ Code generation encountered an error: //│ unresolved symbol refined @@ -363,7 +363,7 @@ q(0) q(1) //│ 'a //│ where -//│ [1, 'a, 1] in {[1 | 2, false, 1 | 2], [0 | 1, true, 0 | 1]} +//│ [+1, -'a, +1] in {[1 | 2, false, 1 | 2], [0 | 1, true, 0 | 1]} //│ res //│ = //│ q is not implemented @@ -377,7 +377,7 @@ x => q(x): true x => q(x) //│ forall 'a 'b. 'a -> 'b //│ where -//│ ['a, 'b] in {[0 | 1, true], [1 | 2, false]} +//│ [+'a, -'b] in {[0 | 1, true], [1 | 2, false]} //│ res //│ = //│ q is not implemented @@ -385,12 +385,12 @@ x => q(x) fun w = x => q(x) //│ fun w: forall 'a 'b. 'a -> 'b //│ where -//│ ['a, 'b] in {[0 | 1, true], [1 | 2, false]} +//│ [+'a, -'b] in {[0 | 1, true], [1 | 2, false]} w(0) //│ forall 'a. 'a //│ where -//│ ['b, 'a] in {[0 | 1, true, 0 | 1]} +//│ [+'b, -'a] in {[0 | 1, true, 0 | 1]} //│ res //│ = //│ w and q are not implemented @@ -409,8 +409,8 @@ x => r(r(x)) //│ ╙── //│ forall 'a 'b. 'a -> 'b //│ where -//│ ['c, 'b] in {[Bool, Bool], [Int, Int]} -//│ ['a, 'c] in {[Bool, Bool], [Int, Int]} +//│ [+'c, -'b] in {[Bool, Bool], [Int, Int]} +//│ [+'a, -'c] in {[Bool, Bool], [Int, Int]} //│ res //│ = //│ r is not implemented diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index 4fb2f775e2..717532b622 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -61,7 +61,7 @@ f("abc", "abc") //│ 'a //│ where //│ 'a :> error -//│ ["abc", "abc", 'a, "abc"] in {} +//│ [+"abc", +"abc", -'a, +"abc"] in {} //│ res //│ = //│ f is not implemented From e759d2928de20d36b749f6f5ea09d9fba51eaedb Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sun, 24 Mar 2024 23:48:12 +0800 Subject: [PATCH 16/43] add lcg record --- .../main/scala/mlscript/TyperDatatypes.scala | 20 +++++++++++++++---- shared/src/test/diff/nu/HeungTung.mls | 17 ++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index bdaaf54769..07056965f3 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -675,6 +675,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } case ((S(false), ub), c) => c.map { ty => val dnf = DNF.mk(MaxLevel, Nil, ty & ub.neg(), true) + println(s"tag0: $ub, $ty, $dnf") if (dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) S(ty) else N @@ -750,15 +751,26 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => case (a: ArrayType, b) => N case (a: TupleType, b: TupleType) if a.fields.sizeCompare(b.fields) === 0 => val fs = a.fields.map(_._2).zip(b.fields.map(_._2)).map(u => lcgField(pol, u._1, u._2)) - if (fs.contains(N)) - N - else { + if (!fs.contains(N)) { val (l, m) = fs.flatten.reduce[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] { case ((xl, xm), (yl, ym)) => (xl ++ yl, xm ++ ym) } S(l, m + ((pol, a) -> List(b))) - } + } else N case (a: TupleType, b) => N + case (a: RecordType, b: RecordType) if pol.isDefined => + val default = FieldType(N, if (pol === S(true)) TopType else BotType)(prov) + if (b.fields.map(_._1).forall(a.fields.map(_._1).contains)) { + val u = a.fields.map { + case (v, f) => lcgField(pol, f, b.fields.find(_._1 === v).fold(default)(_._2)) + } + if (!u.contains(N)) { + val (l, m) = u.flatten.reduce[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] { + case ((xl, xm), (yl, ym)) => (xl ++ yl, xm ++ ym) + } + S(l, m + ((pol, a) -> List(b))) + } else N + } else N case (a, b) if a === b => S(Nil, Map((pol, a) -> List(b))) case (a, b) => S(List((pol, a)), Map((pol, a) -> List(b))) } diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index b419136fb2..d132648b56 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -414,3 +414,20 @@ x => r(r(x)) //│ res //│ = //│ r is not implemented + +fun u: {x:0, y:Int} -> Int & {x:1, z: Str} -> Str +//│ fun u: {x: 0, y: Int} -> Int & {x: 1, z: Str} -> Str + +(a, b, c) => u({x: a, y: b, z: c}) +//│ forall 'a 'b 'c 'd. ('a, 'b, 'c) -> 'd +//│ where +//│ [+'a, +'b, +'c, -'d] in {[0, Int, anything, Int], [1, anything, Str, Str]} +//│ res +//│ = +//│ u is not implemented + +(a, b) => u({x: a, y: "abc", z: b}) +//│ (1, Str) -> Str +//│ res +//│ = +//│ u is not implemented From 6f7f30c556ee1b24564baa01ce074d43789dbe5f Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 25 Mar 2024 17:06:24 +0800 Subject: [PATCH 17/43] Changes from meeting --- shared/src/test/diff/fcp/Overloads.mls | 57 ++++++++++++++++++++++---- shared/src/test/diff/nu/HeungTung.mls | 12 ++++++ 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index d7c0f00df5..146d2ad6e2 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -87,17 +87,60 @@ IISS 0 (if true then IISS else BBNN) 0 //│ res: number -// * TODO: update type simplifier -// fixme +// * TODO: should we still allow this? And maybe reduce it +// * Conceptually we'd expect it to reduce to `int -> number` +// * But it's tricky to do the actual reduction since technically +// * 'a = Bot anf 'b = Top could satisfy all tuple alternatives :e -fun x -> (if true then IISS else BBNN) x +def f = fun x -> (if true then IISS else BBNN) x //│ ╔══[ERROR] ambiguous //│ ╙── -//│ res: 'a -> 'b +//│ f: 'a -> 'b //│ where //│ [+'a, -'b] in {[bool, bool], [number, number]} //│ [+'a, -'b] in {[string, string], [int, int]} +// * Q: why 3 elements in the tuple? +f(0) +//│ res: 'a +//│ where +//│ [+'b, -'a] in {[number, number, number]} +//│ [+'b, -'a] in {[int, int, int]} + +// FIXME +f(0) + 1 +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.111: f(0) + 1 +//│ ║ ^^^^^^ +//│ ╟── application of type `?a` does not match type `int` +//│ ║ l.95: def f = fun x -> (if true then IISS else BBNN) x +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into application with expected type `int` +//│ ║ l.111: f(0) + 1 +//│ ╙── ^^^^ +//│ res: error | int + +// FIXME +f : int -> number +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.124: f : int -> number +//│ ║ ^ +//│ ╟── type `int` does not match type `?a` +//│ ║ l.124: f : int -> number +//│ ╙── ^^^ +//│ res: int -> number + +:e +f : number -> int +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.134: f : number -> int +//│ ║ ^ +//│ ╟── type `number` does not match type `?a` +//│ ║ l.134: f : number -> int +//│ ╙── ^^^^^^ +//│ res: number -> int + + if true then IISS else BBNN //│ res: bool -> bool & number -> number | int -> int & string -> string @@ -110,16 +153,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.111: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.154: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.111: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.154: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.111: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.154: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index d132648b56..6495e3b504 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -360,6 +360,12 @@ q(0) //│ = //│ q is not implemented +q(0) : true +//│ true +//│ res +//│ = +//│ q is not implemented + q(1) //│ 'a //│ where @@ -368,6 +374,12 @@ q(1) //│ = //│ q is not implemented +q(1) : Bool +//│ Bool +//│ res +//│ = +//│ q is not implemented + x => q(x): true //│ (0 | 1) -> true //│ res From 420bd5607dd5453e91ab27735b440d2508af5a20 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sat, 30 Mar 2024 00:48:36 +0800 Subject: [PATCH 18/43] fix tsc tuple size mismatch --- shared/src/main/scala/mlscript/Typer.scala | 4 ++-- .../main/scala/mlscript/TyperDatatypes.scala | 15 ++++++------- shared/src/test/diff/fcp/Overloads.mls | 21 +++++++++++-------- shared/src/test/diff/nu/HeungTung.mls | 13 ++++++------ 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 7cb5ddb688..dc46d121d5 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -599,7 +599,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne } tscs.foreach { case (typevars, constrs) => val tvs = typevars.map(x => (x._1, rec(x._2))) - val tsc = new TupleSetConstraints(MutSet.empty ++ constrs.map(_.map(rec)), tvs)(res.prov) + val tsc = new TupleSetConstraints(constrs.map(_.map(rec)), tvs)(res.prov) tvs.zipWithIndex.foreach { case ((_, tv: TV), i) => tv.tsc += tsc -> i case _ => () @@ -1806,7 +1806,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne case (pol, tv: TV) => (pol, tv.asTypeVar) case (pol, t) => (pol, go(t)) } - val constrs = tsc.constraints.toList.map(_.map(go)) + val constrs = tsc.constraints.map(_.map(go)) tscs ::= tvs -> constrs } } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 07056965f3..1cf14f63ca 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -649,15 +649,13 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => val prov = noProv } - class TupleSetConstraints(val constraints: MutSet[Ls[ST]], var tvs: Ls[(Opt[Bool], ST)])(val prov: TypeProvenance) { + class TupleSetConstraints(var constraints: Ls[Ls[ST]], var tvs: Ls[(Opt[Bool], ST)])(val prov: TypeProvenance) { def updateImpl(index: Int, bound: ST)(implicit raise: Raise, ctx: Ctx) : Unit = { - val u = constraints.toList.map(_(index)).map(TupleSetConstraints.lcg(tvs(index)._1, bound, _)(prov, ctx)) - val ncs0 = constraints.toList.zip(u).map { + val u = constraints.map(_(index)).map(TupleSetConstraints.lcg(tvs(index)._1, bound, _)(prov, ctx)) + val ncs0 = constraints.zip(u).map { case (u, v) => if (v.isEmpty) Nil else u }.filter(_.nonEmpty) - constraints.clear() - constraints ++= ncs0 - if (!constraints.isEmpty) { + if (!ncs0.isEmpty) { val (tvs0, m) = u.flatten .reduce[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] { case ((xl, xm), (yl, ym)) => @@ -692,8 +690,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => val ncs = ncs0.zip(cs0.transpose).map { case (u, v) => if (v.exists(_.isEmpty)) Nil else u ++ v.flatten }.filter(_.nonEmpty) - constraints.clear() - constraints ++= ncs + constraints = ncs tvs ++= tvs0 tvs.zipWithIndex.foreach { case ((pol, tv: TV), i) => tv.tsc.update(this, i) @@ -792,7 +789,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => val l = (xl.filter(ym.contains(_)) ++ yl.filter(xm.contains(_))).distinct (l, l.map(t => (t, xm(t) ++ ym(t))).toMap) } - val tsc = new TupleSetConstraints(MutSet.empty ++ tvs.map(m(_)).transpose, tvs)(ov.prov) + val tsc = new TupleSetConstraints(tvs.map(m(_)).transpose, tvs)(ov.prov) println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") tvs.zipWithIndex.foreach { case ((pol, tv: TV), i) => tv.tsc.update(tsc, i) diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 146d2ad6e2..0555808888 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -76,7 +76,7 @@ IISS : (0 | 1) -> number IISS : 'a -> 'a //│ res: 'a -> 'a //│ where -//│ [+'a, -'a] in {[string, string], [int, int]} +//│ [+'a, -'a] in {[int, int], [string, string]} IISS 0 //│ res: int @@ -98,14 +98,14 @@ def f = fun x -> (if true then IISS else BBNN) x //│ f: 'a -> 'b //│ where //│ [+'a, -'b] in {[bool, bool], [number, number]} -//│ [+'a, -'b] in {[string, string], [int, int]} +//│ [+'a, -'b] in {[int, int], [string, string]} // * Q: why 3 elements in the tuple? f(0) //│ res: 'a //│ where -//│ [+'b, -'a] in {[number, number, number]} -//│ [+'b, -'a] in {[int, int, int]} +//│ [+'b, -'a] in {[bool, bool], [number, number]} +//│ [+'b, -'a] in {[int, int], [string, string]} // FIXME f(0) + 1 @@ -135,9 +135,12 @@ f : number -> int //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.134: f : number -> int //│ ║ ^ -//│ ╟── type `number` does not match type `?a` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.134: f : number -> int -//│ ╙── ^^^^^^ +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.12: def IISS: int -> int & string -> string +//│ ╙── ^^^ //│ res: number -> int @@ -153,16 +156,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.154: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.157: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.154: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.157: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.154: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.157: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 6495e3b504..c9cbfdb6c5 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -137,7 +137,7 @@ f(0) x => f(x) //│ forall 'a 'b. 'a -> 'b //│ where -//│ [+'a, -'b] in {[Bool, Bool], [Int, Int]} +//│ [+'a, -'b] in {[Int, Int], [Bool, Bool]} //│ res //│ = [Function: res] @@ -174,7 +174,7 @@ f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^ //│ 'a //│ where -//│ [+'b, -'a] in {[Bool, Bool], [Int, Int]} +//│ [+'b, -'a] in {[Int, Int], [Bool, Bool]} //│ Code generation encountered an error: //│ unresolved symbol refined @@ -369,7 +369,7 @@ q(0) : true q(1) //│ 'a //│ where -//│ [+1, -'a, +1] in {[1 | 2, false, 1 | 2], [0 | 1, true, 0 | 1]} +//│ [+1, -'a, +1] in {[0 | 1, true, 0 | 1], [1 | 2, false, 1 | 2]} //│ res //│ = //│ q is not implemented @@ -399,10 +399,11 @@ fun w = x => q(x) //│ where //│ [+'a, -'b] in {[0 | 1, true], [1 | 2, false]} +// FIXME w(0) //│ forall 'a. 'a //│ where -//│ [+'b, -'a] in {[0 | 1, true, 0 | 1]} +//│ [+'b, -'a] in {[0 | 1, true], [1 | 2, false]} //│ res //│ = //│ w and q are not implemented @@ -421,8 +422,8 @@ x => r(r(x)) //│ ╙── //│ forall 'a 'b. 'a -> 'b //│ where -//│ [+'c, -'b] in {[Bool, Bool], [Int, Int]} -//│ [+'a, -'c] in {[Bool, Bool], [Int, Int]} +//│ [+'c, -'b] in {[Int, Int], [Bool, Bool]} +//│ [+'a, -'c] in {[Int, Int], [Bool, Bool]} //│ res //│ = //│ r is not implemented From e14560f5bff65df2b4201a2bda71cb3cd6ae890f Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Tue, 23 Apr 2024 02:50:12 +0800 Subject: [PATCH 19/43] modify lcg and update tests --- .../scala/mlscript/ConstraintSolver.scala | 26 ++-- shared/src/main/scala/mlscript/Typer.scala | 4 +- .../main/scala/mlscript/TyperDatatypes.scala | 119 +++++++----------- shared/src/main/scala/mlscript/helpers.scala | 7 +- shared/src/main/scala/mlscript/syntax.scala | 2 +- .../diff/ecoop23/SimpleRegionDSL_annot.mls | 2 +- shared/src/test/diff/fcp/Overloads.mls | 40 +++--- shared/src/test/diff/nu/HeungTung.mls | 80 +++++++++--- shared/src/test/diff/nu/WeirdUnions.mls | 17 ++- 9 files changed, 157 insertions(+), 140 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 8201e2d7e5..bcae8827f8 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -1568,14 +1568,24 @@ class ConstraintSolver extends NormalForms { self: Typer => freshened += tv -> v v.lowerBounds = tv.lowerBounds.mapConserve(freshen) v.upperBounds = tv.upperBounds.mapConserve(freshen) - v.tsc ++= tv.tsc.map { case (tsc, i) => freshenedTsc.get(tsc) match { - case S(tsc) => (tsc, i) - case N => - val t = new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov) - freshenedTsc += tsc -> t - t.tvs = t.tvs.map(x => (x._1, freshen(x._2))) - (t, i) - }} + tv.tsc.foreachEntry { + case (tsc, i) => + val t = freshenedTsc.get(tsc) match { + case S(tsc) => tsc + case N => + val t = new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov) + freshenedTsc += tsc -> t + t + } + t.tvs = t.tvs.zipWithIndex.map { + case ((p, tv: TV), j) if j == i => tv.tsc.remove(t); (p, v) + case (u, _) => u + } + t.tvs.zipWithIndex.foreach { + case ((_, tv: TV), i) => tv.tsc.update(t, i) + case _ => () + } + } v } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index dc46d121d5..089ae614fc 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1688,7 +1688,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne val expandType = () var bounds: Ls[TypeVar -> Bounds] = Nil - var tscs: Ls[Ls[(Opt[Bool], Type)] -> Ls[Ls[Type]]] = Nil + var tscs: Ls[Ls[(Bool, Type)] -> Ls[Ls[Type]]] = Nil val seenVars = mutable.Set.empty[TV] val seenTscs = mutable.Set.empty[TupleSetConstraints] @@ -1872,7 +1872,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne val ftvs = b.freeTypeVariables ++ newBounds.iterator.map(_._1) ++ newBounds.iterator.flatMap(_._2.freeTypeVariables) ++ - newTscs.iterator.flatMap(_._1) + newTscs.iterator.flatMap(_._1.map(_._2)) val fvars = qvars.filter(tv => ftvs.contains(tv.asTypeVar)) if (fvars.isEmpty) b else PolyType(fvars.map(_.asTypeVar pipe (R(_))).toList, b) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 1cf14f63ca..764cdd9797 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -649,52 +649,26 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => val prov = noProv } - class TupleSetConstraints(var constraints: Ls[Ls[ST]], var tvs: Ls[(Opt[Bool], ST)])(val prov: TypeProvenance) { + class TupleSetConstraints(var constraints: Ls[Ls[ST]], var tvs: Ls[(Bool, ST)])(val prov: TypeProvenance) { def updateImpl(index: Int, bound: ST)(implicit raise: Raise, ctx: Ctx) : Unit = { - val u = constraints.map(_(index)).map(TupleSetConstraints.lcg(tvs(index)._1, bound, _)(prov, ctx)) - val ncs0 = constraints.zip(u).map { - case (u, v) => if (v.isEmpty) Nil else u - }.filter(_.nonEmpty) - if (!ncs0.isEmpty) { - val (tvs0, m) = u.flatten - .reduce[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] { - case ((xl, xm), (yl, ym)) => - val l = (xl.filter(ym.contains(_)) ++ yl.filter(xm.contains(_))).distinct - (l, l.map(t => (t, xm(t) ++ ym(t))).toMap) - } - val cs = tvs0.map(m(_)) - val cs0 = tvs0.zip(cs).map { - case ((_, v: TV), c) => c.map(S(_)) - case ((S(true), lb), c) => c.map { ty => - val dnf = DNF.mk(MaxLevel, Nil, lb & ty.neg(), true) - if (dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) - S(ty) - else N - } - case ((S(false), ub), c) => c.map { ty => - val dnf = DNF.mk(MaxLevel, Nil, ty & ub.neg(), true) - println(s"tag0: $ub, $ty, $dnf") - if (dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) - S(ty) - else N - } - case ((N, b), c) => c.map { ty => - val dnf = DNF.mk(MaxLevel, Nil, ty & b.neg(), true) - val dnf0 = DNF.mk(MaxLevel, Nil, b & ty.neg(), true) - if ((dnf.isBot || dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) - && (dnf0.isBot || dnf0.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty)))) - S(ty) - else N - } + val (cs0, u) = constraints.flatMap { c => + TupleSetConstraints.lcg(tvs(index)._1, bound, c(index))(prov, ctx).map(u => (c, u)) + }.unzip + constraints = cs0 + if (!u.isEmpty) { + val (tvs0, m) = u.reduce[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] { + case ((xl, xm), (yl, ym)) => + val l = (xl.filter(ym.contains(_)) ++ yl.filter(xm.contains(_))).distinct + (l, l.map(t => (t, xm(t) ++ ym(t))).toMap) } - val ncs = ncs0.zip(cs0.transpose).map { - case (u, v) => if (v.exists(_.isEmpty)) Nil else u ++ v.flatten - }.filter(_.nonEmpty) - constraints = ncs - tvs ++= tvs0 - tvs.zipWithIndex.foreach { - case ((pol, tv: TV), i) => tv.tsc.update(this, i) - case _ => () + if (!tvs0.isEmpty) { + val ncs = cs0.zip(tvs0.map(m(_)).transpose).map { case (u, v) => u ++ v } + constraints = ncs + tvs ++= tvs0 + tvs.zipWithIndex.foreach { + case ((pol, tv: TV), i) => tv.tsc.update(this, i) + case _ => () + } } } } @@ -704,109 +678,110 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => println(s"TSC update: $tvs in $constraints") if (constraints.sizeCompare(1) === 0) { tvs.foreach { - case (pol, tv: TV) => tv.tsc.clear() + case (pol, tv: TV) => tv.tsc.remove(this) case _ => () } constraints.head.zip(tvs).foreach { case (c, (pol, t)) => - if (pol =/= S(true)) constrain(c, t)(raise, prov, ctx) - if (pol =/= S(false)) constrain(t, c)(raise, prov, ctx) + if (!pol) constrain(c, t)(raise, prov, ctx) + if (pol) constrain(t, c)(raise, prov, ctx) } } } } object TupleSetConstraints { - def lcgField(pol: Opt[Bool], first: FieldType, rest: FieldType) + def lcgField(pol: Bool, first: FieldType, rest: FieldType) (implicit prov: TypeProvenance, ctx: Ctx) - : Opt[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] = { + : Opt[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] = { for { (ubl, ubm) <- lcg(pol, first.ub, rest.ub) (lbl, lbm) <- { if (first.lb.isEmpty && rest.lb.isEmpty) S(Nil, Map()) else - lcg(pol.map(!_), first.lb.getOrElse(BotType), rest.lb.getOrElse(BotType)) + lcg(!pol, first.lb.getOrElse(BotType), rest.lb.getOrElse(BotType)) } } yield { (ubl ++ lbl, ubm ++ lbm) } } - def lcg(pol: Opt[Bool], first: ST, rest: ST) + def lcg(pol: Bool, first: ST, rest: ST) (implicit prov: TypeProvenance, ctx: Ctx) - : Opt[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] = (first.unwrapProxies, rest.unwrapProxies) match { + : Opt[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] = (first.unwrapProxies, rest.unwrapProxies) match { case (a: TV, b: TV) if a.compare(b) === 0 => S(Nil, Map()) case (a: TV, b) => S(List((pol, a)), Map((pol, a) -> List(b))) case (a, b: TV) => S(List((pol, a)), Map((pol, a) -> List(b))) - case (a: ComposedType, b) => S(List((pol, a)), Map((pol, a) -> List(b))) - case (a, b: ComposedType) => S(List((pol, a)), Map((pol, a) -> List(b))) case (a: FT, b: FT) => lcgFunction(pol, a, b) case (a: FT, b) => N case (a: ArrayType, b: ArrayType) => for { (l, m) <- lcgField(pol, a.inner, b.inner) } yield { (l, m + ((pol, a) -> List(b))) } - case (a: ArrayType, b) => N case (a: TupleType, b: TupleType) if a.fields.sizeCompare(b.fields) === 0 => val fs = a.fields.map(_._2).zip(b.fields.map(_._2)).map(u => lcgField(pol, u._1, u._2)) if (!fs.contains(N)) { - val (l, m) = fs.flatten.reduce[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] { + val (l, m) = fs.flatten.reduce[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] { case ((xl, xm), (yl, ym)) => (xl ++ yl, xm ++ ym) } S(l, m + ((pol, a) -> List(b))) } else N - case (a: TupleType, b) => N - case (a: RecordType, b: RecordType) if pol.isDefined => - val default = FieldType(N, if (pol === S(true)) TopType else BotType)(prov) + case (a: RecordType, b: RecordType) => + val default = FieldType(N, if (pol) TopType else BotType)(prov) if (b.fields.map(_._1).forall(a.fields.map(_._1).contains)) { val u = a.fields.map { case (v, f) => lcgField(pol, f, b.fields.find(_._1 === v).fold(default)(_._2)) } if (!u.contains(N)) { - val (l, m) = u.flatten.reduce[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] { + val (l, m) = u.flatten.reduce[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] { case ((xl, xm), (yl, ym)) => (xl ++ yl, xm ++ ym) } S(l, m + ((pol, a) -> List(b))) } else N } else N case (a, b) if a === b => S(Nil, Map((pol, a) -> List(b))) - case (a, b) => S(List((pol, a)), Map((pol, a) -> List(b))) + case (a, b) => + val dnf = DNF.mk(MaxLevel, Nil, if (pol) a & b.neg() else b & a.neg(), true) + if (dnf.isBot) + S(Nil, Map((pol, a) -> List(b))) + else if (dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) + S(List((pol, a)), Map((pol, a) -> List(b))) + else N } - def lcgFunction(pol: Opt[Bool], first: FT, rest: FT) + def lcgFunction(pol: Bool, first: FT, rest: FT) (implicit prov: TypeProvenance, ctx: Ctx) - : Opt[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] = { + : Opt[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] = { for { - (ll, lm) <- lcg(pol.map(!_), first.lhs, rest.lhs) + (ll, lm) <- lcg(!pol, first.lhs, rest.lhs) (rl, rm) <- lcg(pol, first.rhs, rest.rhs) } yield { (ll ++ rl,lm ++ rm + ((pol, first) -> List(rest))) } } def mk(ov: Overload, f: FT)(implicit raise: Raise, ctx: Ctx): Opt[TupleSetConstraints] = { - val u = ov.alts.map(lcgFunction(S(false), f, _)(ov.prov, ctx)).flatten + val u = ov.alts.map(lcgFunction(false, f, _)(ov.prov, ctx)).flatten if (u.isEmpty) { return N } - val (tvs, m) = u.reduce[(Ls[(Opt[Bool], ST)], Map[(Opt[Bool], ST), Ls[ST]])] { + val (tvs, m) = u.reduce[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] { case ((xl, xm), (yl, ym)) => val l = (xl.filter(ym.contains(_)) ++ yl.filter(xm.contains(_))).distinct (l, l.map(t => (t, xm(t) ++ ym(t))).toMap) } val tsc = new TupleSetConstraints(tvs.map(m(_)).transpose, tvs)(ov.prov) - println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") tvs.zipWithIndex.foreach { case ((pol, tv: TV), i) => tv.tsc.update(tsc, i) - case ((_, ty), i) => tsc.updateImpl(i, ty) + case _ => () } + println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") if (tsc.constraints.sizeCompare(1) === 0) { tvs.foreach { - case (pol, tv: TV) => tv.tsc.clear() + case (_, tv: TV) => tv.tsc.remove(tsc) case _ => () } tsc.constraints.head.zip(tvs).foreach { case (c, (pol, t)) => - if (pol =/= S(true)) constrain(c, t)(raise, ov.prov, ctx) - if (pol =/= S(false)) constrain(t, c)(raise, ov.prov, ctx) + if (!pol) constrain(c, t)(raise, ov.prov, ctx) + if (pol) constrain(t, c)(raise, ov.prov, ctx) } } - println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") S(tsc) } } diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index c2f9ecf98f..b7aa326af2 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -138,11 +138,8 @@ trait TypeLikeImpl extends Located { self: TypeLike => }.mkString }${tscs.map{ case (tvs, constrs) => - val s = tvs.map { - case (S(true), t) => "+" ++ t.showIn(ctx, 0) - case (S(false), t) => "-" ++ t.showIn(ctx, 0) - case (N, t) => "=" ++ t.showIn(ctx, 0) - }.mkString("[", ", ", "]") + val s = tvs.map(u => (if (u._1) "+" else "-") ++ u._2.showIn(ctx, 0)) + .mkString("[", ", ", "]") s"\n${ctx.indStr}" + s + s" in ${constrs.map(_.map(_.showIn(ctx, 0)).mkString("[", ", ", "]")).mkString("{", ", ", "}")}" }.mkString}" diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 767727ea47..dbc8e7a6de 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -156,7 +156,7 @@ final case class Rem(base: Type, names: Ls[Var]) extends Type final case class Bounds(lb: Type, ub: Type) extends Type final case class WithExtension(base: Type, rcd: Record) extends Type final case class Splice(fields: Ls[Either[Type, Field]]) extends Type -final case class Constrained(base: TypeLike, tvBounds: Ls[TypeVar -> Bounds], where: Ls[Bounds], tscs: Ls[Ls[(Opt[Bool], Type)] -> Ls[Ls[Type]]]) extends Type +final case class Constrained(base: TypeLike, tvBounds: Ls[TypeVar -> Bounds], where: Ls[Bounds], tscs: Ls[Ls[(Bool, Type)] -> Ls[Ls[Type]]]) extends Type // final case class FirstClassDefn(defn: NuTypeDef) extends Type // TODO // final case class Refinement(base: Type, decls: TypingUnit) extends Type // TODO diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls index c634f7c8dc..ae9192d9df 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls @@ -348,7 +348,7 @@ fun mk(n) = if n is _ then Scale(Vector(0, 0), mk(n)) //│ fun mk: forall 'a. Object -> 'a //│ where -//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] +//│ 'a :> Outside['a] | Translate['a] | Scale['a] | Union['a] | Intersect['a] :re TestElim.eliminate(mk(100)) diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 0555808888..143c41f2f3 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -100,43 +100,41 @@ def f = fun x -> (if true then IISS else BBNN) x //│ [+'a, -'b] in {[bool, bool], [number, number]} //│ [+'a, -'b] in {[int, int], [string, string]} -// * Q: why 3 elements in the tuple? +// FIXME f(0) -//│ res: 'a -//│ where -//│ [+'b, -'a] in {[bool, bool], [number, number]} -//│ [+'b, -'a] in {[int, int], [string, string]} +//│ ╔══[ERROR] Type mismatch in function type: +//│ ║ l.13: def BBNN: bool -> bool & number -> number +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╟── variable of type `?a` does not match type `number` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.13: def BBNN: bool -> bool & number -> number +//│ ╙── ^^^^^^ +//│ res: error // FIXME f(0) + 1 //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.111: f(0) + 1 +//│ ║ l.115: f(0) + 1 //│ ║ ^^^^^^ -//│ ╟── application of type `?a` does not match type `int` -//│ ║ l.95: def f = fun x -> (if true then IISS else BBNN) x -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `number` is not an instance of type `int` +//│ ║ l.13: def BBNN: bool -> bool & number -> number +//│ ║ ^^^^^^ //│ ╟── but it flows into application with expected type `int` -//│ ║ l.111: f(0) + 1 +//│ ║ l.115: f(0) + 1 //│ ╙── ^^^^ //│ res: error | int // FIXME f : int -> number -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.124: f : int -> number -//│ ║ ^ -//│ ╟── type `int` does not match type `?a` -//│ ║ l.124: f : int -> number -//│ ╙── ^^^ //│ res: int -> number :e f : number -> int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.134: f : number -> int +//│ ║ l.132: f : number -> int //│ ║ ^ //│ ╟── type `number` is not an instance of type `int` -//│ ║ l.134: f : number -> int +//│ ║ l.132: f : number -> int //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.12: def IISS: int -> int & string -> string @@ -156,16 +154,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.157: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.155: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.157: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.155: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.157: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.155: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index c9cbfdb6c5..053badd455 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -154,10 +154,7 @@ f(if true then 0 else false) //│ ╟── but it flows into reference with expected type `(0 | false) -> ?a` //│ ║ l.147: f(if true then 0 else false) //│ ╙── ^ -//│ 'a -//│ where -//│ 'a :> error -//│ [+0 | false, -'a, +0 | false] in {} +//│ error //│ res //│ = 0 @@ -167,10 +164,10 @@ f(if true then 0 else false) :w f(refined if true then 0 else false) // this one can be precise again! //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.168: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.165: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.168: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.165: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^ //│ 'a //│ where @@ -230,7 +227,7 @@ type T = List[Int] :e // TODO application types type Res = M(T) //│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 -//│ ║ l.231: type Res = M(T) +//│ ║ l.228: type Res = M(T) //│ ╙── ^^^^ //│ type Res = M @@ -253,7 +250,7 @@ fun f: Int -> Int fun f: Bool -> Bool fun f = id //│ ╔══[ERROR] A type signature for 'f' was already given -//│ ║ l.253: fun f: Bool -> Bool +//│ ║ l.250: fun f: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun f: forall 'a. 'a -> 'a //│ fun f: Int -> Int @@ -261,13 +258,13 @@ fun f = id :e // TODO support f: (Int -> Int) & (Bool -> Bool) //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.262: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.259: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^ //│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.262: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.259: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.252: fun f: Int -> Int +//│ ║ l.249: fun f: Int -> Int //│ ╙── ^^^ //│ Int -> Int & Bool -> Bool //│ res @@ -334,14 +331,14 @@ fun test(x) = refined if x is A then 0 B then 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.333: fun test(x) = refined if x is +//│ ║ l.330: fun test(x) = refined if x is //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.334: A then 0 +//│ ║ l.331: A then 0 //│ ║ ^^^^^^^^^^ -//│ ║ l.335: B then 1 +//│ ║ l.332: B then 1 //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.333: fun test(x) = refined if x is +//│ ║ l.330: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ fun test: (A | B) -> error //│ Code generation encountered an error: @@ -369,7 +366,7 @@ q(0) : true q(1) //│ 'a //│ where -//│ [+1, -'a, +1] in {[0 | 1, true, 0 | 1], [1 | 2, false, 1 | 2]} +//│ [-'a] in {[true], [false]} //│ res //│ = //│ q is not implemented @@ -399,11 +396,8 @@ fun w = x => q(x) //│ where //│ [+'a, -'b] in {[0 | 1, true], [1 | 2, false]} -// FIXME w(0) -//│ forall 'a. 'a -//│ where -//│ [+'b, -'a] in {[0 | 1, true], [1 | 2, false]} +//│ true //│ res //│ = //│ w and q are not implemented @@ -428,6 +422,21 @@ x => r(r(x)) //│ = //│ r is not implemented +// FIXME +r(r(0)) +//│ 'a +//│ where +//│ [+'b, -'a] in {[Int, Int], [Bool, Bool]} +//│ res +//│ = +//│ r is not implemented + +x => r(r(x))+1 +//│ Int -> Int +//│ res +//│ = +//│ r is not implemented + fun u: {x:0, y:Int} -> Int & {x:1, z: Str} -> Str //│ fun u: {x: 0, y: Int} -> Int & {x: 1, z: Str} -> Str @@ -444,3 +453,34 @@ fun u: {x:0, y:Int} -> Int & {x:1, z: Str} -> Str //│ res //│ = //│ u is not implemented + +fun s: Str -> Str & AA -> AA +//│ fun s: Str -> Str & AA -> AA + +:e +let g = x => s(r(x)) +//│ ╔══[ERROR] ambiguous +//│ ╙── +//│ let g: forall 'a 'b. 'a -> 'b +//│ where +//│ [+'c, -'b] in {[Str, Str], [AA, AA]} +//│ [+'a, -'c] in {[Int, Int], [Bool, Bool]} +//│ g +//│ = +//│ s is not implemented + +:e +g(0) +//│ ╔══[ERROR] Type mismatch in function type: +//│ ║ l.410: fun r: Int -> Int & Bool -> Bool +//│ ║ ^^^^^^^^^^^^ +//│ ╟── expression of type `Int` does not match type `?a` +//│ ╟── Note: constraint arises from application: +//│ ║ l.461: let g = x => s(r(x)) +//│ ╙── ^^^^ +//│ forall 'a. error | 'a +//│ where +//│ [+'b, -'a] in {} +//│ res +//│ = +//│ g and s are not implemented diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index 717532b622..23ca812d87 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -58,10 +58,7 @@ f("abc", "abc") //│ ╟── but it flows into reference with expected type `("abc", "abc") -> ?a` //│ ║ l.51: f("abc", "abc") //│ ╙── ^ -//│ 'a -//│ where -//│ 'a :> error -//│ [+"abc", +"abc", -'a, +"abc"] in {} +//│ error //│ res //│ = //│ f is not implemented @@ -84,19 +81,19 @@ let r = if true then id else (x, y) => [y, x] r(error) r(error, error) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.84: r(error) +//│ ║ l.81: r(error) //│ ║ ^^^^^^^^ //│ ╟── argument of type `[nothing]` does not match type `[?a, ?b]` -//│ ║ l.84: r(error) +//│ ║ l.81: r(error) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.78: let r = if true then id else (x, y) => [y, x] +//│ ║ l.75: let r = if true then id else (x, y) => [y, x] //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.85: r(error, error) +//│ ║ l.82: r(error, error) //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── argument list of type `[nothing, nothing]` does not match type `[?a]` -//│ ║ l.85: r(error, error) +//│ ║ l.82: r(error, error) //│ ╙── ^^^^^^^^^^^^^^ //│ error | [nothing, nothing] //│ res @@ -119,7 +116,7 @@ r of [0, 1] // Also currently parses the same: let r = if true then id else [x, y] => [y, x] -//│ let r: forall 'a 'b 'c. (['a, 'b] & 'c) -> (['b, 'a] | 'c) +//│ let r: forall 'a 'b 'c. (['b, 'c] & 'a) -> (['c, 'b] | 'a) //│ r //│ = [Function: id] From 13d8c8f326d0e7eebdf249347bf5b268b02dcf72 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Tue, 23 Apr 2024 21:26:07 +0800 Subject: [PATCH 20/43] fix bounds before tsc --- .../scala/mlscript/ConstraintSolver.scala | 26 +++++++-- .../main/scala/mlscript/TyperDatatypes.scala | 18 +++---- .../diff/ecoop23/SimpleRegionDSL_annot.mls | 2 +- shared/src/test/diff/fcp/Overloads.mls | 45 ++++++++-------- shared/src/test/diff/nu/HeungTung.mls | 54 ++++++++++++------- 5 files changed, 87 insertions(+), 58 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index bcae8827f8..a0fc62db85 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -827,8 +827,17 @@ class ConstraintSolver extends NormalForms { self: Typer => lhs.upperBounds ::= newBound // update the bound lhs.tsc.foreachEntry { case (tsc, i) => - tsc.updateOn(i, rhs) - if (tsc.constraints.isEmpty) reportError() + if (!tsc.tvs(i)._1) { + tsc.updateOn(i, rhs) + if (tsc.constraints.isEmpty) reportError() + } + } + val u = lhs.tsc.filter(_._1.constraints.sizeCompare(1) === 0) + u.foreachEntry { case (k, _) => lhs.tsc.remove(k) } + u.foreachEntry { case (k, _) => + k.constraints.head.zip(k.tvs).foreach { + case (c, (pol, t)) => if (pol) rec(t, c, true) else rec(c, t, true) + } } lhs.lowerBounds.foreach(rec(_, rhs, true)) // propagate from the bound @@ -839,8 +848,17 @@ class ConstraintSolver extends NormalForms { self: Typer => rhs.lowerBounds ::= newBound // update the bound rhs.tsc.foreachEntry { case (tsc, i) => - tsc.updateOn(i, lhs) - if (tsc.constraints.isEmpty) reportError() + if(tsc.tvs(i)._1) { + tsc.updateOn(i, lhs) + if (tsc.constraints.isEmpty) reportError() + } + } + val u = rhs.tsc.filter(_._1.constraints.sizeCompare(1) === 0) + u.foreachEntry { case (k, _) => rhs.tsc.remove(k) } + u.foreachEntry { case (k, _) => + k.constraints.head.zip(k.tvs).foreach { + case (c, (pol, t)) => if (pol) rec(t, c, true) else rec(c, t, true) + } } rhs.upperBounds.foreach(rec(lhs, _, true)) // propagate from the bound diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 764cdd9797..3d45d7fba3 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -676,17 +676,6 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => println(s"TSC update: $tvs in $constraints") updateImpl(index, bound) println(s"TSC update: $tvs in $constraints") - if (constraints.sizeCompare(1) === 0) { - tvs.foreach { - case (pol, tv: TV) => tv.tsc.remove(this) - case _ => () - } - constraints.head.zip(tvs).foreach { - case (c, (pol, t)) => - if (!pol) constrain(c, t)(raise, prov, ctx) - if (pol) constrain(t, c)(raise, prov, ctx) - } - } } } object TupleSetConstraints { @@ -767,7 +756,12 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } val tsc = new TupleSetConstraints(tvs.map(m(_)).transpose, tvs)(ov.prov) tvs.zipWithIndex.foreach { - case ((pol, tv: TV), i) => tv.tsc.update(tsc, i) + case ((true, tv: TV), i) => + tv.tsc.update(tsc, i) + tv.lowerBounds.foreach(tsc.updateImpl(i, _)) + case ((false, tv: TV), i) => + tv.tsc.update(tsc, i) + tv.upperBounds.foreach(tsc.updateImpl(i, _)) case _ => () } println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls index ae9192d9df..edeecb9c98 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls @@ -348,7 +348,7 @@ fun mk(n) = if n is _ then Scale(Vector(0, 0), mk(n)) //│ fun mk: forall 'a. Object -> 'a //│ where -//│ 'a :> Outside['a] | Translate['a] | Scale['a] | Union['a] | Intersect['a] +//│ 'a :> Outside['a] | Intersect['a] | Translate['a] | Scale['a] | Union['a] :re TestElim.eliminate(mk(100)) diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 143c41f2f3..c4aae0a5e1 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -100,25 +100,25 @@ def f = fun x -> (if true then IISS else BBNN) x //│ [+'a, -'b] in {[bool, bool], [number, number]} //│ [+'a, -'b] in {[int, int], [string, string]} +f: int -> number +//│ res: int -> number + // FIXME f(0) -//│ ╔══[ERROR] Type mismatch in function type: -//│ ║ l.13: def BBNN: bool -> bool & number -> number -//│ ║ ^^^^^^^^^^^^^^^^ -//│ ╟── variable of type `?a` does not match type `number` -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.13: def BBNN: bool -> bool & number -> number -//│ ╙── ^^^^^^ -//│ res: error +//│ res: 'a +//│ where +//│ 'a :> number +//│ [+'b, -'a] in {[bool, bool], [number, number]} +//│ [+'b, -'a] in {[int, int], [string, string]} // FIXME f(0) + 1 //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.115: f(0) + 1 //│ ║ ^^^^^^ -//│ ╟── type `number` is not an instance of type `int` -//│ ║ l.13: def BBNN: bool -> bool & number -> number -//│ ║ ^^^^^^ +//│ ╟── application of type `?a` does not match type `int` +//│ ║ l.95: def f = fun x -> (if true then IISS else BBNN) x +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `int` //│ ║ l.115: f(0) + 1 //│ ╙── ^^^^ @@ -126,19 +126,22 @@ f(0) + 1 // FIXME f : int -> number +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.128: f : int -> number +//│ ║ ^ +//│ ╟── type `int` does not match type `?a` +//│ ║ l.128: f : int -> number +//│ ╙── ^^^ //│ res: int -> number :e f : number -> int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.132: f : number -> int +//│ ║ l.138: f : number -> int //│ ║ ^ -//│ ╟── type `number` is not an instance of type `int` -//│ ║ l.132: f : number -> int -//│ ║ ^^^^^^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ╙── ^^^ +//│ ╟── type `number` does not match type `?a` +//│ ║ l.138: f : number -> int +//│ ╙── ^^^^^^ //│ res: number -> int @@ -154,16 +157,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.155: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.158: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.155: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.158: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.155: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.158: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 053badd455..1de8622dbe 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -169,9 +169,19 @@ f(refined if true then 0 else false) // this one can be precise again! //│ ╔══[ERROR] identifier not found: refined //│ ║ l.165: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.165: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `Int -> Int & Bool -> Bool` is not a function +//│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `?a -> ?b` +//│ ║ l.165: f(refined if true then 0 else false) // this one can be precise again! +//│ ╙── ^ //│ 'a //│ where -//│ [+'b, -'a] in {[Int, Int], [Bool, Bool]} +//│ 'a :> error +//│ [+'b, -'a] in {} //│ Code generation encountered an error: //│ unresolved symbol refined @@ -227,7 +237,7 @@ type T = List[Int] :e // TODO application types type Res = M(T) //│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 -//│ ║ l.228: type Res = M(T) +//│ ║ l.238: type Res = M(T) //│ ╙── ^^^^ //│ type Res = M @@ -250,7 +260,7 @@ fun f: Int -> Int fun f: Bool -> Bool fun f = id //│ ╔══[ERROR] A type signature for 'f' was already given -//│ ║ l.250: fun f: Bool -> Bool +//│ ║ l.260: fun f: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun f: forall 'a. 'a -> 'a //│ fun f: Int -> Int @@ -258,13 +268,13 @@ fun f = id :e // TODO support f: (Int -> Int) & (Bool -> Bool) //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.259: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.269: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^ //│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.259: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.269: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.249: fun f: Int -> Int +//│ ║ l.259: fun f: Int -> Int //│ ╙── ^^^ //│ Int -> Int & Bool -> Bool //│ res @@ -331,14 +341,14 @@ fun test(x) = refined if x is A then 0 B then 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.330: fun test(x) = refined if x is +//│ ║ l.340: fun test(x) = refined if x is //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.331: A then 0 +//│ ║ l.341: A then 0 //│ ║ ^^^^^^^^^^ -//│ ║ l.332: B then 1 +//│ ║ l.342: B then 1 //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.330: fun test(x) = refined if x is +//│ ║ l.340: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ fun test: (A | B) -> error //│ Code generation encountered an error: @@ -396,8 +406,12 @@ fun w = x => q(x) //│ where //│ [+'a, -'b] in {[0 | 1, true], [1 | 2, false]} +// TODO w(0) -//│ true +//│ forall 'a. 'a +//│ where +//│ 'a :> true +//│ [+'b, -'a] in {[0 | 1, true], [1 | 2, false]} //│ res //│ = //│ w and q are not implemented @@ -422,11 +436,9 @@ x => r(r(x)) //│ = //│ r is not implemented -// FIXME + r(r(0)) -//│ 'a -//│ where -//│ [+'b, -'a] in {[Int, Int], [Bool, Bool]} +//│ Int //│ res //│ = //│ r is not implemented @@ -471,12 +483,14 @@ let g = x => s(r(x)) :e g(0) -//│ ╔══[ERROR] Type mismatch in function type: -//│ ║ l.410: fun r: Int -> Int & Bool -> Bool -//│ ║ ^^^^^^^^^^^^ -//│ ╟── expression of type `Int` does not match type `?a` +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.485: g(0) +//│ ║ ^^^^ +//│ ╟── integer literal of type `Int` does not match type `?a` +//│ ║ l.485: g(0) +//│ ║ ^ //│ ╟── Note: constraint arises from application: -//│ ║ l.461: let g = x => s(r(x)) +//│ ║ l.473: let g = x => s(r(x)) //│ ╙── ^^^^ //│ forall 'a. error | 'a //│ where From ed52d0bd550208592a7a98f9240302f3a7f8214e Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 13 Jun 2024 00:34:32 +0800 Subject: [PATCH 21/43] modify freshenAbove and disable distributivity --- .../scala/mlscript/ConstraintSolver.scala | 33 ++++++--------- .../main/scala/mlscript/TyperHelpers.scala | 4 +- shared/src/test/diff/fcp/Overloads.mls | 41 ++++++------------- shared/src/test/diff/nu/HeungTung.mls | 12 ++---- 4 files changed, 33 insertions(+), 57 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index a0fc62db85..be16814430 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -1507,7 +1507,7 @@ class ConstraintSolver extends NormalForms { self: Typer => (implicit ctx: Ctx, freshened: MutMap[TV, ST]) : SimpleType = { - val freshenedTsc: MutMap[TupleSetConstraints, TupleSetConstraints] = MutMap.empty + val freshenTsc: MutSet[TupleSetConstraints] = MutSet.empty def freshenImpl(ty: SimpleType, below: Level): SimpleType = // (trace(s"${lvl}. FRESHEN $ty || $above .. $below ${ty.level} ${ty.level <= above}") { @@ -1586,24 +1586,7 @@ class ConstraintSolver extends NormalForms { self: Typer => freshened += tv -> v v.lowerBounds = tv.lowerBounds.mapConserve(freshen) v.upperBounds = tv.upperBounds.mapConserve(freshen) - tv.tsc.foreachEntry { - case (tsc, i) => - val t = freshenedTsc.get(tsc) match { - case S(tsc) => tsc - case N => - val t = new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov) - freshenedTsc += tsc -> t - t - } - t.tvs = t.tvs.zipWithIndex.map { - case ((p, tv: TV), j) if j == i => tv.tsc.remove(t); (p, v) - case (u, _) => u - } - t.tvs.zipWithIndex.foreach { - case ((_, tv: TV), i) => tv.tsc.update(t, i) - case _ => () - } - } + tv.tsc.foreachEntry { case (tsc, _) => freshenTsc += tsc } v } @@ -1650,7 +1633,17 @@ class ConstraintSolver extends NormalForms { self: Typer => }} // (r => s"=> $r")) - freshenImpl(ty, below) + val r = freshenImpl(ty, below) + val fr = Map.empty[ST, ST] ++ freshened + freshenTsc.foreach { tsc => + val t = new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov) + t.tvs = t.tvs.map(x => (x._1, substSyntax(x._2)(fr))) + t.tvs.zipWithIndex.foreach { + case ((pol, tv: TV), i) => tv.tsc.update(t, i) + case _ => () + } + } + r } diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 41bdf61795..dab659e4a0 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -1012,7 +1012,9 @@ abstract class TyperHelpers { Typer: Typer => val couldBeDistribbed = bod.varsBetween(polymLevel, MaxLevel) println(s"could be distribbed: $couldBeDistribbed") if (couldBeDistribbed.isEmpty) return N - val cannotBeDistribbed = par.varsBetween(polymLevel, MaxLevel) + val cannotBeDistribbed = par.varsBetween(polymLevel, MaxLevel).flatMap { v => + v :: v.tsc.keys.flatMap(_.tvs.flatMap(_._2.getVars)).toList + } println(s"cannot be distribbed: $cannotBeDistribbed") val canBeDistribbed = couldBeDistribbed -- cannotBeDistribbed if (canBeDistribbed.isEmpty) return N // TODO diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index c4aae0a5e1..6c5d4e2747 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -100,47 +100,32 @@ def f = fun x -> (if true then IISS else BBNN) x //│ [+'a, -'b] in {[bool, bool], [number, number]} //│ [+'a, -'b] in {[int, int], [string, string]} -f: int -> number -//│ res: int -> number - -// FIXME f(0) -//│ res: 'a -//│ where -//│ 'a :> number -//│ [+'b, -'a] in {[bool, bool], [number, number]} -//│ [+'b, -'a] in {[int, int], [string, string]} +//│ res: number // FIXME f(0) + 1 //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.115: f(0) + 1 +//│ ║ l.107: f(0) + 1 //│ ║ ^^^^^^ -//│ ╟── application of type `?a` does not match type `int` -//│ ║ l.95: def f = fun x -> (if true then IISS else BBNN) x -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into application with expected type `int` -//│ ║ l.115: f(0) + 1 -//│ ╙── ^^^^ +//│ ╟── type `number` is not an instance of type `int` +//│ ║ l.13: def BBNN: bool -> bool & number -> number +//│ ║ ^^^^^^ +//│ ╟── but it flows into integer literal with expected type `int` +//│ ║ l.107: f(0) + 1 +//│ ╙── ^ //│ res: error | int -// FIXME f : int -> number -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.128: f : int -> number -//│ ║ ^ -//│ ╟── type `int` does not match type `?a` -//│ ║ l.128: f : int -> number -//│ ╙── ^^^ //│ res: int -> number :e f : number -> int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.138: f : number -> int +//│ ║ l.123: f : number -> int //│ ║ ^ //│ ╟── type `number` does not match type `?a` -//│ ║ l.138: f : number -> int +//│ ║ l.123: f : number -> int //│ ╙── ^^^^^^ //│ res: number -> int @@ -157,16 +142,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.158: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.143: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.158: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.143: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.158: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.143: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 1de8622dbe..a58d7da9ad 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -406,12 +406,8 @@ fun w = x => q(x) //│ where //│ [+'a, -'b] in {[0 | 1, true], [1 | 2, false]} -// TODO w(0) -//│ forall 'a. 'a -//│ where -//│ 'a :> true -//│ [+'b, -'a] in {[0 | 1, true], [1 | 2, false]} +//│ true //│ res //│ = //│ w and q are not implemented @@ -484,13 +480,13 @@ let g = x => s(r(x)) :e g(0) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.485: g(0) +//│ ║ l.481: g(0) //│ ║ ^^^^ //│ ╟── integer literal of type `Int` does not match type `?a` -//│ ║ l.485: g(0) +//│ ║ l.481: g(0) //│ ║ ^ //│ ╟── Note: constraint arises from application: -//│ ║ l.473: let g = x => s(r(x)) +//│ ║ l.469: let g = x => s(r(x)) //│ ╙── ^^^^ //│ forall 'a. error | 'a //│ where From e254f860f5102277602ebf16ceeb5a49c2636b6a Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Fri, 14 Jun 2024 23:59:38 +0800 Subject: [PATCH 22/43] fix tuple and record subtyping --- .../src/main/scala/mlscript/TyperDatatypes.scala | 1 + shared/src/test/diff/nu/HeungTung.mls | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 3d45d7fba3..b8b7cbc943 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -714,6 +714,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } S(l, m + ((pol, a) -> List(b))) } else N + case (a: TupleType, b: RecordType) if pol => lcg(pol, a.toRecord, b) case (a: RecordType, b: RecordType) => val default = FieldType(N, if (pol) TopType else BotType)(prov) if (b.fields.map(_._1).forall(a.fields.map(_._1).contains)) { diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index a58d7da9ad..397dda4144 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -494,3 +494,18 @@ g(0) //│ res //│ = //│ g and s are not implemented + +fun rt: {0: Int} -> Int & {0: Str} -> Str +//│ fun rt: {0: Int} -> Int & {0: Str} -> Str + +rt([1,"str"]) +//│ Int +//│ res +//│ = +//│ rt is not implemented + +rt(["str",1]) +//│ Str +//│ res +//│ = +//│ rt is not implemented From 0e2717168a4aeda3323af24e4768d1d3ea955a84 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Tue, 2 Jul 2024 22:39:59 +0800 Subject: [PATCH 23/43] fix type variables with multiple indices --- .../scala/mlscript/ConstraintSolver.scala | 6 ++--- shared/src/main/scala/mlscript/Typer.scala | 2 +- .../main/scala/mlscript/TyperDatatypes.scala | 8 +++---- .../main/scala/mlscript/TyperHelpers.scala | 6 ++++- shared/src/test/diff/nu/HeungTung.mls | 24 +++++++++++++++++++ 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index be16814430..259d854d6c 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -825,7 +825,7 @@ class ConstraintSolver extends NormalForms { self: Typer => val newBound = (cctx._1 ::: cctx._2.reverse).foldRight(rhs)((c, ty) => if (c.prov is noProv) ty else mkProxy(ty, c.prov)) lhs.upperBounds ::= newBound // update the bound - lhs.tsc.foreachEntry { + lhs.tsc.toList.flatMap { case (k,v)=>v.map((k,_)) }.foreach { case (tsc, i) => if (!tsc.tvs(i)._1) { tsc.updateOn(i, rhs) @@ -846,7 +846,7 @@ class ConstraintSolver extends NormalForms { self: Typer => val newBound = (cctx._1 ::: cctx._2.reverse).foldLeft(lhs)((ty, c) => if (c.prov is noProv) ty else mkProxy(ty, c.prov)) rhs.lowerBounds ::= newBound // update the bound - rhs.tsc.foreachEntry { + rhs.tsc.toList.flatMap { case (k,v)=>v.map((k,_)) }.foreach { case (tsc, i) => if(tsc.tvs(i)._1) { tsc.updateOn(i, lhs) @@ -1639,7 +1639,7 @@ class ConstraintSolver extends NormalForms { self: Typer => val t = new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov) t.tvs = t.tvs.map(x => (x._1, substSyntax(x._2)(fr))) t.tvs.zipWithIndex.foreach { - case ((pol, tv: TV), i) => tv.tsc.update(t, i) + case ((pol, tv: TV), i) => tv.tsc.updateWith(t)(_.map(_ + i).orElse(S(Set(i)))) case _ => () } } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 089ae614fc..3a9ffd9f69 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -601,7 +601,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne val tvs = typevars.map(x => (x._1, rec(x._2))) val tsc = new TupleSetConstraints(constrs.map(_.map(rec)), tvs)(res.prov) tvs.zipWithIndex.foreach { - case ((_, tv: TV), i) => tv.tsc += tsc -> i + case ((_, tv: TV), i) => tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) case _ => () } } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index b8b7cbc943..b0b3f3b330 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -535,7 +535,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => _assignedTo = value } - val tsc: LinkedHashMap[TupleSetConstraints, Int] = LinkedHashMap.empty + val tsc: LinkedHashMap[TupleSetConstraints, Set[Int]] = LinkedHashMap.empty // * Bounds should always be disregarded when `equatedTo` is defined, as they are then irrelevant: def lowerBounds: List[SimpleType] = { require(assignedTo.isEmpty, this); _lowerBounds } @@ -666,7 +666,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => constraints = ncs tvs ++= tvs0 tvs.zipWithIndex.foreach { - case ((pol, tv: TV), i) => tv.tsc.update(this, i) + case ((pol, tv: TV), i) => tv.tsc.updateWith(this)(_.map(_ + i).orElse(S(Set(i)))) case _ => () } } @@ -758,10 +758,10 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => val tsc = new TupleSetConstraints(tvs.map(m(_)).transpose, tvs)(ov.prov) tvs.zipWithIndex.foreach { case ((true, tv: TV), i) => - tv.tsc.update(tsc, i) + tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) tv.lowerBounds.foreach(tsc.updateImpl(i, _)) case ((false, tv: TV), i) => - tv.tsc.update(tsc, i) + tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) tv.upperBounds.foreach(tsc.updateImpl(i, _)) case _ => () } diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index dab659e4a0..5749274787 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -756,9 +756,13 @@ abstract class TyperHelpers { Typer: Typer => pol -> ty :: Nil case tv: TypeVariable => val poltv = pol(tv) + val (tvs0, tvs1) = tv.tsc.toList.flatMap(_._1.tvs).partition(_._2 === tv) (if (poltv =/= S(false)) tv.lowerBounds.map(pol.at(tv.level, true) -> _) else Nil) ::: (if (poltv =/= S(true)) tv.upperBounds.map(pol.at(tv.level, false) -> _) else Nil) ::: - (tv.tsc.toList.flatMap { case (tsc, i) => (tsc.tvs.take(i) ++ tsc.tvs.drop(i+1)).map(PolMap.neu -> _._2) }) + (if (poltv =/= S(false) && tvs0.exists(!_._1)) + tvs1.map(u => pol.at(tv.level, true) -> u._2) else Nil) ::: + (if (poltv =/= S(true) && tvs0.exists(_._1)) + tvs1.map(u => pol.at(tv.level, false) -> u._2) else Nil) case FunctionType(l, r) => pol.contravar -> l :: pol.covar -> r :: Nil case Overload(as) => as.map(pol -> _) case ComposedType(_, l, r) => pol -> l :: pol -> r :: Nil diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 397dda4144..0565773aa6 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -509,3 +509,27 @@ rt(["str",1]) //│ res //│ = //│ rt is not implemented + +fun app (f:'a -> 'a) = x => f(x) +//│ fun app: forall 'a. (f: 'a -> 'a) -> 'a -> 'a + +fun id: Int -> Int & Str -> Str +//│ fun id: Int -> Int & Str -> Str + +fun id0 = app(id) +//│ fun id0: forall 'a 'b. 'a -> 'b +//│ where +//│ 'a <: 'b +//│ [+'a, -'a, -'b] in {[Int, Int, Int], [Str, Str, Str]} + +x => id0(x): Int +//│ Int -> Int +//│ res +//│ = +//│ id0 and id are not implemented + +id0("str") +//│ Str +//│ res +//│ = +//│ id0 and id are not implemented From 0e110ad9fdf04bb6447e9180d8f88830d7d75ed7 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Wed, 3 Jul 2024 22:10:03 +0800 Subject: [PATCH 24/43] fix type variable with multiple indices and add test cases --- .../main/scala/mlscript/TyperDatatypes.scala | 56 ++++++++++++------- .../main/scala/mlscript/TyperHelpers.scala | 8 +-- .../diff/ecoop23/SimpleRegionDSL_annot.mls | 2 +- shared/src/test/diff/nu/HeungTung.mls | 47 +++++++++------- 4 files changed, 67 insertions(+), 46 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index b0b3f3b330..5292b399e9 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -651,11 +651,17 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => class TupleSetConstraints(var constraints: Ls[Ls[ST]], var tvs: Ls[(Bool, ST)])(val prov: TypeProvenance) { def updateImpl(index: Int, bound: ST)(implicit raise: Raise, ctx: Ctx) : Unit = { - val (cs0, u) = constraints.flatMap { c => + val (cs0, u0) = constraints.flatMap { c => TupleSetConstraints.lcg(tvs(index)._1, bound, c(index))(prov, ctx).map(u => (c, u)) }.unzip + val u = u0.map { + case (x,y) => (x, y.groupBy(_._1).view.mapValues { l => + val p = l.head._1._1 + List(l.map(_._2).reduce[ST]((x,y) => ComposedType(!p,x,y)(noProv))) + }.toMap) + } constraints = cs0 - if (!u.isEmpty) { + if (!u0.isEmpty) { val (tvs0, m) = u.reduce[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] { case ((xl, xm), (yl, ym)) => val l = (xl.filter(ym.contains(_)) ++ yl.filter(xm.contains(_))).distinct @@ -681,12 +687,12 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => object TupleSetConstraints { def lcgField(pol: Bool, first: FieldType, rest: FieldType) (implicit prov: TypeProvenance, ctx: Ctx) - : Opt[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] = { + : Opt[(Ls[(Bool, ST)], Ls[(Bool, ST) -> ST])] = { for { (ubl, ubm) <- lcg(pol, first.ub, rest.ub) (lbl, lbm) <- { if (first.lb.isEmpty && rest.lb.isEmpty) - S(Nil, Map()) + S(Nil, Nil) else lcg(!pol, first.lb.getOrElse(BotType), rest.lb.getOrElse(BotType)) } @@ -696,23 +702,30 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } def lcg(pol: Bool, first: ST, rest: ST) (implicit prov: TypeProvenance, ctx: Ctx) - : Opt[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] = (first.unwrapProxies, rest.unwrapProxies) match { - case (a: TV, b: TV) if a.compare(b) === 0 => S(Nil, Map()) - case (a: TV, b) => S(List((pol, a)), Map((pol, a) -> List(b))) - case (a, b: TV) => S(List((pol, a)), Map((pol, a) -> List(b))) + : Opt[(Ls[(Bool, ST)], Ls[(Bool, ST) -> ST])] = (first.unwrapProxies, rest.unwrapProxies) match { + case (a, ComposedType(p,l,r)) if p =/= pol => + for { + (ll,lm) <- lcg(pol,a,l) + (rl,rm) <- lcg(pol,a,r) + } yield { + (ll ++ rl,((pol, first) -> rest)::lm ++ rm) + } + case (a: TV, b: TV) if a.compare(b) === 0 => S(Nil, Nil) + case (a: TV, b) => S(List((pol, a)), List((pol, a) -> b)) + case (a, b: TV) => S(List((pol, a)), List((pol, a) -> b)) case (a: FT, b: FT) => lcgFunction(pol, a, b) case (a: FT, b) => N case (a: ArrayType, b: ArrayType) => for { (l, m) <- lcgField(pol, a.inner, b.inner) } yield { - (l, m + ((pol, a) -> List(b))) + (l, ((pol, a) -> b) :: m) } case (a: TupleType, b: TupleType) if a.fields.sizeCompare(b.fields) === 0 => val fs = a.fields.map(_._2).zip(b.fields.map(_._2)).map(u => lcgField(pol, u._1, u._2)) if (!fs.contains(N)) { - val (l, m) = fs.flatten.reduce[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] { + val (l, m) = fs.flatten.reduce[(Ls[(Bool, ST)], Ls[(Bool, ST) -> ST])] { case ((xl, xm), (yl, ym)) => (xl ++ yl, xm ++ ym) } - S(l, m + ((pol, a) -> List(b))) + S(l, ((pol, a) -> b) :: m) } else N case (a: TupleType, b: RecordType) if pol => lcg(pol, a.toRecord, b) case (a: RecordType, b: RecordType) => @@ -722,33 +735,38 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => case (v, f) => lcgField(pol, f, b.fields.find(_._1 === v).fold(default)(_._2)) } if (!u.contains(N)) { - val (l, m) = u.flatten.reduce[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] { + val (l, m) = u.flatten.reduce[(Ls[(Bool, ST)], Ls[(Bool, ST) -> ST])] { case ((xl, xm), (yl, ym)) => (xl ++ yl, xm ++ ym) } - S(l, m + ((pol, a) -> List(b))) + S(l, ((pol, a) -> b) :: m) } else N } else N - case (a, b) if a === b => S(Nil, Map((pol, a) -> List(b))) + case (a, b) if a === b => S(Nil, List((pol, a) -> b)) case (a, b) => val dnf = DNF.mk(MaxLevel, Nil, if (pol) a & b.neg() else b & a.neg(), true) if (dnf.isBot) - S(Nil, Map((pol, a) -> List(b))) + S(Nil, List((pol, a) -> b)) else if (dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) - S(List((pol, a)), Map((pol, a) -> List(b))) + S(List((pol, a)), List((pol, a) -> b)) else N } def lcgFunction(pol: Bool, first: FT, rest: FT) (implicit prov: TypeProvenance, ctx: Ctx) - : Opt[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] = { + : Opt[(Ls[(Bool, ST)], Ls[(Bool, ST) -> ST])] = { for { (ll, lm) <- lcg(!pol, first.lhs, rest.lhs) (rl, rm) <- lcg(pol, first.rhs, rest.rhs) } yield { - (ll ++ rl,lm ++ rm + ((pol, first) -> List(rest))) + (ll ++ rl,((pol, first) -> rest) :: lm ++ rm) } } def mk(ov: Overload, f: FT)(implicit raise: Raise, ctx: Ctx): Opt[TupleSetConstraints] = { - val u = ov.alts.map(lcgFunction(false, f, _)(ov.prov, ctx)).flatten + val u = ov.alts.map(lcgFunction(false, f, _)(ov.prov, ctx)).flatten.map { + case (x,y) => (x, y.groupBy(_._1).view.mapValues { l => + val p = l.head._1._1 + List(l.map(_._2).reduce[ST]((x,y) => ComposedType(!p,x,y)(noProv))) + }.toMap) + } if (u.isEmpty) { return N } val (tvs, m) = u.reduce[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] { case ((xl, xm), (yl, ym)) => diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 5749274787..c0a6a543cf 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -756,13 +756,9 @@ abstract class TyperHelpers { Typer: Typer => pol -> ty :: Nil case tv: TypeVariable => val poltv = pol(tv) - val (tvs0, tvs1) = tv.tsc.toList.flatMap(_._1.tvs).partition(_._2 === tv) (if (poltv =/= S(false)) tv.lowerBounds.map(pol.at(tv.level, true) -> _) else Nil) ::: (if (poltv =/= S(true)) tv.upperBounds.map(pol.at(tv.level, false) -> _) else Nil) ::: - (if (poltv =/= S(false) && tvs0.exists(!_._1)) - tvs1.map(u => pol.at(tv.level, true) -> u._2) else Nil) ::: - (if (poltv =/= S(true) && tvs0.exists(_._1)) - tvs1.map(u => pol.at(tv.level, false) -> u._2) else Nil) + (tv.tsc.keys.flatMap(_.tvs).toList.distinct.map(u => pol.at(tv.level,u._1) -> u._2)) case FunctionType(l, r) => pol.contravar -> l :: pol.covar -> r :: Nil case Overload(as) => as.map(pol -> _) case ComposedType(_, l, r) => pol -> l :: pol -> r :: Nil @@ -958,7 +954,7 @@ abstract class TyperHelpers { Typer: Typer => def getVars: SortedSet[TypeVariable] = getVarsImpl(includeBounds = true) def showBounds: String = - getVars.iterator.filter(tv => (tv.assignedTo.nonEmpty || (tv.upperBounds ++ tv.lowerBounds).nonEmpty) && tv.tsc.isEmpty).map { + getVars.iterator.filter(tv => (tv.assignedTo.nonEmpty || (tv.upperBounds ++ tv.lowerBounds).nonEmpty)).map { case tv @ AssignedVariable(ty) => "\n\t\t" + tv.toString + " := " + ty case tv => ("\n\t\t" + tv.toString + (if (tv.lowerBounds.isEmpty) "" else " :> " + tv.lowerBounds.mkString(" | ")) diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls index edeecb9c98..c634f7c8dc 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls @@ -348,7 +348,7 @@ fun mk(n) = if n is _ then Scale(Vector(0, 0), mk(n)) //│ fun mk: forall 'a. Object -> 'a //│ where -//│ 'a :> Outside['a] | Intersect['a] | Translate['a] | Scale['a] | Union['a] +//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] :re TestElim.eliminate(mk(100)) diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 0565773aa6..df5d37bcdd 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -373,6 +373,7 @@ q(0) : true //│ = //│ q is not implemented + q(1) //│ 'a //│ where @@ -480,13 +481,13 @@ let g = x => s(r(x)) :e g(0) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.481: g(0) +//│ ║ l.482: g(0) //│ ║ ^^^^ //│ ╟── integer literal of type `Int` does not match type `?a` -//│ ║ l.481: g(0) +//│ ║ l.482: g(0) //│ ║ ^ //│ ╟── Note: constraint arises from application: -//│ ║ l.469: let g = x => s(r(x)) +//│ ║ l.470: let g = x => s(r(x)) //│ ╙── ^^^^ //│ forall 'a. error | 'a //│ where @@ -510,26 +511,32 @@ rt(["str",1]) //│ = //│ rt is not implemented -fun app (f:'a -> 'a) = x => f(x) -//│ fun app: forall 'a. (f: 'a -> 'a) -> 'a -> 'a +fun app2: ('a -> 'a -> 'a) -> 'a -> 'a +//│ fun app2: forall 'a. ('a -> 'a -> 'a) -> 'a -> 'a -fun id: Int -> Int & Str -> Str -//│ fun id: Int -> Int & Str -> Str +fun snd: A -> Int -> Int & Str -> Str -> Str +//│ fun snd: A -> Int -> Int & Str -> Str -> Str -fun id0 = app(id) -//│ fun id0: forall 'a 'b. 'a -> 'b -//│ where -//│ 'a <: 'b -//│ [+'a, -'a, -'b] in {[Int, Int, Int], [Str, Str, Str]} +// FIXME +:e +x => app2(snd)(x):Int +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.522: x => app2(snd)(x):Int +//│ ║ ^^^^^^^^^^^^ +//│ ╟── application of type `'a` does not match type `nothing` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.522: x => app2(snd)(x):Int +//│ ╙── ^^^ +//│ /!!!\ Uncaught error: java.lang.AssertionError: assertion failed: α316_323' has no occurrences... -x => id0(x): Int -//│ Int -> Int -//│ res -//│ = -//│ id0 and id are not implemented +fun app2_ (f:'a -> 'a -> 'a)(x) = f(x)(x) +//│ fun app2_: forall 'a. (f: 'a -> 'a -> 'a) -> 'a -> 'a -id0("str") -//│ Str +app2_(snd) +//│ 'a -> 'b +//│ where +//│ 'a <: 'b +//│ [+'a, -'a, -'b] in {[A & Int, Int, Int], [Str, Str, Str]} //│ res //│ = -//│ id0 and id are not implemented +//│ snd is not implemented From 0819149ea0a051508e7912396360d5b364f2bd75 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Wed, 3 Jul 2024 22:21:53 +0800 Subject: [PATCH 25/43] fix ambiguity test --- shared/src/main/scala/mlscript/Typer.scala | 6 +++--- shared/src/test/diff/fcp/Overloads.mls | 17 +++++++---------- shared/src/test/diff/nu/HeungTung.mls | 2 ++ 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 3a9ffd9f69..7b9369fa4b 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -114,9 +114,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne }.toList, innerTy) val ambiguous: Bool = innerTy.getVars.toList.flatMap(_.tsc) - .flatMap(_._1.tvs.map(_._2)) - .collect { case x: TV => x } - .exists(_.tsc.sizeIs > 1) + .flatMap(_._1.tvs) + .groupBy(_._2) + .exists { case (v,pvs) => pvs.distinct.sizeIs > 1 } if (ambiguous) raise(ErrorReport(Ls(fromStr("ambiguous") -> N), true)) println(s"Inferred poly constr: $cty —— where ${cty.showBounds}") diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 6c5d4e2747..6e474c7e00 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -91,10 +91,7 @@ IISS 0 // * Conceptually we'd expect it to reduce to `int -> number` // * But it's tricky to do the actual reduction since technically // * 'a = Bot anf 'b = Top could satisfy all tuple alternatives -:e def f = fun x -> (if true then IISS else BBNN) x -//│ ╔══[ERROR] ambiguous -//│ ╙── //│ f: 'a -> 'b //│ where //│ [+'a, -'b] in {[bool, bool], [number, number]} @@ -106,13 +103,13 @@ f(0) // FIXME f(0) + 1 //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.107: f(0) + 1 +//│ ║ l.104: f(0) + 1 //│ ║ ^^^^^^ //│ ╟── type `number` is not an instance of type `int` //│ ║ l.13: def BBNN: bool -> bool & number -> number //│ ║ ^^^^^^ //│ ╟── but it flows into integer literal with expected type `int` -//│ ║ l.107: f(0) + 1 +//│ ║ l.104: f(0) + 1 //│ ╙── ^ //│ res: error | int @@ -122,10 +119,10 @@ f : int -> number :e f : number -> int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.123: f : number -> int +//│ ║ l.120: f : number -> int //│ ║ ^ //│ ╟── type `number` does not match type `?a` -//│ ║ l.123: f : number -> int +//│ ║ l.120: f : number -> int //│ ╙── ^^^^^^ //│ res: number -> int @@ -142,16 +139,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.143: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.140: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.143: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.140: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.143: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.140: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index df5d37bcdd..27578a3aee 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -527,6 +527,8 @@ x => app2(snd)(x):Int //│ ╟── Note: constraint arises from type reference: //│ ║ l.522: x => app2(snd)(x):Int //│ ╙── ^^^ +//│ ╔══[ERROR] ambiguous +//│ ╙── //│ /!!!\ Uncaught error: java.lang.AssertionError: assertion failed: α316_323' has no occurrences... fun app2_ (f:'a -> 'a -> 'a)(x) = f(x)(x) From b8f3a3af5eaf35b48678e74820d7a18dd622c5d4 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sun, 28 Jul 2024 21:01:34 +0800 Subject: [PATCH 26/43] fix polarity and modify type simplifier --- .../main/scala/mlscript/TypeSimplifier.scala | 19 ++++++++---- shared/src/main/scala/mlscript/Typer.scala | 4 +-- .../main/scala/mlscript/TyperHelpers.scala | 5 ++-- shared/src/test/diff/nu/HeungTung.mls | 29 +++++-------------- 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 469014a70e..a3b3dea68f 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -555,9 +555,13 @@ trait TypeSimplifier { self: Typer => if (pol(tv) =/= S(false)) analyzed1.setAndIfUnset(tv -> true) { tv.lowerBounds.foreach(apply(pol.at(tv.level, true))) + tv.tsc.keys.flatMap(_.tvs).foreach(u => apply(pol.at(tv.level,u._1))(u._2)) } if (pol(tv) =/= S(true)) - analyzed1.setAndIfUnset(tv -> false) { tv.upperBounds.foreach(apply(pol.at(tv.level, false))) } + analyzed1.setAndIfUnset(tv -> false) { + tv.upperBounds.foreach(apply(pol.at(tv.level, false))) + tv.tsc.keys.flatMap(_.tvs).foreach(u => apply(pol.at(tv.level,u._1))(u._2)) + } } case _ => super.apply(pol)(st) @@ -649,8 +653,10 @@ trait TypeSimplifier { self: Typer => case tv: TypeVariable => pol(tv) match { case S(pol_tv) => - if (analyzed2.add(pol_tv -> tv)) + if (analyzed2.add(pol_tv -> tv)) { processImpl(st, pol, pol_tv) + tv.tsc.keys.flatMap(_.tvs).foreach(u => processImpl(u._2,pol.at(tv.level,u._1),pol_tv)) + } case N => if (analyzed2.add(true -> tv)) // * To compute the positive co-occurrences @@ -696,6 +702,7 @@ trait TypeSimplifier { self: Typer => case S(p) => (if (p) tv2.lowerBounds else tv2.upperBounds).foreach(go) // (if (p) getLbs(tv2) else getUbs(tv2)).foreach(go) + tv2.tsc.keys.flatMap(_.tvs).foreach(u => go(u._2)) case N => trace(s"Analyzing invar-occ of $tv2") { analyze2(tv2, pol) @@ -795,7 +802,7 @@ trait TypeSimplifier { self: Typer => // * Remove variables that are 'dominated' by another type or variable // * A variable v dominated by T if T is in both of v's positive and negative cooccurrences - allVars.foreach { case v => if (v.assignedTo.isEmpty && !varSubst.contains(v)) { + allVars.foreach { case v => if (v.assignedTo.isEmpty && !varSubst.contains(v) && v.tsc.isEmpty) { println(s"2[v] $v ${coOccurrences.get(true -> v)} ${coOccurrences.get(false -> v)}") coOccurrences.get(true -> v).iterator.flatMap(_.iterator).foreach { @@ -813,6 +820,7 @@ trait TypeSimplifier { self: Typer => case w: TV if !(w is v) && !varSubst.contains(w) && !varSubst.contains(v) && !recVars(v) && coOccurrences.get(false -> v).exists(_(w)) + && w.tsc.isEmpty => // * Here we know that v is 'dominated' by w, so v can be inlined. // * Note that we don't want to unify the two variables here @@ -839,7 +847,7 @@ trait TypeSimplifier { self: Typer => // * Unify equivalent variables based on polar co-occurrence analysis: allVars.foreach { case v => - if (!v.assignedTo.isDefined && !varSubst.contains(v)) // TODO also handle v.assignedTo.isDefined? + if (!v.assignedTo.isDefined && !varSubst.contains(v) && v.tsc.isEmpty) // TODO also handle v.assignedTo.isDefined? trace(s"3[v] $v +${coOccurrences.get(true -> v).mkString} -${coOccurrences.get(false -> v).mkString}") { def go(pol: Bool): Unit = coOccurrences.get(pol -> v).iterator.flatMap(_.iterator).foreach { @@ -856,6 +864,7 @@ trait TypeSimplifier { self: Typer => ) && (v.level === w.level) // ^ Don't merge variables of differing levels + && w.tsc.isEmpty => trace(s"[w] $w ${printPol(S(pol))}${coOccurrences.get(pol -> w).mkString}") { @@ -1006,7 +1015,7 @@ trait TypeSimplifier { self: Typer => nv }) pol(tv) match { - case S(p) if inlineBounds && !occursInvariantly(tv) && !recVars.contains(tv) => + case S(p) if inlineBounds && !occursInvariantly(tv) && !recVars.contains(tv) && tv.tsc.isEmpty => // * Inline the bounds of non-rec non-invar-occ type variables println(s"Inlining [${printPol(p)}] bounds of $tv (~> $res)") // if (p) mergeTransform(true, pol, tv, Set.single(tv), canDistribForall) | res diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 7b9369fa4b..a1912eaa85 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -114,9 +114,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne }.toList, innerTy) val ambiguous: Bool = innerTy.getVars.toList.flatMap(_.tsc) - .flatMap(_._1.tvs) + .flatMap(_._1.tvs).distinct .groupBy(_._2) - .exists { case (v,pvs) => pvs.distinct.sizeIs > 1 } + .exists { case (v,pvs) => pvs.sizeIs > 1 } if (ambiguous) raise(ErrorReport(Ls(fromStr("ambiguous") -> N), true)) println(s"Inferred poly constr: $cty —— where ${cty.showBounds}") diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index c0a6a543cf..21d2978883 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -758,7 +758,7 @@ abstract class TyperHelpers { Typer: Typer => val poltv = pol(tv) (if (poltv =/= S(false)) tv.lowerBounds.map(pol.at(tv.level, true) -> _) else Nil) ::: (if (poltv =/= S(true)) tv.upperBounds.map(pol.at(tv.level, false) -> _) else Nil) ::: - (tv.tsc.keys.flatMap(_.tvs).toList.distinct.map(u => pol.at(tv.level,u._1) -> u._2)) + tv.tsc.keys.flatMap(_.tvs).map(u => pol.at(tv.level,u._1) -> u._2).toList case FunctionType(l, r) => pol.contravar -> l :: pol.covar -> r :: Nil case Overload(as) => as.map(pol -> _) case ComposedType(_, l, r) => pol -> l :: pol -> r :: Nil @@ -1307,6 +1307,7 @@ abstract class TyperHelpers { Typer: Typer => val poltv = pol(tv) if (poltv =/= S(false)) tv.lowerBounds.foreach(apply(pol.at(tv.level, true))) if (poltv =/= S(true)) tv.upperBounds.foreach(apply(pol.at(tv.level, false))) + tv.tsc.keys.flatMap(_.tvs).foreach(u => apply(pol.at(tv.level,u._1))(u._2)) case FunctionType(l, r) => apply(pol.contravar)(l); apply(pol)(r) case Overload(as) => as.foreach(apply(pol)) case ComposedType(_, l, r) => apply(pol)(l); apply(pol)(r) @@ -1399,7 +1400,7 @@ abstract class TyperHelpers { Typer: Typer => private val lvl = 0 def apply(lvl: Level): Pol def quantifPolarity(lvl: Level): PolMap - final def apply(tv: TV): Pol = if (tv.tsc.isEmpty) apply(tv.level) else N + final def apply(tv: TV): Pol = apply(tv.level) def enter(polymLvl: Level): PolMap = new PolMap(base) { def apply(lvl: Level): Pol = diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 27578a3aee..d1daf19164 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -373,7 +373,6 @@ q(0) : true //│ = //│ q is not implemented - q(1) //│ 'a //│ where @@ -481,17 +480,15 @@ let g = x => s(r(x)) :e g(0) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.482: g(0) +//│ ║ l.481: g(0) //│ ║ ^^^^ //│ ╟── integer literal of type `Int` does not match type `?a` -//│ ║ l.482: g(0) +//│ ║ l.481: g(0) //│ ║ ^ //│ ╟── Note: constraint arises from application: -//│ ║ l.470: let g = x => s(r(x)) +//│ ║ l.469: let g = x => s(r(x)) //│ ╙── ^^^^ -//│ forall 'a. error | 'a -//│ where -//│ [+'b, -'a] in {} +//│ error //│ res //│ = //│ g and s are not implemented @@ -517,28 +514,18 @@ fun app2: ('a -> 'a -> 'a) -> 'a -> 'a fun snd: A -> Int -> Int & Str -> Str -> Str //│ fun snd: A -> Int -> Int & Str -> Str -> Str -// FIXME :e x => app2(snd)(x):Int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.522: x => app2(snd)(x):Int +//│ ║ l.518: x => app2(snd)(x):Int //│ ║ ^^^^^^^^^^^^ //│ ╟── application of type `'a` does not match type `nothing` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.522: x => app2(snd)(x):Int +//│ ║ l.518: x => app2(snd)(x):Int //│ ╙── ^^^ //│ ╔══[ERROR] ambiguous //│ ╙── -//│ /!!!\ Uncaught error: java.lang.AssertionError: assertion failed: α316_323' has no occurrences... - -fun app2_ (f:'a -> 'a -> 'a)(x) = f(x)(x) -//│ fun app2_: forall 'a. (f: 'a -> 'a -> 'a) -> 'a -> 'a - -app2_(snd) -//│ 'a -> 'b -//│ where -//│ 'a <: 'b -//│ [+'a, -'a, -'b] in {[A & Int, Int, Int], [Str, Str, Str]} +//│ nothing -> Int //│ res //│ = -//│ snd is not implemented +//│ app2 is not implemented From c46b74fe2aedee256b360dfb267d0f93e98007b5 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 1 Aug 2024 00:00:04 +0800 Subject: [PATCH 27/43] minor changes --- .../scala/mlscript/ConstraintSolver.scala | 10 +++--- shared/src/main/scala/mlscript/Typer.scala | 9 +++-- shared/src/test/diff/nu/HeungTung.mls | 33 ++++++++++++++----- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 259d854d6c..fbc02abb75 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -825,12 +825,13 @@ class ConstraintSolver extends NormalForms { self: Typer => val newBound = (cctx._1 ::: cctx._2.reverse).foldRight(rhs)((c, ty) => if (c.prov is noProv) ty else mkProxy(ty, c.prov)) lhs.upperBounds ::= newBound // update the bound - lhs.tsc.toList.flatMap { case (k,v)=>v.map((k,_)) }.foreach { - case (tsc, i) => + lhs.tsc.foreachEntry { (tsc, v) => + v.foreach { i => if (!tsc.tvs(i)._1) { tsc.updateOn(i, rhs) if (tsc.constraints.isEmpty) reportError() } + } } val u = lhs.tsc.filter(_._1.constraints.sizeCompare(1) === 0) u.foreachEntry { case (k, _) => lhs.tsc.remove(k) } @@ -846,12 +847,13 @@ class ConstraintSolver extends NormalForms { self: Typer => val newBound = (cctx._1 ::: cctx._2.reverse).foldLeft(lhs)((ty, c) => if (c.prov is noProv) ty else mkProxy(ty, c.prov)) rhs.lowerBounds ::= newBound // update the bound - rhs.tsc.toList.flatMap { case (k,v)=>v.map((k,_)) }.foreach { - case (tsc, i) => + rhs.tsc.foreachEntry { (tsc, v) => + v.foreach { i => if(tsc.tvs(i)._1) { tsc.updateOn(i, lhs) if (tsc.constraints.isEmpty) reportError() } + } } val u = rhs.tsc.filter(_._1.constraints.sizeCompare(1) === 0) u.foreachEntry { case (k, _) => rhs.tsc.remove(k) } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index a1912eaa85..45b3d956a6 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -113,11 +113,14 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne if (p) (b, tv) else (tv, b) } }.toList, innerTy) - val ambiguous: Bool = innerTy.getVars.toList.flatMap(_.tsc) + val ambiguous = innerTy.getVars.toList.flatMap(_.tsc) .flatMap(_._1.tvs).distinct .groupBy(_._2) - .exists { case (v,pvs) => pvs.sizeIs > 1 } - if (ambiguous) raise(ErrorReport(Ls(fromStr("ambiguous") -> N), true)) + .filter { case (v,pvs) => pvs.sizeIs > 1 } + if (ambiguous.nonEmpty) raise(ErrorReport( + msg"ambiguous" -> N :: + ambiguous.map { case (v,_) => msg"cannot determine satisfiability of type ${v.expPos}" -> v.prov.loco }.toList + , true)) println(s"Inferred poly constr: $cty —— where ${cty.showBounds}") diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index d1daf19164..744a84f869 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -423,7 +423,9 @@ fun r: Int -> Int & Bool -> Bool :e x => r(r(x)) //│ ╔══[ERROR] ambiguous -//│ ╙── +//│ ╟── cannot determine satisfiability of type ?a +//│ ║ l.424: x => r(r(x)) +//│ ╙── ^^^^ //│ forall 'a 'b. 'a -> 'b //│ where //│ [+'c, -'b] in {[Int, Int], [Bool, Bool]} @@ -468,7 +470,9 @@ fun s: Str -> Str & AA -> AA :e let g = x => s(r(x)) //│ ╔══[ERROR] ambiguous -//│ ╙── +//│ ╟── cannot determine satisfiability of type ?a +//│ ║ l.471: let g = x => s(r(x)) +//│ ╙── ^^^^ //│ let g: forall 'a 'b. 'a -> 'b //│ where //│ [+'c, -'b] in {[Str, Str], [AA, AA]} @@ -480,13 +484,13 @@ let g = x => s(r(x)) :e g(0) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.481: g(0) +//│ ║ l.485: g(0) //│ ║ ^^^^ //│ ╟── integer literal of type `Int` does not match type `?a` -//│ ║ l.481: g(0) +//│ ║ l.485: g(0) //│ ║ ^ //│ ╟── Note: constraint arises from application: -//│ ║ l.469: let g = x => s(r(x)) +//│ ║ l.471: let g = x => s(r(x)) //│ ╙── ^^^^ //│ error //│ res @@ -514,18 +518,31 @@ fun app2: ('a -> 'a -> 'a) -> 'a -> 'a fun snd: A -> Int -> Int & Str -> Str -> Str //│ fun snd: A -> Int -> Int & Str -> Str -> Str + :e x => app2(snd)(x):Int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.518: x => app2(snd)(x):Int +//│ ║ l.523: x => app2(snd)(x):Int //│ ║ ^^^^^^^^^^^^ //│ ╟── application of type `'a` does not match type `nothing` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.518: x => app2(snd)(x):Int +//│ ║ l.523: x => app2(snd)(x):Int //│ ╙── ^^^ //│ ╔══[ERROR] ambiguous -//│ ╙── +//│ ╙── cannot determine satisfiability of type 'a //│ nothing -> Int //│ res //│ = //│ app2 is not implemented + +fun app2_ (f:'a -> 'a -> 'a)(x) = f(x)(x) +//│ fun app2_: forall 'a. (f: 'a -> 'a -> 'a) -> 'a -> 'a + +app2_(snd) +//│ 'a -> 'b +//│ where +//│ 'a <: 'b +//│ [+'a, -'a, -'b] in {[A & Int, Int, Int], [Str, Str, Str]} +//│ res +//│ = +//│ snd is not implemented From cf244aaa5788c464e19b9aca64b002f5e1bb8b0e Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 1 Aug 2024 20:20:31 +0800 Subject: [PATCH 28/43] fix compilation error --- .../scala/mlscript/compiler/ClassLifter.scala | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala index 533ab83b16..b6aa7bcce3 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala @@ -510,7 +510,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { val nlhs = liftType(lb) val nrhs = liftType(ub) Bounds(nlhs._1, nrhs._1) -> (nlhs._2 ++ nrhs._2) - case Constrained(base: Type, bounds, where) => + case Constrained(base: Type, bounds, where, tscs) => val (nTargs, nCtx) = bounds.map { case (tv, Bounds(lb, ub)) => val nlhs = liftType(lb) val nrhs = liftType(ub) @@ -521,10 +521,18 @@ class ClassLifter(logDebugMsg: Boolean = false) { val nrhs = liftType(ub) Bounds(nlhs._1, nrhs._1) -> (nlhs._2 ++ nrhs._2) }.unzip + val (tscs0, nCtx3) = tscs.map { case (tvs, cs) => + val (ntvs,c0) = tvs.map { case (p,v) => + val (nv, c) = liftType(v) + (p,nv) -> c + }.unzip + val (ncs,c1) = cs.map(_.map(liftType).unzip).unzip + (ntvs,ncs) -> (c0 ++ c1.flatten) + }.unzip val (nBase, bCtx) = liftType(base) - Constrained(nBase, nTargs, bounds2) -> - ((nCtx ++ nCtx2).fold(emptyCtx)(_ ++ _) ++ bCtx) - case Constrained(_, _, _) => die + Constrained(nBase, nTargs, bounds2, tscs0) -> + ((nCtx ++ nCtx2 ++ nCtx3.flatten).fold(emptyCtx)(_ ++ _) ++ bCtx) + case Constrained(_, _, _, _) => die case Function(lhs, rhs) => val nlhs = liftType(lhs) val nrhs = liftType(rhs) From db8379e5cef6252dd1d9d3d3fc45e7b5b01df504 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Fri, 2 Aug 2024 00:25:21 +0800 Subject: [PATCH 29/43] tests explanation --- shared/src/test/diff/basics/Intersections.fun | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shared/src/test/diff/basics/Intersections.fun b/shared/src/test/diff/basics/Intersections.fun index d39f38d083..a3b54a0566 100644 --- a/shared/src/test/diff/basics/Intersections.fun +++ b/shared/src/test/diff/basics/Intersections.fun @@ -26,7 +26,10 @@ succ / foo(1) let foo = (Int => Int) & (Bool => Bool) //│ foo: int -> int & bool -> bool -foo(1) // returns int & bool, equivalent to nothing +// used to return int & bool, equivalent to nothing +// or approximated as int | bool in MLscript +// overloaded function foo can now be used as either int -> int or bool -> bool +foo(1) succ / foo(1) foo(true) not / foo(true) From d2b8f2b6acbb3aab6211aeed314fff6094b36c10 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Fri, 2 Aug 2024 00:42:42 +0800 Subject: [PATCH 30/43] run tests --- shared/src/test/diff/basics/Intersections.fun | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/shared/src/test/diff/basics/Intersections.fun b/shared/src/test/diff/basics/Intersections.fun index a3b54a0566..f409b8e61a 100644 --- a/shared/src/test/diff/basics/Intersections.fun +++ b/shared/src/test/diff/basics/Intersections.fun @@ -42,46 +42,46 @@ not / foo(true) not / foo(1) foo(1) as Nothing //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.39: not / foo(1) +//│ ║ l.42: not / foo(1) //│ ║ ^^^^^^^^^^^^ //│ ╟── application of type `int` is not an instance of type `bool` -//│ ║ l.39: not / foo(1) +//│ ║ l.42: not / foo(1) //│ ╙── ^^^^^^ //│ res: bool | error //│ ╔══[ERROR] Type mismatch in 'as' binding: -//│ ║ l.40: foo(1) as Nothing +//│ ║ l.43: foo(1) as Nothing //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── application of type `int` does not match type `nothing` -//│ ║ l.40: foo(1) as Nothing +//│ ║ l.43: foo(1) as Nothing //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.40: foo(1) as Nothing +//│ ║ l.43: foo(1) as Nothing //│ ╙── ^^^^^^^ //│ res: nothing :e foo as Nothing //│ ╔══[ERROR] Type mismatch in 'as' binding: -//│ ║ l.60: foo as Nothing +//│ ║ l.63: foo as Nothing //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type intersection of type `int -> int & bool -> bool` does not match type `nothing` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `nothing` -//│ ║ l.60: foo as Nothing +//│ ║ l.63: foo as Nothing //│ ║ ^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.60: foo as Nothing +//│ ║ l.63: foo as Nothing //│ ╙── ^^^^^^^ //│ res: nothing :e let oops = (&) //│ ╔══[ERROR] Illegal use of reserved operator: & -//│ ║ l.76: let oops = (&) +//│ ║ l.79: let oops = (&) //│ ╙── ^^^ //│ ╔══[ERROR] identifier not found: & -//│ ║ l.76: let oops = (&) +//│ ║ l.79: let oops = (&) //│ ╙── ^^^ //│ oops: error From fc32f52ceb4dcd21c04612572adebc1ec6e4b81c Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:09:27 +0800 Subject: [PATCH 31/43] fix freshenAbove --- .../scala/mlscript/ConstraintSolver.scala | 49 ++++--- shared/src/main/scala/mlscript/Typer.scala | 2 + .../main/scala/mlscript/TyperDatatypes.scala | 127 ++++++++---------- shared/src/test/diff/basics/Intersections.fun | 20 ++- shared/src/test/diff/fcp/Overloads.mls | 23 ++-- shared/src/test/diff/nu/HeungTung.mls | 24 ++-- 6 files changed, 128 insertions(+), 117 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index ee95d28a29..60bad56778 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -848,7 +848,13 @@ class ConstraintSolver extends NormalForms { self: Typer => } } val u = lhs.tsc.filter(_._1.constraints.sizeCompare(1) === 0) - u.foreachEntry { case (k, _) => lhs.tsc.remove(k) } + u.foreachEntry { case (k, _) => + k.tvs.foreach { + case (_,tv: TV) => tv.tsc.remove(k) + case (_,ProvType(tv: TV)) => tv.tsc.remove(k) + case _ => () + } + } u.foreachEntry { case (k, _) => k.constraints.head.zip(k.tvs).foreach { case (c, (pol, t)) => if (pol) rec(t, c, true) else rec(c, t, true) @@ -870,7 +876,13 @@ class ConstraintSolver extends NormalForms { self: Typer => } } val u = rhs.tsc.filter(_._1.constraints.sizeCompare(1) === 0) - u.foreachEntry { case (k, _) => rhs.tsc.remove(k) } + u.foreachEntry { case (k, _) => + k.tvs.foreach { + case (_,tv: TV) => tv.tsc.remove(k) + case (_,ProvType(tv: TV)) => tv.tsc.remove(k) + case _ => () + } + } u.foreachEntry { case (k, _) => k.constraints.head.zip(k.tvs).foreach { case (c, (pol, t)) => if (pol) rec(t, c, true) else rec(c, t, true) @@ -1524,7 +1536,6 @@ class ConstraintSolver extends NormalForms { self: Typer => (implicit ctx: Ctx, freshened: MutMap[TV, ST]) : SimpleType = { - val freshenTsc: MutSet[TupleSetConstraints] = MutSet.empty def freshenImpl(ty: SimpleType, below: Level): SimpleType = // (trace(s"${lvl}. FRESHEN $ty || $above .. $below ${ty.level} ${ty.level <= above}") { @@ -1600,10 +1611,28 @@ class ConstraintSolver extends NormalForms { self: Typer => assert(lvl <= below, "this condition should be false for the result to be correct") lvl }) + val freshentsc = tv.tsc.flatMap { case (tsc,_) => + if (tsc.tvs.forall { + case (_,tv: TV) => !freshened.contains(tv) + case (_,ProvType(tv: TV)) => !freshened.contains(tv) + case _ => true + }) S(tsc) else N + } freshened += tv -> v v.lowerBounds = tv.lowerBounds.mapConserve(freshen) v.upperBounds = tv.upperBounds.mapConserve(freshen) - tv.tsc.foreachEntry { case (tsc, _) => freshenTsc += tsc } + freshentsc.foreach { tsc => + val t = new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov) + t.constraints = t.constraints.map(_.map(freshen)) + t.tvs = t.tvs.map(x => (x._1,freshen(x._2))) + t.tvs.zipWithIndex.foreach { + case ((pol, tv: TV), i) => + tv.tsc.updateWith(t)(_.map(_ + i).orElse(S(Set(i)))) + case ((pol, ProvType(tv: TV)), i) => + tv.tsc.updateWith(t)(_.map(_ + i).orElse(S(Set(i)))) + case _ => () + } + } v } @@ -1650,17 +1679,7 @@ class ConstraintSolver extends NormalForms { self: Typer => }} // (r => s"=> $r")) - val r = freshenImpl(ty, below) - val fr = Map.empty[ST, ST] ++ freshened - freshenTsc.foreach { tsc => - val t = new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov) - t.tvs = t.tvs.map(x => (x._1, substSyntax(x._2)(fr))) - t.tvs.zipWithIndex.foreach { - case ((pol, tv: TV), i) => tv.tsc.updateWith(t)(_.map(_ + i).orElse(S(Set(i)))) - case _ => () - } - } - r + freshenImpl(ty, below) } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index e29f76e6f6..af8f1416a2 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -689,6 +689,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne val tsc = new TupleSetConstraints(constrs.map(_.map(rec)), tvs)(res.prov) tvs.zipWithIndex.foreach { case ((_, tv: TV), i) => tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) + case ((_, ProvType(tv: TV)), i) => tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) case _ => () } } @@ -1993,6 +1994,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne if (seenTscs.add(tsc)) { val tvs = tsc.tvs.map { case (pol, tv: TV) => (pol, tv.asTypeVar) + case (pol, ProvType(tv: TV)) => (pol, tv.asTypeVar) case (pol, t) => (pol, go(t)) } val constrs = tsc.constraints.map(_.map(go)) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 1b772b0e1c..56bcc8e755 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -675,31 +675,29 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => class TupleSetConstraints(var constraints: Ls[Ls[ST]], var tvs: Ls[(Bool, ST)])(val prov: TypeProvenance) { def updateImpl(index: Int, bound: ST)(implicit raise: Raise, ctx: Ctx) : Unit = { - val (cs0, u0) = constraints.flatMap { c => - TupleSetConstraints.lcg(tvs(index)._1, bound, c(index))(prov, ctx).map(u => (c, u)) - }.unzip - val u = u0.map { - case (x,y) => (x, y.groupBy(_._1).view.mapValues { l => - val p = l.head._1._1 - List(l.map(_._2).reduce[ST]((x,y) => ComposedType(!p,x,y)(noProv))) - }.toMap) + val u0 = constraints.flatMap { c => + TupleSetConstraints.lcg(tvs(index)._1, bound, c(index)).map(tvs.zip(c)++_) } - constraints = cs0 - if (!u0.isEmpty) { - val (tvs0, m) = u.reduce[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] { - case ((xl, xm), (yl, ym)) => - val l = (xl.filter(ym.contains(_)) ++ yl.filter(xm.contains(_))).distinct - (l, l.map(t => (t, xm(t) ++ ym(t))).toMap) + val u = u0.map { x => + x.groupMap(_._1)(_._2).map { case (u@(p,_),l) => + (u,l.reduce((x,y) => ComposedType(!p,x,y)(noProv))) } - if (!tvs0.isEmpty) { - val ncs = cs0.zip(tvs0.map(m(_)).transpose).map { case (u, v) => u ++ v } - constraints = ncs - tvs ++= tvs0 - tvs.zipWithIndex.foreach { - case ((pol, tv: TV), i) => tv.tsc.updateWith(this)(_.map(_ + i).orElse(S(Set(i)))) - case _ => () - } + } + tvs.foreach { + case (_, tv: TV) => tv.tsc += this -> Set.empty + case (_, ProvType(tv: TV)) => tv.tsc += this -> Set.empty + case _ => () + } + if (!u.isEmpty) { + tvs = u.flatMap(_.keys).distinct + constraints = tvs.map(x => u.map(_.getOrElse(x,if (x._1) TopType else BotType))).transpose + tvs.zipWithIndex.foreach { + case ((pol, tv: TV), i) => tv.tsc.updateWith(this)(_.map(_ + i).orElse(S(Set(i)))) + case ((pol, ProvType(tv: TV)), i) => tv.tsc.updateWith(this)(_.map(_ + i).orElse(S(Set(i)))) + case _ => () } + } else { + constraints = Nil } } def updateOn(index: Int, bound: ST)(implicit raise: Raise, ctx: Ctx) : Unit = { @@ -709,96 +707,80 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } } object TupleSetConstraints { - def lcgField(pol: Bool, first: FieldType, rest: FieldType) - (implicit prov: TypeProvenance, ctx: Ctx) - : Opt[(Ls[(Bool, ST)], Ls[(Bool, ST) -> ST])] = { + def lcgField(pol: Bool, first: FieldType, rest: FieldType)(implicit ctx: Ctx) + : Opt[Ls[(Bool, ST) -> ST]] = { for { - (ubl, ubm) <- lcg(pol, first.ub, rest.ub) - (lbl, lbm) <- { + ubm <- lcg(pol, first.ub, rest.ub) + lbm <- { if (first.lb.isEmpty && rest.lb.isEmpty) - S(Nil, Nil) + S(Nil) else lcg(!pol, first.lb.getOrElse(BotType), rest.lb.getOrElse(BotType)) } } yield { - (ubl ++ lbl, ubm ++ lbm) + ubm ++ lbm } } - def lcg(pol: Bool, first: ST, rest: ST) - (implicit prov: TypeProvenance, ctx: Ctx) - : Opt[(Ls[(Bool, ST)], Ls[(Bool, ST) -> ST])] = (first.unwrapProxies, rest.unwrapProxies) match { + def lcg(pol: Bool, first: ST, rest: ST)(implicit ctx: Ctx) + : Opt[Ls[(Bool, ST) -> ST]] = (first.unwrapProxies, rest.unwrapProxies) match { case (a, ComposedType(p,l,r)) if p =/= pol => for { - (ll,lm) <- lcg(pol,a,l) - (rl,rm) <- lcg(pol,a,r) + lm <- lcg(pol,a,l) + rm <- lcg(pol,a,r) } yield { - (ll ++ rl,((pol, first) -> rest)::lm ++ rm) + lm ++ rm } - case (a: TV, b: TV) if a.compare(b) === 0 => S(Nil, Nil) - case (a: TV, b) => S(List((pol, a)), List((pol, a) -> b)) - case (a, b: TV) => S(List((pol, a)), List((pol, a) -> b)) + case (a: TV, b: TV) if a.compare(b) === 0 => S(Nil) + case (a: TV, b) => S(List((pol, first) -> rest)) + case (a, b: TV) => S(List((pol, first) -> rest)) case (a: FT, b: FT) => lcgFunction(pol, a, b) - case (a: FT, b) => N - case (a: ArrayType, b: ArrayType) => - for { (l, m) <- lcgField(pol, a.inner, b.inner) } yield { - (l, ((pol, a) -> b) :: m) - } + case (a: ArrayType, b: ArrayType) => lcgField(pol, a.inner, b.inner) case (a: TupleType, b: TupleType) if a.fields.sizeCompare(b.fields) === 0 => val fs = a.fields.map(_._2).zip(b.fields.map(_._2)).map(u => lcgField(pol, u._1, u._2)) if (!fs.contains(N)) { - val (l, m) = fs.flatten.reduce[(Ls[(Bool, ST)], Ls[(Bool, ST) -> ST])] { - case ((xl, xm), (yl, ym)) => (xl ++ yl, xm ++ ym) - } - S(l, ((pol, a) -> b) :: m) + S(fs.flatten.reduce(_++_)) } else N case (a: TupleType, b: RecordType) if pol => lcg(pol, a.toRecord, b) case (a: RecordType, b: RecordType) => - val default = FieldType(N, if (pol) TopType else BotType)(prov) + val default = FieldType(N, if (pol) TopType else BotType)(noProv) if (b.fields.map(_._1).forall(a.fields.map(_._1).contains)) { val u = a.fields.map { case (v, f) => lcgField(pol, f, b.fields.find(_._1 === v).fold(default)(_._2)) } if (!u.contains(N)) { - val (l, m) = u.flatten.reduce[(Ls[(Bool, ST)], Ls[(Bool, ST) -> ST])] { - case ((xl, xm), (yl, ym)) => (xl ++ yl, xm ++ ym) - } - S(l, ((pol, a) -> b) :: m) + S(u.flatten.reduce(_++_)) } else N } else N - case (a, b) if a === b => S(Nil, List((pol, a) -> b)) + case (a, b) if a === b => S(Nil) case (a, b) => val dnf = DNF.mk(MaxLevel, Nil, if (pol) a & b.neg() else b & a.neg(), true) if (dnf.isBot) - S(Nil, List((pol, a) -> b)) + S(Nil) else if (dnf.cs.forall(c => !(c.vars.isEmpty && c.nvars.isEmpty))) - S(List((pol, a)), List((pol, a) -> b)) + S(List((pol, first) -> rest)) else N } def lcgFunction(pol: Bool, first: FT, rest: FT) - (implicit prov: TypeProvenance, ctx: Ctx) - : Opt[(Ls[(Bool, ST)], Ls[(Bool, ST) -> ST])] = { + (implicit ctx: Ctx) + : Opt[Ls[(Bool, ST) -> ST]] = { for { - (ll, lm) <- lcg(!pol, first.lhs, rest.lhs) - (rl, rm) <- lcg(pol, first.rhs, rest.rhs) + lm <- lcg(!pol, first.lhs, rest.lhs) + rm <- lcg(pol, first.rhs, rest.rhs) } yield { - (ll ++ rl,((pol, first) -> rest) :: lm ++ rm) + lm ++ rm } } def mk(ov: Overload, f: FT)(implicit raise: Raise, ctx: Ctx): Opt[TupleSetConstraints] = { - val u = ov.alts.map(lcgFunction(false, f, _)(ov.prov, ctx)).flatten.map { - case (x,y) => (x, y.groupBy(_._1).view.mapValues { l => - val p = l.head._1._1 - List(l.map(_._2).reduce[ST]((x,y) => ComposedType(!p,x,y)(noProv))) - }.toMap) + val u = ov.alts.map(lcgFunction(false, f, _)).flatten.map { x => + x.groupMap(_._1)(_._2).map { case (u@(p,_),l) => + (u,l.reduce((x,y) => ComposedType(!p,x,y)(noProv))) + } } if (u.isEmpty) { return N } - val (tvs, m) = u.reduce[(Ls[(Bool, ST)], Map[(Bool, ST), Ls[ST]])] { - case ((xl, xm), (yl, ym)) => - val l = (xl.filter(ym.contains(_)) ++ yl.filter(xm.contains(_))).distinct - (l, l.map(t => (t, xm(t) ++ ym(t))).toMap) - } - val tsc = new TupleSetConstraints(tvs.map(m(_)).transpose, tvs)(ov.prov) - tvs.zipWithIndex.foreach { + val tvs = u.flatMap(_.keys).distinct + val m = tvs.map(x => u.map(_.getOrElse(x,if (x._1) TopType else BotType))) + val tsc = new TupleSetConstraints(m.transpose, tvs)(ov.prov) + tvs.map(x => (x._1,x._2.unwrapProxies)).zipWithIndex.foreach { case ((true, tv: TV), i) => tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) tv.lowerBounds.foreach(tsc.updateImpl(i, _)) @@ -811,6 +793,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => if (tsc.constraints.sizeCompare(1) === 0) { tvs.foreach { case (_, tv: TV) => tv.tsc.remove(tsc) + case (_, ProvType(tv: TV)) => tv.tsc.remove(tsc) case _ => () } tsc.constraints.head.zip(tvs).foreach { diff --git a/shared/src/test/diff/basics/Intersections.fun b/shared/src/test/diff/basics/Intersections.fun index f409b8e61a..9b4f8347b2 100644 --- a/shared/src/test/diff/basics/Intersections.fun +++ b/shared/src/test/diff/basics/Intersections.fun @@ -44,14 +44,20 @@ foo(1) as Nothing //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.42: not / foo(1) //│ ║ ^^^^^^^^^^^^ -//│ ╟── application of type `int` is not an instance of type `bool` +//│ ╟── reference of type `int` is not an instance of type `bool` +//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) +//│ ║ ^^^ +//│ ╟── but it flows into application with expected type `bool` //│ ║ l.42: not / foo(1) //│ ╙── ^^^^^^ //│ res: bool | error //│ ╔══[ERROR] Type mismatch in 'as' binding: //│ ║ l.43: foo(1) as Nothing //│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `int` does not match type `nothing` +//│ ╟── reference of type `int` does not match type `nothing` +//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) +//│ ║ ^^^ +//│ ╟── but it flows into application with expected type `nothing` //│ ║ l.43: foo(1) as Nothing //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from reference: @@ -62,26 +68,26 @@ foo(1) as Nothing :e foo as Nothing //│ ╔══[ERROR] Type mismatch in 'as' binding: -//│ ║ l.63: foo as Nothing +//│ ║ l.69: foo as Nothing //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type intersection of type `int -> int & bool -> bool` does not match type `nothing` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `nothing` -//│ ║ l.63: foo as Nothing +//│ ║ l.69: foo as Nothing //│ ║ ^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.63: foo as Nothing +//│ ║ l.69: foo as Nothing //│ ╙── ^^^^^^^ //│ res: nothing :e let oops = (&) //│ ╔══[ERROR] Illegal use of reserved operator: & -//│ ║ l.79: let oops = (&) +//│ ║ l.85: let oops = (&) //│ ╙── ^^^ //│ ╔══[ERROR] identifier not found: & -//│ ║ l.79: let oops = (&) +//│ ║ l.85: let oops = (&) //│ ╙── ^^^ //│ oops: error diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index d886432ff5..7c41492a83 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -76,7 +76,7 @@ IISS : (0 | 1) -> number IISS : 'a -> 'a //│ res: 'a -> 'a //│ where -//│ [+'a, -'a] in {[int, int], [string, string]} +//│ [-'a, +'a] in {[int, int], [string, string]} IISS 0 //│ res: int @@ -100,16 +100,17 @@ def f = fun x -> (if true then IISS else BBNN) x f(0) //│ res: number + // FIXME f(0) + 1 //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.104: f(0) + 1 +//│ ║ l.105: f(0) + 1 //│ ║ ^^^^^^ //│ ╟── type `number` is not an instance of type `int` //│ ║ l.13: def BBNN: bool -> bool & number -> number //│ ║ ^^^^^^ //│ ╟── but it flows into integer literal with expected type `int` -//│ ║ l.104: f(0) + 1 +//│ ║ l.105: f(0) + 1 //│ ╙── ^ //│ res: error | int @@ -119,10 +120,10 @@ f : int -> number :e f : number -> int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.120: f : number -> int +//│ ║ l.121: f : number -> int //│ ║ ^ //│ ╟── type `number` does not match type `?a` -//│ ║ l.120: f : number -> int +//│ ║ l.121: f : number -> int //│ ╙── ^^^^^^ //│ res: number -> int @@ -139,16 +140,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.140: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.141: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.140: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.141: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.140: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.141: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number @@ -167,13 +168,13 @@ not test //│ <: test: //│ ~(int -> int) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.165: not test +//│ ║ l.166: not test //│ ║ ^^^^^^^^ //│ ╟── type `~(int -> int)` is not an instance of type `bool` -//│ ║ l.159: def test: ~(int -> int) +//│ ║ l.160: def test: ~(int -> int) //│ ║ ^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `bool` -//│ ║ l.165: not test +//│ ║ l.166: not test //│ ╙── ^^^^ //│ res: bool | error diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index d745ad214f..15239d1721 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -434,8 +434,8 @@ x => r(r(x)) //│ ╙── ^^^^ //│ forall 'a 'b. 'a -> 'b //│ where -//│ [+'c, -'b] in {[Int, Int], [Bool, Bool]} -//│ [+'a, -'c] in {[Int, Int], [Bool, Bool]} +//│ [-'b, +'c] in {[Int, Int], [Bool, Bool]} +//│ [-'c, +'a] in {[Int, Int], [Bool, Bool]} //│ res //│ = //│ r is not implemented @@ -457,9 +457,9 @@ fun u: {x:0, y:Int} -> Int & {x:1, z: Str} -> Str //│ fun u: {x: 0, y: Int} -> Int & {x: 1, z: Str} -> Str (a, b, c) => u({x: a, y: b, z: c}) -//│ forall 'a 'b 'c 'd. ('a, 'b, 'c) -> 'd +//│ forall 'a 'b 'c 'd. ('a, 'c, 'd) -> 'b //│ where -//│ [+'a, +'b, +'c, -'d] in {[0, Int, anything, Int], [1, anything, Str, Str]} +//│ [-'b, +'c, +'a, +'d] in {[Int, Int, 0, anything], [Str, anything, 1, Str]} //│ res //│ = //│ u is not implemented @@ -477,7 +477,7 @@ fun s: Str -> Str & AA -> AA let g = x => s(r(x)) //│ let g: forall 'a 'b. 'a -> 'b //│ where -//│ [+'c, -'b] in {[Str, Str], [AA, AA]} +//│ [-'b, +'c] in {[Str, Str], [AA, AA]} //│ [+'a, -'c] in {[Int, Int], [Bool, Bool]} //│ g //│ = @@ -520,18 +520,18 @@ fun app2: ('a -> 'a -> 'a) -> 'a -> 'a fun snd: A -> Int -> Int & Str -> Str -> Str //│ fun snd: A -> Int -> Int & Str -> Str -> Str - :e x => app2(snd)(x):Int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.525: x => app2(snd)(x):Int +//│ ║ l.524: x => app2(snd)(x):Int //│ ║ ^^^^^^^^^^^^ -//│ ╟── application of type `'a` does not match type `nothing` +//│ ╟── application of type `Int` is not an instance of type `A` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.525: x => app2(snd)(x):Int +//│ ║ l.520: fun snd: A -> Int -> Int & Str -> Str -> Str +//│ ║ ^ +//│ ╟── from type reference: +//│ ║ l.524: x => app2(snd)(x):Int //│ ╙── ^^^ -//│ ╔══[ERROR] ambiguous -//│ ╙── cannot determine satisfiability of type 'a //│ nothing -> Int //│ res //│ = @@ -544,7 +544,7 @@ app2_(snd) //│ 'a -> 'b //│ where //│ 'a <: 'b -//│ [+'a, -'a, -'b] in {[A & Int, Int, Int], [Str, Str, Str]} +//│ [-'b, +'a, -'a] in {[Int, A & Int, Int], [Str, Str, Str]} //│ res //│ = //│ snd is not implemented From 09b50829f926afcecefcb7add816c67c0d4bcbc4 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 26 Aug 2024 16:51:23 +0800 Subject: [PATCH 32/43] Changes from meeting --- .../main/scala/mlscript/ConstraintSolver.scala | 8 ++++---- shared/src/test/diff/fcp/Overloads.mls | 4 ++-- shared/src/test/diff/nu/HeungTung.mls | 17 +++++++---------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 60bad56778..3654d1e342 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -849,7 +849,7 @@ class ConstraintSolver extends NormalForms { self: Typer => } val u = lhs.tsc.filter(_._1.constraints.sizeCompare(1) === 0) u.foreachEntry { case (k, _) => - k.tvs.foreach { + k.tvs.mapValues(_.unwrapProxies).foreach { // TODO less inefficient; remove useless case case (_,tv: TV) => tv.tsc.remove(k) case (_,ProvType(tv: TV)) => tv.tsc.remove(k) case _ => () @@ -857,7 +857,7 @@ class ConstraintSolver extends NormalForms { self: Typer => } u.foreachEntry { case (k, _) => k.constraints.head.zip(k.tvs).foreach { - case (c, (pol, t)) => if (pol) rec(t, c, true) else rec(c, t, true) + case (c, (pol, t)) => if (pol) rec(t, c, false) else rec(c, t, false) } } lhs.lowerBounds.foreach(rec(_, rhs, true)) // propagate from the bound @@ -877,7 +877,7 @@ class ConstraintSolver extends NormalForms { self: Typer => } val u = rhs.tsc.filter(_._1.constraints.sizeCompare(1) === 0) u.foreachEntry { case (k, _) => - k.tvs.foreach { + k.tvs.mapValues(_.unwrapProxies).foreach { // TODO less inefficient; remove useless case case (_,tv: TV) => tv.tsc.remove(k) case (_,ProvType(tv: TV)) => tv.tsc.remove(k) case _ => () @@ -885,7 +885,7 @@ class ConstraintSolver extends NormalForms { self: Typer => } u.foreachEntry { case (k, _) => k.constraints.head.zip(k.tvs).foreach { - case (c, (pol, t)) => if (pol) rec(t, c, true) else rec(c, t, true) + case (c, (pol, t)) => if (pol) rec(t, c, false) else rec(c, t, false) } } rhs.upperBounds.foreach(rec(lhs, _, true)) // propagate from the bound diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 7c41492a83..b8c75bdbdb 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -109,9 +109,9 @@ f(0) + 1 //│ ╟── type `number` is not an instance of type `int` //│ ║ l.13: def BBNN: bool -> bool & number -> number //│ ║ ^^^^^^ -//│ ╟── but it flows into integer literal with expected type `int` +//│ ╟── but it flows into application with expected type `int` //│ ║ l.105: f(0) + 1 -//│ ╙── ^ +//│ ╙── ^^^^ //│ res: error | int f : int -> number diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 15239d1721..b3335a9653 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -488,9 +488,7 @@ g(0) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.487: g(0) //│ ║ ^^^^ -//│ ╟── integer literal of type `Int` does not match type `?a` -//│ ║ l.487: g(0) -//│ ║ ^ +//│ ╟── expression of type `Int` does not match type `?a` //│ ╟── Note: constraint arises from application: //│ ║ l.477: let g = x => s(r(x)) //│ ╙── ^^^^ @@ -523,15 +521,14 @@ fun snd: A -> Int -> Int & Str -> Str -> Str :e x => app2(snd)(x):Int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.524: x => app2(snd)(x):Int +//│ ║ l.522: x => app2(snd)(x):Int //│ ║ ^^^^^^^^^^^^ -//│ ╟── application of type `Int` is not an instance of type `A` +//│ ╟── type `Int` is not an instance of type `A` +//│ ║ l.515: fun app2: ('a -> 'a -> 'a) -> 'a -> 'a +//│ ║ ^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.520: fun snd: A -> Int -> Int & Str -> Str -> Str -//│ ║ ^ -//│ ╟── from type reference: -//│ ║ l.524: x => app2(snd)(x):Int -//│ ╙── ^^^ +//│ ║ l.518: fun snd: A -> Int -> Int & Str -> Str -> Str +//│ ╙── ^ //│ nothing -> Int //│ res //│ = From e1b7fba80315d9d4c446704f2d3f51537d2f6a57 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Tue, 27 Aug 2024 21:53:32 +0800 Subject: [PATCH 33/43] fix provtype --- .../scala/mlscript/ConstraintSolver.scala | 22 ++---- .../main/scala/mlscript/TypeSimplifier.scala | 4 +- shared/src/main/scala/mlscript/Typer.scala | 13 +-- .../main/scala/mlscript/TyperDatatypes.scala | 21 +++-- .../main/scala/mlscript/TyperHelpers.scala | 6 +- shared/src/test/diff/fcp/Overloads.mls | 23 +++--- shared/src/test/diff/nu/HeungTung.mls | 79 +++++++++++++------ 7 files changed, 89 insertions(+), 79 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 3654d1e342..8f356ea253 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -632,8 +632,6 @@ class ConstraintSolver extends NormalForms { self: Typer => case S(tsc) => if (!tsc.tvs.isEmpty && tsc.constraints.isEmpty) reportError() case N => reportError() } - // val t = TupleSetConstraints.mk(ov) - // annoying(Nil, LhsRefined(S(t), ts, r, trs), Nil, done_rs) case (LhsRefined(S(ov: Overload), ts, r, trs), _) => annoying(Nil, LhsRefined(S(ov.approximatePos), ts, r, trs), Nil, done_rs) // TODO remove approx. with ambiguous constraints case (LhsRefined(S(Without(b, ns)), ts, r, _), RhsBases(pts, N | S(L(_)), _)) => @@ -849,9 +847,8 @@ class ConstraintSolver extends NormalForms { self: Typer => } val u = lhs.tsc.filter(_._1.constraints.sizeCompare(1) === 0) u.foreachEntry { case (k, _) => - k.tvs.mapValues(_.unwrapProxies).foreach { // TODO less inefficient; remove useless case + k.tvs.mapValues(_.unwrapProxies).foreach { case (_,tv: TV) => tv.tsc.remove(k) - case (_,ProvType(tv: TV)) => tv.tsc.remove(k) case _ => () } } @@ -877,9 +874,8 @@ class ConstraintSolver extends NormalForms { self: Typer => } val u = rhs.tsc.filter(_._1.constraints.sizeCompare(1) === 0) u.foreachEntry { case (k, _) => - k.tvs.mapValues(_.unwrapProxies).foreach { // TODO less inefficient; remove useless case + k.tvs.mapValues(_.unwrapProxies).foreach { case (_,tv: TV) => tv.tsc.remove(k) - case (_,ProvType(tv: TV)) => tv.tsc.remove(k) case _ => () } } @@ -1612,9 +1608,8 @@ class ConstraintSolver extends NormalForms { self: Typer => lvl }) val freshentsc = tv.tsc.flatMap { case (tsc,_) => - if (tsc.tvs.forall { - case (_,tv: TV) => !freshened.contains(tv) - case (_,ProvType(tv: TV)) => !freshened.contains(tv) + if (tsc.tvs.map(_._2.unwrapProxies).forall { + case tv: TV => !freshened.contains(tv) case _ => true }) S(tsc) else N } @@ -1622,14 +1617,11 @@ class ConstraintSolver extends NormalForms { self: Typer => v.lowerBounds = tv.lowerBounds.mapConserve(freshen) v.upperBounds = tv.upperBounds.mapConserve(freshen) freshentsc.foreach { tsc => - val t = new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov) + val t = new TupleSetConstraints(tsc.constraints, tsc.tvs) t.constraints = t.constraints.map(_.map(freshen)) t.tvs = t.tvs.map(x => (x._1,freshen(x._2))) - t.tvs.zipWithIndex.foreach { - case ((pol, tv: TV), i) => - tv.tsc.updateWith(t)(_.map(_ + i).orElse(S(Set(i)))) - case ((pol, ProvType(tv: TV)), i) => - tv.tsc.updateWith(t)(_.map(_ + i).orElse(S(Set(i)))) + t.tvs.map(_._2.unwrapProxies).zipWithIndex.foreach { + case (tv: TV, i) => tv.tsc.updateWith(t)(_.map(_ + i).orElse(S(Set(i)))) case _ => () } } diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 81b49eabb1..6b34a94736 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -83,7 +83,7 @@ trait TypeSimplifier { self: Typer => case S(tsc) => (tsc, i) case N if inPlace => (tsc, i) case N => - val t = new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov) + val t = new TupleSetConstraints(tsc.constraints, tsc.tvs) renewedtsc += tsc -> t t.tvs = t.tvs.map(x => (x._1, process(x._2, N))) (t, i) @@ -1041,7 +1041,7 @@ trait TypeSimplifier { self: Typer => res.tsc ++= tv.tsc.map { case (tsc, i) => renewaltsc.get(tsc) match { case S(tsc) => (tsc, i) case N => - val t = new TupleSetConstraints(tsc.constraints, tsc.tvs)(tsc.prov) + val t = new TupleSetConstraints(tsc.constraints, tsc.tvs) renewaltsc += tsc -> t t.tvs = t.tvs.map(x => (x._1, transform(x._2, PolMap.neu, Set.empty))) (t, i) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index af8f1416a2..ae70065caa 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -686,10 +686,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne } tscs.foreach { case (typevars, constrs) => val tvs = typevars.map(x => (x._1, rec(x._2))) - val tsc = new TupleSetConstraints(constrs.map(_.map(rec)), tvs)(res.prov) - tvs.zipWithIndex.foreach { - case ((_, tv: TV), i) => tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) - case ((_, ProvType(tv: TV)), i) => tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) + val tsc = new TupleSetConstraints(constrs.map(_.map(rec)), tvs) + tvs.map(_._2.unwrapProxies).zipWithIndex.foreach { + case (tv: TV, i) => tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) case _ => () } } @@ -1992,11 +1991,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne tv.tsc.foreachEntry { case (tsc, i) => if (seenTscs.add(tsc)) { - val tvs = tsc.tvs.map { - case (pol, tv: TV) => (pol, tv.asTypeVar) - case (pol, ProvType(tv: TV)) => (pol, tv.asTypeVar) - case (pol, t) => (pol, go(t)) - } + val tvs = tsc.tvs.map(x => (x._1,go(x._2))) val constrs = tsc.constraints.map(_.map(go)) tscs ::= tvs -> constrs } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 56bcc8e755..4af2bfb369 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -673,7 +673,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => val prov = noProv } - class TupleSetConstraints(var constraints: Ls[Ls[ST]], var tvs: Ls[(Bool, ST)])(val prov: TypeProvenance) { + class TupleSetConstraints(var constraints: Ls[Ls[ST]], var tvs: Ls[(Bool, ST)]) { def updateImpl(index: Int, bound: ST)(implicit raise: Raise, ctx: Ctx) : Unit = { val u0 = constraints.flatMap { c => TupleSetConstraints.lcg(tvs(index)._1, bound, c(index)).map(tvs.zip(c)++_) @@ -683,17 +683,15 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => (u,l.reduce((x,y) => ComposedType(!p,x,y)(noProv))) } } - tvs.foreach { - case (_, tv: TV) => tv.tsc += this -> Set.empty - case (_, ProvType(tv: TV)) => tv.tsc += this -> Set.empty + tvs.map(_._2.unwrapProxies).foreach { + case tv: TV => tv.tsc += this -> Set.empty case _ => () } if (!u.isEmpty) { tvs = u.flatMap(_.keys).distinct constraints = tvs.map(x => u.map(_.getOrElse(x,if (x._1) TopType else BotType))).transpose - tvs.zipWithIndex.foreach { - case ((pol, tv: TV), i) => tv.tsc.updateWith(this)(_.map(_ + i).orElse(S(Set(i)))) - case ((pol, ProvType(tv: TV)), i) => tv.tsc.updateWith(this)(_.map(_ + i).orElse(S(Set(i)))) + tvs.map(_._2.unwrapProxies).zipWithIndex.foreach { + case (tv: TV, i) => tv.tsc.updateWith(this)(_.map(_ + i).orElse(S(Set(i)))) case _ => () } } else { @@ -779,8 +777,8 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => if (u.isEmpty) { return N } val tvs = u.flatMap(_.keys).distinct val m = tvs.map(x => u.map(_.getOrElse(x,if (x._1) TopType else BotType))) - val tsc = new TupleSetConstraints(m.transpose, tvs)(ov.prov) - tvs.map(x => (x._1,x._2.unwrapProxies)).zipWithIndex.foreach { + val tsc = new TupleSetConstraints(m.transpose, tvs) + tvs.mapValues(_.unwrapProxies).zipWithIndex.foreach { case ((true, tv: TV), i) => tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) tv.lowerBounds.foreach(tsc.updateImpl(i, _)) @@ -791,9 +789,8 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") if (tsc.constraints.sizeCompare(1) === 0) { - tvs.foreach { - case (_, tv: TV) => tv.tsc.remove(tsc) - case (_, ProvType(tv: TV)) => tv.tsc.remove(tsc) + tvs.map(_._2.unwrapProxies).foreach { + case tv: TV => tv.tsc.remove(tsc) case _ => () } tsc.constraints.head.zip(tvs).foreach { diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 5d34159a9a..ad7bda57fd 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -917,7 +917,7 @@ abstract class TyperHelpers { Typer: Typer => } def children(includeBounds: Bool): List[SimpleType] = this match { case tv @ AssignedVariable(ty) => if (includeBounds) ty :: Nil else Nil - case tv: TypeVariable => if (includeBounds) tv.lowerBounds ::: tv.upperBounds else Nil + case tv: TypeVariable => if (includeBounds) tv.lowerBounds ::: tv.upperBounds ++ tv.tsc.keys.flatMap(_.tvs.map(_._2)) else Nil case FunctionType(l, r) => l :: r :: Nil case Overload(as) => as case ComposedType(_, l, r) => l :: r :: Nil @@ -1014,9 +1014,7 @@ abstract class TyperHelpers { Typer: Typer => val couldBeDistribbed = bod.varsBetween(polymLevel, MaxLevel) println(s"could be distribbed: $couldBeDistribbed") if (couldBeDistribbed.isEmpty) return N - val cannotBeDistribbed = par.varsBetween(polymLevel, MaxLevel).flatMap { v => - v :: v.tsc.keys.flatMap(_.tvs.flatMap(_._2.getVars)).toList - } + val cannotBeDistribbed = par.varsBetween(polymLevel, MaxLevel) println(s"cannot be distribbed: $cannotBeDistribbed") val canBeDistribbed = couldBeDistribbed -- cannotBeDistribbed if (canBeDistribbed.isEmpty) return N // TODO diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index b8c75bdbdb..b273ae6f73 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -94,23 +94,22 @@ IISS 0 def f = fun x -> (if true then IISS else BBNN) x //│ f: 'a -> 'b //│ where -//│ [+'a, -'b] in {[bool, bool], [number, number]} //│ [+'a, -'b] in {[int, int], [string, string]} +//│ [+'a, -'b] in {[bool, bool], [number, number]} f(0) //│ res: number - // FIXME f(0) + 1 //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.105: f(0) + 1 +//│ ║ l.104: f(0) + 1 //│ ║ ^^^^^^ //│ ╟── type `number` is not an instance of type `int` //│ ║ l.13: def BBNN: bool -> bool & number -> number //│ ║ ^^^^^^ //│ ╟── but it flows into application with expected type `int` -//│ ║ l.105: f(0) + 1 +//│ ║ l.104: f(0) + 1 //│ ╙── ^^^^ //│ res: error | int @@ -120,10 +119,10 @@ f : int -> number :e f : number -> int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.121: f : number -> int +//│ ║ l.120: f : number -> int //│ ║ ^ //│ ╟── type `number` does not match type `?a` -//│ ║ l.121: f : number -> int +//│ ║ l.120: f : number -> int //│ ╙── ^^^^^^ //│ res: number -> int @@ -140,16 +139,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.141: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.140: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not a function //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.141: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.140: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.141: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.140: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number @@ -168,13 +167,13 @@ not test //│ <: test: //│ ~(int -> int) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.166: not test +//│ ║ l.165: not test //│ ║ ^^^^^^^^ //│ ╟── type `~(int -> int)` is not an instance of type `bool` -//│ ║ l.160: def test: ~(int -> int) +//│ ║ l.159: def test: ~(int -> int) //│ ║ ^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `bool` -//│ ║ l.166: not test +//│ ║ l.165: not test //│ ╙── ^^^^ //│ res: bool | error diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index b3335a9653..82a5ae7fa9 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -183,6 +183,7 @@ f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^ //│ 'a //│ where +//│ 'b :> error //│ 'a :> error //│ [+'b, -'a] in {} //│ Code generation encountered an error: @@ -240,7 +241,7 @@ type T = List[Int] :e // TODO application types type Res = M(T) //│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 -//│ ║ l.241: type Res = M(T) +//│ ║ l.242: type Res = M(T) //│ ╙── ^^^^ //│ type Res = M @@ -263,7 +264,7 @@ fun f: Int -> Int fun f: Bool -> Bool fun f = id //│ ╔══[ERROR] A type signature for 'f' was already given -//│ ║ l.263: fun f: Bool -> Bool +//│ ║ l.264: fun f: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun f: forall 'a. 'a -> 'a //│ fun f: Int -> Int @@ -271,13 +272,13 @@ fun f = id :e // TODO support f: (Int -> Int) & (Bool -> Bool) //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.272: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.273: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^ //│ ╟── type `Bool` is not an instance of type `Int` -//│ ║ l.272: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.273: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.262: fun f: Int -> Int +//│ ║ l.263: fun f: Int -> Int //│ ╙── ^^^ //│ Int -> Int & Bool -> Bool //│ res @@ -344,17 +345,17 @@ fun test(x) = refined if x is A then 0 B then 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.343: fun test(x) = refined if x is +//│ ║ l.344: fun test(x) = refined if x is //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.344: A then 0 +//│ ║ l.345: A then 0 //│ ║ ^^^^^^^^^^ -//│ ║ l.345: B then 1 +//│ ║ l.346: B then 1 //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] Illegal use of reserved operator: refined -//│ ║ l.343: fun test(x) = refined if x is +//│ ║ l.344: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.343: fun test(x) = refined if x is +//│ ║ l.344: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ fun test: (A | B) -> error //│ Code generation encountered an error: @@ -407,6 +408,34 @@ x => q(x) //│ = //│ q is not implemented +:e +(x => q(x))(1):int +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.412: (x => q(x))(1):int +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── application of type `?a` does not match type `int` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.412: (x => q(x))(1):int +//│ ╙── ^^^ +//│ int +//│ res +//│ = +//│ q is not implemented + +:e +q(1):int +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.426: q(1):int +//│ ║ ^^^^ +//│ ╟── application of type `?a` does not match type `int` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.426: q(1):int +//│ ╙── ^^^ +//│ int +//│ res +//│ = +//│ q is not implemented + fun w = x => q(x) //│ fun w: forall 'a 'b. 'a -> 'b //│ where @@ -430,12 +459,12 @@ fun r: Int -> Int & Bool -> Bool x => r(r(x)) //│ ╔══[ERROR] ambiguous //│ ╟── cannot determine satisfiability of type ?a -//│ ║ l.430: x => r(r(x)) +//│ ║ l.459: x => r(r(x)) //│ ╙── ^^^^ -//│ forall 'a 'b. 'a -> 'b +//│ forall 'a 'b 'c. 'a -> 'c //│ where -//│ [-'b, +'c] in {[Int, Int], [Bool, Bool]} -//│ [-'c, +'a] in {[Int, Int], [Bool, Bool]} +//│ [+'a, -'b] in {[Int, Int], [Bool, Bool]} +//│ [-'c, +'b] in {[Int, Int], [Bool, Bool]} //│ res //│ = //│ r is not implemented @@ -457,9 +486,9 @@ fun u: {x:0, y:Int} -> Int & {x:1, z: Str} -> Str //│ fun u: {x: 0, y: Int} -> Int & {x: 1, z: Str} -> Str (a, b, c) => u({x: a, y: b, z: c}) -//│ forall 'a 'b 'c 'd. ('a, 'c, 'd) -> 'b +//│ forall 'a 'b 'c 'd. ('a, 'd, 'b) -> 'c //│ where -//│ [-'b, +'c, +'a, +'d] in {[Int, Int, 0, anything], [Str, anything, 1, Str]} +//│ [+'b, -'c, +'a, +'d] in {[anything, Int, 0, Int], [Str, Str, 1, anything]} //│ res //│ = //│ u is not implemented @@ -475,10 +504,10 @@ fun s: Str -> Str & AA -> AA // FIXME let g = x => s(r(x)) -//│ let g: forall 'a 'b. 'a -> 'b +//│ let g: forall 'a 'b 'c. 'a -> 'c //│ where -//│ [-'b, +'c] in {[Str, Str], [AA, AA]} -//│ [+'a, -'c] in {[Int, Int], [Bool, Bool]} +//│ [+'a, -'b] in {[Int, Int], [Bool, Bool]} +//│ [+'b, -'c] in {[Str, Str], [AA, AA]} //│ g //│ = //│ s is not implemented @@ -486,11 +515,11 @@ let g = x => s(r(x)) :e g(0) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.487: g(0) +//│ ║ l.516: g(0) //│ ║ ^^^^ //│ ╟── expression of type `Int` does not match type `?a` //│ ╟── Note: constraint arises from application: -//│ ║ l.477: let g = x => s(r(x)) +//│ ║ l.506: let g = x => s(r(x)) //│ ╙── ^^^^ //│ error //│ res @@ -521,13 +550,13 @@ fun snd: A -> Int -> Int & Str -> Str -> Str :e x => app2(snd)(x):Int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.522: x => app2(snd)(x):Int +//│ ║ l.551: x => app2(snd)(x):Int //│ ║ ^^^^^^^^^^^^ //│ ╟── type `Int` is not an instance of type `A` -//│ ║ l.515: fun app2: ('a -> 'a -> 'a) -> 'a -> 'a +//│ ║ l.544: fun app2: ('a -> 'a -> 'a) -> 'a -> 'a //│ ║ ^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.518: fun snd: A -> Int -> Int & Str -> Str -> Str +//│ ║ l.547: fun snd: A -> Int -> Int & Str -> Str -> Str //│ ╙── ^ //│ nothing -> Int //│ res @@ -541,7 +570,7 @@ app2_(snd) //│ 'a -> 'b //│ where //│ 'a <: 'b -//│ [-'b, +'a, -'a] in {[Int, A & Int, Int], [Str, Str, Str]} +//│ [-'a, +'a, -'b] in {[Int, A & Int, Int], [Str, Str, Str]} //│ res //│ = //│ snd is not implemented From 9cf43a4e3a0ddb2504cbee267941707d0b0f72f8 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 29 Aug 2024 21:27:18 +0800 Subject: [PATCH 34/43] use iterator --- .../scala/mlscript/ConstraintSolver.scala | 26 ++++++++++--------- shared/src/main/scala/mlscript/Typer.scala | 5 ++-- .../main/scala/mlscript/TyperDatatypes.scala | 12 ++++----- .../main/scala/mlscript/TyperHelpers.scala | 6 ++--- shared/src/test/diff/nu/HeungTung.mls | 10 +++---- 5 files changed, 30 insertions(+), 29 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 8f356ea253..d5681d930e 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -845,18 +845,20 @@ class ConstraintSolver extends NormalForms { self: Typer => } } } - val u = lhs.tsc.filter(_._1.constraints.sizeCompare(1) === 0) - u.foreachEntry { case (k, _) => - k.tvs.mapValues(_.unwrapProxies).foreach { + val u = lhs.tsc.keysIterator.filter(_.constraints.sizeCompare(1)===0).duplicate + u._1.foreach { k => + k.tvs.mapValuesIter(_.unwrapProxies).foreach { case (_,tv: TV) => tv.tsc.remove(k) case _ => () } } - u.foreachEntry { case (k, _) => - k.constraints.head.zip(k.tvs).foreach { + u._2.foreach { k => + println(s"tag5: ${k.tvs}") + k.constraints.head.iterator.zip(k.tvs).foreach { case (c, (pol, t)) => if (pol) rec(t, c, false) else rec(c, t, false) } } + println(s"tag2: $u") lhs.lowerBounds.foreach(rec(_, rhs, true)) // propagate from the bound case (lhs, rhs: TypeVariable) if lhs.level <= rhs.level => @@ -872,15 +874,15 @@ class ConstraintSolver extends NormalForms { self: Typer => } } } - val u = rhs.tsc.filter(_._1.constraints.sizeCompare(1) === 0) - u.foreachEntry { case (k, _) => - k.tvs.mapValues(_.unwrapProxies).foreach { + val u = rhs.tsc.keysIterator.filter(_.constraints.sizeCompare(1)===0).duplicate + u._1.foreach { k => + k.tvs.mapValuesIter(_.unwrapProxies).foreach { case (_,tv: TV) => tv.tsc.remove(k) case _ => () } } - u.foreachEntry { case (k, _) => - k.constraints.head.zip(k.tvs).foreach { + u._2.foreach { k => + k.constraints.head.iterator.zip(k.tvs).foreach { case (c, (pol, t)) => if (pol) rec(t, c, false) else rec(c, t, false) } } @@ -1608,7 +1610,7 @@ class ConstraintSolver extends NormalForms { self: Typer => lvl }) val freshentsc = tv.tsc.flatMap { case (tsc,_) => - if (tsc.tvs.map(_._2.unwrapProxies).forall { + if (tsc.tvs.values.map(_.unwrapProxies).forall { case tv: TV => !freshened.contains(tv) case _ => true }) S(tsc) else N @@ -1620,7 +1622,7 @@ class ConstraintSolver extends NormalForms { self: Typer => val t = new TupleSetConstraints(tsc.constraints, tsc.tvs) t.constraints = t.constraints.map(_.map(freshen)) t.tvs = t.tvs.map(x => (x._1,freshen(x._2))) - t.tvs.map(_._2.unwrapProxies).zipWithIndex.foreach { + t.tvs.values.map(_.unwrapProxies).zipWithIndex.foreach { case (tv: TV, i) => tv.tsc.updateWith(t)(_.map(_ + i).orElse(S(Set(i)))) case _ => () } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index ae70065caa..22490b85ed 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -169,8 +169,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne if (p) (b, tv) else (tv, b) } }.toList, innerTy) - val ambiguous = innerTy.getVars.toList.flatMap(_.tsc) - .flatMap(_._1.tvs).distinct + val ambiguous = innerTy.getVars.unsorted.flatMap(_.tsc.keys.flatMap(_.tvs)) .groupBy(_._2) .filter { case (v,pvs) => pvs.sizeIs > 1 } if (ambiguous.nonEmpty) raise(ErrorReport( @@ -687,7 +686,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne tscs.foreach { case (typevars, constrs) => val tvs = typevars.map(x => (x._1, rec(x._2))) val tsc = new TupleSetConstraints(constrs.map(_.map(rec)), tvs) - tvs.map(_._2.unwrapProxies).zipWithIndex.foreach { + tvs.values.map(_.unwrapProxies).zipWithIndex.foreach { case (tv: TV, i) => tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) case _ => () } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 4af2bfb369..1666394e3c 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -683,14 +683,14 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => (u,l.reduce((x,y) => ComposedType(!p,x,y)(noProv))) } } - tvs.map(_._2.unwrapProxies).foreach { + tvs.values.map(_.unwrapProxies).foreach { case tv: TV => tv.tsc += this -> Set.empty case _ => () } if (!u.isEmpty) { tvs = u.flatMap(_.keys).distinct constraints = tvs.map(x => u.map(_.getOrElse(x,if (x._1) TopType else BotType))).transpose - tvs.map(_._2.unwrapProxies).zipWithIndex.foreach { + tvs.values.map(_.unwrapProxies).zipWithIndex.foreach { case (tv: TV, i) => tv.tsc.updateWith(this)(_.map(_ + i).orElse(S(Set(i)))) case _ => () } @@ -769,7 +769,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } } def mk(ov: Overload, f: FT)(implicit raise: Raise, ctx: Ctx): Opt[TupleSetConstraints] = { - val u = ov.alts.map(lcgFunction(false, f, _)).flatten.map { x => + val u = ov.alts.flatMap(lcgFunction(false, f, _)).map { x => x.groupMap(_._1)(_._2).map { case (u@(p,_),l) => (u,l.reduce((x,y) => ComposedType(!p,x,y)(noProv))) } @@ -778,7 +778,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => val tvs = u.flatMap(_.keys).distinct val m = tvs.map(x => u.map(_.getOrElse(x,if (x._1) TopType else BotType))) val tsc = new TupleSetConstraints(m.transpose, tvs) - tvs.mapValues(_.unwrapProxies).zipWithIndex.foreach { + tvs.mapValuesIter(_.unwrapProxies).zipWithIndex.foreach { case ((true, tv: TV), i) => tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) tv.lowerBounds.foreach(tsc.updateImpl(i, _)) @@ -789,11 +789,11 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") if (tsc.constraints.sizeCompare(1) === 0) { - tvs.map(_._2.unwrapProxies).foreach { + tvs.values.map(_.unwrapProxies).foreach { case tv: TV => tv.tsc.remove(tsc) case _ => () } - tsc.constraints.head.zip(tvs).foreach { + tsc.constraints.head.iterator.zip(tvs).foreach { case (c, (pol, t)) => if (!pol) constrain(c, t)(raise, ov.prov, ctx) if (pol) constrain(t, c)(raise, ov.prov, ctx) diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index ad7bda57fd..3ce562ac20 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -759,8 +759,8 @@ abstract class TyperHelpers { Typer: Typer => case tv: TypeVariable => val poltv = pol(tv) (if (poltv =/= S(false)) tv.lowerBounds.map(pol.at(tv.level, true) -> _) else Nil) ::: - (if (poltv =/= S(true)) tv.upperBounds.map(pol.at(tv.level, false) -> _) else Nil) ::: - tv.tsc.keys.flatMap(_.tvs).map(u => pol.at(tv.level,u._1) -> u._2).toList + (if (poltv =/= S(true)) tv.upperBounds.map(pol.at(tv.level, false) -> _) else Nil) ++ + tv.tsc.keys.flatMap(_.tvs).map(u => pol.at(tv.level,u._1) -> u._2) case FunctionType(l, r) => pol.contravar -> l :: pol.covar -> r :: Nil case Overload(as) => as.map(pol -> _) case ComposedType(_, l, r) => pol -> l :: pol -> r :: Nil @@ -917,7 +917,7 @@ abstract class TyperHelpers { Typer: Typer => } def children(includeBounds: Bool): List[SimpleType] = this match { case tv @ AssignedVariable(ty) => if (includeBounds) ty :: Nil else Nil - case tv: TypeVariable => if (includeBounds) tv.lowerBounds ::: tv.upperBounds ++ tv.tsc.keys.flatMap(_.tvs.map(_._2)) else Nil + case tv: TypeVariable => if (includeBounds) tv.lowerBounds ::: tv.upperBounds ++ tv.tsc.keys.flatMap(_.tvs.values) else Nil case FunctionType(l, r) => l :: r :: Nil case Overload(as) => as case ComposedType(_, l, r) => l :: r :: Nil diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 82a5ae7fa9..45f342607e 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -409,15 +409,15 @@ x => q(x) //│ q is not implemented :e -(x => q(x))(1):int +(x => q(x))(1):Int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.412: (x => q(x))(1):int +//│ ║ l.412: (x => q(x))(1):Int //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── application of type `?a` does not match type `int` +//│ ╟── application of type `?a` does not match type `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.412: (x => q(x))(1):int +//│ ║ l.412: (x => q(x))(1):Int //│ ╙── ^^^ -//│ int +//│ Int //│ res //│ = //│ q is not implemented From 50afcc485a223d2bcaefe65b5ec2dbe830de4c40 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Wed, 11 Sep 2024 21:23:26 +0800 Subject: [PATCH 35/43] add flag --- .../scala/mlscript/ConstraintSolver.scala | 2 +- shared/src/main/scala/mlscript/Typer.scala | 1 + shared/src/test/diff/basics/Intersections.fun | 56 +++++---- shared/src/test/diff/fcp/Overloads.mls | 2 +- shared/src/test/diff/mlscript/BadPolym.mls | 4 +- shared/src/test/diff/nu/ArrayProg.mls | 14 +-- shared/src/test/diff/nu/HeungTung.mls | 112 ++++++++++++------ shared/src/test/diff/nu/WeirdUnions.mls | 24 ++-- .../src/test/scala/mlscript/DiffTests.scala | 3 + 9 files changed, 133 insertions(+), 85 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index d5681d930e..58831ef7af 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -627,7 +627,7 @@ class ConstraintSolver extends NormalForms { self: Typer => recLb(ar.inner, b.inner) rec(b.inner.ub, ar.inner.ub, false) case (LhsRefined(S(b: ArrayBase), ts, r, _), _) => reportError() - case (LhsRefined(S(ov: Overload), ts, r, trs), RhsBases(_, S(L(f: FunctionType)), _)) => + case (LhsRefined(S(ov: Overload), ts, r, trs), RhsBases(_, S(L(f: FunctionType)), _)) if noApproximateOverload => TupleSetConstraints.mk(ov, f) match { case S(tsc) => if (!tsc.tvs.isEmpty && tsc.constraints.isEmpty) reportError() case N => reportError() diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 22490b85ed..380590558d 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -34,6 +34,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne var constrainedTypes: Boolean = false var recordProvenances: Boolean = true + var noApproximateOverload: Boolean = false type Binding = Str -> SimpleType type Bindings = Map[Str, SimpleType] diff --git a/shared/src/test/diff/basics/Intersections.fun b/shared/src/test/diff/basics/Intersections.fun index 9b4f8347b2..4bbdaa0f74 100644 --- a/shared/src/test/diff/basics/Intersections.fun +++ b/shared/src/test/diff/basics/Intersections.fun @@ -26,68 +26,84 @@ succ / foo(1) let foo = (Int => Int) & (Bool => Bool) //│ foo: int -> int & bool -> bool -// used to return int & bool, equivalent to nothing -// or approximated as int | bool in MLscript -// overloaded function foo can now be used as either int -> int or bool -> bool -foo(1) +:e +foo(1) // returns int & bool, equivalent to nothing succ / foo(1) foo(true) not / foo(true) -//│ res: int -//│ res: int -//│ res: bool -//│ res: bool +//│ res: bool | int +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.31: succ / foo(1) +//│ ║ ^^^^^^^^^^^^^ +//│ ╟── reference of type `bool` is not an instance of type `int` +//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) +//│ ║ ^^^^ +//│ ╟── but it flows into application with expected type `int` +//│ ║ l.31: succ / foo(1) +//│ ╙── ^^^^^^ +//│ res: error | int +//│ res: bool | int +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.33: not / foo(true) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── reference of type `int` is not an instance of type `bool` +//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) +//│ ║ ^^^ +//│ ╟── but it flows into application with expected type `bool` +//│ ║ l.33: not / foo(true) +//│ ╙── ^^^^^^^^^ +//│ res: bool | error :e not / foo(1) foo(1) as Nothing //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.42: not / foo(1) +//│ ║ l.58: not / foo(1) //│ ║ ^^^^^^^^^^^^ //│ ╟── reference of type `int` is not an instance of type `bool` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^ //│ ╟── but it flows into application with expected type `bool` -//│ ║ l.42: not / foo(1) +//│ ║ l.58: not / foo(1) //│ ╙── ^^^^^^ //│ res: bool | error //│ ╔══[ERROR] Type mismatch in 'as' binding: -//│ ║ l.43: foo(1) as Nothing +//│ ║ l.59: foo(1) as Nothing //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `int` does not match type `nothing` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^ //│ ╟── but it flows into application with expected type `nothing` -//│ ║ l.43: foo(1) as Nothing +//│ ║ l.59: foo(1) as Nothing //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.43: foo(1) as Nothing +//│ ║ l.59: foo(1) as Nothing //│ ╙── ^^^^^^^ //│ res: nothing :e foo as Nothing //│ ╔══[ERROR] Type mismatch in 'as' binding: -//│ ║ l.69: foo as Nothing +//│ ║ l.85: foo as Nothing //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type intersection of type `int -> int & bool -> bool` does not match type `nothing` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `nothing` -//│ ║ l.69: foo as Nothing +//│ ║ l.85: foo as Nothing //│ ║ ^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.69: foo as Nothing +//│ ║ l.85: foo as Nothing //│ ╙── ^^^^^^^ //│ res: nothing :e let oops = (&) //│ ╔══[ERROR] Illegal use of reserved operator: & -//│ ║ l.85: let oops = (&) -//│ ╙── ^^^ +//│ ║ l.101: let oops = (&) +//│ ╙── ^^^ //│ ╔══[ERROR] identifier not found: & -//│ ║ l.85: let oops = (&) -//│ ╙── ^^^ +//│ ║ l.101: let oops = (&) +//│ ╙── ^^^ //│ oops: error diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index b273ae6f73..a3967c6c54 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -1,6 +1,6 @@ :NoJS - +:NoApproximateOverload type IISS = int -> int & string -> string type BBNN = bool -> bool & number -> number diff --git a/shared/src/test/diff/mlscript/BadPolym.mls b/shared/src/test/diff/mlscript/BadPolym.mls index ced0b225e8..d8695bb76e 100644 --- a/shared/src/test/diff/mlscript/BadPolym.mls +++ b/shared/src/test/diff/mlscript/BadPolym.mls @@ -40,11 +40,11 @@ fooImpl id fooImpl2 (f: int -> int & string -> string) = f 1 -//│ fooImpl2: (int -> int & string -> string) -> int +//│ fooImpl2: (int -> int & string -> string) -> (int | string) //│ = [Function: fooImpl2] fooImpl2 id -//│ res: int +//│ res: int | string //│ = 1 :e diff --git a/shared/src/test/diff/nu/ArrayProg.mls b/shared/src/test/diff/nu/ArrayProg.mls index a288ac8058..e75f0fddfb 100644 --- a/shared/src/test/diff/nu/ArrayProg.mls +++ b/shared/src/test/diff/nu/ArrayProg.mls @@ -155,7 +155,7 @@ module A { //│ } A.g(0) -//│ Int +//│ Int | Str //│ res //│ = 0 @@ -174,13 +174,13 @@ s([Numbr(0),Numbr(0)]) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.+1: s([Numbr(0),Numbr(0)]) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `(Numbr | Vectr, Numbr | Vectr) -> Int` is not a function -//│ ║ l.136: fun s: ([Numbr,Numbr] -> Int) & ([Vectr,Vectr] -> Int) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `([?a, ?b]) -> ?c` +//│ ╟── argument of type `[[?a, ?b]]` does not match type `[Numbr | Vectr, Numbr | Vectr]` //│ ║ l.+1: s([Numbr(0),Numbr(0)]) -//│ ╙── ^ -//│ error +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from tuple type: +//│ ║ l.136: fun s: ([Numbr,Numbr] -> Int) & ([Vectr,Vectr] -> Int) +//│ ╙── ^^^^^^^^^^^^^ +//│ Int | error // g <: 0 -> 'a :e diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 45f342607e..c4a7f3930a 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -1,4 +1,5 @@ :NewDefs +:NoApproximateOverload @@ -70,16 +71,16 @@ fun g = h fun g: (Int | Bool) -> (Int | Bool) fun g = f //│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.71: fun g = f +//│ ║ l.72: fun g = f //│ ║ ^^^^^ //│ ╟── type `Int -> Int & Bool -> Bool` is not a function -//│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.51: fun f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(Int | false | true) -> (Int | false | true)` -//│ ║ l.71: fun g = f +//│ ║ l.72: fun g = f //│ ║ ^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.70: fun g: (Int | Bool) -> (Int | Bool) +//│ ║ l.71: fun g: (Int | Bool) -> (Int | Bool) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ fun g: Int -> Int & Bool -> Bool //│ fun g: (Int | false | true) -> (Int | false | true) @@ -101,16 +102,16 @@ fun j = i fun j: (Int & Bool) -> (Int & Bool) fun j = f //│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.102: fun j = f +//│ ║ l.103: fun j = f //│ ║ ^^^^^ //│ ╟── type `Int -> Int & Bool -> Bool` is not a function -//│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.51: fun f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `nothing -> nothing` -//│ ║ l.102: fun j = f +//│ ║ l.103: fun j = f //│ ║ ^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.101: fun j: (Int & Bool) -> (Int & Bool) +//│ ║ l.102: fun j: (Int & Bool) -> (Int & Bool) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ fun j: Int -> Int & Bool -> Bool //│ fun j: nothing -> nothing @@ -146,13 +147,13 @@ x => f(x) :e f(if true then 0 else false) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.147: f(if true then 0 else false) +//│ ║ l.148: f(if true then 0 else false) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `Int -> Int & Bool -> Bool` is not a function -//│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.51: fun f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | false) -> ?a` -//│ ║ l.147: f(if true then 0 else false) +//│ ║ l.148: f(if true then 0 else false) //│ ╙── ^ //│ error //│ res @@ -164,22 +165,22 @@ f(if true then 0 else false) :w f(refined if true then 0 else false) // this one can be precise again! //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.165: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.166: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Illegal use of reserved operator: refined -//│ ║ l.165: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.166: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.165: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.166: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.165: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.166: f(refined if true then 0 else false) // this one can be precise again! //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `Int -> Int & Bool -> Bool` is not a function -//│ ║ l.50: fun f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.51: fun f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `?a -> ?b` -//│ ║ l.165: f(refined if true then 0 else false) // this one can be precise again! +//│ ║ l.166: f(refined if true then 0 else false) // this one can be precise again! //│ ╙── ^ //│ 'a //│ where @@ -241,7 +242,7 @@ type T = List[Int] :e // TODO application types type Res = M(T) //│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 -//│ ║ l.242: type Res = M(T) +//│ ║ l.243: type Res = M(T) //│ ╙── ^^^^ //│ type Res = M @@ -264,7 +265,7 @@ fun f: Int -> Int fun f: Bool -> Bool fun f = id //│ ╔══[ERROR] A type signature for 'f' was already given -//│ ║ l.264: fun f: Bool -> Bool +//│ ║ l.265: fun f: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun f: forall 'a. 'a -> 'a //│ fun f: Int -> Int @@ -272,13 +273,13 @@ fun f = id :e // TODO support f: (Int -> Int) & (Bool -> Bool) //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.273: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.274: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^ //│ ╟── type `Bool` is not an instance of type `Int` -//│ ║ l.273: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.274: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.263: fun f: Int -> Int +//│ ║ l.264: fun f: Int -> Int //│ ╙── ^^^ //│ Int -> Int & Bool -> Bool //│ res @@ -345,17 +346,17 @@ fun test(x) = refined if x is A then 0 B then 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.344: fun test(x) = refined if x is +//│ ║ l.345: fun test(x) = refined if x is //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.345: A then 0 +//│ ║ l.346: A then 0 //│ ║ ^^^^^^^^^^ -//│ ║ l.346: B then 1 +//│ ║ l.347: B then 1 //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] Illegal use of reserved operator: refined -//│ ║ l.344: fun test(x) = refined if x is +//│ ║ l.345: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.344: fun test(x) = refined if x is +//│ ║ l.345: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ fun test: (A | B) -> error //│ Code generation encountered an error: @@ -411,11 +412,11 @@ x => q(x) :e (x => q(x))(1):Int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.412: (x => q(x))(1):Int +//│ ║ l.413: (x => q(x))(1):Int //│ ║ ^^^^^^^^^^^^^^ //│ ╟── application of type `?a` does not match type `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.412: (x => q(x))(1):Int +//│ ║ l.413: (x => q(x))(1):Int //│ ╙── ^^^ //│ Int //│ res @@ -425,11 +426,11 @@ x => q(x) :e q(1):int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.426: q(1):int +//│ ║ l.427: q(1):int //│ ║ ^^^^ //│ ╟── application of type `?a` does not match type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.426: q(1):int +//│ ║ l.427: q(1):int //│ ╙── ^^^ //│ int //│ res @@ -459,7 +460,7 @@ fun r: Int -> Int & Bool -> Bool x => r(r(x)) //│ ╔══[ERROR] ambiguous //│ ╟── cannot determine satisfiability of type ?a -//│ ║ l.459: x => r(r(x)) +//│ ║ l.460: x => r(r(x)) //│ ╙── ^^^^ //│ forall 'a 'b 'c. 'a -> 'c //│ where @@ -515,11 +516,11 @@ let g = x => s(r(x)) :e g(0) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.516: g(0) +//│ ║ l.517: g(0) //│ ║ ^^^^ //│ ╟── expression of type `Int` does not match type `?a` //│ ╟── Note: constraint arises from application: -//│ ║ l.506: let g = x => s(r(x)) +//│ ║ l.507: let g = x => s(r(x)) //│ ╙── ^^^^ //│ error //│ res @@ -550,13 +551,13 @@ fun snd: A -> Int -> Int & Str -> Str -> Str :e x => app2(snd)(x):Int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.551: x => app2(snd)(x):Int +//│ ║ l.552: x => app2(snd)(x):Int //│ ║ ^^^^^^^^^^^^ //│ ╟── type `Int` is not an instance of type `A` -//│ ║ l.544: fun app2: ('a -> 'a -> 'a) -> 'a -> 'a +//│ ║ l.545: fun app2: ('a -> 'a -> 'a) -> 'a -> 'a //│ ║ ^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.547: fun snd: A -> Int -> Int & Str -> Str -> Str +//│ ║ l.548: fun snd: A -> Int -> Int & Str -> Str -> Str //│ ╙── ^ //│ nothing -> Int //│ res @@ -574,3 +575,40 @@ app2_(snd) //│ res //│ = //│ snd is not implemented + +// * Example from WeirdUnions.mls. +// * This type merges the input tuples: +fun f: (Str => Str) & ((Str, Int) => Str) +//│ fun f: (...Array[Int | Str] & {0: Str}) -> Str + +f("abc", "abc") +//│ Str +//│ res +//│ = +//│ f is not implemented + +fun f: (Str => Str) & ((Str, Int) => Int) +//│ fun f: Str -> Str & (Str, Int) -> Int + +// * Different from WeirdUnions.mls: +:e +f("abc", "abc") +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.595: f("abc", "abc") +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── type `Str -> Str & (Str, Int) -> Int` is not a function +//│ ║ l.590: fun f: (Str => Str) & ((Str, Int) => Int) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `("abc", "abc") -> ?a` +//│ ║ l.595: f("abc", "abc") +//│ ╙── ^ +//│ error +//│ res +//│ = +//│ f is not implemented + +f("abcabc") +//│ Str +//│ res +//│ = +//│ f is not implemented diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index 465cd9eb9f..d5b600e875 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -47,24 +47,14 @@ fun f: (Str => Str) & ((Str, Int) => Int) //│ fun f: Str -> Str & (Str, Int) -> Int // * ...resulting in approximation at call sites (we don't handle overloading) -:e f("abc", "abc") -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.51: f("abc", "abc") -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── type `Str -> Str & (Str, Int) -> Int` is not a function -//│ ║ l.46: fun f: (Str => Str) & ((Str, Int) => Int) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `("abc", "abc") -> ?a` -//│ ║ l.51: f("abc", "abc") -//│ ╙── ^ -//│ error +//│ Int | Str //│ res //│ = //│ f is not implemented f("abcabc") -//│ Str +//│ Int | Str //│ res //│ = //│ f is not implemented @@ -81,19 +71,19 @@ let r = if true then id else (x, y) => [y, x] r(error) r(error, error) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.81: r(error) +//│ ║ l.71: r(error) //│ ║ ^^^^^^^^ //│ ╟── argument of type `[nothing]` does not match type `[?a, ?b]` -//│ ║ l.81: r(error) +//│ ║ l.71: r(error) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.75: let r = if true then id else (x, y) => [y, x] +//│ ║ l.65: let r = if true then id else (x, y) => [y, x] //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.82: r(error, error) +//│ ║ l.72: r(error, error) //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── argument list of type `[nothing, nothing]` does not match type `[?a]` -//│ ║ l.82: r(error, error) +//│ ║ l.72: r(error, error) //│ ╙── ^^^^^^^^^^^^^^ //│ error | [nothing, nothing] //│ res diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index cd1309a9c2..f193f76511 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -216,6 +216,7 @@ class DiffTests(state: DiffTests.State) // Enable this to see the errors from unfinished `PreTyper`. var showPreTyperErrors = false var noTailRec = false + var noApproximateOverload = false // * This option makes some test cases pass which assume generalization should happen in arbitrary arguments // * but it's way too aggressive to be ON by default, as it leads to more extrusion, cycle errors, etc. @@ -287,6 +288,7 @@ class DiffTests(state: DiffTests.State) case "GeneralizeArguments" => generalizeArguments = true; mode case "DontGeneralizeArguments" => generalizeArguments = false; mode case "IrregularTypes" => irregularTypes = true; mode + case "NoApproximateOverload" => noApproximateOverload = true; mode case str @ "Fuel" => // println("'"+line.drop(str.length + 2)+"'") typer.startingFuel = line.drop(str.length + 2).toInt; mode @@ -542,6 +544,7 @@ class DiffTests(state: DiffTests.State) typer.explainErrors = mode.explainErrors stdout = mode.stdout typer.preciselyTypeRecursion = mode.preciselyTypeRecursion + typer.noApproximateOverload = noApproximateOverload val oldCtx = ctx From a540d0070c8c1f957b304393c885f0b28067bb5c Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sun, 15 Sep 2024 21:02:58 +0800 Subject: [PATCH 36/43] fix not a function error --- .../scala/mlscript/ConstraintSolver.scala | 30 ++++- .../main/scala/mlscript/TyperDatatypes.scala | 22 +--- shared/src/test/diff/fcp/Overloads.mls | 6 +- shared/src/test/diff/nu/HeungTung.mls | 109 ++++++++++++------ 4 files changed, 108 insertions(+), 59 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 58831ef7af..13ec610c31 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -629,8 +629,32 @@ class ConstraintSolver extends NormalForms { self: Typer => case (LhsRefined(S(b: ArrayBase), ts, r, _), _) => reportError() case (LhsRefined(S(ov: Overload), ts, r, trs), RhsBases(_, S(L(f: FunctionType)), _)) if noApproximateOverload => TupleSetConstraints.mk(ov, f) match { - case S(tsc) => if (!tsc.tvs.isEmpty && tsc.constraints.isEmpty) reportError() - case N => reportError() + case S(tsc) => + if (tsc.tvs.nonEmpty) { + tsc.tvs.mapValuesIter(_.unwrapProxies).zipWithIndex.flatMap { + case ((true, tv: TV), i) => tv.lowerBounds.iterator.map((_,tv,i,true)) + case ((false, tv: TV), i) => tv.upperBounds.iterator.map((_,tv,i,false)) + case _ => Nil + }.find { + case (b,_,i,_) => + tsc.updateImpl(i,b) + tsc.constraints.isEmpty + }.foreach { + case (b,tv,_,p) => if (p) rec(b,tv,false) else rec(tv,b,false) + } + if (tsc.constraints.sizeCompare(1) === 0) { + tsc.tvs.values.map(_.unwrapProxies).foreach { + case tv: TV => tv.tsc.remove(tsc) + case _ => () + } + tsc.constraints.head.iterator.zip(tsc.tvs).foreach { + case (c, (pol, t)) => + if (!pol) rec(c, t, false) + if (pol) rec(t, c, false) + } + } + } + case N => reportError(S(msg"is not an instance of `${f.expNeg}`")) } case (LhsRefined(S(ov: Overload), ts, r, trs), _) => annoying(Nil, LhsRefined(S(ov.approximatePos), ts, r, trs), Nil, done_rs) // TODO remove approx. with ambiguous constraints @@ -853,12 +877,10 @@ class ConstraintSolver extends NormalForms { self: Typer => } } u._2.foreach { k => - println(s"tag5: ${k.tvs}") k.constraints.head.iterator.zip(k.tvs).foreach { case (c, (pol, t)) => if (pol) rec(t, c, false) else rec(c, t, false) } } - println(s"tag2: $u") lhs.lowerBounds.foreach(rec(_, rhs, true)) // propagate from the bound case (lhs, rhs: TypeVariable) if lhs.level <= rhs.level => diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 1666394e3c..25bbc72555 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -683,11 +683,11 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => (u,l.reduce((x,y) => ComposedType(!p,x,y)(noProv))) } } - tvs.values.map(_.unwrapProxies).foreach { - case tv: TV => tv.tsc += this -> Set.empty - case _ => () - } if (!u.isEmpty) { + tvs.values.map(_.unwrapProxies).foreach { + case tv: TV => tv.tsc += this -> Set.empty + case _ => () + } tvs = u.flatMap(_.keys).distinct constraints = tvs.map(x => u.map(_.getOrElse(x,if (x._1) TopType else BotType))).transpose tvs.values.map(_.unwrapProxies).zipWithIndex.foreach { @@ -721,6 +721,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } def lcg(pol: Bool, first: ST, rest: ST)(implicit ctx: Ctx) : Opt[Ls[(Bool, ST) -> ST]] = (first.unwrapProxies, rest.unwrapProxies) match { + case (a, ExtrType(p)) if p =/= pol => S(Nil) case (a, ComposedType(p,l,r)) if p =/= pol => for { lm <- lcg(pol,a,l) @@ -781,24 +782,11 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => tvs.mapValuesIter(_.unwrapProxies).zipWithIndex.foreach { case ((true, tv: TV), i) => tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) - tv.lowerBounds.foreach(tsc.updateImpl(i, _)) case ((false, tv: TV), i) => tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) - tv.upperBounds.foreach(tsc.updateImpl(i, _)) case _ => () } println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") - if (tsc.constraints.sizeCompare(1) === 0) { - tvs.values.map(_.unwrapProxies).foreach { - case tv: TV => tv.tsc.remove(tsc) - case _ => () - } - tsc.constraints.head.iterator.zip(tvs).foreach { - case (c, (pol, t)) => - if (!pol) constrain(c, t)(raise, ov.prov, ctx) - if (pol) constrain(t, c)(raise, ov.prov, ctx) - } - } S(tsc) } } diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index a3967c6c54..e1308ef309 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -31,7 +31,7 @@ IISS : ZZII //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.30: IISS : ZZII //│ ║ ^^^^ -//│ ╟── type `int -> int & string -> string` is not a function +//│ ╟── type `int -> int & string -> string` is not an instance of `0 -> 0` //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `0 -> 0` @@ -50,7 +50,7 @@ IISS : BBNN //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.49: IISS : BBNN //│ ║ ^^^^ -//│ ╟── type `int -> int & string -> string` is not a function +//│ ╟── type `int -> int & string -> string` is not an instance of `bool -> bool` //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `bool -> bool` @@ -141,7 +141,7 @@ if true then IISS else BBNN //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.140: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `int -> int & string -> string` is not a function +//│ ╟── type `int -> int & string -> string` is not an instance of `(0 | 1 | true) -> number` //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index c4a7f3930a..11d225a411 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -73,7 +73,7 @@ fun g = f //│ ╔══[ERROR] Type mismatch in definition: //│ ║ l.72: fun g = f //│ ║ ^^^^^ -//│ ╟── type `Int -> Int & Bool -> Bool` is not a function +//│ ╟── type `Int -> Int & Bool -> Bool` is not an instance of `(Int | false | true) -> (Int | false | true)` //│ ║ l.51: fun f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(Int | false | true) -> (Int | false | true)` @@ -104,7 +104,7 @@ fun j = f //│ ╔══[ERROR] Type mismatch in definition: //│ ║ l.103: fun j = f //│ ║ ^^^^^ -//│ ╟── type `Int -> Int & Bool -> Bool` is not a function +//│ ╟── type `Int -> Int & Bool -> Bool` is not an instance of `nothing -> nothing` //│ ║ l.51: fun f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `nothing -> nothing` @@ -149,7 +149,7 @@ f(if true then 0 else false) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.148: f(if true then 0 else false) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `Int -> Int & Bool -> Bool` is not a function +//│ ╟── type `Int -> Int & Bool -> Bool` is not an instance of `(0 | false) -> ?a` //│ ║ l.51: fun f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | false) -> ?a` @@ -176,12 +176,9 @@ f(refined if true then 0 else false) // this one can be precise again! //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.166: f(refined if true then 0 else false) // this one can be precise again! //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `Int -> Int & Bool -> Bool` is not a function -//│ ║ l.51: fun f: (Int -> Int) & (Bool -> Bool) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `?a -> ?b` +//│ ╟── application of type `error` does not match type `?a` //│ ║ l.166: f(refined if true then 0 else false) // this one can be precise again! -//│ ╙── ^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ 'a //│ where //│ 'b :> error @@ -242,7 +239,7 @@ type T = List[Int] :e // TODO application types type Res = M(T) //│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 -//│ ║ l.243: type Res = M(T) +//│ ║ l.240: type Res = M(T) //│ ╙── ^^^^ //│ type Res = M @@ -265,7 +262,7 @@ fun f: Int -> Int fun f: Bool -> Bool fun f = id //│ ╔══[ERROR] A type signature for 'f' was already given -//│ ║ l.265: fun f: Bool -> Bool +//│ ║ l.262: fun f: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun f: forall 'a. 'a -> 'a //│ fun f: Int -> Int @@ -273,13 +270,13 @@ fun f = id :e // TODO support f: (Int -> Int) & (Bool -> Bool) //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.274: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.271: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^ //│ ╟── type `Bool` is not an instance of type `Int` -//│ ║ l.274: f: (Int -> Int) & (Bool -> Bool) +//│ ║ l.271: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.264: fun f: Int -> Int +//│ ║ l.261: fun f: Int -> Int //│ ╙── ^^^ //│ Int -> Int & Bool -> Bool //│ res @@ -346,17 +343,17 @@ fun test(x) = refined if x is A then 0 B then 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.345: fun test(x) = refined if x is +//│ ║ l.342: fun test(x) = refined if x is //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.346: A then 0 +//│ ║ l.343: A then 0 //│ ║ ^^^^^^^^^^ -//│ ║ l.347: B then 1 +//│ ║ l.344: B then 1 //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] Illegal use of reserved operator: refined -//│ ║ l.345: fun test(x) = refined if x is +//│ ║ l.342: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ ╔══[ERROR] identifier not found: refined -//│ ║ l.345: fun test(x) = refined if x is +//│ ║ l.342: fun test(x) = refined if x is //│ ╙── ^^^^^^^ //│ fun test: (A | B) -> error //│ Code generation encountered an error: @@ -412,11 +409,11 @@ x => q(x) :e (x => q(x))(1):Int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.413: (x => q(x))(1):Int +//│ ║ l.410: (x => q(x))(1):Int //│ ║ ^^^^^^^^^^^^^^ //│ ╟── application of type `?a` does not match type `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.413: (x => q(x))(1):Int +//│ ║ l.410: (x => q(x))(1):Int //│ ╙── ^^^ //│ Int //│ res @@ -426,11 +423,11 @@ x => q(x) :e q(1):int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.427: q(1):int +//│ ║ l.424: q(1):int //│ ║ ^^^^ //│ ╟── application of type `?a` does not match type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.427: q(1):int +//│ ║ l.424: q(1):int //│ ╙── ^^^ //│ int //│ res @@ -460,7 +457,7 @@ fun r: Int -> Int & Bool -> Bool x => r(r(x)) //│ ╔══[ERROR] ambiguous //│ ╟── cannot determine satisfiability of type ?a -//│ ║ l.460: x => r(r(x)) +//│ ║ l.457: x => r(r(x)) //│ ╙── ^^^^ //│ forall 'a 'b 'c. 'a -> 'c //│ where @@ -487,9 +484,9 @@ fun u: {x:0, y:Int} -> Int & {x:1, z: Str} -> Str //│ fun u: {x: 0, y: Int} -> Int & {x: 1, z: Str} -> Str (a, b, c) => u({x: a, y: b, z: c}) -//│ forall 'a 'b 'c 'd. ('a, 'd, 'b) -> 'c +//│ forall 'a 'b 'c 'd. ('a, 'c, 'd) -> 'b //│ where -//│ [+'b, -'c, +'a, +'d] in {[anything, Int, 0, Int], [Str, Str, 1, anything]} +//│ [-'b, +'a, +'c, +'d] in {[Int, 0, Int, anything], [Str, 1, anything, Str]} //│ res //│ = //│ u is not implemented @@ -516,11 +513,11 @@ let g = x => s(r(x)) :e g(0) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.517: g(0) +//│ ║ l.514: g(0) //│ ║ ^^^^ //│ ╟── expression of type `Int` does not match type `?a` //│ ╟── Note: constraint arises from application: -//│ ║ l.507: let g = x => s(r(x)) +//│ ║ l.504: let g = x => s(r(x)) //│ ╙── ^^^^ //│ error //│ res @@ -551,13 +548,13 @@ fun snd: A -> Int -> Int & Str -> Str -> Str :e x => app2(snd)(x):Int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.552: x => app2(snd)(x):Int +//│ ║ l.549: x => app2(snd)(x):Int //│ ║ ^^^^^^^^^^^^ //│ ╟── type `Int` is not an instance of type `A` -//│ ║ l.545: fun app2: ('a -> 'a -> 'a) -> 'a -> 'a +//│ ║ l.542: fun app2: ('a -> 'a -> 'a) -> 'a -> 'a //│ ║ ^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.548: fun snd: A -> Int -> Int & Str -> Str -> Str +//│ ║ l.545: fun snd: A -> Int -> Int & Str -> Str -> Str //│ ╙── ^ //│ nothing -> Int //│ res @@ -571,7 +568,7 @@ app2_(snd) //│ 'a -> 'b //│ where //│ 'a <: 'b -//│ [-'a, +'a, -'b] in {[Int, A & Int, Int], [Str, Str, Str]} +//│ [+'a, -'a, -'b] in {[A & Int, Int, Int], [Str, Str, Str]} //│ res //│ = //│ snd is not implemented @@ -594,13 +591,13 @@ fun f: (Str => Str) & ((Str, Int) => Int) :e f("abc", "abc") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.595: f("abc", "abc") +//│ ║ l.592: f("abc", "abc") //│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── type `Str -> Str & (Str, Int) -> Int` is not a function -//│ ║ l.590: fun f: (Str => Str) & ((Str, Int) => Int) +//│ ╟── type `Str -> Str & (Str, Int) -> Int` is not an instance of `("abc", "abc") -> ?a` +//│ ║ l.587: fun f: (Str => Str) & ((Str, Int) => Int) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `("abc", "abc") -> ?a` -//│ ║ l.595: f("abc", "abc") +//│ ║ l.592: f("abc", "abc") //│ ╙── ^ //│ error //│ res @@ -612,3 +609,45 @@ f("abcabc") //│ res //│ = //│ f is not implemented + +:e +x => rt([not(x)]) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.614: x => rt([not(x)]) +//│ ║ ^^^^^^^^^^^^ +//│ ╟── application of type `Bool` does not match type `?a` +//│ ║ l.614: x => rt([not(x)]) +//│ ╙── ^^^^^^ +//│ forall 'a 'b. Bool -> 'a +//│ where +//│ 'b :> Bool +//│ 'a :> error +//│ [-'a, +'b] in {} +//│ res +//│ = +//│ rt is not implemented + +:e +rt(0) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.631: rt(0) +//│ ║ ^^^^^ +//│ ╟── type `{0: Int} -> Int & {0: Str} -> Str` is not an instance of `0 -> ?a` +//│ ║ l.527: fun rt: {0: Int} -> Int & {0: Str} -> Str +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `0 -> ?a` +//│ ║ l.631: rt(0) +//│ ╙── ^^ +//│ error +//│ res +//│ = +//│ rt is not implemented + +fun z: {0:Int} -> nothing & Str -> Str +//│ fun z: {0: Int} -> nothing & Str -> Str + +z([1]) +//│ nothing +//│ res +//│ = +//│ z is not implemented From 71032164100b9e62c36d58a6bbc0173ed0462ffd Mon Sep 17 00:00:00 2001 From: auht <101095686+auht@users.noreply.github.com> Date: Thu, 19 Sep 2024 23:51:42 +0800 Subject: [PATCH 37/43] Update shared/src/test/diff/fcp/Overloads.mls Co-authored-by: Lionel Parreaux --- shared/src/test/diff/fcp/Overloads.mls | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index e1308ef309..ca1093ec74 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -87,10 +87,12 @@ IISS 0 (if true then IISS else BBNN) 0 //│ res: number -// * TODO: should we still allow this? And maybe reduce it -// * Conceptually we'd expect it to reduce to `int -> number` -// * But it's tricky to do the actual reduction since technically -// * 'a = Bot anf 'b = Top could satisfy all tuple alternatives +// * Note that this is not considered ambiguous +// * because the type variable occurrences are polar, +// * meaning that the TSCs are always trivially satisfiable +// * and thus the code is well-typed. +// * Conceptually, we'd expect this inferred type to reduce to `int -> number`, +// * but it's tricky to do such simplifications in general. def f = fun x -> (if true then IISS else BBNN) x //│ f: 'a -> 'b //│ where From eff743cd5c3807fa94aadbbca548e303768ab8eb Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sun, 22 Sep 2024 13:44:40 +0800 Subject: [PATCH 38/43] add ambiguity check to toplevel forall --- .../src/main/scala/mlscript/NuTypeDefs.scala | 14 ++++- shared/src/test/diff/fcp/Overloads.mls | 20 +++--- shared/src/test/diff/nu/HeungTung.mls | 61 ++++++++++++++----- 3 files changed, 68 insertions(+), 27 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 3470c6807b..45a19986aa 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -1165,7 +1165,19 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx.nextLevel { implicit ctx: Ctx => assert(fd.tparams.sizeCompare(tparamsSkolems) === 0, (fd.tparams, tparamsSkolems)) vars ++ tparamsSkolems |> { implicit vars => - typeTerm(body) + val ty = typeTerm(body) + if (noApproximateOverload) { + val ambiguous = ty.getVars.unsorted.flatMap(_.tsc.keys.flatMap(_.tvs)) + .groupBy(_._2) + .filter { case (v,pvs) => pvs.sizeIs > 1 } + if (ambiguous.nonEmpty) raise(ErrorReport( + msg"ambiguous" -> N :: + ambiguous.map { case (v,_) => + msg"cannot determine satisfiability of type ${v.expPos}" -> v.prov.loco + }.toList + , true)) + } + ty } } } else { diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index ca1093ec74..a74fbc536b 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -105,13 +105,13 @@ f(0) // FIXME f(0) + 1 //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.104: f(0) + 1 +//│ ║ l.106: f(0) + 1 //│ ║ ^^^^^^ //│ ╟── type `number` is not an instance of type `int` //│ ║ l.13: def BBNN: bool -> bool & number -> number //│ ║ ^^^^^^ //│ ╟── but it flows into application with expected type `int` -//│ ║ l.104: f(0) + 1 +//│ ║ l.106: f(0) + 1 //│ ╙── ^^^^ //│ res: error | int @@ -121,10 +121,10 @@ f : int -> number :e f : number -> int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.120: f : number -> int +//│ ║ l.122: f : number -> int //│ ║ ^ //│ ╟── type `number` does not match type `?a` -//│ ║ l.120: f : number -> int +//│ ║ l.122: f : number -> int //│ ╙── ^^^^^^ //│ res: number -> int @@ -141,16 +141,16 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.140: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.142: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `int -> int & string -> string` is not an instance of `(0 | 1 | true) -> number` //│ ║ l.12: def IISS: int -> int & string -> string //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.140: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.142: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.140: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.142: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: (0 | 1 | true) -> number @@ -169,13 +169,13 @@ not test //│ <: test: //│ ~(int -> int) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.165: not test +//│ ║ l.167: not test //│ ║ ^^^^^^^^ //│ ╟── type `~(int -> int)` is not an instance of type `bool` -//│ ║ l.159: def test: ~(int -> int) +//│ ║ l.161: def test: ~(int -> int) //│ ║ ^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `bool` -//│ ║ l.165: not test +//│ ║ l.167: not test //│ ╙── ^^^^ //│ res: bool | error diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 11d225a411..79aff1df67 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -500,8 +500,12 @@ fun u: {x:0, y:Int} -> Int & {x:1, z: Str} -> Str fun s: Str -> Str & AA -> AA //│ fun s: Str -> Str & AA -> AA -// FIXME +:e // FIXME let g = x => s(r(x)) +//│ ╔══[ERROR] ambiguous +//│ ╟── cannot determine satisfiability of type ?a +//│ ║ l.504: let g = x => s(r(x)) +//│ ╙── ^^^^ //│ let g: forall 'a 'b 'c. 'a -> 'c //│ where //│ [+'a, -'b] in {[Int, Int], [Bool, Bool]} @@ -510,15 +514,40 @@ let g = x => s(r(x)) //│ = //│ s is not implemented +:e +fun g(x) = s(r(x)) +//│ ╔══[ERROR] ambiguous +//│ ╟── cannot determine satisfiability of type ?a +//│ ║ l.518: fun g(x) = s(r(x)) +//│ ╙── ^^^^ +//│ fun g: forall 'a 'b 'c. 'a -> 'c +//│ where +//│ [+'a, -'b] in {[Int, Int], [Bool, Bool]} +//│ [-'c, +'b] in {[Str, Str], [AA, AA]} + +:e +x => s(r(x)) +//│ ╔══[ERROR] ambiguous +//│ ╟── cannot determine satisfiability of type ?a +//│ ║ l.529: x => s(r(x)) +//│ ╙── ^^^^ +//│ forall 'a 'b 'c. 'a -> 'c +//│ where +//│ [+'a, -'b] in {[Int, Int], [Bool, Bool]} +//│ [-'c, +'b] in {[Str, Str], [AA, AA]} +//│ res +//│ = +//│ s is not implemented + :e g(0) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.514: g(0) +//│ ║ l.543: g(0) //│ ║ ^^^^ //│ ╟── expression of type `Int` does not match type `?a` //│ ╟── Note: constraint arises from application: -//│ ║ l.504: let g = x => s(r(x)) -//│ ╙── ^^^^ +//│ ║ l.518: fun g(x) = s(r(x)) +//│ ╙── ^^^^ //│ error //│ res //│ = @@ -548,13 +577,13 @@ fun snd: A -> Int -> Int & Str -> Str -> Str :e x => app2(snd)(x):Int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.549: x => app2(snd)(x):Int +//│ ║ l.578: x => app2(snd)(x):Int //│ ║ ^^^^^^^^^^^^ //│ ╟── type `Int` is not an instance of type `A` -//│ ║ l.542: fun app2: ('a -> 'a -> 'a) -> 'a -> 'a +//│ ║ l.571: fun app2: ('a -> 'a -> 'a) -> 'a -> 'a //│ ║ ^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.545: fun snd: A -> Int -> Int & Str -> Str -> Str +//│ ║ l.574: fun snd: A -> Int -> Int & Str -> Str -> Str //│ ╙── ^ //│ nothing -> Int //│ res @@ -568,7 +597,7 @@ app2_(snd) //│ 'a -> 'b //│ where //│ 'a <: 'b -//│ [+'a, -'a, -'b] in {[A & Int, Int, Int], [Str, Str, Str]} +//│ [-'b, -'a, +'a] in {[Int, Int, A & Int], [Str, Str, Str]} //│ res //│ = //│ snd is not implemented @@ -591,13 +620,13 @@ fun f: (Str => Str) & ((Str, Int) => Int) :e f("abc", "abc") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.592: f("abc", "abc") +//│ ║ l.621: f("abc", "abc") //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type `Str -> Str & (Str, Int) -> Int` is not an instance of `("abc", "abc") -> ?a` -//│ ║ l.587: fun f: (Str => Str) & ((Str, Int) => Int) +//│ ║ l.616: fun f: (Str => Str) & ((Str, Int) => Int) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `("abc", "abc") -> ?a` -//│ ║ l.592: f("abc", "abc") +//│ ║ l.621: f("abc", "abc") //│ ╙── ^ //│ error //│ res @@ -613,10 +642,10 @@ f("abcabc") :e x => rt([not(x)]) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.614: x => rt([not(x)]) +//│ ║ l.643: x => rt([not(x)]) //│ ║ ^^^^^^^^^^^^ //│ ╟── application of type `Bool` does not match type `?a` -//│ ║ l.614: x => rt([not(x)]) +//│ ║ l.643: x => rt([not(x)]) //│ ╙── ^^^^^^ //│ forall 'a 'b. Bool -> 'a //│ where @@ -630,13 +659,13 @@ x => rt([not(x)]) :e rt(0) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.631: rt(0) +//│ ║ l.660: rt(0) //│ ║ ^^^^^ //│ ╟── type `{0: Int} -> Int & {0: Str} -> Str` is not an instance of `0 -> ?a` -//│ ║ l.527: fun rt: {0: Int} -> Int & {0: Str} -> Str +//│ ║ l.556: fun rt: {0: Int} -> Int & {0: Str} -> Str //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `0 -> ?a` -//│ ║ l.631: rt(0) +//│ ║ l.660: rt(0) //│ ╙── ^^ //│ error //│ res From bbd8f9b435df253f24b2cc6ee151ef07f3f94e80 Mon Sep 17 00:00:00 2001 From: auht <101095686+auht@users.noreply.github.com> Date: Mon, 23 Sep 2024 20:33:57 +0800 Subject: [PATCH 39/43] Update HeungTung.mls --- shared/src/test/diff/nu/HeungTung.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 79aff1df67..3785f32dd9 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -500,7 +500,7 @@ fun u: {x:0, y:Int} -> Int & {x:1, z: Str} -> Str fun s: Str -> Str & AA -> AA //│ fun s: Str -> Str & AA -> AA -:e // FIXME +:e let g = x => s(r(x)) //│ ╔══[ERROR] ambiguous //│ ╟── cannot determine satisfiability of type ?a From 4f2176246a3016ef55faf84d509d8275d943352a Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Fri, 27 Sep 2024 20:55:46 +0800 Subject: [PATCH 40/43] minor changes --- shared/src/main/scala/mlscript/TyperDatatypes.scala | 11 +++-------- shared/src/main/scala/mlscript/TyperHelpers.scala | 5 ++--- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 25bbc72555..17a95fc8ff 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -699,7 +699,6 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } } def updateOn(index: Int, bound: ST)(implicit raise: Raise, ctx: Ctx) : Unit = { - println(s"TSC update: $tvs in $constraints") updateImpl(index, bound) println(s"TSC update: $tvs in $constraints") } @@ -759,8 +758,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => S(List((pol, first) -> rest)) else N } - def lcgFunction(pol: Bool, first: FT, rest: FT) - (implicit ctx: Ctx) + def lcgFunction(pol: Bool, first: FT, rest: FT)(implicit ctx: Ctx) : Opt[Ls[(Bool, ST) -> ST]] = { for { lm <- lcg(!pol, first.lhs, rest.lhs) @@ -779,11 +777,8 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => val tvs = u.flatMap(_.keys).distinct val m = tvs.map(x => u.map(_.getOrElse(x,if (x._1) TopType else BotType))) val tsc = new TupleSetConstraints(m.transpose, tvs) - tvs.mapValuesIter(_.unwrapProxies).zipWithIndex.foreach { - case ((true, tv: TV), i) => - tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) - case ((false, tv: TV), i) => - tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) + tvs.values.map(_.unwrapProxies).zipWithIndex.foreach { + case (tv: TV, i) => tv.tsc.updateWith(tsc)(_.map(_ + i).orElse(S(Set(i)))) case _ => () } println(s"TSC mk: ${tsc.tvs} in ${tsc.constraints}") diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 3ce562ac20..c4e9c2299b 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -956,12 +956,11 @@ abstract class TyperHelpers { Typer: Typer => def getVars: SortedSet[TypeVariable] = getVarsImpl(includeBounds = true) def showBounds: String = - getVars.iterator.filter(tv => (tv.assignedTo.nonEmpty || (tv.upperBounds ++ tv.lowerBounds).nonEmpty)).map { + getVars.iterator.filter(tv => tv.assignedTo.nonEmpty || (tv.upperBounds ++ tv.lowerBounds).nonEmpty).map { case tv @ AssignedVariable(ty) => "\n\t\t" + tv.toString + " := " + ty case tv => ("\n\t\t" + tv.toString + (if (tv.lowerBounds.isEmpty) "" else " :> " + tv.lowerBounds.mkString(" | ")) - + (if (tv.upperBounds.isEmpty) "" else " <: " + tv.upperBounds.mkString(" & ")) - ) + + (if (tv.upperBounds.isEmpty) "" else " <: " + tv.upperBounds.mkString(" & "))) }.mkString + { val visited: MutSet[TupleSetConstraints] = MutSet.empty getVars.iterator.flatMap(_.tsc).map { case (tsc, i) => From e74015980186e302eed0fd3c750ad90332a01026 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Fri, 4 Oct 2024 20:47:09 +0800 Subject: [PATCH 41/43] guard with flag --- .../scala/mlscript/ConstraintSolver.scala | 64 +++--- .../main/scala/mlscript/TypeSimplifier.scala | 47 +++-- shared/src/main/scala/mlscript/Typer.scala | 16 +- shared/src/test/diff/fcp/Overloads.mls | 101 ++++----- .../src/test/diff/fcp/Overloads_Precise.mls | 197 ++++++++++++++++++ 5 files changed, 310 insertions(+), 115 deletions(-) create mode 100644 shared/src/test/diff/fcp/Overloads_Precise.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 13ec610c31..5d60ac1ff5 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -861,24 +861,26 @@ class ConstraintSolver extends NormalForms { self: Typer => val newBound = (cctx._1 ::: cctx._2.reverse).foldRight(rhs)((c, ty) => if (c.prov is noProv) ty else mkProxy(ty, c.prov)) lhs.upperBounds ::= newBound // update the bound - lhs.tsc.foreachEntry { (tsc, v) => - v.foreach { i => - if (!tsc.tvs(i)._1) { - tsc.updateOn(i, rhs) - if (tsc.constraints.isEmpty) reportError() + if (noApproximateOverload) { + lhs.tsc.foreachEntry { (tsc, v) => + v.foreach { i => + if (!tsc.tvs(i)._1) { + tsc.updateOn(i, rhs) + if (tsc.constraints.isEmpty) reportError() + } } } - } - val u = lhs.tsc.keysIterator.filter(_.constraints.sizeCompare(1)===0).duplicate - u._1.foreach { k => - k.tvs.mapValuesIter(_.unwrapProxies).foreach { - case (_,tv: TV) => tv.tsc.remove(k) - case _ => () + val u = lhs.tsc.keysIterator.filter(_.constraints.sizeCompare(1)===0).duplicate + u._1.foreach { k => + k.tvs.mapValuesIter(_.unwrapProxies).foreach { + case (_,tv: TV) => tv.tsc.remove(k) + case _ => () + } } - } - u._2.foreach { k => - k.constraints.head.iterator.zip(k.tvs).foreach { - case (c, (pol, t)) => if (pol) rec(t, c, false) else rec(c, t, false) + u._2.foreach { k => + k.constraints.head.iterator.zip(k.tvs).foreach { + case (c, (pol, t)) => if (pol) rec(t, c, false) else rec(c, t, false) + } } } lhs.lowerBounds.foreach(rec(_, rhs, true)) // propagate from the bound @@ -888,24 +890,26 @@ class ConstraintSolver extends NormalForms { self: Typer => val newBound = (cctx._1 ::: cctx._2.reverse).foldLeft(lhs)((ty, c) => if (c.prov is noProv) ty else mkProxy(ty, c.prov)) rhs.lowerBounds ::= newBound // update the bound - rhs.tsc.foreachEntry { (tsc, v) => - v.foreach { i => - if(tsc.tvs(i)._1) { - tsc.updateOn(i, lhs) - if (tsc.constraints.isEmpty) reportError() + if (noApproximateOverload) { + rhs.tsc.foreachEntry { (tsc, v) => + v.foreach { i => + if(tsc.tvs(i)._1) { + tsc.updateOn(i, lhs) + if (tsc.constraints.isEmpty) reportError() + } } } - } - val u = rhs.tsc.keysIterator.filter(_.constraints.sizeCompare(1)===0).duplicate - u._1.foreach { k => - k.tvs.mapValuesIter(_.unwrapProxies).foreach { - case (_,tv: TV) => tv.tsc.remove(k) - case _ => () + val u = rhs.tsc.keysIterator.filter(_.constraints.sizeCompare(1)===0).duplicate + u._1.foreach { k => + k.tvs.mapValuesIter(_.unwrapProxies).foreach { + case (_,tv: TV) => tv.tsc.remove(k) + case _ => () + } } - } - u._2.foreach { k => - k.constraints.head.iterator.zip(k.tvs).foreach { - case (c, (pol, t)) => if (pol) rec(t, c, false) else rec(c, t, false) + u._2.foreach { k => + k.constraints.head.iterator.zip(k.tvs).foreach { + case (c, (pol, t)) => if (pol) rec(t, c, false) else rec(c, t, false) + } } } rhs.upperBounds.foreach(rec(lhs, _, true)) // propagate from the bound diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 6b34a94736..f5a0bd8136 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -79,15 +79,16 @@ trait TypeSimplifier { self: Typer => ).map(process(_, S(false -> tv))) .reduceOption(_ &- _).filterNot(_.isTop).toList else Nil - nv.tsc ++= tv.tsc.map { case (tsc, i) => renewedtsc.get(tsc) match { - case S(tsc) => (tsc, i) - case N if inPlace => (tsc, i) - case N => - val t = new TupleSetConstraints(tsc.constraints, tsc.tvs) - renewedtsc += tsc -> t - t.tvs = t.tvs.map(x => (x._1, process(x._2, N))) - (t, i) - }} + if (noApproximateOverload) + nv.tsc ++= tv.tsc.iterator.map { case (tsc, i) => renewedtsc.get(tsc) match { + case S(tsc) => (tsc, i) + case N if inPlace => (tsc, i) + case N => + val t = new TupleSetConstraints(tsc.constraints, tsc.tvs) + renewedtsc += tsc -> t + t.tvs = t.tvs.map(x => (x._1, process(x._2, N))) + (t, i) + }} } nv @@ -560,12 +561,14 @@ trait TypeSimplifier { self: Typer => if (pol(tv) =/= S(false)) analyzed1.setAndIfUnset(tv -> true) { tv.lowerBounds.foreach(apply(pol.at(tv.level, true))) - tv.tsc.keys.flatMap(_.tvs).foreach(u => apply(pol.at(tv.level,u._1))(u._2)) + if (noApproximateOverload) + tv.tsc.keys.flatMap(_.tvs).foreach(u => apply(pol.at(tv.level,u._1))(u._2)) } if (pol(tv) =/= S(true)) analyzed1.setAndIfUnset(tv -> false) { tv.upperBounds.foreach(apply(pol.at(tv.level, false))) - tv.tsc.keys.flatMap(_.tvs).foreach(u => apply(pol.at(tv.level,u._1))(u._2)) + if (noApproximateOverload) + tv.tsc.keys.flatMap(_.tvs).foreach(u => apply(pol.at(tv.level,u._1))(u._2)) } } case _ => @@ -660,7 +663,8 @@ trait TypeSimplifier { self: Typer => case S(pol_tv) => if (analyzed2.add(pol_tv -> tv)) { processImpl(st, pol, pol_tv) - tv.tsc.keys.flatMap(_.tvs).foreach(u => processImpl(u._2,pol.at(tv.level,u._1),pol_tv)) + if (noApproximateOverload) + tv.tsc.keys.flatMap(_.tvs).foreach(u => processImpl(u._2,pol.at(tv.level,u._1),pol_tv)) } case N => if (analyzed2.add(true -> tv)) @@ -707,7 +711,7 @@ trait TypeSimplifier { self: Typer => case S(p) => (if (p) tv2.lowerBounds else tv2.upperBounds).foreach(go) // (if (p) getLbs(tv2) else getUbs(tv2)).foreach(go) - tv2.tsc.keys.flatMap(_.tvs).foreach(u => go(u._2)) + if (noApproximateOverload) tv2.tsc.keys.flatMap(_.tvs).foreach(u => go(u._2)) case N => trace(s"Analyzing invar-occ of $tv2") { analyze2(tv2, pol) @@ -1038,14 +1042,15 @@ trait TypeSimplifier { self: Typer => res.lowerBounds = tv.lowerBounds.map(transform(_, pol.at(tv.level, true), Set.single(tv))) if (occNums.contains(false -> tv)) res.upperBounds = tv.upperBounds.map(transform(_, pol.at(tv.level, false), Set.single(tv))) - res.tsc ++= tv.tsc.map { case (tsc, i) => renewaltsc.get(tsc) match { - case S(tsc) => (tsc, i) - case N => - val t = new TupleSetConstraints(tsc.constraints, tsc.tvs) - renewaltsc += tsc -> t - t.tvs = t.tvs.map(x => (x._1, transform(x._2, PolMap.neu, Set.empty))) - (t, i) - }} + if (noApproximateOverload) + res.tsc ++= tv.tsc.map { case (tsc, i) => renewaltsc.get(tsc) match { + case S(tsc) => (tsc, i) + case N => + val t = new TupleSetConstraints(tsc.constraints, tsc.tvs) + renewaltsc += tsc -> t + t.tvs = t.tvs.map(x => (x._1, transform(x._2, PolMap.neu, Set.empty))) + (t, i) + }} } res }() diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 380590558d..af88e803bc 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -170,13 +170,15 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne if (p) (b, tv) else (tv, b) } }.toList, innerTy) - val ambiguous = innerTy.getVars.unsorted.flatMap(_.tsc.keys.flatMap(_.tvs)) - .groupBy(_._2) - .filter { case (v,pvs) => pvs.sizeIs > 1 } - if (ambiguous.nonEmpty) raise(ErrorReport( - msg"ambiguous" -> N :: - ambiguous.map { case (v,_) => msg"cannot determine satisfiability of type ${v.expPos}" -> v.prov.loco }.toList - , true)) + if (noApproximateOverload) { + val ambiguous = innerTy.getVars.unsorted.flatMap(_.tsc.keys.flatMap(_.tvs)) + .groupBy(_._2) + .filter { case (v,pvs) => pvs.sizeIs > 1 } + if (ambiguous.nonEmpty) raise(ErrorReport( + msg"ambiguous" -> N :: + ambiguous.map { case (v,_) => msg"cannot determine satisfiability of type ${v.expPos}" -> v.prov.loco }.toList + , true)) + } println(s"Inferred poly constr: $cty —— where ${cty.showBounds}") diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index a74fbc536b..d000a52f90 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -1,6 +1,6 @@ :NoJS -:NoApproximateOverload + type IISS = int -> int & string -> string type BBNN = bool -> bool & number -> number @@ -31,37 +31,22 @@ IISS : ZZII //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.30: IISS : ZZII //│ ║ ^^^^ -//│ ╟── type `int -> int & string -> string` is not an instance of `0 -> 0` +//│ ╟── type `int` does not match type `0` //│ ║ l.12: def IISS: int -> int & string -> string -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `0 -> 0` -//│ ║ l.30: IISS : ZZII -//│ ║ ^^^^ -//│ ╟── Note: constraint arises from function type: +//│ ║ ^^^ +//│ ╟── Note: constraint arises from literal type: //│ ║ l.7: type ZZII = 0 -> 0 & int -> int -//│ ║ ^^^^^^ -//│ ╟── from type reference: -//│ ║ l.30: IISS : ZZII -//│ ╙── ^^^^ +//│ ╙── ^ //│ res: ZZII :e IISS : BBNN //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.49: IISS : BBNN -//│ ║ ^^^^ -//│ ╟── type `int -> int & string -> string` is not an instance of `bool -> bool` -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `bool -> bool` -//│ ║ l.49: IISS : BBNN +//│ ║ l.43: IISS : BBNN //│ ║ ^^^^ -//│ ╟── Note: constraint arises from function type: +//│ ╟── type `bool` does not match type `int | string` //│ ║ l.6: type BBNN = bool -> bool & number -> number -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from type reference: -//│ ║ l.49: IISS : BBNN -//│ ╙── ^^^^ +//│ ╙── ^^^^ //│ res: BBNN @@ -74,18 +59,16 @@ IISS : (0 | 1) -> number //│ res: (0 | 1) -> number IISS : 'a -> 'a -//│ res: 'a -> 'a -//│ where -//│ [-'a, +'a] in {[int, int], [string, string]} +//│ res: ('a & (int | string)) -> (int | string | 'a) IISS 0 -//│ res: int +//│ res: int | string (IISS : int -> int) 0 //│ res: int (if true then IISS else BBNN) 0 -//│ res: number +//│ res: bool | number | string // * Note that this is not considered ambiguous // * because the type variable occurrences are polar, @@ -94,38 +77,48 @@ IISS 0 // * Conceptually, we'd expect this inferred type to reduce to `int -> number`, // * but it's tricky to do such simplifications in general. def f = fun x -> (if true then IISS else BBNN) x -//│ f: 'a -> 'b -//│ where -//│ [+'a, -'b] in {[int, int], [string, string]} -//│ [+'a, -'b] in {[bool, bool], [number, number]} +//│ f: int -> (bool | number | string) f(0) -//│ res: number +//│ res: bool | number | string -// FIXME +:e f(0) + 1 //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.106: f(0) + 1 -//│ ║ ^^^^^^ -//│ ╟── type `number` is not an instance of type `int` +//│ ║ l.86: f(0) + 1 +//│ ║ ^^^^^^ +//│ ╟── type `bool` is not an instance of type `int` //│ ║ l.13: def BBNN: bool -> bool & number -> number -//│ ║ ^^^^^^ +//│ ║ ^^^^ //│ ╟── but it flows into application with expected type `int` -//│ ║ l.106: f(0) + 1 -//│ ╙── ^^^^ +//│ ║ l.86: f(0) + 1 +//│ ╙── ^^^^ //│ res: error | int +:e f : int -> number +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.99: f : int -> number +//│ ║ ^ +//│ ╟── type `bool` is not an instance of type `number` +//│ ║ l.13: def BBNN: bool -> bool & number -> number +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.99: f : int -> number +//│ ╙── ^^^^^^ //│ res: int -> number :e f : number -> int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.122: f : number -> int +//│ ║ l.112: f : number -> int //│ ║ ^ -//│ ╟── type `number` does not match type `?a` -//│ ║ l.122: f : number -> int -//│ ╙── ^^^^^^ +//│ ╟── type `number` does not match type `int | string` +//│ ║ l.112: f : number -> int +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.79: def f = fun x -> (if true then IISS else BBNN) x +//│ ╙── ^ //│ res: number -> int @@ -141,17 +134,11 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.142: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.135: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `int -> int & string -> string` is not an instance of `(0 | 1 | true) -> number` -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` -//│ ║ l.142: (if true then IISS else BBNN) : (0 | 1 | true) -> number -//│ ║ ^^^^ -//│ ╟── Note: constraint arises from function type: -//│ ║ l.142: (if true then IISS else BBNN) : (0 | 1 | true) -> number -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `true` does not match type `int | string` +//│ ║ l.135: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ╙── ^^^^ //│ res: (0 | 1 | true) -> number @@ -169,13 +156,13 @@ not test //│ <: test: //│ ~(int -> int) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.167: not test +//│ ║ l.154: not test //│ ║ ^^^^^^^^ //│ ╟── type `~(int -> int)` is not an instance of type `bool` -//│ ║ l.161: def test: ~(int -> int) +//│ ║ l.148: def test: ~(int -> int) //│ ║ ^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `bool` -//│ ║ l.167: not test +//│ ║ l.154: not test //│ ╙── ^^^^ //│ res: bool | error diff --git a/shared/src/test/diff/fcp/Overloads_Precise.mls b/shared/src/test/diff/fcp/Overloads_Precise.mls new file mode 100644 index 0000000000..d24fc5dfc0 --- /dev/null +++ b/shared/src/test/diff/fcp/Overloads_Precise.mls @@ -0,0 +1,197 @@ + +:NoJS +:NoApproximateOverload + +type IISS = int -> int & string -> string +type BBNN = bool -> bool & number -> number +type ZZII = 0 -> 0 & int -> int +//│ Defined type alias IISS +//│ Defined type alias BBNN +//│ Defined type alias ZZII + +def IISS: int -> int & string -> string +def BBNN: bool -> bool & number -> number +def ZZII: 0 -> 0 & int -> int +//│ IISS: int -> int & string -> string +//│ BBNN: bool -> bool & number -> number +//│ ZZII: 0 -> 0 & int -> int + + +IISS : IISS +//│ res: IISS + +IISS : int -> int & string -> string +//│ res: int -> int & string -> string + +IISS : IISS | BBNN +//│ res: BBNN | IISS + +:e +IISS : ZZII +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.30: IISS : ZZII +//│ ║ ^^^^ +//│ ╟── type `int -> int & string -> string` is not an instance of `0 -> 0` +//│ ║ l.12: def IISS: int -> int & string -> string +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `0 -> 0` +//│ ║ l.30: IISS : ZZII +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from function type: +//│ ║ l.7: type ZZII = 0 -> 0 & int -> int +//│ ║ ^^^^^^ +//│ ╟── from type reference: +//│ ║ l.30: IISS : ZZII +//│ ╙── ^^^^ +//│ res: ZZII + +:e +IISS : BBNN +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.49: IISS : BBNN +//│ ║ ^^^^ +//│ ╟── type `int -> int & string -> string` is not an instance of `bool -> bool` +//│ ║ l.12: def IISS: int -> int & string -> string +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `bool -> bool` +//│ ║ l.49: IISS : BBNN +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from function type: +//│ ║ l.6: type BBNN = bool -> bool & number -> number +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from type reference: +//│ ║ l.49: IISS : BBNN +//│ ╙── ^^^^ +//│ res: BBNN + + +// * These tests show that we currently throw away information when constraining LHS overloading sets: + +IISS : int -> int +//│ res: int -> int + +IISS : (0 | 1) -> number +//│ res: (0 | 1) -> number + +IISS : 'a -> 'a +//│ res: 'a -> 'a +//│ where +//│ [-'a, +'a] in {[int, int], [string, string]} + +IISS 0 +//│ res: int + +(IISS : int -> int) 0 +//│ res: int + +(if true then IISS else BBNN) 0 +//│ res: number + +// * Note that this is not considered ambiguous +// * because the type variable occurrences are polar, +// * meaning that the TSCs are always trivially satisfiable +// * and thus the code is well-typed. +// * Conceptually, we'd expect this inferred type to reduce to `int -> number`, +// * but it's tricky to do such simplifications in general. +def f = fun x -> (if true then IISS else BBNN) x +//│ f: 'a -> 'b +//│ where +//│ [+'a, -'b] in {[int, int], [string, string]} +//│ [+'a, -'b] in {[bool, bool], [number, number]} + +f(0) +//│ res: number + +:e +f(0) + 1 +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.106: f(0) + 1 +//│ ║ ^^^^^^ +//│ ╟── type `number` is not an instance of type `int` +//│ ║ l.13: def BBNN: bool -> bool & number -> number +//│ ║ ^^^^^^ +//│ ╟── but it flows into application with expected type `int` +//│ ║ l.106: f(0) + 1 +//│ ╙── ^^^^ +//│ res: error | int + +f : int -> number +//│ res: int -> number + +:e +f : number -> int +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.122: f : number -> int +//│ ║ ^ +//│ ╟── type `number` does not match type `?a` +//│ ║ l.122: f : number -> int +//│ ╙── ^^^^^^ +//│ res: number -> int + + +if true then IISS else BBNN +//│ res: bool -> bool & number -> number | int -> int & string -> string + +(if true then IISS else ZZII) : int -> int +//│ res: int -> int + +(if true then IISS else BBNN) : (0 | 1) -> number +//│ res: (0 | 1) -> number + +:e +(if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.142: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `int -> int & string -> string` is not an instance of `(0 | 1 | true) -> number` +//│ ║ l.12: def IISS: int -> int & string -> string +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `(0 | 1 | true) -> number` +//│ ║ l.142: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from function type: +//│ ║ l.142: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ res: (0 | 1 | true) -> number + + +// * Note that type normalization used to be very aggressive at approximating non-tag type negations, +// * to simplify the result, but this was changed as it was unsound + +def test: ~(int -> int) +//│ test: ~(int -> int) + +// * See also test file BooleanFail.mls about this previous unsoundness +:e +test = 42 +not test +//│ 42 +//│ <: test: +//│ ~(int -> int) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.167: not test +//│ ║ ^^^^^^^^ +//│ ╟── type `~(int -> int)` is not an instance of type `bool` +//│ ║ l.161: def test: ~(int -> int) +//│ ║ ^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `bool` +//│ ║ l.167: not test +//│ ╙── ^^^^ +//│ res: bool | error + +def test: ~(int -> int) & ~bool +//│ test: ~bool & ~(int -> int) + +def test: ~(int -> int) & bool +//│ test: bool + +def test: ~(int -> int) & ~(bool -> bool) +//│ test: ~(nothing -> (bool | int)) + +def test: ~(int -> int | bool -> bool) +//│ test: ~(nothing -> (bool | int)) + +def test: ~(int -> int & string -> string) & ~(bool -> bool & number -> number) +//│ test: in ~(nothing -> (number | string) & int -> number & nothing -> (bool | string) & nothing -> (bool | int)) out ~(nothing -> (bool | int) & nothing -> (bool | string) & int -> number & nothing -> (number | string)) + + From 81caf7b2abe379eb6f94c62159991af2fc09c13e Mon Sep 17 00:00:00 2001 From: auht <101095686+auht@users.noreply.github.com> Date: Fri, 4 Oct 2024 21:01:12 +0800 Subject: [PATCH 42/43] Update Overloads.mls --- shared/src/test/diff/fcp/Overloads.mls | 6 ------ 1 file changed, 6 deletions(-) diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index d000a52f90..0c14d4a9e9 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -70,12 +70,6 @@ IISS 0 (if true then IISS else BBNN) 0 //│ res: bool | number | string -// * Note that this is not considered ambiguous -// * because the type variable occurrences are polar, -// * meaning that the TSCs are always trivially satisfiable -// * and thus the code is well-typed. -// * Conceptually, we'd expect this inferred type to reduce to `int -> number`, -// * but it's tricky to do such simplifications in general. def f = fun x -> (if true then IISS else BBNN) x //│ f: int -> (bool | number | string) From 8e5118f91c2043fdf2cfb08e988daaa8395f53c7 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Fri, 4 Oct 2024 21:10:34 +0800 Subject: [PATCH 43/43] run tests --- shared/src/test/diff/fcp/Overloads.mls | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 0c14d4a9e9..770079c253 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -79,39 +79,39 @@ f(0) :e f(0) + 1 //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.86: f(0) + 1 +//│ ║ l.80: f(0) + 1 //│ ║ ^^^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ║ l.13: def BBNN: bool -> bool & number -> number //│ ║ ^^^^ //│ ╟── but it flows into application with expected type `int` -//│ ║ l.86: f(0) + 1 +//│ ║ l.80: f(0) + 1 //│ ╙── ^^^^ //│ res: error | int :e f : int -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.99: f : int -> number +//│ ║ l.93: f : int -> number //│ ║ ^ //│ ╟── type `bool` is not an instance of type `number` //│ ║ l.13: def BBNN: bool -> bool & number -> number //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.99: f : int -> number +//│ ║ l.93: f : int -> number //│ ╙── ^^^^^^ //│ res: int -> number :e f : number -> int //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.112: f : number -> int +//│ ║ l.106: f : number -> int //│ ║ ^ //│ ╟── type `number` does not match type `int | string` -//│ ║ l.112: f : number -> int +//│ ║ l.106: f : number -> int //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.79: def f = fun x -> (if true then IISS else BBNN) x +//│ ║ l.73: def f = fun x -> (if true then IISS else BBNN) x //│ ╙── ^ //│ res: number -> int @@ -128,10 +128,10 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.135: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.129: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `true` does not match type `int | string` -//│ ║ l.135: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ l.129: (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╙── ^^^^ //│ res: (0 | 1 | true) -> number @@ -150,13 +150,13 @@ not test //│ <: test: //│ ~(int -> int) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.154: not test +//│ ║ l.148: not test //│ ║ ^^^^^^^^ //│ ╟── type `~(int -> int)` is not an instance of type `bool` -//│ ║ l.148: def test: ~(int -> int) +//│ ║ l.142: def test: ~(int -> int) //│ ║ ^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `bool` -//│ ║ l.154: not test +//│ ║ l.148: not test //│ ╙── ^^^^ //│ res: bool | error