From 9707a3f135ccb0173ff1d814af5d7de690ce150f Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Wed, 26 Feb 2025 05:08:39 +0800 Subject: [PATCH 01/36] disjunctive subtyping --- .../scala/hkmc2/bbml/ConstraintSolver.scala | 41 ++++++++++++++++--- .../main/scala/hkmc2/bbml/NormalForm.scala | 17 +++++--- .../src/main/scala/hkmc2/bbml/types.scala | 16 +++++++- .../shared/src/test/mlscript/bbml/DisjSub.mls | 33 +++++++++++++++ 4 files changed, 94 insertions(+), 13 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index 186992bc9f..36c107cc4d 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -97,6 +97,14 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, cctx.nest(bd -> v) givenIn: v.state.lowerBounds ::= bd v.state.upperBounds.foreach(ub => constrainImpl(bd, ub)) + v.state.disjsub.foreach:(d)=> + Type.disjoint(d.disjoint(v),bd.toBasic.simp)match + case N=> + d.remove(v) + if d.disjoint.isEmpty then + d.dss.foreach(_.commit()) + d.cs.foreach((a,b)=>constrainImpl(a,b)) + case S(k)=>d.disjoint++=k case Conj(i, u, Nil) => (conj.i, conj.u) match case (_, Union(N, Nil)) => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} ∧ ¬⊥" -> N :: Nil)) @@ -107,16 +115,37 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, constrainArgs(ta1, ta2) else constrainConj(Conj(conj.i, Union(f, rest), Nil)) case (int: Inter, Union(f, _ :: rest)) => constrainConj(Conj(int, Union(f, rest), Nil)) - case (Inter(S(FunType(args1, ret1, eff1))), Union(S(FunType(args2, ret2, eff2)), Nil)) => + case (Inter(S(FunType(args1, ret1, eff1)::Nil)), Union(S(FunType(args2, ret2, eff2)), Nil)) => if args1.length =/= args2.length then // raise(ErrorReport(msg"Cannot constrain ${conj.i.toString()} <: ${conj.u.toString()}" -> N :: Nil)) cctx.err else - args1.zip(args2).foreach { - case (a1, a2) => constrainImpl(a2, a1) - } - constrainImpl(ret1, ret2) - constrainImpl(eff1, eff2) + val k=args2.flatMap(x=>Type.disjoint(x,x)) + if k.isEmpty then + args1.zip(args2).foreach { + case (a1, a2) => constrainImpl(a2, a1) + } + constrainImpl(ret1, ret2) + constrainImpl(eff1, eff2) + else if !k.contains(Nil)then + DisjSub(mutable.Map.from(k.flatten),Nil,(ret1,ret2)::(eff1,eff2)::args2.zip(args1)).commit() + case (Inter(S(fs:Ls[FunType])), Union(S(FunType(args2, ret2, eff2)), Nil)) => + val f=fs.filter(_.args.length===args2.length) + val args=f.map(_.args).transpose + val k=args2.flatMap(x=>Type.disjoint(x,x)) + if!k.contains(Nil)then + // assume distinguished by the first arg + constrainImpl(args2.head,args.head.foldLeft(Bot:Type)(_|_)) + args.head.iterator.zip(f).foreach:(a,b)=> + val s=args2.zip(b.args).tail + Type.disjoint(args2.head.toBasic.simp,a.toBasic.simp)match + case N => + s.foreach((x,y)=>constrainImpl(x,y)) + constrainImpl(b.ret,ret2) + constrainImpl(b.eff,eff2) + case S(k) => + val ds=DisjSub(mutable.Map.from(k),Nil,(b.ret,ret2)::(b.eff,eff2)::s) + ds.commit() case _ => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} <: ${conj.u.toString()}" -> N :: Nil)) cctx.err diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala index 78c0588dc6..4787dce13b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala @@ -76,7 +76,7 @@ object Conj: }){} lazy val empty: Conj = Conj(Inter.empty, Union.empty, Nil) def mkVar(v: InfVar, pol: Bool) = Conj(Inter.empty, Union.empty, (v, pol) :: Nil) - def mkInter(inter: ClassLikeType | FunType) = + def mkInter(inter: ClassLikeType | Ls[FunType]) = Conj(Inter(S(inter)), Union.empty, Nil) def mkUnion(union: ClassLikeType | FunType) = Conj(Inter.empty, union match { @@ -85,18 +85,23 @@ object Conj: }, Nil) // * Some(ClassType) -> C[in D_i out D_i], Some(FunType) -> D_1 ->{D_2} D_3, None -> Top -final case class Inter(v: Opt[ClassLikeType | FunType]) extends NormalForm: +final case class Inter(v: Opt[ClassLikeType | Ls[FunType]]) extends NormalForm: def isTop: Bool = v.isEmpty def merge(other: Inter): Option[Inter] = (v, other.v) match case (S(ClassLikeType(cls1, targs1)), S(ClassLikeType(cls2, targs2))) if cls1.uid === cls2.uid => S(Inter(S(ClassLikeType(cls1, targs1.lazyZip(targs2).map(_ & _))))) case (S(_: ClassLikeType), S(_: ClassLikeType)) => N - case (S(FunType(a1, r1, e1)), S(FunType(a2, r2, e2))) => - S(Inter(S(FunType(a1.lazyZip(a2).map(_ | _), r1 & r2, e1 & e2)))) + // case (S(FunType(a1, r1, e1)), S(FunType(a2, r2, e2))) => + // S(Inter(S(FunType(a1.lazyZip(a2).map(_ | _), r1 & r2, e1 & e2)))) + case (S(a:Ls[FunType]),S(b:Ls[FunType]))=>S(Inter(S(a++b))) case (S(v), N) => S(Inter(S(v))) case (N, v) => S(Inter(v)) case _ => N - def toBasic: BasicType = v.getOrElse(Top) + def toBasic: BasicType = v match + case N=>Top + case S(x:ClassLikeType)=>x + case S(Nil)=>Top + case S(x:Ls[FunType])=>x.reduce[Type](_&_).toBasic def toDnf(using TL): Disj = Disj(Conj(this, Union(N, Nil), Nil) :: Nil) override def show(using Scope): Str = toBasic.show @@ -182,7 +187,7 @@ object NormalForm: case Bot => Disj.bot case v: InfVar => Disj(Conj.mkVar(v, true) :: Nil) case ct: ClassLikeType => Disj(Conj.mkInter(ct.toNorm) :: Nil) - case ft: FunType => Disj(Conj.mkInter(ft.toNorm) :: Nil) + case ft: FunType => Disj(Conj.mkInter(Ls(ft.toNorm)) :: Nil) case ComposedType(lhs, rhs, pol) => if pol then union(dnf(lhs), dnf(rhs)) else inter(dnf(lhs), dnf(rhs)) case NegType(ty) => neg(ty) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index fc90a0749e..7f4e2ef0e0 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -5,7 +5,7 @@ import mlscript.utils.*, shorthands.* import syntax.* import semantics.*, semantics.Term.* import utils.* -import scala.collection.mutable.{Set => MutSet} +import scala.collection.mutable.{Set => MutSet, Map => MutMap} import utils.Scope import Elaborator.State @@ -281,6 +281,13 @@ object Type: then lhs | rhs else lhs & rhs def mkNegType(ty: Type): Type = ty.! + def disjoint(a:Type,b:Type):Opt[Ls[InfVar->BasicType]]=(a,b)match + case (Bot,_)|(_,Bot)=>S(Nil) + case (ClassLikeType(a,_),ClassLikeType(b,_))if a.uid=/=b.uid=>S(Nil) + case (a:ClassLikeType,v:InfVar)=>S(Ls(v->a)) + case (v:InfVar,a:ClassLikeType)=>S(Ls(v->a)) + case _=>N + // * Poly types can not be used as type arguments case class PolyType(tvs: Ls[InfVar], outer: Opt[InfVar], body: GeneralType) extends GeneralType: @@ -388,3 +395,10 @@ case class PolyFunType(args: Ls[GeneralType], ret: GeneralType, eff: Type) exten class VarState: var lowerBounds: Ls[Type] = Nil var upperBounds: Ls[Type] = Nil + val disjsub: MutSet[DisjSub] = MutSet.empty + +case class DisjSub(disjoint:MutMap[InfVar,BasicType],dss:Ls[DisjSub],cs:Ls[Type->Type]): + def commit()=disjoint.keys.foreach(_.state.disjsub+=this) + def remove(v:InfVar)= + v.state.disjsub-=this + disjoint-=v diff --git a/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls b/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls new file mode 100644 index 0000000000..13ebef1310 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls @@ -0,0 +1,33 @@ +:bbml +//│ Type: ⊤ + +//│ Type: ⊤ + +fun andt(x)=x&&true +fun k(f:Nothing->Bool)=1 +fun ap(f)=x=>f(x) +//│ Type: ⊤ + +k(andt) +//│ Type: Int + +k(ap(andt)) +//│ Type: Int + +fun id:(Int->Int)&(Bool->Bool) +//│ Type: ⊤ + +id(1) +//│ Type: Int + +fun ap1(f)=f(1) +ap1(id) +//│ Type: Int + +ap(id)(1) +//│ Type: Int + +:todo +x=>id(x) +//│ Type: (Int ∨ Bool) ->{⊥} ⊥ + From cc870591eb30b783a3f1dc4ce6bfa3f55502b67b Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 26 Feb 2025 12:30:27 +0800 Subject: [PATCH 02/36] Changes from meeting --- .../main/scala/hkmc2/bbml/NormalForm.scala | 2 +- .../shared/src/test/mlscript/bbml/DisjSub.mls | 79 +++++++++++++++++-- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala index 4787dce13b..95eacc14a7 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala @@ -126,7 +126,7 @@ extends NormalForm with CachedBasicType: case (cls1, cls2) => cls1.name.uid <= cls2.name.uid }.foldLeft[Ls[ClassLikeType]](Nil)((res, cls) => (res, cls) match { case (Nil, cls) => cls :: Nil - case (ClassLikeType(cls1, targs1) :: tail, ClassLikeType(cls2, targs2)) if cls1.uid === cls2.uid => + case (ClassLikeType(cls1, targs1) :: tail, ClassLikeType(cls2, targs2)) if cls1.uid === cls2.uid => ClassLikeType(cls1, targs1.lazyZip(targs2).map(_ | _)) :: tail case (head :: tail, cls) => cls :: head :: tail })) diff --git a/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls b/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls index 13ebef1310..609d1fe373 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls @@ -3,6 +3,7 @@ //│ Type: ⊤ + fun andt(x)=x&&true fun k(f:Nothing->Bool)=1 fun ap(f)=x=>f(x) @@ -14,20 +15,88 @@ k(andt) k(ap(andt)) //│ Type: Int -fun id:(Int->Int)&(Bool->Bool) +k(k) +//│ Type: Int + +fun idIB: (Int -> Int) & (Bool -> Bool) //│ Type: ⊤ -id(1) +idIB(1) //│ Type: Int +idIB(true) +//│ Type: Bool + +idIB(if true then 1 else true) +//│ Type: Bool ∨ Int + + fun ap1(f)=f(1) -ap1(id) +ap1(idIB) //│ Type: Int -ap(id)(1) +ap(idIB)(1) //│ Type: Int :todo -x=>id(x) +x=>idIB(x) //│ Type: (Int ∨ Bool) ->{⊥} ⊥ + +:todo // BbML +fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) +//│ ╔══[ERROR] General type is not allowed here. +//│ ║ l.47: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) +//│ ╙── ^^^ +//│ ╔══[ERROR] General type is not allowed here. +//│ ║ l.47: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) +//│ ╙── ^^^^ +//│ Type: ⊤ + +:todo // BbML +idIIBB([1, 2]) +//│ ╔══[ERROR] Term shape not yet supported by BbML: Tup(List(Fld(‹›,Lit(IntLit(1)),None), Fld(‹›,Lit(IntLit(2)),None))) +//│ ║ l.57: idIIBB([1, 2]) +//│ ╙── ^^^^^^ +//│ Type: ⊥ + + +class Pair[out A, out B](fst: A, snd: B) +//│ Type: ⊤ + +new Pair(1, 2) +//│ Type: Pair['A, 'B] +//│ Where: +//│ Int <: 'A +//│ Int <: 'B + +:todo // WF check on intersection types +:e +fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) +//│ Type: ⊤ + +idIIBB(new Pair(1, 2)) +//│ Type: Bool ∨ Int + +idIIBB(new Pair(1, true)) +//│ Type: Bool ∨ Int + + + +:todo +fun foo: ["x": Int, "y": Int] +//│ ╔══[ERROR] Invalid type +//│ ║ l.87: fun foo: ["x": Int, "y": Int] +//│ ╙── ^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ + +foo +//│ Type: ⊥ + +:todo +fun foo(x) = if x is + [true, true] then 1 + [false, false] then 2 +//│ /!!!\ Uncaught error: scala.MatchError: Tuple(2,false) (of class hkmc2.semantics.Pattern$Tuple) + + From 0298463355b8c7cc50d44f75c84699a2dffedc4e Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Wed, 5 Mar 2025 23:44:23 +0800 Subject: [PATCH 03/36] disjoint upperbound --- .../scala/hkmc2/bbml/ConstraintSolver.scala | 50 +++++++++++-------- .../main/scala/hkmc2/bbml/PrettyPrinter.scala | 14 +++++- .../scala/hkmc2/bbml/TypeSimplifier.scala | 20 ++++---- .../src/main/scala/hkmc2/bbml/types.scala | 44 +++++++++++++--- .../shared/src/test/mlscript/bbml/DisjSub.mls | 22 ++++++-- .../src/test/mlscript/bbml/bbBasics.mls | 21 +++++--- .../src/test/mlscript/bbml/bbBounds.mls | 6 ++- .../test/mlscript/bbml/bbCyclicExtrude.mls | 12 +---- hkmc2/shared/src/test/mlscript/bbml/bbRec.mls | 14 +++--- 9 files changed, 136 insertions(+), 67 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index 36c107cc4d..2836716508 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -92,19 +92,23 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, cctx.nest(v -> nc) givenIn: v.state.upperBounds ::= nc v.state.lowerBounds.foreach(lb => constrainImpl(lb, nc)) + v.state.disjsub.foreach: d => + Type.disjoint(d.disjoint(v), bd.toBasic.simp.toBasic)(Set.empty)(using c = mutable.Map.empty) + .foreach(_.foreach(k => DisjSub(d.disjoint ++ k, d.dss, d.cs).commit())) else log(s"New bound: ${v.showDbg} :> ${bd.showDbg}") cctx.nest(bd -> v) givenIn: v.state.lowerBounds ::= bd v.state.upperBounds.foreach(ub => constrainImpl(bd, ub)) - v.state.disjsub.foreach:(d)=> - Type.disjoint(d.disjoint(v),bd.toBasic.simp)match - case N=> + v.state.disjsub.foreach: d => + Type.disjoint(d.disjoint(v), bd.toBasic.simp.toBasic)(Set.empty)(using c = mutable.Map.empty) match + case N => d.remove(v) if d.disjoint.isEmpty then d.dss.foreach(_.commit()) - d.cs.foreach((a,b)=>constrainImpl(a,b)) - case S(k)=>d.disjoint++=k + d.cs.foreach((a, b) => constrainImpl(a, b)) + case S(k) => + k.foreach(k => DisjSub(d.disjoint ++ k, d.dss, d.cs).commit()) case Conj(i, u, Nil) => (conj.i, conj.u) match case (_, Union(N, Nil)) => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} ∧ ¬⊥" -> N :: Nil)) @@ -120,32 +124,38 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, // raise(ErrorReport(msg"Cannot constrain ${conj.i.toString()} <: ${conj.u.toString()}" -> N :: Nil)) cctx.err else - val k=args2.flatMap(x=>Type.disjoint(x,x)) + val k = args2.flatMap: x => + val u = x.toBasic.simp.toBasic + Type.disjoint(u, u)(Set.empty)(using c = mutable.Map.empty) if k.isEmpty then args1.zip(args2).foreach { case (a1, a2) => constrainImpl(a2, a1) } constrainImpl(ret1, ret2) constrainImpl(eff1, eff2) - else if !k.contains(Nil)then - DisjSub(mutable.Map.from(k.flatten),Nil,(ret1,ret2)::(eff1,eff2)::args2.zip(args1)).commit() + else + val cs = (ret1, ret2) :: (eff1, eff2) :: args2.zip(args1) + k.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => + DisjSub(mutable.Map.from(k), Nil, cs).commit() case (Inter(S(fs:Ls[FunType])), Union(S(FunType(args2, ret2, eff2)), Nil)) => - val f=fs.filter(_.args.length===args2.length) - val args=f.map(_.args).transpose - val k=args2.flatMap(x=>Type.disjoint(x,x)) - if!k.contains(Nil)then + val f = fs.filter(_.args.length === args2.length) + val args = f.map(_.args).transpose + val k = args2.flatMap: x => + val u = x.toBasic.simp.toBasic + Type.disjoint(u, u)(Set.empty)(using c = mutable.Map.empty) + if !k.contains(Nil) then // assume distinguished by the first arg constrainImpl(args2.head,args.head.foldLeft(Bot:Type)(_|_)) - args.head.iterator.zip(f).foreach:(a,b)=> - val s=args2.zip(b.args).tail - Type.disjoint(args2.head.toBasic.simp,a.toBasic.simp)match + args.head.iterator.zip(f).foreach: (a, b) => + val s = args2.zip(b.args).tail + Type.disjoint(args2.head.toBasic.simp.toBasic,a.toBasic.simp.toBasic)(Set.empty)(using c = mutable.Map.empty) match case N => - s.foreach((x,y)=>constrainImpl(x,y)) - constrainImpl(b.ret,ret2) - constrainImpl(b.eff,eff2) + s.foreach((x, y) => constrainImpl(x, y)) + constrainImpl(b.ret, ret2) + constrainImpl(b.eff, eff2) case S(k) => - val ds=DisjSub(mutable.Map.from(k),Nil,(b.ret,ret2)::(b.eff,eff2)::s) - ds.commit() + val cs = (b.ret,ret2) :: (b.eff,eff2) :: s + k.foreach(k => DisjSub(mutable.Map.from(k), Nil, cs).commit()) case _ => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} <: ${conj.u.toString()}" -> N :: Nil)) cctx.err diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala index 80d011d4ad..c0e2c60f51 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala @@ -11,15 +11,21 @@ class PrettyPrinter(output: String => Unit)(using Scope): output("Where:") bounds.foreach { case (lhs, rhs) => output(s" ${lhs.show} <: ${rhs.show}") + case ((x, y), z, w) => + val g = s"${x.show}#${y.show} ∨ " + val h = z.iterator.map { case (x, y) => s"${x.show}#${y.show} ∨ "}.mkString + val b = w.iterator.map { case (x, y) => s"${x.show}<:${y.show}"}.mkString(" ∧ ") + output(s" $g$h$b}") } object PrettyPrinter: def apply(output: String => Unit)(using Scope): PrettyPrinter = new PrettyPrinter(output) type Bound = (Type, Type) // * Type <: Type + type DisjBound=(Bound,List[Bound],List[Bound]) - private def collectBounds(ty: GeneralType): List[Bound] = - val res = ListBuffer[Bound]() + private def collectBounds(ty: GeneralType): List[Bound|DisjBound] = + val res = ListBuffer[Bound|DisjBound]() val cache = MutSet[Uid[InfVar]]() object CollectBounds extends TypeTraverser: override def apply(pol: Boolean)(ty: GeneralType): Unit = ty match @@ -31,6 +37,10 @@ object PrettyPrinter: res ++= state.upperBounds.map: bd => apply(false)(bd) (v, bd) + res ++= state.disjsub.map: d => + val ds = d.disjoint.iterator + val k = ds.next() + (k, ds.toList, d.cs.toList) super.apply(pol)(ty) case _ => super.apply(pol)(ty) CollectBounds(true)(ty) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeSimplifier.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeSimplifier.scala index 229f914766..c87ddc60b2 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeSimplifier.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeSimplifier.scala @@ -191,15 +191,17 @@ class TypeSimplifier(tl: TraceLogger): tv.state.upperBounds = newUBs val isPos = Analysis.posVars.contains(tv) val isNeg = Analysis.negVars.contains(tv) - // if (isPos && !isNeg && (Analysis.occsNum(tv) === 1 && {newLBs match { case (tv: IV) :: Nil => true; case _ => false }} || newLBs.forall(_.isSmall))) { - if isPos && !isNeg && ({newLBs match { case (tv: IV) :: Nil => true; case _ => false }} || newLBs.forall(_ => true)) then { - // if (isPos && !isNeg && ({newLBs match { case (tv: IV) :: Nil => true; case _ => false }})) { - newLBs.foldLeft(Bot: Type)(_ | _) - } else - // if (isNeg && !isPos && (Analysis.occsNum(tv) === 1 && {newUBs match { case (tv: IV) :: Nil => true; case _ => false }} || newUBs.forall(_.isSmall))) { - if isNeg && !isPos && ({newUBs match { case (tv: IV) :: Nil => true; case _ => false }} || newUBs.forall(_ => true)) then - // if (isNeg && !isPos && ({newUBs match { case (tv: IV) :: Nil => true; case _ => false }})) { - newUBs.foldLeft(Top: Type)(_ & _) + if tv.state.disjsub.isEmpty then + // if (isPos && !isNeg && (Analysis.occsNum(tv) === 1 && {newLBs match { case (tv: IV) :: Nil => true; case _ => false }} || newLBs.forall(_.isSmall))) { + if isPos && !isNeg && ({newLBs match { case (tv: IV) :: Nil => true; case _ => false }} || newLBs.forall(_ => true)) then { + // if (isPos && !isNeg && ({newLBs match { case (tv: IV) :: Nil => true; case _ => false }})) { + newLBs.foldLeft(Bot: Type)(_ | _) + } else + // if (isNeg && !isPos && (Analysis.occsNum(tv) === 1 && {newUBs match { case (tv: IV) :: Nil => true; case _ => false }} || newUBs.forall(_.isSmall))) { + if isNeg && !isPos && ({newUBs match { case (tv: IV) :: Nil => true; case _ => false }} || newUBs.forall(_ => true)) then + // if (isNeg && !isPos && ({newUBs match { case (tv: IV) :: Nil => true; case _ => false }})) { + newUBs.foldLeft(Top: Type)(_ & _) + else tv else // tv.lowerBounds = newLBs // tv.upperBounds = newUBs diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 7f4e2ef0e0..b6ea6267a7 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -281,12 +281,39 @@ object Type: then lhs | rhs else lhs & rhs def mkNegType(ty: Type): Type = ty.! - def disjoint(a:Type,b:Type):Opt[Ls[InfVar->BasicType]]=(a,b)match - case (Bot,_)|(_,Bot)=>S(Nil) - case (ClassLikeType(a,_),ClassLikeType(b,_))if a.uid=/=b.uid=>S(Nil) - case (a:ClassLikeType,v:InfVar)=>S(Ls(v->a)) - case (v:InfVar,a:ClassLikeType)=>S(Ls(v->a)) - case _=>N + def disjoint(a: BasicType, b: BasicType)(prev: Set[BasicType -> BasicType]) + (using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]) + : Opt[Set[Set[InfVar->BasicType]]] = + if !prev.contains(a -> b) then c.getOrElseUpdate(a -> b, { + (a, b) match + case (Bot, _) | (_, Bot) => S(Set.empty) + case (NegType(t),_) => t.toBasic.!.simp.toBasic match + case NegType(_) => N + case a => disjoint(a, b)(prev) + case (_, NegType(t)) => t.toBasic.!.simp.toBasic match + case NegType(_) => N + case a => disjoint(a, b)(prev) + case (ClassLikeType(a, _), ClassLikeType(b, _)) if a.uid =/= b.uid => S(Set.empty) + case (ComposedType(p, q, true), _) => + val u = disjoint(p.toBasic.simp.toBasic, b)(prev) + val w = disjoint(q.toBasic.simp.toBasic, b)(prev) + u.flatMap(u => w.map(u ++ _)) + case (_, ComposedType(p, q, true)) => + val u = disjoint(a, p.toBasic.simp.toBasic)(prev) + val w = disjoint(a, q.toBasic.simp.toBasic)(prev) + u.flatMap(u => w.map(u ++ _)) + case (a: InfVar, b: InfVar) if a.uid =/= b.uid => N + case (v: InfVar, _) => + val p = prev + (v->b) + val k = v.state.lowerBounds.map(lb => disjoint(lb.toBasic.simp.toBasic, b)(p)) + if k.exists(_.isEmpty) then N + else + val u = (k.flatten.flatten.toSet + Set.empty).map(_ + (v -> b)) + val w = v.state.upperBounds.flatMap(ub => disjoint(ub.toBasic.simp.toBasic, b)(p)) + S(w.fold(u)((x, y) => y.flatMap(y => x.map(_ ++ y)))) + case (_, v: InfVar) => disjoint(v, a)(prev) + case _ => N + }) else N // * Poly types can not be used as type arguments @@ -396,9 +423,10 @@ class VarState: var lowerBounds: Ls[Type] = Nil var upperBounds: Ls[Type] = Nil val disjsub: MutSet[DisjSub] = MutSet.empty + override def toString = "<>" -case class DisjSub(disjoint:MutMap[InfVar,BasicType],dss:Ls[DisjSub],cs:Ls[Type->Type]): - def commit()=disjoint.keys.foreach(_.state.disjsub+=this) +case class DisjSub(disjoint: MutMap[InfVar,BasicType], dss:Ls[DisjSub], cs:Ls[Type->Type]): + def commit() = disjoint.keys.foreach(_.state.disjsub += this) def remove(v:InfVar)= v.state.disjsub-=this disjoint-=v diff --git a/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls b/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls index 609d1fe373..26c7ccf807 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls @@ -30,6 +30,14 @@ idIB(true) idIB(if true then 1 else true) //│ Type: Bool ∨ Int +x=> + let y = x+1 + idIB(x) +//│ Type: ('x) ->{⊥} ⊥ +//│ Where: +//│ 'x <: Int ∨ Bool +//│ 'x <: Int +//│ 'x#Int ∨ Int<:'app ∧ ⊥<:'eff} fun ap1(f)=f(1) ap1(idIB) @@ -40,23 +48,27 @@ ap(idIB)(1) :todo x=>idIB(x) -//│ Type: (Int ∨ Bool) ->{⊥} ⊥ +//│ Type: ('x) ->{⊥} ⊥ +//│ Where: +//│ 'x <: Int ∨ Bool +//│ 'x#Int ∨ Int<:'app ∧ ⊥<:'eff} +//│ 'x#Bool ∨ Bool<:'app ∧ ⊥<:'eff} :todo // BbML fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╔══[ERROR] General type is not allowed here. -//│ ║ l.47: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) +//│ ║ l.59: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╙── ^^^ //│ ╔══[ERROR] General type is not allowed here. -//│ ║ l.47: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) +//│ ║ l.59: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╙── ^^^^ //│ Type: ⊤ :todo // BbML idIIBB([1, 2]) //│ ╔══[ERROR] Term shape not yet supported by BbML: Tup(List(Fld(‹›,Lit(IntLit(1)),None), Fld(‹›,Lit(IntLit(2)),None))) -//│ ║ l.57: idIIBB([1, 2]) +//│ ║ l.69: idIIBB([1, 2]) //│ ╙── ^^^^^^ //│ Type: ⊥ @@ -86,7 +98,7 @@ idIIBB(new Pair(1, true)) :todo fun foo: ["x": Int, "y": Int] //│ ╔══[ERROR] Invalid type -//│ ║ l.87: fun foo: ["x": Int, "y": Int] +//│ ║ l.99: fun foo: ["x": Int, "y": Int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index eae45c3181..039613030f 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -152,7 +152,7 @@ fun foofoo(x) = new Printer(foofoo) //│ Type: Printer['T] //│ Where: -//│ 'T <: Int +//│ 'T#'T ∨ Str<:Str ∧ ⊥<:⊥ ∧ 'T<:'x} let ip = new Printer(foofoo) in ip.Printer#f(42) //│ Type: Str @@ -166,6 +166,10 @@ let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: ¬(¬'T) //│ ╟── because: cannot constrain Str <: 'T +//│ ╟── because: cannot constrain 'T <: 'x +//│ ╟── because: cannot constrain 'T <: 'x +//│ ╟── because: cannot constrain 'T <: ¬¬Int +//│ ╟── because: cannot constrain 'T <: ¬(¬{Int}) //│ ╙── because: cannot constrain Str <: ¬(¬{Int}) //│ Type: Str @@ -178,8 +182,7 @@ fun inc(x) = x + 1 new TFun(inc) //│ Type: TFun['T] //│ Where: -//│ Int <: 'T -//│ 'T <: Int +//│ 'T#'T ∨ Int<:'T ∧ ⊥<:⊥ ∧ 'T<:'x} let tf = new TFun(inc) in tf.TFun#f(1) //│ Type: Int @@ -187,14 +190,18 @@ let tf = new TFun(inc) in tf.TFun#f(1) :e let tf = new TFun(inc) in tf.TFun#f("1") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.188: let tf = new TFun(inc) in tf.TFun#f("1") +//│ ║ l.191: let tf = new TFun(inc) in tf.TFun#f("1") //│ ║ ^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: ¬(¬'T) //│ ╟── because: cannot constrain Str <: 'T +//│ ╟── because: cannot constrain 'T <: 'x +//│ ╟── because: cannot constrain 'T <: 'x +//│ ╟── because: cannot constrain 'T <: ¬¬Int +//│ ╟── because: cannot constrain 'T <: ¬(¬{Int}) //│ ╙── because: cannot constrain Str <: ¬(¬{Int}) -//│ Type: Str ∨ Int +//│ Type: Int ∨ Str class Pair[A, B](fst: A, snd: B) //│ Type: ⊤ @@ -296,6 +303,8 @@ f f(x => x).Foo#x //│ Type: ('A) ->{⊥} 'A +//│ Where: +//│ 'A#'A ∨ 'x<:'A ∧ ⊥<:⊥ ∧ 'A<:'x} g => (new Foo(g)).Foo#x //│ Type: ('A -> 'A) ->{⊥} ('A) ->{⊥} 'A @@ -308,7 +317,7 @@ throw new Error("oops") :e throw 42 //│ ╔══[ERROR] Type error in throw -//│ ║ l.309: throw 42 +//│ ║ l.318: throw 42 //│ ║ ^^ //│ ╙── because: cannot constrain Int <: Error //│ Type: ⊥ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls index d2c0a80950..80c9449d79 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls @@ -87,6 +87,7 @@ bazbaz //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int +//│ 'A#Int ∨ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A} bazbaz(42)(x => x + 1) //│ Type: Int @@ -97,6 +98,7 @@ cc //│ Where: //│ 'A -> 'A <: 'B //│ 'B <: 'A -> 'A +//│ 'B#'B ∨ 'B<:'B ∧ ⊥<:⊥ ∧ 'B<:'B} //│ 'B -> 'B <: 'A //│ 'A <: 'B -> 'B @@ -112,17 +114,19 @@ fun h: [C] -> ([A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B :e bazbaz: [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> A //│ ╔══[ERROR] Cannot type non-function term Ref(member:bazbaz) as (A) ->{⊥} ([outer, 'B] -> 'B) ->{⊥} A -//│ ║ l.113: bazbaz: [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> A +//│ ║ l.115: bazbaz: [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> A //│ ╙── ^^^^^^ //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int +//│ 'A#Int ∨ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A} (x => f => bazbaz(x)(f)): [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> A //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int +//│ 'A#Int ∨ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A} h(x => f => bazbaz(x)(f))(42) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbCyclicExtrude.mls b/hkmc2/shared/src/test/mlscript/bbml/bbCyclicExtrude.mls index 0a3d78cda1..214bf137ca 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbCyclicExtrude.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbCyclicExtrude.mls @@ -18,16 +18,8 @@ let foo = f => (x => f(x(x)) : [A] -> A -> A) in foo f => (let g = x => x(x) in f(g(g))) : [A] -> A -> A //│ Type: (⊥ -> (⊤ -> ⊥)) ->{⊥} ['A] -> ('A) ->{⊥} 'A -:e f => (let g = x => f(x(x)) in g) : [A] -> A -> A -//│ ╔══[ERROR] Type error in block with expected type (A) ->{⊥} A -//│ ║ l.22: f => (let g = x => f(x(x)) in g) : [A] -> A -> A -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain 'x ->{'eff ∨ 'eff1} 'app <: A -> A -//│ ╟── because: cannot constrain A <: 'x -//│ ╟── because: cannot constrain A <: 'x -//│ ╙── because: cannot constrain A <: ¬(¬{'x ->{'eff1} 'app1}) -//│ Type: (⊥ -> ⊥) ->{⊥} ['A] -> ('A) ->{⊥} 'A +//│ Type: (⊥ ->{⊤} ⊤) ->{⊥} ['A] -> ('A) ->{⊥} 'A f => (x => f(x(x)) : [A] -> A -> A) //│ Type: ('app -> (⊤ -> ⊥)) ->{⊥} ('x -> 'app) ->{⊥} ['A] -> ('A) ->{⊥} 'A @@ -48,7 +40,7 @@ let foo(f) = (f(x => x(x)) : [A] -> A -> A) in foo :todo fun foo(f) = (f(x => x(x)) : [A] -> A -> A) //│ ╔══[ERROR] Expected a monomorphic type or an instantiable type here, but ('f) ->{⊥} [outer, 'A] -> ('A) ->{⊥} 'A found -//│ ║ l.49: fun foo(f) = (f(x => x(x)) : [A] -> A -> A) +//│ ║ l.42: fun foo(f) = (f(x => x(x)) : [A] -> A -> A) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls index 846ca5bebc..1408001fe9 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls @@ -35,12 +35,14 @@ f fun f(x) = f(x) f -//│ Type: ⊤ -> ⊥ +//│ Type: ['x] -> 'x -> ⊥ +//│ Where: +//│ 'x#'x ∨ 'app<:'app ∧ 'eff<:'eff ∧ 'x<:'x} :todo fun f(x) = f(x.a) //│ ╔══[ERROR] Term shape not yet supported by BbML: Sel(Ref(x),Ident(a)) -//│ ║ l.41: fun f(x) = f(x.a) +//│ ║ l.43: fun f(x) = f(x.a) //│ ╙── ^^^ //│ Type: ⊤ @@ -51,7 +53,7 @@ class Foo[A](a: A) :todo proper error Foo(123) //│ ╔══[ERROR] Variable not found: Foo -//│ ║ l.52: Foo(123) +//│ ║ l.54: Foo(123) //│ ╙── ^^^ //│ Type: ⊥ @@ -63,14 +65,14 @@ new Foo(123) :todo proper error fun f(x) = f(Foo.a(x)) //│ ╔══[ERROR] Term shape not yet supported by BbML: Sel(Ref(member:Foo),Ident(a)) -//│ ║ l.64: fun f(x) = f(Foo.a(x)) +//│ ║ l.66: fun f(x) = f(Foo.a(x)) //│ ╙── ^^^^^ //│ Type: ⊤ fun f(x) = f(x.Foo#a) f -//│ Type: ['x] -> Foo[out 'x] -> ⊥ +//│ Type: ['A] -> Foo[out 'A] -> ⊥ //│ Where: -//│ 'x <: Foo[out 'x] +//│ 'A#'A ∨ 'app<:'app ∧ 'eff<:'eff ∧ 'A<:'x} From ec5c55e16c8f88d495d58c0734e8d89d7fc3de38 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 6 Mar 2025 00:12:09 +0800 Subject: [PATCH 04/36] no disjoint upperbound --- .../src/main/scala/hkmc2/bbml/ConstraintSolver.scala | 3 --- hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala | 7 ++----- hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls | 11 ++++++----- hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls | 6 +++--- .../shared/src/test/mlscript/bbml/bbCyclicExtrude.mls | 2 +- 5 files changed, 12 insertions(+), 17 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index 2836716508..f8cbf707b5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -92,9 +92,6 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, cctx.nest(v -> nc) givenIn: v.state.upperBounds ::= nc v.state.lowerBounds.foreach(lb => constrainImpl(lb, nc)) - v.state.disjsub.foreach: d => - Type.disjoint(d.disjoint(v), bd.toBasic.simp.toBasic)(Set.empty)(using c = mutable.Map.empty) - .foreach(_.foreach(k => DisjSub(d.disjoint ++ k, d.dss, d.cs).commit())) else log(s"New bound: ${v.showDbg} :> ${bd.showDbg}") cctx.nest(bd -> v) givenIn: diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index b6ea6267a7..4546cb6c19 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -306,11 +306,8 @@ object Type: case (v: InfVar, _) => val p = prev + (v->b) val k = v.state.lowerBounds.map(lb => disjoint(lb.toBasic.simp.toBasic, b)(p)) - if k.exists(_.isEmpty) then N - else - val u = (k.flatten.flatten.toSet + Set.empty).map(_ + (v -> b)) - val w = v.state.upperBounds.flatMap(ub => disjoint(ub.toBasic.simp.toBasic, b)(p)) - S(w.fold(u)((x, y) => y.flatMap(y => x.map(_ ++ y)))) + if k.exists(_.isEmpty) then N + else S((k.flatten.flatten.toSet + Set.empty).map(_ + (v -> b))) case (_, v: InfVar) => disjoint(v, a)(prev) case _ => N }) else N diff --git a/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls b/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls index 26c7ccf807..474518781a 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls @@ -38,6 +38,7 @@ x=> //│ 'x <: Int ∨ Bool //│ 'x <: Int //│ 'x#Int ∨ Int<:'app ∧ ⊥<:'eff} +//│ 'x#Bool ∨ Bool<:'app ∧ ⊥<:'eff} fun ap1(f)=f(1) ap1(idIB) @@ -58,17 +59,17 @@ x=>idIB(x) :todo // BbML fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╔══[ERROR] General type is not allowed here. -//│ ║ l.59: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) +//│ ║ l.60: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╙── ^^^ //│ ╔══[ERROR] General type is not allowed here. -//│ ║ l.59: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) +//│ ║ l.60: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╙── ^^^^ //│ Type: ⊤ :todo // BbML idIIBB([1, 2]) //│ ╔══[ERROR] Term shape not yet supported by BbML: Tup(List(Fld(‹›,Lit(IntLit(1)),None), Fld(‹›,Lit(IntLit(2)),None))) -//│ ║ l.69: idIIBB([1, 2]) +//│ ║ l.70: idIIBB([1, 2]) //│ ╙── ^^^^^^ //│ Type: ⊥ @@ -98,8 +99,8 @@ idIIBB(new Pair(1, true)) :todo fun foo: ["x": Int, "y": Int] //│ ╔══[ERROR] Invalid type -//│ ║ l.99: fun foo: ["x": Int, "y": Int] -//│ ╙── ^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.100: fun foo: ["x": Int, "y": Int] +//│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ foo diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls index 5390dd8841..f78d51a03a 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls @@ -87,7 +87,7 @@ bazbaz //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#Int ∨ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A} +//│ 'A#'A ∨ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A} bazbaz(42)(x => x + 1) //│ Type: Int @@ -119,14 +119,14 @@ bazbaz as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#Int ∨ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A} +//│ 'A#'A ∨ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A} (x => f => bazbaz(x)(f)) as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> A //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#Int ∨ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A} +//│ 'A#'A ∨ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A} h(x => f => bazbaz(x)(f))(42) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbCyclicExtrude.mls b/hkmc2/shared/src/test/mlscript/bbml/bbCyclicExtrude.mls index dc0468dee1..677547e7bf 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbCyclicExtrude.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbCyclicExtrude.mls @@ -40,7 +40,7 @@ let foo(f) = (f(x => x(x)) as [A] -> A -> A) in foo :todo fun foo(f) = (f(x => x(x)) as [A] -> A -> A) //│ ╔══[ERROR] Expected a monomorphic type or an instantiable type here, but ('f) ->{⊥} [outer, 'A] -> ('A) ->{⊥} 'A found -//│ ║ l.42: fun foo(f) = (f(x => x(x)) as [A] -> A -> A) +//│ ║ l.41: fun foo(f) = (f(x => x(x)) as [A] -> A -> A) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ From aa956a7d9a0ab40f6cabca1c698c7f69ca20df5f Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 6 Mar 2025 00:39:20 +0800 Subject: [PATCH 05/36] multiple disjointness --- .../scala/hkmc2/bbml/ConstraintSolver.scala | 23 +++++++++++-------- .../main/scala/hkmc2/bbml/PrettyPrinter.scala | 3 ++- .../src/main/scala/hkmc2/bbml/types.scala | 7 +++--- .../shared/src/test/mlscript/bbml/DisjSub.mls | 2 +- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index f8cbf707b5..6847340931 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -98,14 +98,17 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, v.state.lowerBounds ::= bd v.state.upperBounds.foreach(ub => constrainImpl(bd, ub)) v.state.disjsub.foreach: d => - Type.disjoint(d.disjoint(v), bd.toBasic.simp.toBasic)(Set.empty)(using c = mutable.Map.empty) match - case N => - d.remove(v) - if d.disjoint.isEmpty then - d.dss.foreach(_.commit()) - d.cs.foreach((a, b) => constrainImpl(a, b)) - case S(k) => - k.foreach(k => DisjSub(d.disjoint ++ k, d.dss, d.cs).commit()) + val u = d.disjoint(v).flatMap: t => + Type.disjoint(t, bd.toBasic.simp.toBasic)(Set.empty)(using c = mutable.Map.empty) + if u.isEmpty then + d.remove(v) + if d.disjoint.isEmpty then + d.dss.foreach(_.commit()) + d.cs.foreach((a, b) => constrainImpl(a, b)) + else + d.clear() + u.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => + DisjSub(mutable.Map.from(k.groupMap(_._1)(_._2)), d.dss, d.cs).commit() case Conj(i, u, Nil) => (conj.i, conj.u) match case (_, Union(N, Nil)) => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} ∧ ¬⊥" -> N :: Nil)) @@ -133,7 +136,7 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, else val cs = (ret1, ret2) :: (eff1, eff2) :: args2.zip(args1) k.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - DisjSub(mutable.Map.from(k), Nil, cs).commit() + DisjSub(mutable.Map.from(k.groupMap(_._1)(_._2)), Nil, cs).commit() case (Inter(S(fs:Ls[FunType])), Union(S(FunType(args2, ret2, eff2)), Nil)) => val f = fs.filter(_.args.length === args2.length) val args = f.map(_.args).transpose @@ -152,7 +155,7 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, constrainImpl(b.eff, eff2) case S(k) => val cs = (b.ret,ret2) :: (b.eff,eff2) :: s - k.foreach(k => DisjSub(mutable.Map.from(k), Nil, cs).commit()) + k.foreach(k => DisjSub(mutable.Map.from(k.groupMap(_._1)(_._2)), Nil, cs).commit()) case _ => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} <: ${conj.u.toString()}" -> N :: Nil)) cctx.err diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala index c0e2c60f51..57b65ffb98 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala @@ -38,7 +38,8 @@ object PrettyPrinter: apply(false)(bd) (v, bd) res ++= state.disjsub.map: d => - val ds = d.disjoint.iterator + val ds = d.disjoint.iterator.flatMap: + case (v, u) => u.map(v -> _) val k = ds.next() (k, ds.toList, d.cs.toList) super.apply(pol)(ty) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 4546cb6c19..49d89ba635 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -422,8 +422,9 @@ class VarState: val disjsub: MutSet[DisjSub] = MutSet.empty override def toString = "<>" -case class DisjSub(disjoint: MutMap[InfVar,BasicType], dss:Ls[DisjSub], cs:Ls[Type->Type]): +case class DisjSub(disjoint: MutMap[InfVar, Set[BasicType]], dss:Ls[DisjSub], cs:Ls[Type->Type]): def commit() = disjoint.keys.foreach(_.state.disjsub += this) + def clear() = disjoint.keys.foreach(_.state.disjsub -= this) def remove(v:InfVar)= - v.state.disjsub-=this - disjoint-=v + v.state.disjsub -= this + disjoint -= v diff --git a/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls b/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls index 474518781a..614370c004 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls @@ -37,8 +37,8 @@ x=> //│ Where: //│ 'x <: Int ∨ Bool //│ 'x <: Int -//│ 'x#Int ∨ Int<:'app ∧ ⊥<:'eff} //│ 'x#Bool ∨ Bool<:'app ∧ ⊥<:'eff} +//│ 'x#Int ∨ Int<:'app ∧ ⊥<:'eff} fun ap1(f)=f(1) ap1(idIB) From 8bad1a5c352ce4b0f0688625b67895cde98008c2 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 6 Mar 2025 10:48:23 +0800 Subject: [PATCH 06/36] Changes from meeting --- .../src/main/scala/hkmc2/bbml/types.scala | 14 ++--- .../shared/src/test/mlscript/bbml/DisjSub.mls | 54 +++++++++++++++---- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 49d89ba635..aaad382eec 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -287,25 +287,25 @@ object Type: if !prev.contains(a -> b) then c.getOrElseUpdate(a -> b, { (a, b) match case (Bot, _) | (_, Bot) => S(Set.empty) - case (NegType(t),_) => t.toBasic.!.simp.toBasic match + case (NegType(t),_) => t.!.simp.toBasic match case NegType(_) => N case a => disjoint(a, b)(prev) - case (_, NegType(t)) => t.toBasic.!.simp.toBasic match + case (_, NegType(t)) => t.!.simp.toBasic match case NegType(_) => N case a => disjoint(a, b)(prev) case (ClassLikeType(a, _), ClassLikeType(b, _)) if a.uid =/= b.uid => S(Set.empty) case (ComposedType(p, q, true), _) => - val u = disjoint(p.toBasic.simp.toBasic, b)(prev) - val w = disjoint(q.toBasic.simp.toBasic, b)(prev) + val u = disjoint(p.simp.toBasic, b)(prev) + val w = disjoint(q.simp.toBasic, b)(prev) u.flatMap(u => w.map(u ++ _)) case (_, ComposedType(p, q, true)) => - val u = disjoint(a, p.toBasic.simp.toBasic)(prev) - val w = disjoint(a, q.toBasic.simp.toBasic)(prev) + val u = disjoint(a, p.simp.toBasic)(prev) + val w = disjoint(a, q.simp.toBasic)(prev) u.flatMap(u => w.map(u ++ _)) case (a: InfVar, b: InfVar) if a.uid =/= b.uid => N case (v: InfVar, _) => val p = prev + (v->b) - val k = v.state.lowerBounds.map(lb => disjoint(lb.toBasic.simp.toBasic, b)(p)) + val k = v.state.lowerBounds.map(lb => disjoint(lb.simp.toBasic, b)(p)) if k.exists(_.isEmpty) then N else S((k.flatten.flatten.toSet + Set.empty).map(_ + (v -> b))) case (_, v: InfVar) => disjoint(v, a)(prev) diff --git a/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls b/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls index 614370c004..4b08ca576d 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls @@ -4,9 +4,9 @@ //│ Type: ⊤ -fun andt(x)=x&&true -fun k(f:Nothing->Bool)=1 -fun ap(f)=x=>f(x) +fun andt(x) = x && true +fun k(f: Nothing -> Bool) = 1 +fun ap(f) = x => f(x) //│ Type: ⊤ k(andt) @@ -30,15 +30,28 @@ idIB(true) idIB(if true then 1 else true) //│ Type: Bool ∨ Int -x=> +x => let y = x+1 idIB(x) //│ Type: ('x) ->{⊥} ⊥ //│ Where: //│ 'x <: Int ∨ Bool //│ 'x <: Int -//│ 'x#Bool ∨ Bool<:'app ∧ ⊥<:'eff} //│ 'x#Int ∨ Int<:'app ∧ ⊥<:'eff} +//│ 'x#Bool ∨ Bool<:'app ∧ ⊥<:'eff} + +(x: Int) => + let y = x + 1 + idIB(x) +//│ Type: (Int) ->{⊥} Int + +(x: Bool) => + idIB(x) +//│ Type: (Bool) ->{⊥} Bool + +(x: Bool) => + idIB(idIB(x)) +//│ Type: (Bool) ->{⊥} Bool ∨ Int fun ap1(f)=f(1) ap1(idIB) @@ -48,32 +61,53 @@ ap(idIB)(1) //│ Type: Int :todo -x=>idIB(x) +x => idIB(x) //│ Type: ('x) ->{⊥} ⊥ //│ Where: //│ 'x <: Int ∨ Bool +//│ 'x#Bool ∨ Bool<:'app ∧ ⊥<:'eff} //│ 'x#Int ∨ Int<:'app ∧ ⊥<:'eff} + +fun forward(x) = idIB(x) +forward +//│ Type: ['x] -> 'x -> ⊥ +//│ Where: +//│ 'x <: Int ∨ Bool //│ 'x#Bool ∨ Bool<:'app ∧ ⊥<:'eff} +//│ 'x#Int ∨ Int<:'app ∧ ⊥<:'eff} + +forward(1) +//│ Type: ⊥ + +forward(true) +//│ Type: ⊥ :todo // BbML fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╔══[ERROR] General type is not allowed here. -//│ ║ l.60: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) +//│ ║ l.87: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╙── ^^^ //│ ╔══[ERROR] General type is not allowed here. -//│ ║ l.60: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) +//│ ║ l.87: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╙── ^^^^ //│ Type: ⊤ :todo // BbML idIIBB([1, 2]) //│ ╔══[ERROR] Term shape not yet supported by BbML: Tup(List(Fld(‹›,Lit(IntLit(1)),None), Fld(‹›,Lit(IntLit(2)),None))) -//│ ║ l.70: idIIBB([1, 2]) +//│ ║ l.97: idIIBB([1, 2]) //│ ╙── ^^^^^^ //│ Type: ⊥ +x => if x is + Int then 0 + Bool then 0 +//│ Type: (((¬Bool ∨ Int) ∨ Bool) ∧ (¬Int ∨ Int)) ->{⊥} Int + + + class Pair[out A, out B](fst: A, snd: B) //│ Type: ⊤ @@ -99,7 +133,7 @@ idIIBB(new Pair(1, true)) :todo fun foo: ["x": Int, "y": Int] //│ ╔══[ERROR] Invalid type -//│ ║ l.100: fun foo: ["x": Int, "y": Int] +//│ ║ l.134: fun foo: ["x": Int, "y": Int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ From 86d300ddab723d9f84bbc807aae86db8400306cf Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 6 Mar 2025 12:15:29 +0800 Subject: [PATCH 07/36] Add test case and move tests to logicsub folder --- .../mlscript/{bbml => logicsub}/DisjSub.mls | 0 .../test/mlscript/logicsub/MarlowWadler97.mls | 62 +++++++++++++++++++ .../src/test/scala/hkmc2/BbmlDiffMaker.scala | 2 +- 3 files changed, 63 insertions(+), 1 deletion(-) rename hkmc2/shared/src/test/mlscript/{bbml => logicsub}/DisjSub.mls (100%) create mode 100644 hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls diff --git a/hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls similarity index 100% rename from hkmc2/shared/src/test/mlscript/bbml/DisjSub.mls rename to hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls new file mode 100644 index 0000000000..ea79bb8e0b --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -0,0 +1,62 @@ +:bbml +//│ Type: ⊤ +:js + +//│ Type: ⊤ + + +// * Sec. 9 of A Practical Subtyping System For Erlang +// * (https://homepages.inf.ed.ac.uk/wadler/papers/erlang/erlang.pdf) + + +class + Tru() + Fls() +//│ Type: ⊤ + +let + tru = new Tru() + fls = new Fls() +//│ fls = Fls() +//│ tru = Tru() +//│ Type: ⊤ + +:ucs normalized +fun test(x, y) = if + x is Tru and y is Tru then tru + x is Fls then fls + y is Fls then fls +//│ Normalized: +//│ > if +//│ > x is Tru and +//│ > y is Tru then tru#666 +//│ > y is Fls then fls#666 +//│ > x is Fls then fls#666 +//│ > y is Fls then fls#666 +//│ Type: ⊤ + +test(tru, tru) +//│ = Tru() +//│ Type: Tru ∨ Fls + +test(tru, fls) +//│ = Fls() +//│ Type: Tru ∨ Fls + +test(fls, tru) +//│ = Fls() +//│ Type: Tru ∨ Fls + +test(fls, fls) +//│ = Fls() +//│ Type: Tru ∨ Fls + + +:fixme +:e +test(true, false) +//│ ═══[RUNTIME ERROR] Error: match error +//│ Type: Tru ∨ Fls +//│ FAILURE: Unexpected lack of type error + + diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/BbmlDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/BbmlDiffMaker.scala index 71b8248465..29f7ba63f9 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/BbmlDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/BbmlDiffMaker.scala @@ -9,7 +9,7 @@ import utils.Scope abstract class BbmlDiffMaker extends JSBackendDiffMaker: - val bbPreludeFile = file / os.up / os.RelPath("bbPrelude.mls") + val bbPreludeFile = file / os.up / os.up / "bbml" / os.RelPath("bbPrelude.mls") val bbmlOpt = new NullaryCommand("bbml"): override def onSet(): Unit = From 3b34199395b9934c7556a83f37199d37ef9d0626 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sat, 8 Mar 2025 04:30:02 +0800 Subject: [PATCH 08/36] constraints solving nested disjsub --- .../scala/hkmc2/bbml/ConstraintSolver.scala | 79 ++++++++----------- .../main/scala/hkmc2/bbml/PrettyPrinter.scala | 23 +++--- .../src/main/scala/hkmc2/bbml/types.scala | 73 ++++++++++++----- .../src/test/mlscript/bbml/bbBasics.mls | 47 ++++++++--- .../src/test/mlscript/bbml/bbBounds.mls | 8 +- .../src/test/mlscript/bbml/bbDisjoint.mls | 45 ----------- .../src/test/mlscript/bbml/bbExtrude.mls | 8 +- .../shared/src/test/mlscript/bbml/bbFuns.mls | 10 ++- .../shared/src/test/mlscript/bbml/bbGPCE.mls | 21 ++--- .../test/mlscript/bbml/bbLetRegEncoding.mls | 25 ++---- .../shared/src/test/mlscript/bbml/bbList.mls | 52 ------------ .../shared/src/test/mlscript/bbml/bbPoly.mls | 2 +- hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls | 24 +++--- hkmc2/shared/src/test/mlscript/bbml/bbRec.mls | 4 +- .../src/test/mlscript/logicsub/DisjSub.mls | 22 ++---- .../test/mlscript/logicsub/MarlowWadler97.mls | 2 - 16 files changed, 189 insertions(+), 256 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index 6847340931..0d5bf4c496 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -97,18 +97,8 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, cctx.nest(bd -> v) givenIn: v.state.lowerBounds ::= bd v.state.upperBounds.foreach(ub => constrainImpl(bd, ub)) - v.state.disjsub.foreach: d => - val u = d.disjoint(v).flatMap: t => - Type.disjoint(t, bd.toBasic.simp.toBasic)(Set.empty)(using c = mutable.Map.empty) - if u.isEmpty then - d.remove(v) - if d.disjoint.isEmpty then - d.dss.foreach(_.commit()) - d.cs.foreach((a, b) => constrainImpl(a, b)) - else - d.clear() - u.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - DisjSub(mutable.Map.from(k.groupMap(_._1)(_._2)), d.dss, d.cs).commit() + v.state.disjsub.toList.iterator.flatMap(_.check(v)).foreach: + case (a, b) => constrainImpl(a, b) case Conj(i, u, Nil) => (conj.i, conj.u) match case (_, Union(N, Nil)) => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} ∧ ¬⊥" -> N :: Nil)) @@ -119,43 +109,36 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, constrainArgs(ta1, ta2) else constrainConj(Conj(conj.i, Union(f, rest), Nil)) case (int: Inter, Union(f, _ :: rest)) => constrainConj(Conj(int, Union(f, rest), Nil)) - case (Inter(S(FunType(args1, ret1, eff1)::Nil)), Union(S(FunType(args2, ret2, eff2)), Nil)) => - if args1.length =/= args2.length then - // raise(ErrorReport(msg"Cannot constrain ${conj.i.toString()} <: ${conj.u.toString()}" -> N :: Nil)) - cctx.err - else - val k = args2.flatMap: x => - val u = x.toBasic.simp.toBasic - Type.disjoint(u, u)(Set.empty)(using c = mutable.Map.empty) - if k.isEmpty then - args1.zip(args2).foreach { - case (a1, a2) => constrainImpl(a2, a1) - } - constrainImpl(ret1, ret2) - constrainImpl(eff1, eff2) - else - val cs = (ret1, ret2) :: (eff1, eff2) :: args2.zip(args1) - k.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - DisjSub(mutable.Map.from(k.groupMap(_._1)(_._2)), Nil, cs).commit() case (Inter(S(fs:Ls[FunType])), Union(S(FunType(args2, ret2, eff2)), Nil)) => - val f = fs.filter(_.args.length === args2.length) - val args = f.map(_.args).transpose - val k = args2.flatMap: x => - val u = x.toBasic.simp.toBasic - Type.disjoint(u, u)(Set.empty)(using c = mutable.Map.empty) - if !k.contains(Nil) then - // assume distinguished by the first arg - constrainImpl(args2.head,args.head.foldLeft(Bot:Type)(_|_)) - args.head.iterator.zip(f).foreach: (a, b) => - val s = args2.zip(b.args).tail - Type.disjoint(args2.head.toBasic.simp.toBasic,a.toBasic.simp.toBasic)(Set.empty)(using c = mutable.Map.empty) match - case N => - s.foreach((x, y) => constrainImpl(x, y)) - constrainImpl(b.ret, ret2) - constrainImpl(b.eff, eff2) - case S(k) => - val cs = (b.ret,ret2) :: (b.eff,eff2) :: s - k.foreach(k => DisjSub(mutable.Map.from(k.groupMap(_._1)(_._2)), Nil, cs).commit()) + val k = args2.flatMap(x => Type.disjoint(x, x)) + if k.forall(_.nonEmpty) then + val f = fs.filter(_.args.length === args2.length) + if args2.isEmpty then + if f.isEmpty then + cctx.err + else f.foreach: f => + constrainImpl(f.ret, ret2) + constrainImpl(f.eff, eff2) + else + val args = f.map(x => Type.discriminant(x.args)) + val c = (args2.head, args.foldLeft(Bot: Type) { case (t, (q, _)) => t | q }) + val (cs, dss) = (args.iterator.zip(f).map: + case ((q, r), f) => + val cs = c :: (f.ret, ret2) :: (f.eff, eff2) :: args2.tail.zip(r) + Type.disjoint(q, args2.head) match + case N => (cs, Nil) + case S(k) => + if k.nonEmpty then (Nil, k.map(k => DisjSub(mutable.Set.from(k), Nil, cs))) + else (Nil, Nil)).toList.unzip + if k.isEmpty then + if f.isEmpty then + cctx.err + else + cs.flatten.foreach(u => constrainImpl(u._1, u._2)) + dss.flatten.foreach(_.commit()) + else + k.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => + DisjSub(mutable.Set.from(k), dss.flatten, cs.flatten).commit() case _ => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} <: ${conj.u.toString()}" -> N :: Nil)) cctx.err diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala index 57b65ffb98..24d3338d2b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala @@ -4,6 +4,12 @@ import scala.collection.mutable.{Set => MutSet, ListBuffer} import utils.Scope class PrettyPrinter(output: String => Unit)(using Scope): + def showDisjSub(ds: DisjSub): String = ds match + case DisjSub(d, dss, cs) => + val g = d.iterator.map { case (x, y) => s"${x.show}#${y.show} ∨ " }.mkString + val h = dss.iterator.map("(" + showDisjSub(_) + ")").mkString(" ∧ ") + val b = cs.map { case (x, y) => s" ∧ ${x.simp.show}<:${y.simp.show}"}.mkString + s" $g$h$b" def print(ty: GeneralType): Unit = output(s"Type: ${ty.show}") val bounds = PrettyPrinter.collectBounds(ty).distinct @@ -11,21 +17,16 @@ class PrettyPrinter(output: String => Unit)(using Scope): output("Where:") bounds.foreach { case (lhs, rhs) => output(s" ${lhs.show} <: ${rhs.show}") - case ((x, y), z, w) => - val g = s"${x.show}#${y.show} ∨ " - val h = z.iterator.map { case (x, y) => s"${x.show}#${y.show} ∨ "}.mkString - val b = w.iterator.map { case (x, y) => s"${x.show}<:${y.show}"}.mkString(" ∧ ") - output(s" $g$h$b}") + case ds: DisjSub => output(showDisjSub(ds)) } object PrettyPrinter: def apply(output: String => Unit)(using Scope): PrettyPrinter = new PrettyPrinter(output) type Bound = (Type, Type) // * Type <: Type - type DisjBound=(Bound,List[Bound],List[Bound]) - private def collectBounds(ty: GeneralType): List[Bound|DisjBound] = - val res = ListBuffer[Bound|DisjBound]() + private def collectBounds(ty: GeneralType): List[Bound | DisjSub] = + val res = ListBuffer[Bound | DisjSub]() val cache = MutSet[Uid[InfVar]]() object CollectBounds extends TypeTraverser: override def apply(pol: Boolean)(ty: GeneralType): Unit = ty match @@ -37,11 +38,7 @@ object PrettyPrinter: res ++= state.upperBounds.map: bd => apply(false)(bd) (v, bd) - res ++= state.disjsub.map: d => - val ds = d.disjoint.iterator.flatMap: - case (v, u) => u.map(v -> _) - val k = ds.next() - (k, ds.toList, d.cs.toList) + res ++= state.disjsub super.apply(pol)(ty) case _ => super.apply(pol)(ty) CollectBounds(true)(ty) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index aaad382eec..6ccc9ff918 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -281,7 +281,8 @@ object Type: then lhs | rhs else lhs & rhs def mkNegType(ty: Type): Type = ty.! - def disjoint(a: BasicType, b: BasicType)(prev: Set[BasicType -> BasicType]) + def discriminant(a: Ls[Type]): (BasicType, Ls[Type]) = (a.head.toBasic.simp.toBasic, a.tail) + def disjointImpl(a: BasicType, b: BasicType)(prev: Set[BasicType -> BasicType]) (using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]) : Opt[Set[Set[InfVar->BasicType]]] = if !prev.contains(a -> b) then c.getOrElseUpdate(a -> b, { @@ -289,28 +290,34 @@ object Type: case (Bot, _) | (_, Bot) => S(Set.empty) case (NegType(t),_) => t.!.simp.toBasic match case NegType(_) => N - case a => disjoint(a, b)(prev) + case a => disjointImpl(a, b)(prev) case (_, NegType(t)) => t.!.simp.toBasic match case NegType(_) => N - case a => disjoint(a, b)(prev) + case a => disjointImpl(a, b)(prev) case (ClassLikeType(a, _), ClassLikeType(b, _)) if a.uid =/= b.uid => S(Set.empty) case (ComposedType(p, q, true), _) => - val u = disjoint(p.simp.toBasic, b)(prev) - val w = disjoint(q.simp.toBasic, b)(prev) + val u = disjointImpl(p.simp.toBasic, b)(prev) + val w = disjointImpl(q.simp.toBasic, b)(prev) u.flatMap(u => w.map(u ++ _)) case (_, ComposedType(p, q, true)) => - val u = disjoint(a, p.simp.toBasic)(prev) - val w = disjoint(a, q.simp.toBasic)(prev) + val u = disjointImpl(a, p.simp.toBasic)(prev) + val w = disjointImpl(a, q.simp.toBasic)(prev) u.flatMap(u => w.map(u ++ _)) case (a: InfVar, b: InfVar) if a.uid =/= b.uid => N case (v: InfVar, _) => - val p = prev + (v->b) - val k = v.state.lowerBounds.map(lb => disjoint(lb.simp.toBasic, b)(p)) - if k.exists(_.isEmpty) then N - else S((k.flatten.flatten.toSet + Set.empty).map(_ + (v -> b))) - case (_, v: InfVar) => disjoint(v, a)(prev) + val p = prev + (v -> b) + val k = v.state.lowerBounds.map(lb => disjointImpl(lb.toBasic.simp.toBasic, b)(p)) + if k.exists(_.isEmpty) then N + else S((k.flatten.flatten.toSet + Set.empty).map(_ + (v -> b))) + case (_, v: InfVar) => + val p = prev + (a -> v) + val k = v.state.lowerBounds.map(lb => disjointImpl(a, lb.toBasic.simp.toBasic)(p)) + if k.exists(_.isEmpty) then N + else S((k.flatten.flatten.toSet + Set.empty).map(_ + (v -> a))) case _ => N - }) else N + }) else S(Set.empty) + def disjoint(a: Type, b: Type): Opt[Set[Set[InfVar->BasicType]]] = + disjointImpl(a.simp.toBasic, b.simp.toBasic)(Set.empty)(using c = MutMap.empty) // * Poly types can not be used as type arguments @@ -422,9 +429,39 @@ class VarState: val disjsub: MutSet[DisjSub] = MutSet.empty override def toString = "<>" -case class DisjSub(disjoint: MutMap[InfVar, Set[BasicType]], dss:Ls[DisjSub], cs:Ls[Type->Type]): +case class DisjSub(disjoint: MutSet[InfVar -> BasicType], dss: Ls[DisjSub], cs: Ls[Type -> Type]): def commit() = disjoint.keys.foreach(_.state.disjsub += this) - def clear() = disjoint.keys.foreach(_.state.disjsub -= this) - def remove(v:InfVar)= - v.state.disjsub -= this - disjoint -= v + def checkAndCommit()(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]): Ls[Type -> Type] = + val cc: MutSet[InfVar -> BasicType] = MutSet.empty + val d = disjoint.flatMap: u => + Type.disjointImpl(u._2, u._1)(Set.empty) match + case N => + disjoint -= u + cc += u + N + case S(k) => if k.nonEmpty then S(k) else N + if disjoint.isEmpty then + dss.flatMap(_.checkAndCommit()) ++ cs + else + if d.nonEmpty then + commit() + d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => + DisjSub(MutSet.from(k), dss, cs).commit() + Nil + def checkImpl(v: InfVar)(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]) = + val (u, w) = disjoint.toList.partition(_._1.uid === v.uid) + val d = u.flatMap: u => + Type.disjointImpl(u._2, u._1)(Set.empty) match + case N => + disjoint -= u + N + case S(k) => if k.nonEmpty then S(k) else N + if disjoint.isEmpty then + dss.flatMap(_.checkAndCommit()) ++ cs + else + if disjoint.forall(_._1.uid =/= v.uid) then v.state.disjsub -= this + else if d.nonEmpty then + d.foldLeft(Set(w))((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => + DisjSub(MutSet.from(k), dss, cs).commit() + Nil + def check(v: InfVar) = checkImpl(v)(using c = MutMap.empty) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index d300772f20..f4274ff992 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -152,7 +152,7 @@ fun foofoo(x) = new Printer(foofoo) //│ Type: Printer['T] //│ Where: -//│ 'T#'T ∨ Str<:Str ∧ ⊥<:⊥ ∧ 'T<:'x} +//│ 'T#'T ∨ ∧ 'T<:'x ∧ Str<:Str ∧ ⊥<:⊥ let ip = new Printer(foofoo) in ip.Printer#f(42) //│ Type: Str @@ -182,15 +182,19 @@ fun inc(x) = x + 1 new TFun(inc) //│ Type: TFun['T] //│ Where: -//│ 'T#'T ∨ Int<:'T ∧ ⊥<:⊥ ∧ 'T<:'x} +//│ 'T#'T ∨ ∧ 'T<:'x ∧ Int<:'T ∧ ⊥<:⊥ let tf = new TFun(inc) in tf.TFun#f(1) -//│ Type: Int +//│ Type: 'T +//│ Where: +//│ Int <: 'T +//│ 'T <: Int +//│ ∧ 'T<:'x ∧ Int<:'T ∧ ⊥<:⊥ :e let tf = new TFun(inc) in tf.TFun#f("1") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.191: let tf = new TFun(inc) in tf.TFun#f("1") +//│ ║ l.195: let tf = new TFun(inc) in tf.TFun#f("1") //│ ║ ^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -201,7 +205,26 @@ let tf = new TFun(inc) in tf.TFun#f("1") //│ ╟── because: cannot constrain 'T <: ¬¬Int //│ ╟── because: cannot constrain 'T <: ¬(¬{Int}) //│ ╙── because: cannot constrain Str <: ¬(¬{Int}) -//│ Type: Int ∨ Str +//│ ╔══[ERROR] Type error in string literal with expected type 'T +//│ ║ l.195: let tf = new TFun(inc) in tf.TFun#f("1") +//│ ║ ^^^ +//│ ╟── because: cannot constrain Str <: 'T +//│ ╟── because: cannot constrain Str <: 'T +//│ ╟── because: cannot constrain Str <: ¬(¬'T) +//│ ╟── because: cannot constrain Str <: 'T +//│ ╟── because: cannot constrain Int <: 'T +//│ ╟── because: cannot constrain Int <: 'T +//│ ╟── because: cannot constrain 'T <: 'x +//│ ╟── because: cannot constrain 'T <: 'x +//│ ╟── because: cannot constrain 'T <: ¬¬Int +//│ ╟── because: cannot constrain 'T <: ¬(¬{Int}) +//│ ╙── because: cannot constrain Str <: ¬(¬{Int}) +//│ Type: 'T +//│ Where: +//│ Int <: 'T +//│ Str <: 'T +//│ 'T <: Int +//│ ∧ 'T<:'x ∧ Int<:'T ∧ ⊥<:⊥ class Pair[A, B](fst: A, snd: B) //│ Type: ⊤ @@ -261,7 +284,10 @@ fun fact(n) = //│ Type: ⊤ fact -//│ Type: Int -> Int +//│ Type: ['n] -> 'n -> Int +//│ Where: +//│ 'n <: Int +//│ 'n#Int ∨ ∧ Int<:'n ∧ Int<:'app ∧ 'eff<:'eff fact(1) //│ Type: Int @@ -285,7 +311,10 @@ fun fact2 = case //│ Type: ⊤ fact2 -//│ Type: Int -> Int +//│ Type: ['caseScrut] -> 'caseScrut -> Int +//│ Where: +//│ 'caseScrut <: Int +//│ 'caseScrut#Int ∨ ∧ Int<:'caseScrut ∧ Int<:'app ∧ 'eff<:'eff fact2(0) //│ Type: Int @@ -304,7 +333,7 @@ f f(x => x).Foo#x //│ Type: ('A) ->{⊥} 'A //│ Where: -//│ 'A#'A ∨ 'x<:'A ∧ ⊥<:⊥ ∧ 'A<:'x} +//│ 'A#'A ∨ ∧ 'A<:'x ∧ 'x<:'A ∧ ⊥<:⊥ g => (new Foo(g)).Foo#x //│ Type: ('A -> 'A) ->{⊥} ('A) ->{⊥} 'A @@ -317,7 +346,7 @@ throw new Error("oops") :e throw 42 //│ ╔══[ERROR] Type error in throw -//│ ║ l.318: throw 42 +//│ ║ l.347: throw 42 //│ ║ ^^ //│ ╙── because: cannot constrain Int <: Error //│ Type: ⊥ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls index f78d51a03a..ee670a89d1 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls @@ -87,7 +87,7 @@ bazbaz //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A} +//│ 'A#'A ∨ ( 'A#'A ∨ ∧ 'A<:'A ∧ 'A<:'A ∧ ⊥<:⊥) bazbaz(42)(x => x + 1) //│ Type: Int @@ -98,7 +98,7 @@ cc //│ Where: //│ 'A -> 'A <: 'B //│ 'B <: 'A -> 'A -//│ 'B#'B ∨ 'B<:'B ∧ ⊥<:⊥ ∧ 'B<:'B} +//│ 'B#'B ∨ ( 'B#'B ∨ ∧ 'B<:'B ∧ 'B<:'B ∧ ⊥<:⊥) //│ 'B -> 'B <: 'A //│ 'A <: 'B -> 'B @@ -119,14 +119,14 @@ bazbaz as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A} +//│ 'A#'A ∨ ( 'A#'A ∨ ∧ 'A<:'A ∧ 'A<:'A ∧ ⊥<:⊥) (x => f => bazbaz(x)(f)) as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> A //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A} +//│ 'A#'A ∨ ( 'A#'A ∨ ∧ 'A<:'A ∧ 'A<:'A ∧ ⊥<:⊥) h(x => f => bazbaz(x)(f))(42) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls b/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls index 70a31e29e7..ccf9fb66d5 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls @@ -207,55 +207,10 @@ region x in // Cannot type check since foo: 'foo <: Region[T] ->{'eff} 'app // Annotation is required for recursive calls -:e fun foo(r1) = region r2 in fork((_ => r1.ref 1), (_ => r2.ref 2)) foo(r2) -//│ ╔══[ERROR] Type error in function literal -//│ ║ l.211: fun foo(r1) = -//│ ║ ^^^^^ -//│ ║ l.212: region r2 in -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.213: fork((_ => r1.ref 1), (_ => r2.ref 2)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.214: foo(r2) -//│ ║ ^^^^^^^^^^^ -//│ ╟── because: cannot constrain 'r1 ->{'eff} 'app <: 'foo -//│ ╟── because: cannot constrain ('r1) ->{'eff} ('app) <: 'foo -//│ ╟── because: cannot constrain ('r1) ->{'eff} ('app) <: Region[in 'r2 out 'r21] ->{'eff1} 'app1 -//│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: 'r1 -//│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: 'r1 -//│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: Region[in 'reg out 'reg1] -//│ ╟── because: cannot constrain 'r21 <: 'reg1 -//│ ╟── because: cannot constrain 'r21 <: ¬(¬'reg1) -//│ ╟── because: cannot constrain ¬outer <: ¬(¬'reg1) -//│ ╟── because: cannot constrain ¬outer <: 'reg1 -//│ ╟── because: cannot constrain ¬outer <: ¬'r22 ∨ outer -//│ ╟── because: cannot constrain 'r22 <: ¬(¬outer) -//│ ╙── because: cannot constrain ¬outer <: ¬(¬outer) -//│ ╔══[ERROR] Type error in function literal -//│ ║ l.211: fun foo(r1) = -//│ ║ ^^^^^ -//│ ║ l.212: region r2 in -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.213: fork((_ => r1.ref 1), (_ => r2.ref 2)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.214: foo(r2) -//│ ║ ^^^^^^^^^^^ -//│ ╟── because: cannot constrain 'r1 ->{'eff} 'app <: 'foo -//│ ╟── because: cannot constrain ('r1) ->{'eff} ('app) <: 'foo -//│ ╟── because: cannot constrain ('r1) ->{'eff} ('app) <: Region[in 'r2 out 'r21] ->{'eff1} 'app1 -//│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: 'r1 -//│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: 'r1 -//│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: Region[in 'reg out 'reg1] -//│ ╟── because: cannot constrain 'r21 <: 'reg1 -//│ ╟── because: cannot constrain 'r21 <: ¬(¬'reg1) -//│ ╟── because: cannot constrain ¬outer <: ¬(¬'reg1) -//│ ╟── because: cannot constrain ¬outer <: 'reg1 -//│ ╟── because: cannot constrain ¬outer <: 'reg -//│ ╟── because: cannot constrain ¬outer <: 'reg -//│ ╙── because: cannot constrain ¬outer <: ¬() //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls index 6922b4f734..3f823f8549 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls @@ -20,7 +20,9 @@ foo //│ Type: (⊤) ->{⊥} Int f(foo) -//│ Type: ⊤ -> Int +//│ Type: 'A -> Int +//│ Where: +//│ 'A#⊤ ∨ ∧ ⊤<:'A ∧ Int<:Int ∧ ⊥<:⊥ fun g: ([A] -> A -> Int) -> ([A] -> A -> Int) fun g(y) = @@ -36,7 +38,7 @@ g(foo) :e y `=> (let t = run(x `=> x `+ y) in y) //│ ╔══[ERROR] Type error in quoted term with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.37: y `=> (let t = run(x `=> x `+ y) in y) +//│ ║ l.39: y `=> (let t = run(x `=> x `+ y) in y) //│ ║ ^^^^^^^^^^^^ //│ ╟── because: cannot constrain CodeBase[out 'x -> 'cde, out 'ctx, ?] <: CodeBase[out 'T, ⊥, ?] //│ ╟── because: cannot constrain 'ctx <: ⊥ @@ -45,8 +47,6 @@ y `=> (let t = run(x `=> x `+ y) in y) //│ ╟── because: cannot constrain y <: 'x1 //│ ╙── because: cannot constrain y <: ¬() //│ Type: CodeBase[out 'y -> 'y, ⊥, ?] -//│ Where: -//│ 'y <: Int class C[A](m: A, n: A -> Int) //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbFuns.mls b/hkmc2/shared/src/test/mlscript/bbml/bbFuns.mls index 5eac720091..9d42b7f3cd 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbFuns.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbFuns.mls @@ -9,10 +9,16 @@ f f((x => x), 42) -//│ Type: Int +//│ Type: 'y +//│ Where: +//│ Int <: 'y +//│ ∧ 'y<:'x ∧ 'x<:'app ∧ ⊥<:'eff f(x => x, 42) -//│ Type: Int +//│ Type: 'y +//│ Where: +//│ Int <: 'y +//│ ∧ 'y<:'x ∧ 'x<:'app ∧ ⊥<:'eff fun id: [A] -> A -> A diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls index caca71ece7..976dadec6b 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls @@ -17,7 +17,7 @@ fun id(x) = x run(x `=> id(x) `* x) -//│ Type: Int -> Int +//│ Type: ⊤ -> ⊥ fun assertNotZero: [C] -> CodeBase[out Num, out C, out Any] -> CodeBase[out Num, out C, out Any] @@ -25,7 +25,7 @@ fun assertNotZero(x) = `if (x `== `0.0) then `error else x let checkedDiv = x `=> y `=> x `/. (assertNotZero(y)) run(checkedDiv) -//│ Type: Num -> (Num -> Num) +//│ Type: ⊤ -> (Num -> ⊥) @@ -38,10 +38,13 @@ show fun inc(dbg) = x `=> let c = x `+ `1 in let t = dbg(c) in c inc -//│ Type: ['eff] -> (CodeBase[out Int, ?, ?] ->{'eff} ⊤) ->{'eff} CodeBase[out Int -> Int, ⊥, ?] +//│ Type: ['x, 'eff, 'x1] -> (CodeBase[⊥, ?, ?] ->{'eff} ⊤) ->{'eff} CodeBase[out 'x -> ⊥, ⊥, ?] +//│ Where: +//│ 'x <: 'x1 +//│ 'cde#Int ∨ 'x1#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int inc(c => log(show(c))) -//│ Type: CodeBase[out Int -> Int, ⊥, ?] +//│ Type: CodeBase[out ⊤ -> ⊥, ⊥, ?] fun body: [T, C] -> (CodeBase[out Int, out T, out Any], CodeBase[out Int, out C, out Any]) -> Int -> CodeBase[out Int, out T | C, out Any] @@ -58,21 +61,11 @@ fun bind(rhs, k) = `let x = rhs `in k(x) bind //│ Type: ['cde, 'ctx, 'cde1, 'eff, 'cde2, 'ctx1] -> (CodeBase[out 'cde, out 'ctx, ?], CodeBase[in 'cde1 out 'cde1 ∨ 'cde, ?, ⊥] ->{'eff} CodeBase[out 'cde2, out 'ctx1, ?]) ->{'eff} CodeBase[out 'cde2, out 'ctx ∨ 'ctx1, ?] -:e fun body: [G] -> (CodeBase[out Int, out G, out Any], CodeBase[out Int, out G, out Any]) -> Int -> CodeBase[out Int, out G, out Any] fun body(x, y) = case 0 then x 1 then y n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] -//│ ╔══[ERROR] Type error in application with expected type CodeBase[out Int, out G, ?] -//│ ║ l.66: n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain CodeBase[out 'cde, out 'ctx ∨ 'ctx1, ?] <: CodeBase[out Int, out G, ?] -//│ ╟── because: cannot constrain 'ctx ∨ 'ctx1 <: G -//│ ╟── because: cannot constrain 'ctx1 <: ¬(¬G) -//│ ╟── because: cannot constrain 'ctx2 <: ¬(¬G) -//│ ╟── because: cannot constrain 'ctx2 <: ¬(¬G) -//│ ╙── because: cannot constrain <: ¬(¬G) //│ Type: ⊤ fun bind: [G] -> (CodeBase[out Int, out G, out Any], [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out Int, out C | G, out Any]) -> CodeBase[out Int, out G, out Any] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbLetRegEncoding.mls b/hkmc2/shared/src/test/mlscript/bbml/bbLetRegEncoding.mls index fd6a13fb37..ad22e2947f 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbLetRegEncoding.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbLetRegEncoding.mls @@ -70,21 +70,8 @@ let f = letreg(r => arg => r.ref arg) f //│ Type: 'arg ->{⊤} Ref['arg, ?] -:e letreg(r => arg => r.ref arg)(0) -//│ ╔══[ERROR] Type error in block -//│ ║ l.74: letreg(r => arg => r.ref arg)(0) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain 'eff ∨ 'E <: ⊥ -//│ ╟── because: cannot constrain 'eff <: ¬() -//│ ╟── because: cannot constrain 'reg <: ¬() -//│ ╟── because: cannot constrain 'reg <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ 'R <: ¬() -//│ ╟── because: cannot constrain 'R <: ¬() -//│ ╙── because: cannot constrain <: ¬() -//│ Type: Ref['arg, ?] -//│ Where: -//│ Int <: 'arg +//│ Type: ⊥ @@ -96,7 +83,7 @@ fun letreg: [E,Res] -> ([R] -> Region[R] -> Res) ->{E} Res :e letreg(r => r.ref 1) //│ ╔══[ERROR] Type error in function literal with expected type (Region[R]) ->{⊥} 'Res -//│ ║ l.97: letreg(r => r.ref 1) +//│ ║ l.84: letreg(r => r.ref 1) //│ ║ ^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'reg <: ⊥ //│ ╟── because: cannot constrain 'reg <: ¬() @@ -106,16 +93,16 @@ letreg(r => r.ref 1) :e letreg(r => !(r.ref 1)) //│ ╔══[ERROR] Type error in function literal with expected type (Region[R]) ->{⊥} 'Res -//│ ║ l.107: letreg(r => !(r.ref 1)) -//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.94: letreg(r => !(r.ref 1)) +//│ ║ ^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'reg ∨ 'reg1 <: ⊥ //│ ╟── because: cannot constrain 'reg <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() //│ ╙── because: cannot constrain R <: ¬() //│ ╔══[ERROR] Type error in function literal with expected type (Region[R]) ->{⊥} 'Res -//│ ║ l.107: letreg(r => !(r.ref 1)) -//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.94: letreg(r => !(r.ref 1)) +//│ ║ ^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'reg ∨ 'reg1 <: ⊥ //│ ╟── because: cannot constrain 'reg1 <: ¬() //│ ╙── because: cannot constrain R <: ¬() diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbList.mls b/hkmc2/shared/src/test/mlscript/bbml/bbList.mls index 3b32072f6e..59f5b05435 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbList.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbList.mls @@ -43,7 +43,6 @@ region r in // * Should be an error. This definition would not be referentially transparent. // * The error message needs improvement, though. -:e fun mapi: [A, E] -> List[out A] -> ((Int, A) ->{E} A) ->{E} List[out A] fun mapi = s => region r in @@ -51,57 +50,6 @@ fun mapi = s => f => map(s) of x => i := !i + 1 f(!i, x) -//│ ╔══[ERROR] Type error in region expression with expected type ((Int, A) ->{E} A) ->{E} List[out A] -//│ ║ l.50: let i = r.ref 0 -//│ ║ ^^^^^^^ -//│ ║ l.51: f => map(s) of x => -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.52: i := !i + 1 -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.53: f(!i, x) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain 'f ->{'E1} List[out 'B] <: ((Int, A) ->{E} A) ->{E} List[out A] -//│ ╟── because: cannot constrain 'E1 <: E -//│ ╟── because: cannot constrain 'E1 <: ¬(¬E) -//│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) -//│ ╟── because: cannot constrain 'reg <: ¬(¬E) -//│ ╟── because: cannot constrain (¬⊥ ∧ 'r) ∧ ¬outer <: ¬(¬E) -//│ ╟── because: cannot constrain 'r <: ¬(¬E ∧ ¬outer) -//│ ╙── because: cannot constrain ¬outer <: ¬(¬E ∧ ¬outer) -//│ ╔══[ERROR] Type error in region expression with expected type ((Int, A) ->{E} A) ->{E} List[out A] -//│ ║ l.50: let i = r.ref 0 -//│ ║ ^^^^^^^ -//│ ║ l.51: f => map(s) of x => -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.52: i := !i + 1 -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.53: f(!i, x) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain 'f ->{'E1} List[out 'B] <: ((Int, A) ->{E} A) ->{E} List[out A] -//│ ╟── because: cannot constrain 'E1 <: E -//│ ╟── because: cannot constrain 'E1 <: ¬(¬E) -//│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) -//│ ╟── because: cannot constrain 'reg <: ¬(¬E) -//│ ╟── because: cannot constrain (¬⊥ ∧ 'r) ∧ ¬outer <: ¬(¬E) -//│ ╟── because: cannot constrain 'r <: ¬(¬E ∧ ¬outer) -//│ ╙── because: cannot constrain ¬outer <: ¬(¬E ∧ ¬outer) -//│ ╔══[ERROR] Type error in region expression with expected type ((Int, A) ->{E} A) ->{E} List[out A] -//│ ║ l.50: let i = r.ref 0 -//│ ║ ^^^^^^^ -//│ ║ l.51: f => map(s) of x => -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.52: i := !i + 1 -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.53: f(!i, x) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain 'f ->{'E1} List[out 'B] <: ((Int, A) ->{E} A) ->{E} List[out A] -//│ ╟── because: cannot constrain 'E1 <: E -//│ ╟── because: cannot constrain 'E1 <: ¬(¬E) -//│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) -//│ ╟── because: cannot constrain 'reg <: ¬(¬E) -//│ ╟── because: cannot constrain (¬⊥ ∧ 'r) ∧ ¬outer <: ¬(¬E) -//│ ╟── because: cannot constrain 'r <: ¬(¬E ∧ ¬outer) -//│ ╙── because: cannot constrain ¬outer <: ¬(¬E ∧ ¬outer) //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbPoly.mls b/hkmc2/shared/src/test/mlscript/bbml/bbPoly.mls index 3d0c26a18f..fc481ad582 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbPoly.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbPoly.mls @@ -136,7 +136,7 @@ new Some((x => x) as [A] -> A -> A) //│ 'x -> 'x <: 'A let s = new Some((x => x) as [A] -> A -> A) in let t = s.Some#value(42) in s.Some#value(false) -//│ Type: Bool ∨ Int +//│ Type: ⊥ fun gen: Int -> [A] -> A -> A fun gen(x) = diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls index 677363781a..fc6c1027a2 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls @@ -41,16 +41,22 @@ f `=> x `=> f`(x) x `=> y `=> x `+ y -//│ Type: CodeBase[out Int -> (Int -> Int), ⊥, ?] +//│ Type: CodeBase[out 'x -> (⊤ -> ⊥), ⊥, ?] +//│ Where: +//│ 'x#Int ∨ 'cde#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int (x, y) `=> x `+ y -//│ Type: CodeBase[out (Int, Int) -> Int, ⊥, ?] +//│ Type: CodeBase[out ('x, ⊤) -> ⊥, ⊥, ?] +//│ Where: +//│ 'x#Int ∨ 'cde#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int (x, y, z) `=> x `+ y `+ z -//│ Type: CodeBase[out (Int, Int, Int) -> Int, ⊥, ?] +//│ Type: CodeBase[out ('x, ⊤, ⊤) -> ⊥, ⊥, ?] +//│ Where: +//│ 'cde#Int ∨ 'x#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int f `=> x `=> y `=> f`(x, y) //│ Type: CodeBase[out (('x, 'y) -> 'app) -> ('x -> ('y -> 'app)), ⊥, ?] @@ -61,7 +67,7 @@ f `=> x `=> y `=> f`(x, y) :e `let x = 42 `in x //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.62: `let x = 42 `in x +//│ ║ l.68: `let x = 42 `in x //│ ║ ^^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'cde, out 'ctx, ?] //│ Type: CodeBase[⊥, ⊥, ?] @@ -69,7 +75,7 @@ f `=> x `=> y `=> f`(x, y) :e `let x = `0 `in 1 //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.70: `let x = `0 `in 1 +//│ ║ l.76: `let x = `0 `in 1 //│ ║ ^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'cde, out 'ctx, ?] //│ Type: CodeBase[⊥, ⊥, ?] @@ -91,7 +97,7 @@ run(`1) :e run(1) //│ ╔══[ERROR] Type error in integer literal with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.92: run(1) +//│ ║ l.98: run(1) //│ ║ ^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'T, ⊥, ?] //│ Type: ⊥ @@ -99,7 +105,7 @@ run(1) :e x `=> run(x) //│ ╔══[ERROR] Type error in reference with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.100: x `=> run(x) +//│ ║ l.106: x `=> run(x) //│ ║ ^ //│ ╟── because: cannot constrain CodeBase['x, x, ⊥] <: CodeBase[out 'T, ⊥, ?] //│ ╙── because: cannot constrain x <: ⊥ @@ -108,12 +114,12 @@ x `=> run(x) :e `let x = `42 `in run(x) //│ ╔══[ERROR] Type error in reference with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.109: `let x = `42 `in run(x) +//│ ║ l.115: `let x = `42 `in run(x) //│ ║ ^ //│ ╟── because: cannot constrain CodeBase['cde, x, ⊥] <: CodeBase[out 'T, ⊥, ?] //│ ╙── because: cannot constrain x <: ⊥ //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.109: `let x = `42 `in run(x) +//│ ║ l.115: `let x = `42 `in run(x) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain 'T <: CodeBase[out 'cde1, out 'ctx, ?] //│ ╟── because: cannot constrain 'T <: ¬(¬{CodeBase[out 'cde1, out 'ctx, ?]}) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls index 1408001fe9..b415e33a32 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls @@ -37,7 +37,7 @@ fun f(x) = f(x) f //│ Type: ['x] -> 'x -> ⊥ //│ Where: -//│ 'x#'x ∨ 'app<:'app ∧ 'eff<:'eff ∧ 'x<:'x} +//│ 'x#'x ∨ ( 'x#'x ∨ ∧ 'x<:'x ∧ 'app<:'app ∧ 'eff<:'eff) :todo fun f(x) = f(x.a) @@ -73,6 +73,6 @@ fun f(x) = f(x.Foo#a) f //│ Type: ['A] -> Foo[out 'A] -> ⊥ //│ Where: -//│ 'A#'A ∨ 'app<:'app ∧ 'eff<:'eff ∧ 'A<:'x} +//│ 'A#'A ∨ ∧ 'A<:'x ∧ 'app<:'app ∧ 'eff<:'eff diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index 4b08ca576d..bd97cf5d09 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -35,10 +35,8 @@ x => idIB(x) //│ Type: ('x) ->{⊥} ⊥ //│ Where: -//│ 'x <: Int ∨ Bool //│ 'x <: Int -//│ 'x#Int ∨ Int<:'app ∧ ⊥<:'eff} -//│ 'x#Bool ∨ Bool<:'app ∧ ⊥<:'eff} +//│ 'x#'x ∨ ( 'x#Int ∨ ∧ 'x<:Int ∨ Bool ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ 'x<:Int ∨ Bool ∧ Bool<:'app ∧ ⊥<:'eff) (x: Int) => let y = x + 1 @@ -51,7 +49,7 @@ x => (x: Bool) => idIB(idIB(x)) -//│ Type: (Bool) ->{⊥} Bool ∨ Int +//│ Type: (Bool) ->{⊥} Bool fun ap1(f)=f(1) ap1(idIB) @@ -64,17 +62,13 @@ ap(idIB)(1) x => idIB(x) //│ Type: ('x) ->{⊥} ⊥ //│ Where: -//│ 'x <: Int ∨ Bool -//│ 'x#Bool ∨ Bool<:'app ∧ ⊥<:'eff} -//│ 'x#Int ∨ Int<:'app ∧ ⊥<:'eff} +//│ 'x#'x ∨ ( 'x#Int ∨ ∧ 'x<:Int ∨ Bool ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ 'x<:Int ∨ Bool ∧ Bool<:'app ∧ ⊥<:'eff) fun forward(x) = idIB(x) forward //│ Type: ['x] -> 'x -> ⊥ //│ Where: -//│ 'x <: Int ∨ Bool -//│ 'x#Bool ∨ Bool<:'app ∧ ⊥<:'eff} -//│ 'x#Int ∨ Int<:'app ∧ ⊥<:'eff} +//│ 'x#'x ∨ ( 'x#Int ∨ ∧ 'x<:Int ∨ Bool ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ 'x<:Int ∨ Bool ∧ Bool<:'app ∧ ⊥<:'eff) forward(1) //│ Type: ⊥ @@ -86,17 +80,17 @@ forward(true) :todo // BbML fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╔══[ERROR] General type is not allowed here. -//│ ║ l.87: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) +//│ ║ l.81: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╙── ^^^ //│ ╔══[ERROR] General type is not allowed here. -//│ ║ l.87: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) +//│ ║ l.81: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╙── ^^^^ //│ Type: ⊤ :todo // BbML idIIBB([1, 2]) //│ ╔══[ERROR] Term shape not yet supported by BbML: Tup(List(Fld(‹›,Lit(IntLit(1)),None), Fld(‹›,Lit(IntLit(2)),None))) -//│ ║ l.97: idIIBB([1, 2]) +//│ ║ l.91: idIIBB([1, 2]) //│ ╙── ^^^^^^ //│ Type: ⊥ @@ -133,7 +127,7 @@ idIIBB(new Pair(1, true)) :todo fun foo: ["x": Int, "y": Int] //│ ╔══[ERROR] Invalid type -//│ ║ l.134: fun foo: ["x": Int, "y": Int] +//│ ║ l.128: fun foo: ["x": Int, "y": Int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index ea79bb8e0b..c747710930 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -53,10 +53,8 @@ test(fls, fls) :fixme -:e test(true, false) //│ ═══[RUNTIME ERROR] Error: match error //│ Type: Tru ∨ Fls -//│ FAILURE: Unexpected lack of type error From ae28b4231837de028c6487a2587db14a3d0cfc45 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Mon, 10 Mar 2025 17:01:56 +0800 Subject: [PATCH 09/36] ues linkedhashset --- .../src/main/scala/hkmc2/bbml/ConstraintSolver.scala | 4 ++-- hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala | 10 +++++----- hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls | 9 +++++---- hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls | 2 +- hkmc2/shared/src/test/mlscript/bbml/bbList.mls | 2 ++ hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls | 2 +- .../src/test/mlscript/logicsub/MarlowWadler97.mls | 3 ++- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index 0d5bf4c496..b9d675f2fb 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -128,7 +128,7 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, Type.disjoint(q, args2.head) match case N => (cs, Nil) case S(k) => - if k.nonEmpty then (Nil, k.map(k => DisjSub(mutable.Set.from(k), Nil, cs))) + if k.nonEmpty then (Nil, k.map(k => DisjSub(mutable.LinkedHashSet.from(k), Nil, cs))) else (Nil, Nil)).toList.unzip if k.isEmpty then if f.isEmpty then @@ -138,7 +138,7 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, dss.flatten.foreach(_.commit()) else k.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - DisjSub(mutable.Set.from(k), dss.flatten, cs.flatten).commit() + DisjSub(mutable.LinkedHashSet.from(k), dss.flatten, cs.flatten).commit() case _ => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} <: ${conj.u.toString()}" -> N :: Nil)) cctx.err diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 6ccc9ff918..71e98a7410 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -5,7 +5,7 @@ import mlscript.utils.*, shorthands.* import syntax.* import semantics.*, semantics.Term.* import utils.* -import scala.collection.mutable.{Set => MutSet, Map => MutMap} +import scala.collection.mutable.{Set => MutSet, Map => MutMap, LinkedHashSet} import utils.Scope import Elaborator.State @@ -426,10 +426,10 @@ case class PolyFunType(args: Ls[GeneralType], ret: GeneralType, eff: Type) exten class VarState: var lowerBounds: Ls[Type] = Nil var upperBounds: Ls[Type] = Nil - val disjsub: MutSet[DisjSub] = MutSet.empty + val disjsub: LinkedHashSet[DisjSub] = LinkedHashSet.empty override def toString = "<>" -case class DisjSub(disjoint: MutSet[InfVar -> BasicType], dss: Ls[DisjSub], cs: Ls[Type -> Type]): +case class DisjSub(disjoint: LinkedHashSet[InfVar -> BasicType], dss: Ls[DisjSub], cs: Ls[Type -> Type]): def commit() = disjoint.keys.foreach(_.state.disjsub += this) def checkAndCommit()(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]): Ls[Type -> Type] = val cc: MutSet[InfVar -> BasicType] = MutSet.empty @@ -446,7 +446,7 @@ case class DisjSub(disjoint: MutSet[InfVar -> BasicType], dss: Ls[DisjSub], cs: if d.nonEmpty then commit() d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - DisjSub(MutSet.from(k), dss, cs).commit() + DisjSub(LinkedHashSet.from(k), dss, cs).commit() Nil def checkImpl(v: InfVar)(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]) = val (u, w) = disjoint.toList.partition(_._1.uid === v.uid) @@ -462,6 +462,6 @@ case class DisjSub(disjoint: MutSet[InfVar -> BasicType], dss: Ls[DisjSub], cs: if disjoint.forall(_._1.uid =/= v.uid) then v.state.disjsub -= this else if d.nonEmpty then d.foldLeft(Set(w))((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - DisjSub(MutSet.from(k), dss, cs).commit() + DisjSub(LinkedHashSet.from(k), dss, cs).commit() Nil def check(v: InfVar) = checkImpl(v)(using c = MutMap.empty) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index f4274ff992..41f7e8f07d 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -149,6 +149,7 @@ fun foofoo(x) = let t = x + 1 in "foo" //│ Type: ⊤ +:todo new Printer(foofoo) //│ Type: Printer['T] //│ Where: @@ -160,7 +161,7 @@ let ip = new Printer(foofoo) in ip.Printer#f(42) :e let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.161: let ip = new Printer(foofoo) in ip.Printer#f("42") +//│ ║ l.162: let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ║ ^^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -194,7 +195,7 @@ let tf = new TFun(inc) in tf.TFun#f(1) :e let tf = new TFun(inc) in tf.TFun#f("1") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.195: let tf = new TFun(inc) in tf.TFun#f("1") +//│ ║ l.196: let tf = new TFun(inc) in tf.TFun#f("1") //│ ║ ^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -206,7 +207,7 @@ let tf = new TFun(inc) in tf.TFun#f("1") //│ ╟── because: cannot constrain 'T <: ¬(¬{Int}) //│ ╙── because: cannot constrain Str <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.195: let tf = new TFun(inc) in tf.TFun#f("1") +//│ ║ l.196: let tf = new TFun(inc) in tf.TFun#f("1") //│ ║ ^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -346,7 +347,7 @@ throw new Error("oops") :e throw 42 //│ ╔══[ERROR] Type error in throw -//│ ║ l.347: throw 42 +//│ ║ l.348: throw 42 //│ ║ ^^ //│ ╙── because: cannot constrain Int <: Error //│ Type: ⊥ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls index 976dadec6b..226d35a790 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls @@ -41,7 +41,7 @@ inc //│ Type: ['x, 'eff, 'x1] -> (CodeBase[⊥, ?, ?] ->{'eff} ⊤) ->{'eff} CodeBase[out 'x -> ⊥, ⊥, ?] //│ Where: //│ 'x <: 'x1 -//│ 'cde#Int ∨ 'x1#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int +//│ 'x1#Int ∨ 'cde#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int inc(c => log(show(c))) //│ Type: CodeBase[out ⊤ -> ⊥, ⊥, ?] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbList.mls b/hkmc2/shared/src/test/mlscript/bbml/bbList.mls index 59f5b05435..efc436db99 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbList.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbList.mls @@ -43,6 +43,8 @@ region r in // * Should be an error. This definition would not be referentially transparent. // * The error message needs improvement, though. +:todo +:e fun mapi: [A, E] -> List[out A] -> ((Int, A) ->{E} A) ->{E} List[out A] fun mapi = s => region r in diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls index fc6c1027a2..400168187b 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls @@ -56,7 +56,7 @@ x `=> y `=> x `+ y (x, y, z) `=> x `+ y `+ z //│ Type: CodeBase[out ('x, ⊤, ⊤) -> ⊥, ⊥, ?] //│ Where: -//│ 'cde#Int ∨ 'x#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int +//│ 'x#Int ∨ 'cde#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int f `=> x `=> y `=> f`(x, y) //│ Type: CodeBase[out (('x, 'y) -> 'app) -> ('x -> ('y -> 'app)), ⊥, ?] diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index c747710930..0053f04dc5 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -52,7 +52,8 @@ test(fls, fls) //│ Type: Tru ∨ Fls -:fixme +:todo +:e test(true, false) //│ ═══[RUNTIME ERROR] Error: match error //│ Type: Tru ∨ Fls From 2f1f5f3b32a4d01aaed5e0212d7ec86f190ef92c Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Wed, 12 Mar 2025 23:09:09 +0800 Subject: [PATCH 10/36] traverse disjsub --- .../main/scala/hkmc2/bbml/NormalForm.scala | 10 +++--- .../scala/hkmc2/bbml/TypeSimplifier.scala | 9 +++++ .../src/main/scala/hkmc2/bbml/types.scala | 14 ++++++-- .../src/test/mlscript/bbml/bbBasics.mls | 35 ++++--------------- .../shared/src/test/mlscript/bbml/bbFuns.mls | 10 ++---- .../shared/src/test/mlscript/bbml/bbGPCE.mls | 3 +- .../src/test/mlscript/bbml/bbGetters.mls | 2 +- hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls | 12 +++---- hkmc2/shared/src/test/mlscript/bbml/bbRec.mls | 4 +-- .../src/test/mlscript/logicsub/DisjSub.mls | 6 ++-- 10 files changed, 47 insertions(+), 58 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala index 95eacc14a7..7fbbe584f2 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala @@ -93,15 +93,15 @@ final case class Inter(v: Opt[ClassLikeType | Ls[FunType]]) extends NormalForm: case (S(_: ClassLikeType), S(_: ClassLikeType)) => N // case (S(FunType(a1, r1, e1)), S(FunType(a2, r2, e2))) => // S(Inter(S(FunType(a1.lazyZip(a2).map(_ | _), r1 & r2, e1 & e2)))) - case (S(a:Ls[FunType]),S(b:Ls[FunType]))=>S(Inter(S(a++b))) + case (S(a: Ls[FunType]), S(b: Ls[FunType])) => S(Inter(S(a ++ b))) case (S(v), N) => S(Inter(S(v))) case (N, v) => S(Inter(v)) case _ => N def toBasic: BasicType = v match - case N=>Top - case S(x:ClassLikeType)=>x - case S(Nil)=>Top - case S(x:Ls[FunType])=>x.reduce[Type](_&_).toBasic + case N => Top + case S(x: ClassLikeType) => x + case S(Nil) => Top + case S(x: Ls[FunType]) => x.reduce[Type](_&_).toBasic def toDnf(using TL): Disj = Disj(Conj(this, Union(N, Nil), Nil) :: Nil) override def show(using Scope): Str = toBasic.show diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeSimplifier.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeSimplifier.scala index c87ddc60b2..a96a1c5620 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeSimplifier.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeSimplifier.scala @@ -60,6 +60,8 @@ class TypeSimplifier(tl: TraceLogger): val varSubst: MutMap[IV, IV] = MutMap.empty val traversedTVs: MutSet[IV] = MutSet.empty + + val traversedDisjSub: MutSet[DisjSub] = MutSet.empty def getRepr(tv: IV): IV = varSubst.get(tv) match { case S(tv2) => @@ -129,6 +131,13 @@ class TypeSimplifier(tl: TraceLogger): // traversingTVs += tv // traversedTVs += tv super.apply(pol)(ty) + val (p, n) = (tv.state.disjsub.flatMap: ds => + ds.subDisjSub.map: k => + if traversedDisjSub.add(ds) then + ds.children() + else (Nil, Nil)).unzip + p.flatten.foreach(apply(true)) + n.flatten.foreach(apply(false)) // traversingTVs -= tv curPath = oldPath case pt @ PolyType(tvs, outer, _) => // Avoid simplify outer variables to Top unexpectedly diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 71e98a7410..ec99dfa43f 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -388,6 +388,9 @@ object PolyType: apply(true)(bd) state.upperBounds.foreach: bd => apply(false)(bd) + val (p, n) = state.disjsub.map(_.children()).unzip + p.flatten.foreach(apply(true)) + n.flatten.foreach(apply(false)) super.apply(pol)(ty) case _ => super.apply(pol)(ty) CollectTVs(true)(ty) @@ -432,23 +435,24 @@ class VarState: case class DisjSub(disjoint: LinkedHashSet[InfVar -> BasicType], dss: Ls[DisjSub], cs: Ls[Type -> Type]): def commit() = disjoint.keys.foreach(_.state.disjsub += this) def checkAndCommit()(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]): Ls[Type -> Type] = - val cc: MutSet[InfVar -> BasicType] = MutSet.empty + disjoint.keys.foreach(_.state.disjsub -= this) val d = disjoint.flatMap: u => Type.disjointImpl(u._2, u._1)(Set.empty) match case N => disjoint -= u - cc += u N case S(k) => if k.nonEmpty then S(k) else N if disjoint.isEmpty then dss.flatMap(_.checkAndCommit()) ++ cs else + disjoint.keys.foreach(_.state.disjsub += this) if d.nonEmpty then commit() d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => DisjSub(LinkedHashSet.from(k), dss, cs).commit() Nil def checkImpl(v: InfVar)(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]) = + v.state.disjsub -= this val (u, w) = disjoint.toList.partition(_._1.uid === v.uid) val d = u.flatMap: u => Type.disjointImpl(u._2, u._1)(Set.empty) match @@ -459,9 +463,13 @@ case class DisjSub(disjoint: LinkedHashSet[InfVar -> BasicType], dss: Ls[DisjSub if disjoint.isEmpty then dss.flatMap(_.checkAndCommit()) ++ cs else - if disjoint.forall(_._1.uid =/= v.uid) then v.state.disjsub -= this + if disjoint.exists(_._1.uid === v.uid) then v.state.disjsub += this else if d.nonEmpty then d.foldLeft(Set(w))((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => DisjSub(LinkedHashSet.from(k), dss, cs).commit() Nil def check(v: InfVar) = checkImpl(v)(using c = MutMap.empty) + def children(): (Ls[Type], Ls[Type]) = + val (p, n) = dss.map(_.children()).unzip + (p.flatten ++ disjoint.keys ++ cs.keys, n.flatten ++ cs.values) + def subDisjSub: Ls[DisjSub] = this :: dss.flatMap(_.subDisjSub) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index 41f7e8f07d..680f41123c 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -186,16 +186,12 @@ new TFun(inc) //│ 'T#'T ∨ ∧ 'T<:'x ∧ Int<:'T ∧ ⊥<:⊥ let tf = new TFun(inc) in tf.TFun#f(1) -//│ Type: 'T -//│ Where: -//│ Int <: 'T -//│ 'T <: Int -//│ ∧ 'T<:'x ∧ Int<:'T ∧ ⊥<:⊥ +//│ Type: Int :e let tf = new TFun(inc) in tf.TFun#f("1") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.196: let tf = new TFun(inc) in tf.TFun#f("1") +//│ ║ l.192: let tf = new TFun(inc) in tf.TFun#f("1") //│ ║ ^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -206,26 +202,7 @@ let tf = new TFun(inc) in tf.TFun#f("1") //│ ╟── because: cannot constrain 'T <: ¬¬Int //│ ╟── because: cannot constrain 'T <: ¬(¬{Int}) //│ ╙── because: cannot constrain Str <: ¬(¬{Int}) -//│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.196: let tf = new TFun(inc) in tf.TFun#f("1") -//│ ║ ^^^ -//│ ╟── because: cannot constrain Str <: 'T -//│ ╟── because: cannot constrain Str <: 'T -//│ ╟── because: cannot constrain Str <: ¬(¬'T) -//│ ╟── because: cannot constrain Str <: 'T -//│ ╟── because: cannot constrain Int <: 'T -//│ ╟── because: cannot constrain Int <: 'T -//│ ╟── because: cannot constrain 'T <: 'x -//│ ╟── because: cannot constrain 'T <: 'x -//│ ╟── because: cannot constrain 'T <: ¬¬Int -//│ ╟── because: cannot constrain 'T <: ¬(¬{Int}) -//│ ╙── because: cannot constrain Str <: ¬(¬{Int}) -//│ Type: 'T -//│ Where: -//│ Int <: 'T -//│ Str <: 'T -//│ 'T <: Int -//│ ∧ 'T<:'x ∧ Int<:'T ∧ ⊥<:⊥ +//│ Type: Int ∨ Str class Pair[A, B](fst: A, snd: B) //│ Type: ⊤ @@ -285,7 +262,7 @@ fun fact(n) = //│ Type: ⊤ fact -//│ Type: ['n] -> 'n -> Int +//│ Type: ['n, 'eff, 'app] -> 'n ->{'eff} Int //│ Where: //│ 'n <: Int //│ 'n#Int ∨ ∧ Int<:'n ∧ Int<:'app ∧ 'eff<:'eff @@ -312,7 +289,7 @@ fun fact2 = case //│ Type: ⊤ fact2 -//│ Type: ['caseScrut] -> 'caseScrut -> Int +//│ Type: ['caseScrut, 'eff, 'app] -> 'caseScrut ->{'eff} Int //│ Where: //│ 'caseScrut <: Int //│ 'caseScrut#Int ∨ ∧ Int<:'caseScrut ∧ Int<:'app ∧ 'eff<:'eff @@ -347,7 +324,7 @@ throw new Error("oops") :e throw 42 //│ ╔══[ERROR] Type error in throw -//│ ║ l.348: throw 42 +//│ ║ l.325: throw 42 //│ ║ ^^ //│ ╙── because: cannot constrain Int <: Error //│ Type: ⊥ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbFuns.mls b/hkmc2/shared/src/test/mlscript/bbml/bbFuns.mls index 9d42b7f3cd..5eac720091 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbFuns.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbFuns.mls @@ -9,16 +9,10 @@ f f((x => x), 42) -//│ Type: 'y -//│ Where: -//│ Int <: 'y -//│ ∧ 'y<:'x ∧ 'x<:'app ∧ ⊥<:'eff +//│ Type: Int f(x => x, 42) -//│ Type: 'y -//│ Where: -//│ Int <: 'y -//│ ∧ 'y<:'x ∧ 'x<:'app ∧ ⊥<:'eff +//│ Type: Int fun id: [A] -> A -> A diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls index 226d35a790..3a8a4a4463 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls @@ -38,10 +38,11 @@ show fun inc(dbg) = x `=> let c = x `+ `1 in let t = dbg(c) in c inc -//│ Type: ['x, 'eff, 'x1] -> (CodeBase[⊥, ?, ?] ->{'eff} ⊤) ->{'eff} CodeBase[out 'x -> ⊥, ⊥, ?] +//│ Type: ['x, 'cde, 'cde1, 'app, 'app1, 'eff, 'cde2, 'x1] -> (CodeBase[out 'app1, ?, ?] ->{'eff} ⊤) ->{'eff} CodeBase[out 'x -> 'cde2, ⊥, ?] //│ Where: //│ 'x <: 'x1 //│ 'x1#Int ∨ 'cde#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int +//│ 'cde2 <: ⊤ inc(c => log(show(c))) //│ Type: CodeBase[out ⊤ -> ⊥, ⊥, ?] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls index 81e3a81e0d..606465f1c9 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls @@ -37,7 +37,7 @@ fun test2() = 0 then 0 n then funny(n - 1) + 1 funny -//│ ╔══[ERROR] Expected a monomorphic type or an instantiable type here, but () ->{⊥} [outer, 'caseScrut, 'eff] -> 'caseScrut ->{'eff} Int found +//│ ╔══[ERROR] Expected a monomorphic type or an instantiable type here, but () ->{⊥} [outer, 'caseScrut, 'eff, 'app] -> 'caseScrut ->{'eff} Int found //│ ║ l.38: n then funny(n - 1) + 1 //│ ║ ^^^^^^^^^^^^^^^^ //│ ║ l.39: funny diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls index 400168187b..ccdc185457 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls @@ -41,22 +41,22 @@ f `=> x `=> f`(x) x `=> y `=> x `+ y -//│ Type: CodeBase[out 'x -> (⊤ -> ⊥), ⊥, ?] +//│ Type: CodeBase[out 'x -> ('y -> 'cde), ⊥, ?] //│ Where: -//│ 'x#Int ∨ 'cde#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int +//│ 'x#Int ∨ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int (x, y) `=> x `+ y -//│ Type: CodeBase[out ('x, ⊤) -> ⊥, ⊥, ?] +//│ Type: CodeBase[out ('x, 'y) -> 'cde, ⊥, ?] //│ Where: -//│ 'x#Int ∨ 'cde#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int +//│ 'x#Int ∨ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int (x, y, z) `=> x `+ y `+ z -//│ Type: CodeBase[out ('x, ⊤, ⊤) -> ⊥, ⊥, ?] +//│ Type: CodeBase[out ('x, 'y, 'z) -> 'cde, ⊥, ?] //│ Where: -//│ 'x#Int ∨ 'cde#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int +//│ 'x#Int ∨ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int f `=> x `=> y `=> f`(x, y) //│ Type: CodeBase[out (('x, 'y) -> 'app) -> ('x -> ('y -> 'app)), ⊥, ?] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls index b415e33a32..b24c7d385a 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls @@ -35,7 +35,7 @@ f fun f(x) = f(x) f -//│ Type: ['x] -> 'x -> ⊥ +//│ Type: ['x, 'eff, 'app] -> 'x ->{'eff} 'app //│ Where: //│ 'x#'x ∨ ( 'x#'x ∨ ∧ 'x<:'x ∧ 'app<:'app ∧ 'eff<:'eff) @@ -71,7 +71,7 @@ fun f(x) = f(Foo.a(x)) fun f(x) = f(x.Foo#a) f -//│ Type: ['A] -> Foo[out 'A] -> ⊥ +//│ Type: ['x, 'A, 'eff, 'app] -> Foo[out 'A] ->{'eff} 'app //│ Where: //│ 'A#'A ∨ ∧ 'A<:'x ∧ 'app<:'app ∧ 'eff<:'eff diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index bd97cf5d09..978c82bf11 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -33,7 +33,7 @@ idIB(if true then 1 else true) x => let y = x+1 idIB(x) -//│ Type: ('x) ->{⊥} ⊥ +//│ Type: ('x) ->{'eff} 'app //│ Where: //│ 'x <: Int //│ 'x#'x ∨ ( 'x#Int ∨ ∧ 'x<:Int ∨ Bool ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ 'x<:Int ∨ Bool ∧ Bool<:'app ∧ ⊥<:'eff) @@ -60,13 +60,13 @@ ap(idIB)(1) :todo x => idIB(x) -//│ Type: ('x) ->{⊥} ⊥ +//│ Type: ('x) ->{'eff} 'app //│ Where: //│ 'x#'x ∨ ( 'x#Int ∨ ∧ 'x<:Int ∨ Bool ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ 'x<:Int ∨ Bool ∧ Bool<:'app ∧ ⊥<:'eff) fun forward(x) = idIB(x) forward -//│ Type: ['x] -> 'x -> ⊥ +//│ Type: ['x, 'eff, 'app] -> 'x ->{'eff} 'app //│ Where: //│ 'x#'x ∨ ( 'x#Int ∨ ∧ 'x<:Int ∨ Bool ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ 'x<:Int ∨ Bool ∧ Bool<:'app ∧ ⊥<:'eff) From 3d383a23196ce4eddd4553300ef955fe84dfd9e3 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 13 Mar 2025 10:34:22 +0800 Subject: [PATCH 11/36] Changes from meeting --- .../shared/src/main/scala/hkmc2/Config.scala | 2 ++ .../scala/hkmc2/bbml/TypeSimplifier.scala | 4 +-- .../src/main/scala/hkmc2/bbml/bbML.scala | 6 ++-- .../src/main/scala/hkmc2/bbml/types.scala | 21 ++++++++----- .../src/test/mlscript/bbml/bbBasics.mls | 31 +++++++++++++++---- .../test/mlscript/logicsub/MarlowWadler97.mls | 9 +++++- .../src/test/scala/hkmc2/BbmlDiffMaker.scala | 8 +++-- .../src/test/scala/hkmc2/MLsDiffMaker.scala | 4 ++- 8 files changed, 62 insertions(+), 23 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/Config.scala b/hkmc2/shared/src/main/scala/hkmc2/Config.scala index 819c7bbc0c..a0860c3bcc 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/Config.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/Config.scala @@ -12,6 +12,7 @@ case class Config( sanityChecks: Opt[SanityChecks], effectHandlers: Opt[EffectHandlers], liftDefns: Opt[LiftDefns], + simplifyTypes: Bool, ): def stackSafety: Opt[StackSafety] = effectHandlers.flatMap(_.stackSafety) @@ -26,6 +27,7 @@ object Config: // sanityChecks = S(SanityChecks(light = true)), effectHandlers = N, liftDefns = N, + simplifyTypes = true, ) case class SanityChecks(light: Bool) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeSimplifier.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeSimplifier.scala index a96a1c5620..c78b2cf107 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeSimplifier.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeSimplifier.scala @@ -14,7 +14,7 @@ final def printPol(pol: Bool): Str = pol match { case false => "-" } -class TypeSimplifier(tl: TraceLogger): +class TypeSimplifier(using tl: TL): import tl.{trace, log} def apply(pol: Bool, lvl: Int)(ty: GeneralType): GeneralType = @@ -222,7 +222,7 @@ class TypeSimplifier(tl: TraceLogger): subst(ty) - def simplifyForall(ty: GeneralType): GeneralType = ty match + def simplifyForall(ty: GeneralType)(using TL): GeneralType = ty match case PolyType(tvs, outer, body) => val newBody = simplifyForall(body) val visited = PolyType.collectTVs(newBody) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index 1fadf97f5f..b475d39dd4 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -73,7 +73,7 @@ object BbCtx: end BbCtx -class BBTyper(using elState: Elaborator.State, tl: TL): +class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): import tl.{trace, log} private val infVarState = new InfVarUid.State() @@ -190,7 +190,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL): typeAndSubstType(ty, pol = true)(using Map.empty) private def instantiate(ty: PolyType)(using ctx: BbCtx): GeneralType = - ty.instantiate(infVarState.nextUid, freshEnv(new TempSymbol(N, "env")), ctx.lvl)(tl) + ty.instantiate(infVarState.nextUid, freshEnv(new TempSymbol(N, "env")), ctx.lvl) private def extrude(ty: GeneralType)(using ctx: BbCtx, pol: Bool, cctx: CCtx): GeneralType = ty match case ty: Type => solver.extrude(ty)(using ctx.lvl, pol, HashMap.empty) @@ -401,7 +401,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL): constrain(tryMkMono(funTy, t), FunType(argTy.map((tryMkMono(_, t))), retVar, effVar)) (retVar, argEff.foldLeft[Type](effVar | lhsEff)((res, e) => res | e)) - private def skolemize(ty: PolyType)(using ctx: BbCtx) = ty.skolemize(infVarState.nextUid, ctx.lvl)(tl) + private def skolemize(ty: PolyType)(using ctx: BbCtx) = ty.skolemize(infVarState.nextUid, ctx.lvl) // TODO: implement toLoc private def monoOrErr(ty: GeneralType, sc: Located)(using BbCtx) = diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index ec99dfa43f..474a5d4d35 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -177,7 +177,7 @@ sealed abstract class BasicType extends Type: case NegType(ty) => s"¬${ty.paren}" case Top => "⊤" case Bot => "⊥" - + override def showDbg: Str = this match case ClassLikeType(name, targs) => if targs.isEmpty then s"${name.nme}" else s"${name.nme}[${targs.map(_.showDbg).mkString(", ")}]" @@ -251,6 +251,8 @@ case class ClassLikeType(name: TypeSymbol | ModuleSymbol, targs: Ls[TypeArg]) ex final case class InfVar(vlvl: Int, uid: Uid[InfVar], state: VarState, isSkolem: Bool)(val sym: Symbol, val hint: Str) extends BasicType: override def subst(using map: Map[Uid[InfVar], InfVar]): ThisType = map.get(uid).getOrElse(this) + def showBounds: Str = + s"lower: ${state.lowerBounds.map(_.showDbg).mkString(", ")} upper: ${state.upperBounds.map(_.showDbg).mkString(", ")} disjsub: ${state.disjsub}" given Ordering[InfVar] = Ordering.by(_.uid) @@ -347,19 +349,20 @@ case class PolyType(tvs: Ls[InfVar], outer: Opt[InfVar], body: GeneralType) exte newSt.upperBounds = state.upperBounds.map(_.subst) InfVar(lvl, uid, newSt, skolem)(v.sym, v.hint) }, outer, body.subst) // * outer should have no bound! - + // * This function will only return the body after substitution // * and \dom(map) should cover all tvs. // * This function is dedicated to `skolemize` and `instantiate`. - private def substAndGetBody(using map: Map[Uid[InfVar], InfVar]): GeneralType = + private def substAndGetBody(using map: Map[Uid[InfVar], InfVar])(using TL): GeneralType = tvs.foreach: case InfVar(lvl, uid, state, skolem) => val v = map(uid) v.state.lowerBounds = state.lowerBounds.map(_.subst) v.state.upperBounds = state.upperBounds.map(_.subst) + tl.log(s"adding bounds to $v: ${v.showBounds}") body.subst - - def skolemize(nextUid: => Uid[InfVar], lvl: Int)(tl: TL) = + + def skolemize(nextUid: => Uid[InfVar], lvl: Int)(using TL) = // * Note that by this point, the state is supposed to be frozen/treated as immutable // * `outer` is already skolemized when it is declared val map = tvs.map(v => @@ -369,20 +372,22 @@ case class PolyType(tvs: Ls[InfVar], outer: Opt[InfVar], body: GeneralType) exte ).toMap substAndGetBody(using map) - def instantiate(nextUid: => Uid[InfVar], env: InfVar, lvl: Int)(tl: TL)(using State): GeneralType = + def instantiate(nextUid: => Uid[InfVar], env: InfVar, lvl: Int)(using State, TL): GeneralType = val map = (outer.map(_.uid -> env).toList ++ tvs.map(v => val nv = InfVar(lvl, nextUid, new VarState(), false)(new InstSymbol(v.sym), v.hint) tl.log(s"instantiate ${v.showDbg} ~> ${nv.showDbg}") + // tl.log(s"where ${nv.showBounds}") v.uid -> nv )).toMap substAndGetBody(using map) object PolyType: - def collectTVs(ty: GeneralType): Set[InfVar] = + def collectTVs(ty: GeneralType)(using TL): Set[InfVar] = val visited = MutSet.empty[InfVar] object CollectTVs extends TypeTraverser: override def apply(pol: Boolean)(ty: GeneralType): Unit = ty match case v @ InfVar(_, _, state, _) => + tl.log(s"collect ${v.showDbg} ${state.upperBounds}") if visited.add(v) then state.lowerBounds.foreach: bd => apply(true)(bd) @@ -396,7 +401,7 @@ object PolyType: CollectTVs(true)(ty) visited.toSet - def generalize(ty: GeneralType, outer: Opt[InfVar], lvl: Int): PolyType = + def generalize(ty: GeneralType, outer: Opt[InfVar], lvl: Int)(using TL): PolyType = PolyType(collectTVs(ty).filter(v => outer.map(_.uid != v.uid).getOrElse(true)).toList.sorted, outer, ty) // * Functions that accept/return a polymorphic type. diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index 680f41123c..da0d6f4010 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -145,23 +145,42 @@ let t = new Some(true) in t.Some#value class Printer[T](f: T -> Str) //│ Type: ⊤ +fun foofoo(x) = + if x is Int then + let t = x + 1 in "foo" +foofoo +//│ Type: (¬Int ∨ Int) -> Str + fun foofoo(x) = let t = x + 1 in "foo" //│ Type: ⊤ -:todo -new Printer(foofoo) -//│ Type: Printer['T] +:ns +foofoo +//│ Type: [outer, 'x] -> 'x -> Str +//│ Where: +//│ 'x <: ¬(¬{Int}) + +// TODO +fun f() = new Printer(foofoo) +f +//│ Type: ['T, 'x] -> () -> Printer['T] //│ Where: //│ 'T#'T ∨ ∧ 'T<:'x ∧ Str<:Str ∧ ⊥<:⊥ +f().Printer#f(42) +//│ Type: Str + +f().Printer#f("oops") +//│ Type: Str + let ip = new Printer(foofoo) in ip.Printer#f(42) //│ Type: Str :e let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.162: let ip = new Printer(foofoo) in ip.Printer#f("42") +//│ ║ l.181: let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ║ ^^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -191,7 +210,7 @@ let tf = new TFun(inc) in tf.TFun#f(1) :e let tf = new TFun(inc) in tf.TFun#f("1") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.192: let tf = new TFun(inc) in tf.TFun#f("1") +//│ ║ l.211: let tf = new TFun(inc) in tf.TFun#f("1") //│ ║ ^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -324,7 +343,7 @@ throw new Error("oops") :e throw 42 //│ ╔══[ERROR] Type error in throw -//│ ║ l.325: throw 42 +//│ ║ l.344: throw 42 //│ ║ ^^ //│ ╙── because: cannot constrain Int <: Error //│ Type: ⊥ diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index 0053f04dc5..32219d5e7a 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -21,11 +21,13 @@ let //│ tru = Tru() //│ Type: ⊤ +// :ucs desugared :ucs normalized fun test(x, y) = if x is Tru and y is Tru then tru x is Fls then fls y is Fls then fls +test //│ Normalized: //│ > if //│ > x is Tru and @@ -33,7 +35,8 @@ fun test(x, y) = if //│ > y is Fls then fls#666 //│ > x is Fls then fls#666 //│ > y is Fls then fls#666 -//│ Type: ⊤ +//│ = [function test] +//│ Type: (((¬Fls ∨ Fls) ∨ Tru) ∧ (¬Tru ∨ Tru), (¬Fls ∨ Fls) ∧ (¬Tru ∨ Tru)) -> (Tru ∨ Fls) test(tru, tru) //│ = Tru() @@ -51,6 +54,10 @@ test(fls, fls) //│ = Fls() //│ Type: Tru ∨ Fls +test("hi", fls) +//│ = Fls() +//│ Type: Tru ∨ Fls + :todo :e diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/BbmlDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/BbmlDiffMaker.scala index 29f7ba63f9..03c7861dc5 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/BbmlDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/BbmlDiffMaker.scala @@ -43,8 +43,12 @@ abstract class BbmlDiffMaker extends JSBackendDiffMaker: val ty = typer.typePurely(trm) val printer = PrettyPrinter((msg: String) => output(msg)) if debug.isSet then printer.print(ty) - val simplif = TypeSimplifier(tl) - val sty = simplif(true, 0)(ty) + val sty = + if config.simplifyTypes then + given hkmc2.utils.TL = tl + val simplif = new TypeSimplifier + simplif(true, 0)(ty) + else ty printer.print(sty) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index 668d40d4ab..450b4db06a 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -51,6 +51,7 @@ abstract class MLsDiffMaker extends DiffMaker: val parseOnly = NullaryCommand("parseOnly") val typeCheck = FlagCommand(false, "typeCheck") + val noTypeSimplification = FlagCommand(false, "ns") // * Compiler configuration @@ -80,7 +81,8 @@ abstract class MLsDiffMaker extends DiffMaker: S(StackSafety(stackLimit = value)) , )), - liftDefns = Opt.when(liftDefns.isSet)(LiftDefns()) + liftDefns = Opt.when(liftDefns.isSet)(LiftDefns()), + simplifyTypes = noTypeSimplification.isUnset, ) From 00e397b9b0ce769165f2deaed2e27501d015686d Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 13 Mar 2025 20:50:53 +0800 Subject: [PATCH 12/36] fix pretty printer type traverse and tv subst --- .../main/scala/hkmc2/bbml/PrettyPrinter.scala | 3 ++ .../src/main/scala/hkmc2/bbml/types.scala | 7 +++++ .../src/test/mlscript/bbml/bbBasics.mls | 23 ++++++++++++-- .../shared/src/test/mlscript/bbml/bbGPCE.mls | 16 +++++++++- hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls | 31 ++++++++++++++----- hkmc2/shared/src/test/mlscript/bbml/bbRec.mls | 1 + .../src/test/mlscript/logicsub/DisjSub.mls | 4 +-- 7 files changed, 72 insertions(+), 13 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala index 24d3338d2b..95d9a293a6 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala @@ -39,6 +39,9 @@ object PrettyPrinter: apply(false)(bd) (v, bd) res ++= state.disjsub + val (p, n) = state.disjsub.map(_.children()).unzip + p.flatten.foreach(apply(true)) + n.flatten.foreach(apply(false)) super.apply(pol)(ty) case _ => super.apply(pol)(ty) CollectBounds(true)(ty) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 474a5d4d35..20144e7ec7 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -347,6 +347,7 @@ case class PolyType(tvs: Ls[InfVar], outer: Opt[InfVar], body: GeneralType) exte val newSt = new VarState() newSt.lowerBounds = state.lowerBounds.map(_.subst) newSt.upperBounds = state.upperBounds.map(_.subst) + newSt.disjsub ++= state.disjsub.map(_.subst) InfVar(lvl, uid, newSt, skolem)(v.sym, v.hint) }, outer, body.subst) // * outer should have no bound! @@ -359,6 +360,8 @@ case class PolyType(tvs: Ls[InfVar], outer: Opt[InfVar], body: GeneralType) exte val v = map(uid) v.state.lowerBounds = state.lowerBounds.map(_.subst) v.state.upperBounds = state.upperBounds.map(_.subst) + v.state.disjsub ++= state.disjsub.map(_.subst) + v.state.disjsub.foreach(_.commit()) tl.log(s"adding bounds to $v: ${v.showBounds}") body.subst @@ -478,3 +481,7 @@ case class DisjSub(disjoint: LinkedHashSet[InfVar -> BasicType], dss: Ls[DisjSub val (p, n) = dss.map(_.children()).unzip (p.flatten ++ disjoint.keys ++ cs.keys, n.flatten ++ cs.values) def subDisjSub: Ls[DisjSub] = this :: dss.flatMap(_.subDisjSub) + def subst(using map: Map[Uid[InfVar], InfVar]): DisjSub = + val d = disjoint.map: + case (v, t) => (map.get(v.uid).getOrElse(v), t.subst.toBasic) + DisjSub(d, dss.map(_.subst), cs.map(u => (u._1.subst, u._2.subst))) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index da0d6f4010..93e2aced4a 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -167,11 +167,25 @@ f //│ Type: ['T, 'x] -> () -> Printer['T] //│ Where: //│ 'T#'T ∨ ∧ 'T<:'x ∧ Str<:Str ∧ ⊥<:⊥ +//│ 'x <: Int f().Printer#f(42) //│ Type: Str +:e f().Printer#f("oops") +//│ ╔══[ERROR] Type error in string literal with expected type 'T +//│ ║ l.176: f().Printer#f("oops") +//│ ║ ^^^^^^ +//│ ╟── because: cannot constrain Str <: 'T +//│ ╟── because: cannot constrain Str <: 'T +//│ ╟── because: cannot constrain Str <: ¬(¬'T1) +//│ ╟── because: cannot constrain Str <: 'T1 +//│ ╟── because: cannot constrain 'T1 <: 'x +//│ ╟── because: cannot constrain 'T1 <: 'x +//│ ╟── because: cannot constrain 'T1 <: Int +//│ ╟── because: cannot constrain 'T1 <: ¬(¬{Int}) +//│ ╙── because: cannot constrain Str <: ¬(¬{Int}) //│ Type: Str let ip = new Printer(foofoo) in ip.Printer#f(42) @@ -180,7 +194,7 @@ let ip = new Printer(foofoo) in ip.Printer#f(42) :e let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.181: let ip = new Printer(foofoo) in ip.Printer#f("42") +//│ ║ l.195: let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ║ ^^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -203,6 +217,7 @@ new TFun(inc) //│ Type: TFun['T] //│ Where: //│ 'T#'T ∨ ∧ 'T<:'x ∧ Int<:'T ∧ ⊥<:⊥ +//│ 'x <: ¬¬Int let tf = new TFun(inc) in tf.TFun#f(1) //│ Type: Int @@ -210,7 +225,7 @@ let tf = new TFun(inc) in tf.TFun#f(1) :e let tf = new TFun(inc) in tf.TFun#f("1") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.211: let tf = new TFun(inc) in tf.TFun#f("1") +//│ ║ l.226: let tf = new TFun(inc) in tf.TFun#f("1") //│ ║ ^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -285,6 +300,7 @@ fact //│ Where: //│ 'n <: Int //│ 'n#Int ∨ ∧ Int<:'n ∧ Int<:'app ∧ 'eff<:'eff +//│ 'app <: Int fact(1) //│ Type: Int @@ -312,6 +328,7 @@ fact2 //│ Where: //│ 'caseScrut <: Int //│ 'caseScrut#Int ∨ ∧ Int<:'caseScrut ∧ Int<:'app ∧ 'eff<:'eff +//│ 'app <: Int fact2(0) //│ Type: Int @@ -343,7 +360,7 @@ throw new Error("oops") :e throw 42 //│ ╔══[ERROR] Type error in throw -//│ ║ l.344: throw 42 +//│ ║ l.361: throw 42 //│ ║ ^^ //│ ╙── because: cannot constrain Int <: Error //│ Type: ⊥ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls index 3a8a4a4463..26a917e3d9 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls @@ -42,10 +42,24 @@ inc //│ Where: //│ 'x <: 'x1 //│ 'x1#Int ∨ 'cde#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int +//│ 'x1 <: 'cde +//│ 'cde#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int +//│ Int <: 'cde1 //│ 'cde2 <: ⊤ +//│ 'app <: 'cde2 +//│ 'app <: 'app1 inc(c => log(show(c))) -//│ Type: CodeBase[out ⊤ -> ⊥, ⊥, ?] +//│ Type: CodeBase[out 'x -> 'cde, ⊥, ?] +//│ Where: +//│ 'x1 <: 'x +//│ 'x#Int ∨ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'x <: 'cde1 +//│ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ Int <: 'cde2 +//│ 'cde <: ⊤ +//│ 'app <: 'cde +//│ 'app <: 'app1 fun body: [T, C] -> (CodeBase[out Int, out T, out Any], CodeBase[out Int, out C, out Any]) -> Int -> CodeBase[out Int, out T | C, out Any] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls index ccdc185457..6d32a54796 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls @@ -44,6 +44,12 @@ x `=> y `=> x `+ y //│ Type: CodeBase[out 'x -> ('y -> 'cde), ⊥, ?] //│ Where: //│ 'x#Int ∨ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'x <: 'cde1 +//│ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'y <: 'y1 +//│ 'y1 <: 'cde2 +//│ 'cde3 <: 'cde +//│ 'app <: ¬(¬'cde3) @@ -51,12 +57,23 @@ x `=> y `=> x `+ y //│ Type: CodeBase[out ('x, 'y) -> 'cde, ⊥, ?] //│ Where: //│ 'x#Int ∨ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'x <: 'cde1 +//│ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'y <: 'cde2 +//│ 'app <: ¬(¬'cde) (x, y, z) `=> x `+ y `+ z //│ Type: CodeBase[out ('x, 'y, 'z) -> 'cde, ⊥, ?] //│ Where: //│ 'x#Int ∨ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'x <: 'cde1 +//│ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'y <: 'cde2 +//│ 'cde3#'cde3 ∨ ( 'cde3#Int ∨ ∧ 'cde3<:Int ∧ Int<:'app1 ∧ ⊥<:⊥ ∧ 'cde4<:Int) +//│ 'z <: 'cde4 +//│ 'app1 <: ¬(¬'cde) +//│ 'app <: ¬(¬'cde3) f `=> x `=> y `=> f`(x, y) //│ Type: CodeBase[out (('x, 'y) -> 'app) -> ('x -> ('y -> 'app)), ⊥, ?] @@ -67,7 +84,7 @@ f `=> x `=> y `=> f`(x, y) :e `let x = 42 `in x //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.68: `let x = 42 `in x +//│ ║ l.85: `let x = 42 `in x //│ ║ ^^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'cde, out 'ctx, ?] //│ Type: CodeBase[⊥, ⊥, ?] @@ -75,7 +92,7 @@ f `=> x `=> y `=> f`(x, y) :e `let x = `0 `in 1 //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.76: `let x = `0 `in 1 +//│ ║ l.93: `let x = `0 `in 1 //│ ║ ^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'cde, out 'ctx, ?] //│ Type: CodeBase[⊥, ⊥, ?] @@ -97,15 +114,15 @@ run(`1) :e run(1) //│ ╔══[ERROR] Type error in integer literal with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.98: run(1) -//│ ║ ^ +//│ ║ l.115: run(1) +//│ ║ ^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'T, ⊥, ?] //│ Type: ⊥ :e x `=> run(x) //│ ╔══[ERROR] Type error in reference with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.106: x `=> run(x) +//│ ║ l.123: x `=> run(x) //│ ║ ^ //│ ╟── because: cannot constrain CodeBase['x, x, ⊥] <: CodeBase[out 'T, ⊥, ?] //│ ╙── because: cannot constrain x <: ⊥ @@ -114,12 +131,12 @@ x `=> run(x) :e `let x = `42 `in run(x) //│ ╔══[ERROR] Type error in reference with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.115: `let x = `42 `in run(x) +//│ ║ l.132: `let x = `42 `in run(x) //│ ║ ^ //│ ╟── because: cannot constrain CodeBase['cde, x, ⊥] <: CodeBase[out 'T, ⊥, ?] //│ ╙── because: cannot constrain x <: ⊥ //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.115: `let x = `42 `in run(x) +//│ ║ l.132: `let x = `42 `in run(x) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain 'T <: CodeBase[out 'cde1, out 'ctx, ?] //│ ╟── because: cannot constrain 'T <: ¬(¬{CodeBase[out 'cde1, out 'ctx, ?]}) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls index b24c7d385a..4d48888c82 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls @@ -74,5 +74,6 @@ f //│ Type: ['x, 'A, 'eff, 'app] -> Foo[out 'A] ->{'eff} 'app //│ Where: //│ 'A#'A ∨ ∧ 'A<:'x ∧ 'app<:'app ∧ 'eff<:'eff +//│ 'x <: Foo[out 'A] diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index 978c82bf11..2f844bd010 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -71,10 +71,10 @@ forward //│ 'x#'x ∨ ( 'x#Int ∨ ∧ 'x<:Int ∨ Bool ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ 'x<:Int ∨ Bool ∧ Bool<:'app ∧ ⊥<:'eff) forward(1) -//│ Type: ⊥ +//│ Type: Int forward(true) -//│ Type: ⊥ +//│ Type: Bool :todo // BbML From 0bbfeca4d265249bb986bf1e38fc1f4f3bf63fd8 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Fri, 21 Mar 2025 00:00:44 +0800 Subject: [PATCH 13/36] wip rcdtype implementation --- .../scala/hkmc2/bbml/ConstraintSolver.scala | 45 +++++-- .../main/scala/hkmc2/bbml/NormalForm.scala | 31 +++-- .../main/scala/hkmc2/bbml/TypeTraverser.scala | 1 + .../src/main/scala/hkmc2/bbml/bbML.scala | 18 +++ .../src/main/scala/hkmc2/bbml/types.scala | 49 ++++++-- .../src/main/scala/hkmc2/semantics/Term.scala | 1 + .../src/test/mlscript/bbml/bbBasics.mls | 14 +-- .../src/test/mlscript/bbml/bbBounds.mls | 8 +- .../src/test/mlscript/bbml/bbDisjoint.mls | 45 +++++++ .../src/test/mlscript/bbml/bbExtrude.mls | 8 +- .../shared/src/test/mlscript/bbml/bbGPCE.mls | 28 ++++- .../src/test/mlscript/bbml/bbGetters.mls | 2 +- .../test/mlscript/bbml/bbLetRegEncoding.mls | 25 +++- .../shared/src/test/mlscript/bbml/bbList.mls | 115 +++++++++++++++++- .../shared/src/test/mlscript/bbml/bbPoly.mls | 2 +- hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls | 32 +++-- hkmc2/shared/src/test/mlscript/bbml/bbRec.mls | 13 +- .../src/test/mlscript/logicsub/DisjSub.mls | 109 ++++++++++++++++- 18 files changed, 450 insertions(+), 96 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index b9d675f2fb..9f24dfa519 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -97,19 +97,37 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, cctx.nest(bd -> v) givenIn: v.state.lowerBounds ::= bd v.state.upperBounds.foreach(ub => constrainImpl(bd, ub)) - v.state.disjsub.toList.iterator.flatMap(_.check(v)).foreach: + v.state.disjsub.iterator.flatMap(_.check(v)).foreach: case (a, b) => constrainImpl(a, b) case Conj(i, u, Nil) => (conj.i, conj.u) match - case (_, Union(N, Nil)) => + case (_, Union(N, Nil, Nil)) => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} ∧ ¬⊥" -> N :: Nil)) cctx.err - case (Inter(S(ClassLikeType(cls1, targs1))), Union(f, ClassLikeType(cls2, targs2) :: rest)) => + case (Inter(S(ClassLikeType(cls1, targs1))), Union(f, ClassLikeType(cls2, targs2) :: rest, rcd)) => if cls1.uid === cls2.uid then targs1.zip(targs2).foreach: (ta1, ta2) => constrainArgs(ta1, ta2) - else constrainConj(Conj(conj.i, Union(f, rest), Nil)) - case (int: Inter, Union(f, _ :: rest)) => constrainConj(Conj(int, Union(f, rest), Nil)) - case (Inter(S(fs:Ls[FunType])), Union(S(FunType(args2, ret2, eff2)), Nil)) => + else constrainConj(Conj(conj.i, Union(f, rest, rcd), Nil)) + case (int: Inter, Union(f, _ :: rest, rcd)) => constrainConj(Conj(int, Union(f, rest, rcd), Nil)) + case (Inter(S(RcdType(u))), Union(f, Nil, RcdType(w) :: Nil)) => + val um = u.toMap + val wm = w.toMap + val k = w.keys.toSet + if k.subsetOf(um.keySet) then + k.foreach(k => constrainImpl(um(k), wm(k))) + else cctx.err + case (Inter(S(u: RcdType)), Union(f, Nil, rs@(RcdType(w) :: z))) => + val um = u.fields.toMap + val k = w.keys.toSet + if k.subsetOf(um.keySet) then + val r = RcdType(um.filterKeys(k(_)).toList) + val ws = rs.filter(w => Type.disjoint(w, r).isEmpty) + if ws.nonEmpty then + // TODO + constrainImpl(u, ws.reduce(_ & _)) + else cctx.err + else cctx.err + case (Inter(S(fs: Ls[FunType])), Union(S(FunType(args2, ret2, eff2)), Nil, Nil)) => val k = args2.flatMap(x => Type.disjoint(x, x)) if k.forall(_.nonEmpty) then val f = fs.filter(_.args.length === args2.length) @@ -121,24 +139,25 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, constrainImpl(f.eff, eff2) else val args = f.map(x => Type.discriminant(x.args)) - val c = (args2.head, args.foldLeft(Bot: Type) { case (t, (q, _)) => t | q }) + val (cs, dss) = (args.iterator.zip(f).map: case ((q, r), f) => - val cs = c :: (f.ret, ret2) :: (f.eff, eff2) :: args2.tail.zip(r) + val cs = (f.ret, ret2) :: (f.eff, eff2) :: args2.tail.zip(r) Type.disjoint(q, args2.head) match case N => (cs, Nil) case S(k) => - if k.nonEmpty then (Nil, k.map(k => DisjSub(mutable.LinkedHashSet.from(k), Nil, cs))) - else (Nil, Nil)).toList.unzip + (Nil, k.map(k => DisjSub(mutable.LinkedHashSet.from(k), Nil, cs)))).toList.unzip + val c = (args2.head, args.foldLeft(Bot: Type) { case (t, (q, _)) => t | q }) if k.isEmpty then if f.isEmpty then cctx.err else - cs.flatten.foreach(u => constrainImpl(u._1, u._2)) dss.flatten.foreach(_.commit()) + constrainImpl(c._1, c._2) + cs.flatten.foreach(u => constrainImpl(u._1, u._2)) else k.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - DisjSub(mutable.LinkedHashSet.from(k), dss.flatten, cs.flatten).commit() + DisjSub(mutable.LinkedHashSet.from(k), dss.flatten, c :: cs.flatten).commit() case _ => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} <: ${conj.u.toString()}" -> N :: Nil)) cctx.err @@ -156,7 +175,7 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, inlineSkolemBounds(if pol then state.upperBounds.foldLeft[Type](v)(_ & _) else state.lowerBounds.foldLeft[Type](v)(_ | _), pol) case ComposedType(lhs, rhs, p) => ComposedType(inlineSkolemBounds(lhs, pol), inlineSkolemBounds(rhs, pol), p) case NegType(ty) => NegType(inlineSkolemBounds(ty, !pol)) - case _: ClassLikeType | _: FunType | _: InfVar | Top | Bot => ty + case _: ClassLikeType | _: FunType | _: RcdType |_: InfVar | Top | Bot => ty private def constrainImpl(lhs: Type, rhs: Type)(using BbCtx, CCtx, TL): Unit = if cctx.cache((lhs, rhs)) then log(s"Cached!") diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala index 7fbbe584f2..ae5f7f3585 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/NormalForm.scala @@ -76,16 +76,17 @@ object Conj: }){} lazy val empty: Conj = Conj(Inter.empty, Union.empty, Nil) def mkVar(v: InfVar, pol: Bool) = Conj(Inter.empty, Union.empty, (v, pol) :: Nil) - def mkInter(inter: ClassLikeType | Ls[FunType]) = + def mkInter(inter: ClassLikeType | Ls[FunType] | RcdType) = Conj(Inter(S(inter)), Union.empty, Nil) - def mkUnion(union: ClassLikeType | FunType) = + def mkUnion(union: ClassLikeType | FunType | RcdType) = Conj(Inter.empty, union match { - case cls: ClassLikeType => Union(N, cls :: Nil) - case fun: FunType => Union(S(fun), Nil) + case cls: ClassLikeType => Union(N, cls :: Nil, Nil) + case fun: FunType => Union(S(fun), Nil, Nil) + case r: RcdType => Union(N, Nil, Ls(r)) }, Nil) // * Some(ClassType) -> C[in D_i out D_i], Some(FunType) -> D_1 ->{D_2} D_3, None -> Top -final case class Inter(v: Opt[ClassLikeType | Ls[FunType]]) extends NormalForm: +final case class Inter(v: Opt[ClassLikeType | Ls[FunType] | RcdType]) extends NormalForm: def isTop: Bool = v.isEmpty def merge(other: Inter): Option[Inter] = (v, other.v) match case (S(ClassLikeType(cls1, targs1)), S(ClassLikeType(cls2, targs2))) if cls1.uid === cls2.uid => @@ -94,6 +95,7 @@ final case class Inter(v: Opt[ClassLikeType | Ls[FunType]]) extends NormalForm: // case (S(FunType(a1, r1, e1)), S(FunType(a2, r2, e2))) => // S(Inter(S(FunType(a1.lazyZip(a2).map(_ | _), r1 & r2, e1 & e2)))) case (S(a: Ls[FunType]), S(b: Ls[FunType])) => S(Inter(S(a ++ b))) + case (S(a: RcdType), S(b: RcdType)) => S(Inter(S(a & b))) case (S(v), N) => S(Inter(S(v))) case (N, v) => S(Inter(v)) case _ => N @@ -102,7 +104,8 @@ final case class Inter(v: Opt[ClassLikeType | Ls[FunType]]) extends NormalForm: case S(x: ClassLikeType) => x case S(Nil) => Top case S(x: Ls[FunType]) => x.reduce[Type](_&_).toBasic - def toDnf(using TL): Disj = Disj(Conj(this, Union(N, Nil), Nil) :: Nil) + case S(x: RcdType) => x + def toDnf(using TL): Disj = Disj(Conj(this, Union(N, Nil, Nil), Nil) :: Nil) override def show(using Scope): Str = toBasic.show @@ -111,11 +114,11 @@ object Inter: lazy val empty: Inter = Inter(N) // * fun: Some(FunType) -> D_1 ->{D_2} D_3, None -> bot -final case class Union(fun: Opt[FunType], cls: Ls[ClassLikeType]) +final case class Union(fun: Opt[FunType], cls: Ls[ClassLikeType], rcd: Ls[RcdType]) extends NormalForm with CachedBasicType: - def isBot = fun.isEmpty && cls.isEmpty + def isBot = fun.isEmpty && cls.isEmpty && rcd.isEmpty def toType = fun.getOrElse(Bot) | - cls.foldLeft[Type](Bot)(_ | _) + cls.foldLeft[Type](Bot)(_ | _) | rcd.foldLeft[Type](Bot)(_ | _) def merge(other: Union): Union = Union((fun, other.fun) match { case (S(FunType(a1, r1, e1)), S(FunType(a2, r2, e2))) => S(FunType(a1.lazyZip(a2).map(_ & _), r1 | r2, e1 | e2)) @@ -129,16 +132,16 @@ extends NormalForm with CachedBasicType: case (ClassLikeType(cls1, targs1) :: tail, ClassLikeType(cls2, targs2)) if cls1.uid === cls2.uid => ClassLikeType(cls1, targs1.lazyZip(targs2).map(_ | _)) :: tail case (head :: tail, cls) => cls :: head :: tail - })) + }), rcd ++ other.rcd) def mkBasic: BasicType = - BasicType.union(fun.toList ::: cls) + BasicType.union(fun.toList ::: cls ::: rcd) def toDnf(using TL): Disj = NormalForm.neg(this) override def show(using Scope): Str = toType.show override def showDbg: Str = toType.showDbg object Union: - val empty: Union = Union(N, Nil) + val empty: Union = Union(N, Nil, Nil) sealed abstract class NormalForm extends TypeExt: def toBasic: BasicType @@ -172,6 +175,7 @@ object NormalForm: case v: InfVar => Disj(Conj.mkVar(v, false) :: Nil) case ct: ClassLikeType => Disj(Conj.mkUnion(ct) :: Nil) case ft: FunType => Disj(Conj.mkUnion(ft) :: Nil) + case r: RcdType => Disj(Conj.mkUnion(r) :: Nil) case ComposedType(lhs, rhs, pol) => if pol then inter(neg(lhs), neg(rhs)) else union(neg(lhs), neg(rhs)) case NegType(ty) => dnf(ty) @@ -181,13 +185,14 @@ object NormalForm: ty match case d: Disj => d case c: Conj => Disj(c :: Nil) - case i: Inter => Disj(Conj(i, Union(N, Nil), Nil) :: Nil) + case i: Inter => Disj(Conj(i, Union(N, Nil, Nil), Nil) :: Nil) case _ => ty.toBasic match case Top => Disj.top case Bot => Disj.bot case v: InfVar => Disj(Conj.mkVar(v, true) :: Nil) case ct: ClassLikeType => Disj(Conj.mkInter(ct.toNorm) :: Nil) case ft: FunType => Disj(Conj.mkInter(Ls(ft.toNorm)) :: Nil) + case r: RcdType => Disj(Conj.mkInter(r.toNorm) :: Nil) case ComposedType(lhs, rhs, pol) => if pol then union(dnf(lhs), dnf(rhs)) else inter(dnf(lhs), dnf(rhs)) case NegType(ty) => neg(ty) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeTraverser.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeTraverser.scala index 02f1b14b92..47e4e8735e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeTraverser.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/TypeTraverser.scala @@ -20,6 +20,7 @@ class TypeTraverser: case ty: Type => apply(pol)(ty) apply(!pol)(ty) + case RcdType(fields) => fields.values.foreach(apply(pol)) case InfVar(vlvl, uid, state, _) => if pol then state.lowerBounds.foreach(apply(true)) else state.upperBounds.foreach(apply(false)) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index b475d39dd4..2447365810 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -580,6 +580,24 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): (Bot, eff) case Term.Error => (Bot, Bot) // TODO: error type? + case Rcd(fields@((_: RcdField) :: _)) => + val u = fields.collect: + case RcdField(Lit(StrLit(a)), t) => (a, t, typeCheck(t)) + val (w, e) = u.foldRight((Nil: Ls[Str -> Type], Bot: Type)): + case ((a, t, (ty, e)), (w, e0)) => ((a -> tryMkMono(ty, t) :: w), e | e0) + (RcdType(w), e) + case Rcd(stats) => + // TODO RcdSpread + val (s, r) = stats.partitionMap: k => + k match + case RcdField(Lit(_: StrLit), _) => R(k) + case _ => L(k) + typeCheck(Blk(s, Rcd(r))) + case Term.Sel(u, Ident(a)) => + val (ty, e) = typeCheck(u) + val v = freshVar(new TempSymbol(S(t), "sel")) + constrain(tryMkMono(ty, u), RcdType(Ls(a -> v))) + (v, e) case _ => (error(msg"Term shape not yet supported by BbML: ${t.toString}" -> t.toLoc :: Nil), Bot) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 20144e7ec7..7c67d27dce 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -133,11 +133,11 @@ sealed abstract class Type extends GeneralType with TypeArg: case _ => NegType(this) protected[bbml] def paren(using Scope): Str = toBasic match - case _: InfVar | _: ClassLikeType | _: NegType | Top | Bot => show + case _: InfVar | _: ClassLikeType | _: RcdType | _: NegType | Top | Bot => show case _: ComposedType | _: FunType => s"($show)" protected[bbml] def parenDbg: Str = toBasic match - case _: InfVar | _: ClassLikeType | _: NegType | Top | Bot => showDbg + case _: InfVar | _: ClassLikeType | _: RcdType | _: NegType | Top | Bot => showDbg case _: ComposedType | _: FunType => s"($showDbg)" sealed abstract class BasicType extends Type: @@ -148,6 +148,7 @@ sealed abstract class BasicType extends Type: case InfVar(lvl, _, _, _) => lvl case FunType(args, ret, eff) => (ret :: eff :: args).map(_.lvl).max + case RcdType(fields) => fields.values.map(_.lvl).max case ComposedType(lhs, rhs, _) => lhs.lvl.max(rhs.lvl) case NegType(ty) => ty.lvl @@ -156,6 +157,7 @@ sealed abstract class BasicType extends Type: def mapBasic(f: Type => Type): Type = this match case ClassLikeType(name, targs) => ClassLikeType(name, targs.map(_.mapArg(f))) case FunType(args, ret, eff) => FunType(args.map(f), f(ret), f(eff)) + case RcdType(fields) => RcdType(fields.mapValues(f)) case ComposedType(lhs, rhs, pol) => Type.mkComposedType(f(lhs), f(rhs), pol) case NegType(ty) => Type.mkNegType(f(ty)) case Top | Bot | _: InfVar => this @@ -173,6 +175,7 @@ sealed abstract class BasicType extends Type: if isSkolem then name else s"'${name}" case FunType(arg :: Nil, ret, eff) => s"${arg.paren} ->${printEff(eff)} ${ret.paren}" case FunType(args, ret, eff) => s"(${args.map(_.show).mkString(", ")}) ->${printEff(eff)} ${ret.paren}" + case RcdType(fields) => s"{${fields.map { case (l, t) => s"$l: ${t.show}" }.mkString(", ")}}" case ComposedType(lhs, rhs, pol) => s"${lhs.paren} ${if pol then "∨" else "∧"} ${rhs.paren}" case NegType(ty) => s"¬${ty.paren}" case Top => "⊤" @@ -186,6 +189,7 @@ sealed abstract class BasicType extends Type: if isSkolem then s"${name}${uid}_${lvl}" else s"'${name}${uid}_${lvl}" case FunType(arg :: Nil, ret, eff) => s"${arg.parenDbg} ->{${eff.showDbg}} ${ret.parenDbg}" case FunType(args, ret, eff) => s"(${args.map(_.showDbg).mkString(", ")}) ->{${eff.showDbg}} ${ret.parenDbg}" + case RcdType(fields) => s"{${fields.map { case (l, t) => s"$l: ${t.showDbg}" }.mkString(", ")}}" case ComposedType(lhs, rhs, pol) => s"${lhs.parenDbg} ${if pol then "∨" else "∧"} ${rhs.parenDbg}" case NegType(ty) => s"¬${ty.parenDbg}" case Top => "⊤" @@ -223,7 +227,7 @@ trait CachedNorm[A <: AnyRef]: _norm = d d else _norm - + object BasicType: // TOOD dedup @@ -262,6 +266,14 @@ case class FunType(args: Ls[Type], ret: Type, eff: Type) extends BasicType with override def subst(using map: Map[Uid[InfVar], InfVar]): ThisType = FunType(args.map(_.subst), ret.subst, eff.subst) +case class RcdType(fields: Ls[Str -> Type]) extends BasicType with CachedNorm[RcdType]: + def mkNorm(using TL): RcdType = + RcdType(fields.mapValues(_.toDnf)) + override def subst(using map: Map[Uid[InfVar], InfVar]): ThisType = + RcdType(fields.mapValues(_.subst)) + def & (that: RcdType): RcdType = + RcdType((fields ++ that.fields).groupMapReduce(_._1)(_._2)(_ & _).toList) + case class ComposedType(lhs: Type, rhs: Type, pol: Bool) extends BasicType: // * Positive -> union override def subst(using map: Map[Uid[InfVar], InfVar]): ThisType = Type.mkComposedType(lhs.subst, rhs.subst, pol) @@ -288,7 +300,7 @@ object Type: (using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]) : Opt[Set[Set[InfVar->BasicType]]] = if !prev.contains(a -> b) then c.getOrElseUpdate(a -> b, { - (a, b) match + (a.simp.toBasic, b.simp.toBasic) match case (Bot, _) | (_, Bot) => S(Set.empty) case (NegType(t),_) => t.!.simp.toBasic match case NegType(_) => N @@ -297,23 +309,40 @@ object Type: case NegType(_) => N case a => disjointImpl(a, b)(prev) case (ClassLikeType(a, _), ClassLikeType(b, _)) if a.uid =/= b.uid => S(Set.empty) + case (RcdType(u), RcdType(w)) if u.nonEmpty && w.nonEmpty => + val um = u.toMap + val wm = w.toMap + val k = um.keySet & wm.keySet + val ur = RcdType((um -- k).toList) + val wr = RcdType((wm -- k).toList) + val ud = disjointImpl(ur, ur)(prev) + val wd = disjointImpl(wr, wr)(prev) + if ud.exists(_.isEmpty) || wd.exists(_.isEmpty) then + S(Set.empty) + else + val d = k.flatMap(k => disjointImpl(um(k).toBasic, wm(k).toBasic)(prev)) ++ Ls(ud, wd).flatten + if d.isEmpty then N + else if d.exists(_.isEmpty) then S(Set.empty) + else S(d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y)))) + case (_: RcdType, _: FunType) | (_: FunType, _: RcdType) => S(Set.empty) + case (_: ClassLikeType, _: FunType) | (_: FunType, _: ClassLikeType) => S(Set.empty) case (ComposedType(p, q, true), _) => - val u = disjointImpl(p.simp.toBasic, b)(prev) - val w = disjointImpl(q.simp.toBasic, b)(prev) + val u = disjointImpl(p.toBasic, b)(prev) + val w = disjointImpl(q.toBasic, b)(prev) u.flatMap(u => w.map(u ++ _)) case (_, ComposedType(p, q, true)) => - val u = disjointImpl(a, p.simp.toBasic)(prev) - val w = disjointImpl(a, q.simp.toBasic)(prev) + val u = disjointImpl(a, p.toBasic)(prev) + val w = disjointImpl(a, q.toBasic)(prev) u.flatMap(u => w.map(u ++ _)) case (a: InfVar, b: InfVar) if a.uid =/= b.uid => N case (v: InfVar, _) => val p = prev + (v -> b) - val k = v.state.lowerBounds.map(lb => disjointImpl(lb.toBasic.simp.toBasic, b)(p)) + val k = v.state.lowerBounds.map(lb => disjointImpl(lb.toBasic, b)(p)) if k.exists(_.isEmpty) then N else S((k.flatten.flatten.toSet + Set.empty).map(_ + (v -> b))) case (_, v: InfVar) => val p = prev + (a -> v) - val k = v.state.lowerBounds.map(lb => disjointImpl(a, lb.toBasic.simp.toBasic)(p)) + val k = v.state.lowerBounds.map(lb => disjointImpl(a, lb.toBasic)(p)) if k.exists(_.isEmpty) then N else S((k.flatten.flatten.toSet + Set.empty).map(_ + (v -> a))) case _ => N diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala index c3f7f8dca9..e4ae5440ca 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala @@ -101,6 +101,7 @@ enum Term extends Statement: case Forall(tvs, outer, body) => "universal quantification" case WildcardTy(in, out) => "wildcard type" case Blk(stats, res) => "block" + case Rcd(stats) => "record" case Quoted(term) => "quoted term" case Unquoted(term) => "unquoted term" case New(cls, args, rft) => "object creation" diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index da3dd5a63b..888b99feb2 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -296,11 +296,7 @@ fun fact(n) = //│ Type: ⊤ fact -//│ Type: ['n, 'eff, 'app] -> 'n ->{'eff} Int -//│ Where: -//│ 'n <: Int -//│ 'n#Int ∨ ∧ Int<:'n ∧ Int<:'app ∧ 'eff<:'eff -//│ 'app <: Int +//│ Type: Int -> Int fact(1) //│ Type: Int @@ -324,11 +320,7 @@ fun fact2 = case //│ Type: ⊤ fact2 -//│ Type: ['caseScrut, 'eff, 'app] -> 'caseScrut ->{'eff} Int -//│ Where: -//│ 'caseScrut <: Int -//│ 'caseScrut#Int ∨ ∧ Int<:'caseScrut ∧ Int<:'app ∧ 'eff<:'eff -//│ 'app <: Int +//│ Type: Int -> Int fact2(0) //│ Type: Int @@ -360,7 +352,7 @@ throw new Error("oops") :e throw 42 //│ ╔══[ERROR] Type error in throw -//│ ║ l.361: throw 42 +//│ ║ l.353: throw 42 //│ ║ ^^ //│ ╙── because: cannot constrain Int <: Error //│ Type: ⊥ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls index ee670a89d1..0600acbe39 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls @@ -87,7 +87,7 @@ bazbaz //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#'A ∨ ∧ 'A<:'A ∧ 'A<:'A ∧ ⊥<:⊥) +//│ 'A#'A ∨ ( 'A#'A ∨ ∧ 'A<:'A ∧ ⊥<:⊥) ∧ 'A<:'A bazbaz(42)(x => x + 1) //│ Type: Int @@ -98,7 +98,7 @@ cc //│ Where: //│ 'A -> 'A <: 'B //│ 'B <: 'A -> 'A -//│ 'B#'B ∨ ( 'B#'B ∨ ∧ 'B<:'B ∧ 'B<:'B ∧ ⊥<:⊥) +//│ 'B#'B ∨ ( 'B#'B ∨ ∧ 'B<:'B ∧ ⊥<:⊥) ∧ 'B<:'B //│ 'B -> 'B <: 'A //│ 'A <: 'B -> 'B @@ -119,14 +119,14 @@ bazbaz as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#'A ∨ ∧ 'A<:'A ∧ 'A<:'A ∧ ⊥<:⊥) +//│ 'A#'A ∨ ( 'A#'A ∨ ∧ 'A<:'A ∧ ⊥<:⊥) ∧ 'A<:'A (x => f => bazbaz(x)(f)) as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> A //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#'A ∨ ∧ 'A<:'A ∧ 'A<:'A ∧ ⊥<:⊥) +//│ 'A#'A ∨ ( 'A#'A ∨ ∧ 'A<:'A ∧ ⊥<:⊥) ∧ 'A<:'A h(x => f => bazbaz(x)(f))(42) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls b/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls index 7e20066633..eab472c8cb 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls @@ -207,10 +207,55 @@ region x in // Cannot type check since foo: 'foo <: Region[T] ->{'eff} 'app // Annotation is required for recursive calls +:e fun foo(r1) = region r2 in fork((_ => r1.ref 1), (_ => r2.ref 2)) foo(r2) +//│ ╔══[ERROR] Type error in function literal +//│ ║ l.211: fun foo(r1) = +//│ ║ ^^^^^ +//│ ║ l.212: region r2 in +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.213: fork((_ => r1.ref 1), (_ => r2.ref 2)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.214: foo(r2) +//│ ║ ^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'r1 ->{'eff} 'app <: 'foo +//│ ╟── because: cannot constrain ('r1) ->{'eff} ('app) <: 'foo +//│ ╟── because: cannot constrain ('r1) ->{'eff} ('app) <: Region[in 'r2 out 'r21] ->{'eff1} 'app1 +//│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: 'r1 +//│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: 'r1 +//│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: Region[in 'reg out 'reg1] +//│ ╟── because: cannot constrain 'r21 <: 'reg1 +//│ ╟── because: cannot constrain 'r21 <: ¬(¬'reg1) +//│ ╟── because: cannot constrain ¬outer <: ¬(¬'reg1) +//│ ╟── because: cannot constrain ¬outer <: 'reg1 +//│ ╟── because: cannot constrain ¬outer <: ¬'r22 ∨ outer +//│ ╟── because: cannot constrain 'r22 <: ¬(¬outer) +//│ ╙── because: cannot constrain ¬outer <: ¬(¬outer) +//│ ╔══[ERROR] Type error in function literal +//│ ║ l.211: fun foo(r1) = +//│ ║ ^^^^^ +//│ ║ l.212: region r2 in +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.213: fork((_ => r1.ref 1), (_ => r2.ref 2)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.214: foo(r2) +//│ ║ ^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'r1 ->{'eff} 'app <: 'foo +//│ ╟── because: cannot constrain ('r1) ->{'eff} ('app) <: 'foo +//│ ╟── because: cannot constrain ('r1) ->{'eff} ('app) <: Region[in 'r2 out 'r21] ->{'eff1} 'app1 +//│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: 'r1 +//│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: 'r1 +//│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: Region[in 'reg out 'reg1] +//│ ╟── because: cannot constrain 'r21 <: 'reg1 +//│ ╟── because: cannot constrain 'r21 <: ¬(¬'reg1) +//│ ╟── because: cannot constrain ¬outer <: ¬(¬'reg1) +//│ ╟── because: cannot constrain ¬outer <: 'reg1 +//│ ╟── because: cannot constrain ¬outer <: 'reg +//│ ╟── because: cannot constrain ¬outer <: 'reg +//│ ╙── because: cannot constrain ¬outer <: ¬() //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls index 474445e0be..a2b5cd2304 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls @@ -20,9 +20,7 @@ foo //│ Type: (⊤) ->{⊥} Int f(foo) -//│ Type: 'A -> Int -//│ Where: -//│ 'A#⊤ ∨ ∧ ⊤<:'A ∧ Int<:Int ∧ ⊥<:⊥ +//│ Type: ⊤ -> Int fun g: ([A] -> A -> Int) -> ([A] -> A -> Int) fun g(y) = @@ -38,7 +36,7 @@ g(foo) :e y `=> (let t = run(x `=> x `+ y) in y) //│ ╔══[ERROR] Type error in quoted term with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.39: y `=> (let t = run(x `=> x `+ y) in y) +//│ ║ l.37: y `=> (let t = run(x `=> x `+ y) in y) //│ ║ ^^^^^^^^^^^^ //│ ╟── because: cannot constrain CodeBase[out 'x -> 'cde, out 'ctx, ?] <: CodeBase[out 'T, ⊥, ?] //│ ╟── because: cannot constrain 'ctx <: ⊥ @@ -78,7 +76,7 @@ f(g)(foo) :fixme // ??? f(g)(bar) //│ ╔══[ERROR] Type error in reference with expected type 'A -//│ ║ l.79: f(g)(bar) +//│ ║ l.77: f(g)(bar) //│ ║ ^^^ //│ ╟── because: cannot constrain C[Int] <: 'A //│ ╟── because: cannot constrain C[in Int out Int] <: 'A diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls index 26a917e3d9..a3529e1b60 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls @@ -17,7 +17,7 @@ fun id(x) = x run(x `=> id(x) `* x) -//│ Type: ⊤ -> ⊥ +//│ Type: Int -> ⊥ fun assertNotZero: [C] -> CodeBase[out Num, out C, out Any] -> CodeBase[out Num, out C, out Any] @@ -25,7 +25,7 @@ fun assertNotZero(x) = `if (x `== `0.0) then `error else x let checkedDiv = x `=> y `=> x `/. (assertNotZero(y)) run(checkedDiv) -//│ Type: ⊤ -> (Num -> ⊥) +//│ Type: Num -> (Num -> ⊥) @@ -40,10 +40,13 @@ fun inc(dbg) = inc //│ Type: ['x, 'cde, 'cde1, 'app, 'app1, 'eff, 'cde2, 'x1] -> (CodeBase[out 'app1, ?, ?] ->{'eff} ⊤) ->{'eff} CodeBase[out 'x -> 'cde2, ⊥, ?] //│ Where: +//│ 'x <: Int //│ 'x <: 'x1 -//│ 'x1#Int ∨ 'cde#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int +//│ 'x1 <: Int +//│ 'x1#Int ∨ 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int //│ 'x1 <: 'cde -//│ 'cde#Int ∨ ∧ 'cde<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int +//│ 'cde <: Int +//│ 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int //│ Int <: 'cde1 //│ 'cde2 <: ⊤ //│ 'app <: 'cde2 @@ -52,10 +55,13 @@ inc inc(c => log(show(c))) //│ Type: CodeBase[out 'x -> 'cde, ⊥, ?] //│ Where: +//│ 'x1 <: Int //│ 'x1 <: 'x -//│ 'x#Int ∨ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'x <: Int +//│ 'x#Int ∨ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int //│ 'x <: 'cde1 -//│ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'cde1 <: Int +//│ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int //│ Int <: 'cde2 //│ 'cde <: ⊤ //│ 'app <: 'cde @@ -76,11 +82,21 @@ fun bind(rhs, k) = `let x = rhs `in k(x) bind //│ Type: ['cde, 'ctx, 'cde1, 'eff, 'cde2, 'ctx1] -> (CodeBase[out 'cde, out 'ctx, ?], CodeBase[in 'cde1 out 'cde1 ∨ 'cde, ?, ⊥] ->{'eff} CodeBase[out 'cde2, out 'ctx1, ?]) ->{'eff} CodeBase[out 'cde2, out 'ctx ∨ 'ctx1, ?] +:e fun body: [G] -> (CodeBase[out Int, out G, out Any], CodeBase[out Int, out G, out Any]) -> Int -> CodeBase[out Int, out G, out Any] fun body(x, y) = case 0 then x 1 then y n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] +//│ ╔══[ERROR] Type error in application with expected type CodeBase[out Int, out G, ?] +//│ ║ l.90: n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain CodeBase[out 'cde, out 'ctx ∨ 'ctx1, ?] <: CodeBase[out Int, out G, ?] +//│ ╟── because: cannot constrain 'ctx ∨ 'ctx1 <: G +//│ ╟── because: cannot constrain 'ctx1 <: ¬(¬G) +//│ ╟── because: cannot constrain 'ctx2 <: ¬(¬G) +//│ ╟── because: cannot constrain 'ctx2 <: ¬(¬G) +//│ ╙── because: cannot constrain <: ¬(¬G) //│ Type: ⊤ fun bind: [G] -> (CodeBase[out Int, out G, out Any], [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out Int, out C | G, out Any]) -> CodeBase[out Int, out G, out Any] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls index 606465f1c9..81e3a81e0d 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls @@ -37,7 +37,7 @@ fun test2() = 0 then 0 n then funny(n - 1) + 1 funny -//│ ╔══[ERROR] Expected a monomorphic type or an instantiable type here, but () ->{⊥} [outer, 'caseScrut, 'eff, 'app] -> 'caseScrut ->{'eff} Int found +//│ ╔══[ERROR] Expected a monomorphic type or an instantiable type here, but () ->{⊥} [outer, 'caseScrut, 'eff] -> 'caseScrut ->{'eff} Int found //│ ║ l.38: n then funny(n - 1) + 1 //│ ║ ^^^^^^^^^^^^^^^^ //│ ║ l.39: funny diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbLetRegEncoding.mls b/hkmc2/shared/src/test/mlscript/bbml/bbLetRegEncoding.mls index ad22e2947f..fd6a13fb37 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbLetRegEncoding.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbLetRegEncoding.mls @@ -70,8 +70,21 @@ let f = letreg(r => arg => r.ref arg) f //│ Type: 'arg ->{⊤} Ref['arg, ?] +:e letreg(r => arg => r.ref arg)(0) -//│ Type: ⊥ +//│ ╔══[ERROR] Type error in block +//│ ║ l.74: letreg(r => arg => r.ref arg)(0) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'eff ∨ 'E <: ⊥ +//│ ╟── because: cannot constrain 'eff <: ¬() +//│ ╟── because: cannot constrain 'reg <: ¬() +//│ ╟── because: cannot constrain 'reg <: ¬() +//│ ╟── because: cannot constrain ¬⊥ ∧ 'R <: ¬() +//│ ╟── because: cannot constrain 'R <: ¬() +//│ ╙── because: cannot constrain <: ¬() +//│ Type: Ref['arg, ?] +//│ Where: +//│ Int <: 'arg @@ -83,7 +96,7 @@ fun letreg: [E,Res] -> ([R] -> Region[R] -> Res) ->{E} Res :e letreg(r => r.ref 1) //│ ╔══[ERROR] Type error in function literal with expected type (Region[R]) ->{⊥} 'Res -//│ ║ l.84: letreg(r => r.ref 1) +//│ ║ l.97: letreg(r => r.ref 1) //│ ║ ^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'reg <: ⊥ //│ ╟── because: cannot constrain 'reg <: ¬() @@ -93,16 +106,16 @@ letreg(r => r.ref 1) :e letreg(r => !(r.ref 1)) //│ ╔══[ERROR] Type error in function literal with expected type (Region[R]) ->{⊥} 'Res -//│ ║ l.94: letreg(r => !(r.ref 1)) -//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.107: letreg(r => !(r.ref 1)) +//│ ║ ^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'reg ∨ 'reg1 <: ⊥ //│ ╟── because: cannot constrain 'reg <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() //│ ╙── because: cannot constrain R <: ¬() //│ ╔══[ERROR] Type error in function literal with expected type (Region[R]) ->{⊥} 'Res -//│ ║ l.94: letreg(r => !(r.ref 1)) -//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.107: letreg(r => !(r.ref 1)) +//│ ║ ^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'reg ∨ 'reg1 <: ⊥ //│ ╟── because: cannot constrain 'reg1 <: ¬() //│ ╙── because: cannot constrain R <: ¬() diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbList.mls b/hkmc2/shared/src/test/mlscript/bbml/bbList.mls index 4fbda64736..fb27b8276e 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbList.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbList.mls @@ -43,7 +43,6 @@ region r in // * Should be an error. This definition would not be referentially transparent. // * The error message needs improvement, though. -:todo :e fun mapi: [A, E] -> List[out A] -> ((Int, A) ->{E} A) ->{E} List[out A] fun mapi = s => @@ -52,7 +51,119 @@ fun mapi = s => f => map(s) of x => i := !i + 1 f(!i, x) +//│ ╔══[ERROR] Type error in region expression with expected type ((Int, A) ->{E} A) ->{E} List[out A] +//│ ║ l.50: let i = r.ref 0 +//│ ║ ^^^^^^^ +//│ ║ l.51: f => map(s) of x => +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.52: i := !i + 1 +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.53: f(!i, x) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'f ->{'E1} List[out 'B] <: ((Int, A) ->{E} A) ->{E} List[out A] +//│ ╟── because: cannot constrain (Int, A) ->{E} A <: 'f +//│ ╟── because: cannot constrain (Int, A) ->{E} (A) <: 'f +//│ ╟── because: cannot constrain 'E1 <: E +//│ ╟── because: cannot constrain 'E1 <: ¬(¬E) +//│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) +//│ ╟── because: cannot constrain 'reg <: ¬(¬E) +//│ ╟── because: cannot constrain (¬⊥ ∧ 'r) ∧ ¬outer <: ¬(¬E) +//│ ╟── because: cannot constrain 'r <: ¬(¬E ∧ ¬outer) +//│ ╙── because: cannot constrain ¬outer <: ¬(¬E ∧ ¬outer) +//│ ╔══[ERROR] Type error in region expression with expected type ((Int, A) ->{E} A) ->{E} List[out A] +//│ ║ l.50: let i = r.ref 0 +//│ ║ ^^^^^^^ +//│ ║ l.51: f => map(s) of x => +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.52: i := !i + 1 +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.53: f(!i, x) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'f ->{'E1} List[out 'B] <: ((Int, A) ->{E} A) ->{E} List[out A] +//│ ╟── because: cannot constrain (Int, A) ->{E} A <: 'f +//│ ╟── because: cannot constrain (Int, A) ->{E} (A) <: 'f +//│ ╟── because: cannot constrain 'E1 <: E +//│ ╟── because: cannot constrain 'E1 <: ¬(¬E) +//│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) +//│ ╟── because: cannot constrain 'reg <: ¬(¬E) +//│ ╟── because: cannot constrain (¬⊥ ∧ 'r) ∧ ¬outer <: ¬(¬E) +//│ ╟── because: cannot constrain 'r <: ¬(¬E ∧ ¬outer) +//│ ╙── because: cannot constrain ¬outer <: ¬(¬E ∧ ¬outer) +//│ ╔══[ERROR] Type error in region expression with expected type ((Int, A) ->{E} A) ->{E} List[out A] +//│ ║ l.50: let i = r.ref 0 +//│ ║ ^^^^^^^ +//│ ║ l.51: f => map(s) of x => +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.52: i := !i + 1 +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.53: f(!i, x) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'f ->{'E1} List[out 'B] <: ((Int, A) ->{E} A) ->{E} List[out A] +//│ ╟── because: cannot constrain (Int, A) ->{E} A <: 'f +//│ ╟── because: cannot constrain (Int, A) ->{E} (A) <: 'f +//│ ╟── because: cannot constrain 'E1 <: E +//│ ╟── because: cannot constrain 'E1 <: ¬(¬E) +//│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) +//│ ╟── because: cannot constrain 'reg <: ¬(¬E) +//│ ╟── because: cannot constrain (¬⊥ ∧ 'r) ∧ ¬outer <: ¬(¬E) +//│ ╟── because: cannot constrain 'r <: ¬(¬E ∧ ¬outer) +//│ ╙── because: cannot constrain ¬outer <: ¬(¬E ∧ ¬outer) //│ Type: ⊤ +fun mapii = s => + region r in + let i = r.ref 0 + f => map(s) of x => + i := !i + 1 + f(!i, x) +//│ Type: ⊤ - +:e +region r in + let sum = r.ref 0 + let s1 = mkList of !sum + let s2 = mapii(s1) of (x, i) => x * i + !sum + head(s2) +//│ ╔══[ERROR] Type error in block +//│ ║ l.123: let sum = r.ref 0 +//│ ║ ^^^^^^^ +//│ ║ l.124: let s1 = mkList of !sum +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.125: let s2 = mapii(s1) of (x, i) => x * i +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.126: !sum + head(s2) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'eff <: ⊥ +//│ ╟── because: cannot constrain 'eff <: ¬() +//│ ╟── because: cannot constrain ¬⊥ ∧ ¬'r <: ¬() +//│ ╟── because: cannot constrain <: 'r +//│ ╙── because: cannot constrain <: ¬() +//│ ╔══[ERROR] Type error in block +//│ ║ l.123: let sum = r.ref 0 +//│ ║ ^^^^^^^ +//│ ║ l.124: let s1 = mkList of !sum +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.125: let s2 = mapii(s1) of (x, i) => x * i +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.126: !sum + head(s2) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'eff <: ⊥ +//│ ╟── because: cannot constrain 'eff <: ¬() +//│ ╟── because: cannot constrain ¬⊥ ∧ ¬'r1 <: ¬() +//│ ╟── because: cannot constrain <: 'r1 +//│ ╙── because: cannot constrain <: ¬() +//│ ╔══[ERROR] Type error in block +//│ ║ l.123: let sum = r.ref 0 +//│ ║ ^^^^^^^ +//│ ║ l.124: let s1 = mkList of !sum +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.125: let s2 = mapii(s1) of (x, i) => x * i +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.126: !sum + head(s2) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'eff <: ⊥ +//│ ╟── because: cannot constrain 'eff <: ¬() +//│ ╟── because: cannot constrain ¬⊥ ∧ ¬'r2 <: ¬() +//│ ╟── because: cannot constrain <: 'r2 +//│ ╙── because: cannot constrain <: ¬() +//│ Type: Int diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbPoly.mls b/hkmc2/shared/src/test/mlscript/bbml/bbPoly.mls index 1a0119bbab..a66aa7ec02 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbPoly.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbPoly.mls @@ -136,7 +136,7 @@ new Some((x => x) as [A] -> A -> A) //│ 'x -> 'x <: 'A let s = new Some((x => x) as [A] -> A -> A) in let t = s.Some#value(42) in s.Some#value(false) -//│ Type: ⊥ +//│ Type: Bool ∨ Int fun gen: Int -> [A] -> A -> A fun gen(x) = diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls index 6d32a54796..fdd4b181d3 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls @@ -43,9 +43,11 @@ f `=> x `=> f`(x) x `=> y `=> x `+ y //│ Type: CodeBase[out 'x -> ('y -> 'cde), ⊥, ?] //│ Where: -//│ 'x#Int ∨ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'x <: Int +//│ 'x#Int ∨ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int //│ 'x <: 'cde1 -//│ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'cde1 <: ¬(¬{Int}) +//│ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int //│ 'y <: 'y1 //│ 'y1 <: 'cde2 //│ 'cde3 <: 'cde @@ -56,9 +58,11 @@ x `=> y `=> x `+ y (x, y) `=> x `+ y //│ Type: CodeBase[out ('x, 'y) -> 'cde, ⊥, ?] //│ Where: -//│ 'x#Int ∨ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'x <: Int +//│ 'x#Int ∨ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int //│ 'x <: 'cde1 -//│ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'cde1 <: ¬(¬{Int}) +//│ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int //│ 'y <: 'cde2 //│ 'app <: ¬(¬'cde) @@ -66,11 +70,13 @@ x `=> y `=> x `+ y (x, y, z) `=> x `+ y `+ z //│ Type: CodeBase[out ('x, 'y, 'z) -> 'cde, ⊥, ?] //│ Where: -//│ 'x#Int ∨ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'x <: Int +//│ 'x#Int ∨ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int //│ 'x <: 'cde1 -//│ 'cde1#Int ∨ ∧ 'cde1<:Int ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'cde1 <: ¬(¬{Int}) +//│ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int //│ 'y <: 'cde2 -//│ 'cde3#'cde3 ∨ ( 'cde3#Int ∨ ∧ 'cde3<:Int ∧ Int<:'app1 ∧ ⊥<:⊥ ∧ 'cde4<:Int) +//│ 'cde3#'cde3 ∨ ( 'cde3#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥ ∧ 'cde4<:Int) ∧ 'cde3<:Int //│ 'z <: 'cde4 //│ 'app1 <: ¬(¬'cde) //│ 'app <: ¬(¬'cde3) @@ -84,7 +90,7 @@ f `=> x `=> y `=> f`(x, y) :e `let x = 42 `in x //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.85: `let x = 42 `in x +//│ ║ l.91: `let x = 42 `in x //│ ║ ^^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'cde, out 'ctx, ?] //│ Type: CodeBase[⊥, ⊥, ?] @@ -92,7 +98,7 @@ f `=> x `=> y `=> f`(x, y) :e `let x = `0 `in 1 //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.93: `let x = `0 `in 1 +//│ ║ l.99: `let x = `0 `in 1 //│ ║ ^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'cde, out 'ctx, ?] //│ Type: CodeBase[⊥, ⊥, ?] @@ -114,7 +120,7 @@ run(`1) :e run(1) //│ ╔══[ERROR] Type error in integer literal with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.115: run(1) +//│ ║ l.121: run(1) //│ ║ ^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'T, ⊥, ?] //│ Type: ⊥ @@ -122,7 +128,7 @@ run(1) :e x `=> run(x) //│ ╔══[ERROR] Type error in reference with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.123: x `=> run(x) +//│ ║ l.129: x `=> run(x) //│ ║ ^ //│ ╟── because: cannot constrain CodeBase['x, x, ⊥] <: CodeBase[out 'T, ⊥, ?] //│ ╙── because: cannot constrain x <: ⊥ @@ -131,12 +137,12 @@ x `=> run(x) :e `let x = `42 `in run(x) //│ ╔══[ERROR] Type error in reference with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.132: `let x = `42 `in run(x) +//│ ║ l.138: `let x = `42 `in run(x) //│ ║ ^ //│ ╟── because: cannot constrain CodeBase['cde, x, ⊥] <: CodeBase[out 'T, ⊥, ?] //│ ╙── because: cannot constrain x <: ⊥ //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.132: `let x = `42 `in run(x) +//│ ║ l.138: `let x = `42 `in run(x) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain 'T <: CodeBase[out 'cde1, out 'ctx, ?] //│ ╟── because: cannot constrain 'T <: ¬(¬{CodeBase[out 'cde1, out 'ctx, ?]}) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls index c756d3886c..511e31f6ff 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls @@ -37,13 +37,10 @@ fun f(x) = f(x) f //│ Type: ['x, 'eff, 'app] -> 'x ->{'eff} 'app //│ Where: -//│ 'x#'x ∨ ( 'x#'x ∨ ∧ 'x<:'x ∧ 'app<:'app ∧ 'eff<:'eff) +//│ 'x#'x ∨ ( 'x#'x ∨ ∧ 'app<:'app ∧ 'eff<:'eff) ∧ 'x<:'x :todo fun f(x) = f(x.a) -//│ ╔══[ERROR] Term shape not yet supported by BbML: Sel(Ref(x),Ident(a)) -//│ ║ l.43: fun f(x) = f(x.a) -//│ ╙── ^^^ //│ Type: ⊤ @@ -53,7 +50,7 @@ data class Foo[A](a: A) :todo proper error Foo(123) //│ ╔══[ERROR] Variable not found: Foo -//│ ║ l.54: Foo(123) +//│ ║ l.51: Foo(123) //│ ╙── ^^^ //│ Type: ⊥ @@ -64,9 +61,9 @@ new Foo(123) :todo proper error fun f(x) = f(Foo.a(x)) -//│ ╔══[ERROR] Term shape not yet supported by BbML: Sel(Ref(member:Foo),Ident(a)) -//│ ║ l.66: fun f(x) = f(Foo.a(x)) -//│ ╙── ^^^^^ +//│ ╔══[ERROR] Variable not found: Foo +//│ ║ l.63: fun f(x) = f(Foo.a(x)) +//│ ╙── ^^^ //│ Type: ⊤ fun f(x) = f(x.Foo#a) diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index 2f844bd010..9022b1d3b9 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -36,7 +36,7 @@ x => //│ Type: ('x) ->{'eff} 'app //│ Where: //│ 'x <: Int -//│ 'x#'x ∨ ( 'x#Int ∨ ∧ 'x<:Int ∨ Bool ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ 'x<:Int ∨ Bool ∧ Bool<:'app ∧ ⊥<:'eff) +//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ 'x<:Int ∨ Bool (x: Int) => let y = x + 1 @@ -62,13 +62,13 @@ ap(idIB)(1) x => idIB(x) //│ Type: ('x) ->{'eff} 'app //│ Where: -//│ 'x#'x ∨ ( 'x#Int ∨ ∧ 'x<:Int ∨ Bool ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ 'x<:Int ∨ Bool ∧ Bool<:'app ∧ ⊥<:'eff) +//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ 'x<:Int ∨ Bool fun forward(x) = idIB(x) forward //│ Type: ['x, 'eff, 'app] -> 'x ->{'eff} 'app //│ Where: -//│ 'x#'x ∨ ( 'x#Int ∨ ∧ 'x<:Int ∨ Bool ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ 'x<:Int ∨ Bool ∧ Bool<:'app ∧ ⊥<:'eff) +//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ 'x<:Int ∨ Bool forward(1) //│ Type: Int @@ -140,4 +140,107 @@ fun foo(x) = if x is [false, false] then 2 //│ /!!!\ Uncaught error: scala.MatchError: Tuple(2,false) (of class hkmc2.semantics.Pattern$Tuple) +{x:1, y:true} +//│ Type: {x: Int, y: Bool} +fun k(f) = + a: f(0) + b: f(true) +k +//│ Type: ['eff, 'app, 'eff1, 'app1] -> ((Bool ->{'eff1} 'app1) ∧ (Int ->{'eff} 'app)) ->{'eff ∨ 'eff1} {a: 'app, b: 'app1} + +k(idIB) +//│ Type: {a: Int, b: Bool} + +fun k(f) = (x, y) => + a: f(x) + b: f(y) +k +//│ Type: ['x, 'y, 'eff, 'app, 'eff1, 'app1] -> (('y ->{'eff1} 'app1) ∧ ('x ->{'eff} 'app)) -> (('x, 'y) ->{'eff ∨ 'eff1} {a: 'app, b: 'app1}) + +k(idIB)(true, 1) +//│ Type: {a: Bool, b: Int} + +:e +k(idIB)("true", 1) +//│ ╔══[ERROR] Type error in string literal with expected type 'x +//│ ║ l.165: k(idIB)("true", 1) +//│ ║ ^^^^^^ +//│ ╟── because: cannot constrain Str <: 'x +//│ ╟── because: cannot constrain Str <: 'x +//│ ╟── because: cannot constrain 'x <: Int ∨ Bool +//│ ╟── because: cannot constrain 'x <: ¬(¬{Int ∨ Bool}) +//│ ╙── because: cannot constrain Str <: ¬(¬{Int ∨ Bool}) +//│ Type: {a: ⊥, b: Int} + +(x => x.x + idIB(x.y)) of (x:0, y:1) +//│ Type: Int + +data class Ls[A](prim: [R] -> (() -> R, (A, Ls[A]) -> R) -> R) +fun nil() = new Ls((n, _) => n()) +fun cons(x, y) = new Ls((n, r) => r(x, y)) +//│ Type: ⊤ + +fun map: [A, B, E] -> Ls[out A] -> (A -> B) -> Ls[out B] +//│ Type: ⊤ + +fun map: [A, B, E] -> Ls[A] -> (A -> B) -> Ls[B] +fun map = x => f => x.Ls#prim(() => nil(), (a, b) => cons(f(a), map(b)(f))) +//│ Type: ⊤ + +// fun map = x => f => new Ls((n, r) => x.Ls#prim(n, (a, b) => r(f(a), map(b)(f)))) + +x => map(x)(idIB) +//│ Type: (Ls['A]) ->{⊥} Ls['B] +//│ Where: +//│ 'A#'A ∨ ( 'A#Int ∨ ∧ Int<:'B ∧ ⊥<:⊥) ∧ ( 'A#Bool ∨ ∧ Bool<:'B ∧ ⊥<:⊥) ∧ 'A<:Int ∨ Bool + +map(nil())(idIB) +//│ Type: Ls['B] + +map(nil())(idIB) as Ls[Str] +//│ Type: Ls[Str] + +map(cons(1, nil()))(idIB) +//│ Type: Ls['B] +//│ Where: +//│ Int <: 'B + +map(cons(1, cons(true, nil())))(idIB) +//│ Type: Ls['B] +//│ Where: +//│ Bool <: 'B +//│ Int <: 'B + +:e +let x = cons(1, cons(true, nil())) in + map(cons(x, x))(idIB) +//│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B +//│ ║ l.217: map(cons(x, x))(idIB) +//│ ║ ^^^^ +//│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B +//│ ╟── because: cannot constrain 'A <: Int ∨ Bool +//│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) +//│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) +//│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B +//│ ║ l.217: map(cons(x, x))(idIB) +//│ ║ ^^^^ +//│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B +//│ ╟── because: cannot constrain 'A <: Int ∨ Bool +//│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) +//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) +//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) +//│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) +//│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B +//│ ║ l.217: map(cons(x, x))(idIB) +//│ ║ ^^^^ +//│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B +//│ ╟── because: cannot constrain 'A <: Int ∨ Bool +//│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) +//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) +//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) +//│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) +//│ Type: Ls['B] +//│ Where: +//│ Bool <: 'B +//│ Int <: 'B From 3a67c1f53ac070b95353db631445ce47e6e84348 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sat, 22 Mar 2025 19:05:59 +0800 Subject: [PATCH 14/36] wip rcdtype implementation and fun args disjointness --- .../scala/hkmc2/bbml/ConstraintSolver.scala | 47 +++++++++--- .../src/main/scala/hkmc2/bbml/types.scala | 23 +++++- .../src/test/mlscript/bbml/bbBasics.mls | 6 +- .../src/test/mlscript/bbml/bbBounds.mls | 8 +- .../src/test/mlscript/bbml/bbExtrude.mls | 19 ++++- .../shared/src/test/mlscript/bbml/bbGPCE.mls | 18 ++--- .../shared/src/test/mlscript/bbml/bbList.mls | 30 +++----- hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls | 50 +++++++++---- hkmc2/shared/src/test/mlscript/bbml/bbRec.mls | 6 +- .../src/test/mlscript/logicsub/DisjSub.mls | 73 ++++++++++++++++--- 10 files changed, 199 insertions(+), 81 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index 9f24dfa519..cadc8917b5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -116,16 +116,27 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, if k.subsetOf(um.keySet) then k.foreach(k => constrainImpl(um(k), wm(k))) else cctx.err - case (Inter(S(u: RcdType)), Union(f, Nil, rs@(RcdType(w) :: z))) => + case (Inter(S(u: RcdType)), Union(f, Nil, rs@(RcdType(w) :: _))) => val um = u.fields.toMap val k = w.keys.toSet if k.subsetOf(um.keySet) then val r = RcdType(um.filterKeys(k(_)).toList) - val ws = rs.filter(w => Type.disjoint(w, r).isEmpty) - if ws.nonEmpty then - // TODO - constrainImpl(u, ws.reduce(_ & _)) - else cctx.err + rs.filter(w => Type.disjoint(w, r).isEmpty) match + case Nil => cctx.err + case w :: Nil => constrainImpl(u, w) + case ws@(RcdType(w) :: RcdType(z) :: _) => + val (wm, zm) = (w.toMap, z.toMap) + k.filter(k => Type.disjoint(wm(k), zm(k)) === S(Set.empty)).toList match + case Nil => ??? + case k :: Nil => + val (ku, i) = ws.foldLeft((Bot: Type, RcdType(Nil))): + case ((ku, i), RcdType(w)) => + val (a :: _, b) = w.partition(_._1 === k) + (ku | a._2, i & RcdType(b)) + constrainImpl(um(k), ku) + constrainImpl(u, i) + case _ => + constrainImpl(u, ws.reduce(_ & _)) else cctx.err case (Inter(S(fs: Ls[FunType])), Union(S(FunType(args2, ret2, eff2)), Nil, Nil)) => val k = args2.flatMap(x => Type.disjoint(x, x)) @@ -138,16 +149,26 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, constrainImpl(f.ret, ret2) constrainImpl(f.eff, eff2) else - val args = f.map(x => Type.discriminant(x.args)) - + val dargs = f.map(x => Type.discriminant(x.args)) + val ks = if f.nonEmpty then + dargs.iterator.map(_._1.fields.keys.toSet).reduce(_ & _) + else Set.empty + val args = dargs.map: + case (u, w) => + val (q, p) = u.fields.partition(x => ks(x._1)) + (RcdType(q), RcdType(p) & w) + val args2r = args2.zipWithIndex.map(u => (s"${u._2}", u._1)) + val args2q = RcdType(args2r.filter(x => ks(x._1))) val (cs, dss) = (args.iterator.zip(f).map: case ((q, r), f) => - val cs = (f.ret, ret2) :: (f.eff, eff2) :: args2.tail.zip(r) - Type.disjoint(q, args2.head) match + val rm = r.fields.toMap + val rcs = args2r.flatMap(u => rm.get(u._1).filter(_ =/= Top).map(u._2 -> _)) + val cs = (f.ret, ret2) :: (f.eff, eff2) :: rcs + Type.disjoint(q, args2q) match case N => (cs, Nil) case S(k) => (Nil, k.map(k => DisjSub(mutable.LinkedHashSet.from(k), Nil, cs)))).toList.unzip - val c = (args2.head, args.foldLeft(Bot: Type) { case (t, (q, _)) => t | q }) + val c = (args2q, args.foldLeft(Bot: Type) { case (t, (q, _)) => t | q }) if k.isEmpty then if f.isEmpty then cctx.err @@ -156,8 +177,10 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, constrainImpl(c._1, c._2) cs.flatten.foreach(u => constrainImpl(u._1, u._2)) else + val cs0 = c :: cs.flatten + val dss0 = dss.flatten k.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - DisjSub(mutable.LinkedHashSet.from(k), dss.flatten, c :: cs.flatten).commit() + DisjSub(mutable.LinkedHashSet.from(k), dss0, cs0).commit() case _ => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} <: ${conj.u.toString()}" -> N :: Nil)) cctx.err diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 7c67d27dce..249b80d3fb 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -148,7 +148,7 @@ sealed abstract class BasicType extends Type: case InfVar(lvl, _, _, _) => lvl case FunType(args, ret, eff) => (ret :: eff :: args).map(_.lvl).max - case RcdType(fields) => fields.values.map(_.lvl).max + case RcdType(fields) => fields.values.map(_.lvl).maxOption.getOrElse(0) case ComposedType(lhs, rhs, _) => lhs.lvl.max(rhs.lvl) case NegType(ty) => ty.lvl @@ -295,7 +295,26 @@ object Type: then lhs | rhs else lhs & rhs def mkNegType(ty: Type): Type = ty.! - def discriminant(a: Ls[Type]): (BasicType, Ls[Type]) = (a.head.toBasic.simp.toBasic, a.tail) + def discriminant(a: Ls[Type]): (RcdType, RcdType) = + discriminantRcd(RcdType(a.zipWithIndex.map(u => (s"${u._2}", u._1.toBasic)))) + def discriminantRcd(a: RcdType): (RcdType, RcdType) = + val (u, w) = (a.fields.map: + case (a, t) => + val (q, r) = discriminant(t.toBasic) + (RcdType(Ls(a -> q)), RcdType(Ls(a -> r))) + ).unzip + (u.reduce(_ & _), w.reduce(_ & _)) + def discriminant(a: BasicType): (BasicType, BasicType) = a.simp.toBasic match + case Bot => (Bot, Bot) + case c@ClassLikeType(_, Nil) => (c, Top) + case ClassLikeType(c, t) => (ClassLikeType(c, t.map(_ => Wildcard.empty)), a) + case a@RcdType(_ :: _) => discriminantRcd(a) + case a@ComposedType(l, r, true) => ((discriminant(l.toBasic)._1 | discriminant(r.toBasic)._1).toBasic, a) + case ComposedType(l, r, false) => + val (u, w) = discriminant(l.toBasic) + val (q, p) = discriminant(r.toBasic) + ((u & q).toBasic, (w & p).toBasic) + case a => (Top, a) def disjointImpl(a: BasicType, b: BasicType)(prev: Set[BasicType -> BasicType]) (using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]) : Opt[Set[Set[InfVar->BasicType]]] = diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index 888b99feb2..c134b13674 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -166,7 +166,7 @@ fun f() = new Printer(foofoo) f //│ Type: ['T, 'x] -> () -> Printer['T] //│ Where: -//│ 'T#'T ∨ ∧ 'T<:'x ∧ Str<:Str ∧ ⊥<:⊥ +//│ 'T#'T ∨ ( 'T#⊤ ∨ ∧ Str<:Str ∧ ⊥<:⊥ ∧ 'T<:'x) ∧ {0: 'T}<:{0: ⊤} //│ 'x <: Int f().Printer#f(42) @@ -216,7 +216,7 @@ fun inc(x) = x + 1 new TFun(inc) //│ Type: TFun['T] //│ Where: -//│ 'T#'T ∨ ∧ 'T<:'x ∧ Int<:'T ∧ ⊥<:⊥ +//│ 'T#'T ∨ ( 'T#⊤ ∨ ∧ Int<:'T ∧ ⊥<:⊥ ∧ 'T<:'x) ∧ {0: 'T}<:{0: ⊤} //│ 'x <: ¬¬Int let tf = new TFun(inc) in tf.TFun#f(1) @@ -339,7 +339,7 @@ f f(x => x).Foo#x //│ Type: ('A) ->{⊥} 'A //│ Where: -//│ 'A#'A ∨ ∧ 'A<:'x ∧ 'x<:'A ∧ ⊥<:⊥ +//│ 'A#'A ∨ ( 'A#⊤ ∨ ∧ 'x<:'A ∧ ⊥<:⊥ ∧ 'A<:'x) ∧ {0: 'A}<:{0: ⊤} g => (new Foo(g)).Foo#x //│ Type: ('A -> 'A) ->{⊥} ('A) ->{⊥} 'A diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls index 0600acbe39..78d5bc8677 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls @@ -87,7 +87,7 @@ bazbaz //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#'A ∨ ∧ 'A<:'A ∧ ⊥<:⊥) ∧ 'A<:'A +//│ 'A#'A ∨ ( 'A#⊤ ∨ ∧ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A) ∧ {0: 'A}<:{0: ⊤} bazbaz(42)(x => x + 1) //│ Type: Int @@ -98,7 +98,7 @@ cc //│ Where: //│ 'A -> 'A <: 'B //│ 'B <: 'A -> 'A -//│ 'B#'B ∨ ( 'B#'B ∨ ∧ 'B<:'B ∧ ⊥<:⊥) ∧ 'B<:'B +//│ 'B#'B ∨ ( 'B#⊤ ∨ ∧ 'B<:'B ∧ ⊥<:⊥ ∧ 'B<:'B) ∧ {0: 'B}<:{0: ⊤} //│ 'B -> 'B <: 'A //│ 'A <: 'B -> 'B @@ -119,14 +119,14 @@ bazbaz as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#'A ∨ ∧ 'A<:'A ∧ ⊥<:⊥) ∧ 'A<:'A +//│ 'A#'A ∨ ( 'A#⊤ ∨ ∧ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A) ∧ {0: 'A}<:{0: ⊤} (x => f => bazbaz(x)(f)) as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> A //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#'A ∨ ∧ 'A<:'A ∧ ⊥<:⊥) ∧ 'A<:'A +//│ 'A#'A ∨ ( 'A#⊤ ∨ ∧ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A) ∧ {0: 'A}<:{0: ⊤} h(x => f => bazbaz(x)(f))(42) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls index a2b5cd2304..d7acc55c98 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls @@ -45,6 +45,21 @@ y `=> (let t = run(x `=> x `+ y) in y) //│ ╟── because: cannot constrain y <: 'x1 //│ ╙── because: cannot constrain y <: ¬() //│ Type: CodeBase[out 'y -> 'y, ⊥, ?] +//│ Where: +//│ 'y <: Int +//│ 'x#Int ∨ 'cde1#Int ∨ 'y#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'cde1#Int ∨ 'y#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'x2 <: ¬(¬{Int}) +//│ 'x2 <: 'x +//│ 'x <: ¬(¬{Int}) +//│ 'x#Int ∨ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'x <: 'cde1 +//│ 'cde1 <: ¬(¬{Int}) +//│ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'y <: 'cde2 +//│ 'cde2 <: ¬(¬{Int}) +//│ 'cde <: 'cde3 +//│ 'app <: ¬(¬'cde) data class C[A](m: A, n: A -> Int) //│ Type: ⊤ @@ -60,7 +75,7 @@ g f(g) -//│ Type: (¬C[?] ∨ C[in Int out ⊥]) ->{⊥} Int +//│ Type: ((¬C[?] ∨ C[in Int out ⊥]) ∧ (¬C[?] ∨ C[?])) ->{⊥} Int fun foo: C[in Int out Nothing] foo @@ -76,7 +91,7 @@ f(g)(foo) :fixme // ??? f(g)(bar) //│ ╔══[ERROR] Type error in reference with expected type 'A -//│ ║ l.77: f(g)(bar) +//│ ║ l.92: f(g)(bar) //│ ║ ^^^ //│ ╟── because: cannot constrain C[Int] <: 'A //│ ╟── because: cannot constrain C[in Int out Int] <: 'A diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls index a3529e1b60..2d0d93f1a2 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls @@ -38,18 +38,17 @@ show fun inc(dbg) = x `=> let c = x `+ `1 in let t = dbg(c) in c inc -//│ Type: ['x, 'cde, 'cde1, 'app, 'app1, 'eff, 'cde2, 'x1] -> (CodeBase[out 'app1, ?, ?] ->{'eff} ⊤) ->{'eff} CodeBase[out 'x -> 'cde2, ⊥, ?] +//│ Type: ['x, 'cde, 'app, 'app1, 'eff, 'cde1, 'x1] -> (CodeBase[out 'app1, ?, ?] ->{'eff} ⊤) ->{'eff} CodeBase[out 'x -> 'cde1, ⊥, ?] //│ Where: //│ 'x <: Int //│ 'x <: 'x1 //│ 'x1 <: Int -//│ 'x1#Int ∨ 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int +//│ 'x1#Int ∨ 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ //│ 'x1 <: 'cde //│ 'cde <: Int -//│ 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde1<:Int -//│ Int <: 'cde1 -//│ 'cde2 <: ⊤ -//│ 'app <: 'cde2 +//│ 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'cde1 <: ⊤ +//│ 'app <: 'cde1 //│ 'app <: 'app1 inc(c => log(show(c))) @@ -58,11 +57,10 @@ inc(c => log(show(c))) //│ 'x1 <: Int //│ 'x1 <: 'x //│ 'x <: Int -//│ 'x#Int ∨ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'x#Int ∨ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ //│ 'x <: 'cde1 //│ 'cde1 <: Int -//│ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int -//│ Int <: 'cde2 +//│ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ //│ 'cde <: ⊤ //│ 'app <: 'cde //│ 'app <: 'app1 @@ -89,7 +87,7 @@ fun body(x, y) = case 1 then y n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] //│ ╔══[ERROR] Type error in application with expected type CodeBase[out Int, out G, ?] -//│ ║ l.90: n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] +//│ ║ l.88: n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain CodeBase[out 'cde, out 'ctx ∨ 'ctx1, ?] <: CodeBase[out Int, out G, ?] //│ ╟── because: cannot constrain 'ctx ∨ 'ctx1 <: G diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbList.mls b/hkmc2/shared/src/test/mlscript/bbml/bbList.mls index fb27b8276e..df5d2659c6 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbList.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbList.mls @@ -61,8 +61,6 @@ fun mapi = s => //│ ║ l.53: f(!i, x) //│ ║ ^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'f ->{'E1} List[out 'B] <: ((Int, A) ->{E} A) ->{E} List[out A] -//│ ╟── because: cannot constrain (Int, A) ->{E} A <: 'f -//│ ╟── because: cannot constrain (Int, A) ->{E} (A) <: 'f //│ ╟── because: cannot constrain 'E1 <: E //│ ╟── because: cannot constrain 'E1 <: ¬(¬E) //│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) @@ -80,8 +78,6 @@ fun mapi = s => //│ ║ l.53: f(!i, x) //│ ║ ^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'f ->{'E1} List[out 'B] <: ((Int, A) ->{E} A) ->{E} List[out A] -//│ ╟── because: cannot constrain (Int, A) ->{E} A <: 'f -//│ ╟── because: cannot constrain (Int, A) ->{E} (A) <: 'f //│ ╟── because: cannot constrain 'E1 <: E //│ ╟── because: cannot constrain 'E1 <: ¬(¬E) //│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) @@ -99,8 +95,6 @@ fun mapi = s => //│ ║ l.53: f(!i, x) //│ ║ ^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'f ->{'E1} List[out 'B] <: ((Int, A) ->{E} A) ->{E} List[out A] -//│ ╟── because: cannot constrain (Int, A) ->{E} A <: 'f -//│ ╟── because: cannot constrain (Int, A) ->{E} (A) <: 'f //│ ╟── because: cannot constrain 'E1 <: E //│ ╟── because: cannot constrain 'E1 <: ¬(¬E) //│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) @@ -125,13 +119,13 @@ region r in let s2 = mapii(s1) of (x, i) => x * i !sum + head(s2) //│ ╔══[ERROR] Type error in block -//│ ║ l.123: let sum = r.ref 0 +//│ ║ l.117: let sum = r.ref 0 //│ ║ ^^^^^^^ -//│ ║ l.124: let s1 = mkList of !sum +//│ ║ l.118: let s1 = mkList of !sum //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.125: let s2 = mapii(s1) of (x, i) => x * i +//│ ║ l.119: let s2 = mapii(s1) of (x, i) => x * i //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.126: !sum + head(s2) +//│ ║ l.120: !sum + head(s2) //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'eff <: ⊥ //│ ╟── because: cannot constrain 'eff <: ¬() @@ -139,13 +133,13 @@ region r in //│ ╟── because: cannot constrain <: 'r //│ ╙── because: cannot constrain <: ¬() //│ ╔══[ERROR] Type error in block -//│ ║ l.123: let sum = r.ref 0 +//│ ║ l.117: let sum = r.ref 0 //│ ║ ^^^^^^^ -//│ ║ l.124: let s1 = mkList of !sum +//│ ║ l.118: let s1 = mkList of !sum //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.125: let s2 = mapii(s1) of (x, i) => x * i +//│ ║ l.119: let s2 = mapii(s1) of (x, i) => x * i //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.126: !sum + head(s2) +//│ ║ l.120: !sum + head(s2) //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'eff <: ⊥ //│ ╟── because: cannot constrain 'eff <: ¬() @@ -153,13 +147,13 @@ region r in //│ ╟── because: cannot constrain <: 'r1 //│ ╙── because: cannot constrain <: ¬() //│ ╔══[ERROR] Type error in block -//│ ║ l.123: let sum = r.ref 0 +//│ ║ l.117: let sum = r.ref 0 //│ ║ ^^^^^^^ -//│ ║ l.124: let s1 = mkList of !sum +//│ ║ l.118: let s1 = mkList of !sum //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.125: let s2 = mapii(s1) of (x, i) => x * i +//│ ║ l.119: let s2 = mapii(s1) of (x, i) => x * i //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.126: !sum + head(s2) +//│ ║ l.120: !sum + head(s2) //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'eff <: ⊥ //│ ╟── because: cannot constrain 'eff <: ¬() diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls index fdd4b181d3..06e4f7eab4 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls @@ -44,12 +44,17 @@ x `=> y `=> x `+ y //│ Type: CodeBase[out 'x -> ('y -> 'cde), ⊥, ?] //│ Where: //│ 'x <: Int -//│ 'x#Int ∨ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'x#Int ∨ 'cde1#Int ∨ 'y1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'x#Int ∨ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ //│ 'x <: 'cde1 //│ 'cde1 <: ¬(¬{Int}) -//│ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'cde1#Int ∨ 'y1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'y <: Int //│ 'y <: 'y1 +//│ 'y1 <: ¬(¬{Int}) //│ 'y1 <: 'cde2 +//│ 'cde2 <: ¬(¬{Int}) //│ 'cde3 <: 'cde //│ 'app <: ¬(¬'cde3) @@ -59,11 +64,15 @@ x `=> y `=> x `+ y //│ Type: CodeBase[out ('x, 'y) -> 'cde, ⊥, ?] //│ Where: //│ 'x <: Int -//│ 'x#Int ∨ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'x#Int ∨ 'cde1#Int ∨ 'y#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'x#Int ∨ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ //│ 'x <: 'cde1 //│ 'cde1 <: ¬(¬{Int}) -//│ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'cde1#Int ∨ 'y#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'y <: Int //│ 'y <: 'cde2 +//│ 'cde2 <: ¬(¬{Int}) //│ 'app <: ¬(¬'cde) @@ -71,12 +80,16 @@ x `=> y `=> x `+ y //│ Type: CodeBase[out ('x, 'y, 'z) -> 'cde, ⊥, ?] //│ Where: //│ 'x <: Int -//│ 'x#Int ∨ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'x#Int ∨ 'cde1#Int ∨ 'y#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'x#Int ∨ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ //│ 'x <: 'cde1 //│ 'cde1 <: ¬(¬{Int}) -//│ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ ∧ 'cde2<:Int +//│ 'cde1#Int ∨ 'y#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'y <: Int //│ 'y <: 'cde2 -//│ 'cde3#'cde3 ∨ ( 'cde3#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥ ∧ 'cde4<:Int) ∧ 'cde3<:Int +//│ 'cde2 <: ¬(¬{Int}) +//│ 'cde3#'cde3 ∨ ( 'cde3#Int ∨ 'z#Int ∨ 'cde4#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥) ∧ ( 'cde3#Int ∨ 'cde4#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥) ∧ {0: 'cde3, 1: 'cde4}<:{0: Int, 1: Int} //│ 'z <: 'cde4 //│ 'app1 <: ¬(¬'cde) //│ 'app <: ¬(¬'cde3) @@ -90,16 +103,16 @@ f `=> x `=> y `=> f`(x, y) :e `let x = 42 `in x //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.91: `let x = 42 `in x -//│ ║ ^^ +//│ ║ l.104: `let x = 42 `in x +//│ ║ ^^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'cde, out 'ctx, ?] //│ Type: CodeBase[⊥, ⊥, ?] :e `let x = `0 `in 1 //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.99: `let x = `0 `in 1 -//│ ║ ^ +//│ ║ l.112: `let x = `0 `in 1 +//│ ║ ^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'cde, out 'ctx, ?] //│ Type: CodeBase[⊥, ⊥, ?] @@ -112,6 +125,13 @@ f `=> x `=> y `=> f`(x, y) x `=> `if x `== `0.0 then `1.0 else x //│ Type: CodeBase[out 'x -> ('x ∨ Num), ⊥, ?] +//│ Where: +//│ 'x#⊤ ∨ 'cde#⊤ ∨ ∧ Bool<:'app ∧ ⊥<:⊥ ∧ 'cde<:'T ∧ 'cde1<:'T +//│ 'x <: 'cde +//│ 'cde#⊤ ∨ ∧ Bool<:'app ∧ ⊥<:⊥ ∧ 'cde<:'T ∧ 'cde1<:'T +//│ Num <: 'cde1 +//│ 'cde2 <: ¬(¬{Bool}) +//│ 'app <: ¬(¬'cde2) run(`1) //│ Type: Int @@ -120,7 +140,7 @@ run(`1) :e run(1) //│ ╔══[ERROR] Type error in integer literal with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.121: run(1) +//│ ║ l.141: run(1) //│ ║ ^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'T, ⊥, ?] //│ Type: ⊥ @@ -128,7 +148,7 @@ run(1) :e x `=> run(x) //│ ╔══[ERROR] Type error in reference with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.129: x `=> run(x) +//│ ║ l.149: x `=> run(x) //│ ║ ^ //│ ╟── because: cannot constrain CodeBase['x, x, ⊥] <: CodeBase[out 'T, ⊥, ?] //│ ╙── because: cannot constrain x <: ⊥ @@ -137,12 +157,12 @@ x `=> run(x) :e `let x = `42 `in run(x) //│ ╔══[ERROR] Type error in reference with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.138: `let x = `42 `in run(x) +//│ ║ l.158: `let x = `42 `in run(x) //│ ║ ^ //│ ╟── because: cannot constrain CodeBase['cde, x, ⊥] <: CodeBase[out 'T, ⊥, ?] //│ ╙── because: cannot constrain x <: ⊥ //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.138: `let x = `42 `in run(x) +//│ ║ l.158: `let x = `42 `in run(x) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain 'T <: CodeBase[out 'cde1, out 'ctx, ?] //│ ╟── because: cannot constrain 'T <: ¬(¬{CodeBase[out 'cde1, out 'ctx, ?]}) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls index 511e31f6ff..469aa33f31 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls @@ -37,9 +37,9 @@ fun f(x) = f(x) f //│ Type: ['x, 'eff, 'app] -> 'x ->{'eff} 'app //│ Where: -//│ 'x#'x ∨ ( 'x#'x ∨ ∧ 'app<:'app ∧ 'eff<:'eff) ∧ 'x<:'x +//│ 'x#'x ∨ ( 'x#⊤ ∨ ∧ 'app<:'app ∧ 'eff<:'eff ∧ 'x<:'x) ∧ {0: 'x}<:{0: ⊤} + -:todo fun f(x) = f(x.a) //│ Type: ⊤ @@ -70,7 +70,7 @@ fun f(x) = f(x.Foo#a) f //│ Type: ['x, 'A, 'eff, 'app] -> Foo[out 'A] ->{'eff} 'app //│ Where: -//│ 'A#'A ∨ ∧ 'A<:'x ∧ 'app<:'app ∧ 'eff<:'eff +//│ 'A#'A ∨ ( 'A#⊤ ∨ ∧ 'app<:'app ∧ 'eff<:'eff ∧ 'A<:'x) ∧ {0: 'A}<:{0: ⊤} //│ 'x <: Foo[out 'A] diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index 9022b1d3b9..2b4752b65e 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -36,7 +36,7 @@ x => //│ Type: ('x) ->{'eff} 'app //│ Where: //│ 'x <: Int -//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ 'x<:Int ∨ Bool +//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ {0: 'x}<:{0: Int} ∨ {0: Bool} (x: Int) => let y = x + 1 @@ -62,13 +62,13 @@ ap(idIB)(1) x => idIB(x) //│ Type: ('x) ->{'eff} 'app //│ Where: -//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ 'x<:Int ∨ Bool +//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ {0: 'x}<:{0: Int} ∨ {0: Bool} fun forward(x) = idIB(x) forward //│ Type: ['x, 'eff, 'app] -> 'x ->{'eff} 'app //│ Where: -//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ 'x<:Int ∨ Bool +//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ {0: 'x}<:{0: Int} ∨ {0: Bool} forward(1) //│ Type: Int @@ -116,10 +116,44 @@ new Pair(1, 2) fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) //│ Type: ⊤ +:e idIIBB(new Pair(1, 2)) +//│ ╔══[ERROR] Type error in application +//│ ║ l.120: idIIBB(new Pair(1, 2)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app +//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] ∧ ¬⊥ +//│ ╟── because: cannot constrain 'A <: Bool +//│ ╟── because: cannot constrain 'A <: ¬(¬{Bool}) +//│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) +//│ ╔══[ERROR] Type error in application +//│ ║ l.120: idIIBB(new Pair(1, 2)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app +//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] ∧ ¬⊥ +//│ ╟── because: cannot constrain 'B <: Bool +//│ ╟── because: cannot constrain 'B <: ¬(¬{Bool}) +//│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) //│ Type: Bool ∨ Int +:e idIIBB(new Pair(1, true)) +//│ ╔══[ERROR] Type error in application +//│ ║ l.140: idIIBB(new Pair(1, true)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app +//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Int, in ⊥ out Int] ∧ ¬⊥ +//│ ╟── because: cannot constrain 'B <: Int +//│ ╟── because: cannot constrain 'B <: ¬(¬{Int}) +//│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) +//│ ╔══[ERROR] Type error in application +//│ ║ l.140: idIIBB(new Pair(1, true)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app +//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] ∧ ¬⊥ +//│ ╟── because: cannot constrain 'A <: Bool +//│ ╟── because: cannot constrain 'A <: ¬(¬{Bool}) +//│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) //│ Type: Bool ∨ Int @@ -127,7 +161,7 @@ idIIBB(new Pair(1, true)) :todo fun foo: ["x": Int, "y": Int] //│ ╔══[ERROR] Invalid type -//│ ║ l.128: fun foo: ["x": Int, "y": Int] +//│ ║ l.162: fun foo: ["x": Int, "y": Int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -164,13 +198,11 @@ k(idIB)(true, 1) :e k(idIB)("true", 1) //│ ╔══[ERROR] Type error in string literal with expected type 'x -//│ ║ l.165: k(idIB)("true", 1) +//│ ║ l.199: k(idIB)("true", 1) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Str <: 'x //│ ╟── because: cannot constrain Str <: 'x -//│ ╟── because: cannot constrain 'x <: Int ∨ Bool -//│ ╟── because: cannot constrain 'x <: ¬(¬{Int ∨ Bool}) -//│ ╙── because: cannot constrain Str <: ¬(¬{Int ∨ Bool}) +//│ ╙── because: cannot constrain {0: 'x} <: {0: Int} ∨ {0: Bool} //│ Type: {a: ⊥, b: Int} (x => x.x + idIB(x.y)) of (x:0, y:1) @@ -193,7 +225,7 @@ fun map = x => f => x.Ls#prim(() => nil(), (a, b) => cons(f(a), map(b)(f))) x => map(x)(idIB) //│ Type: (Ls['A]) ->{⊥} Ls['B] //│ Where: -//│ 'A#'A ∨ ( 'A#Int ∨ ∧ Int<:'B ∧ ⊥<:⊥) ∧ ( 'A#Bool ∨ ∧ Bool<:'B ∧ ⊥<:⊥) ∧ 'A<:Int ∨ Bool +//│ 'A#'A ∨ ( 'A#Int ∨ ∧ Int<:'B ∧ ⊥<:⊥) ∧ ( 'A#Bool ∨ ∧ Bool<:'B ∧ ⊥<:⊥) ∧ {0: 'A}<:{0: Int} ∨ {0: Bool} map(nil())(idIB) //│ Type: Ls['B] @@ -216,25 +248,28 @@ map(cons(1, cons(true, nil())))(idIB) let x = cons(1, cons(true, nil())) in map(cons(x, x))(idIB) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.217: map(cons(x, x))(idIB) +//│ ║ l.249: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B +//│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} //│ ╟── because: cannot constrain 'A <: Int ∨ Bool //│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.217: map(cons(x, x))(idIB) +//│ ║ l.249: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B +//│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} //│ ╟── because: cannot constrain 'A <: Int ∨ Bool //│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) //│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) //│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.217: map(cons(x, x))(idIB) +//│ ║ l.249: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B +//│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} //│ ╟── because: cannot constrain 'A <: Int ∨ Bool //│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) //│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) @@ -244,3 +279,17 @@ let x = cons(1, cons(true, nil())) in //│ Where: //│ Bool <: 'B //│ Int <: 'B + +fun k: ((Int | Str, Int) -> Int) & ((Bool | Str, Bool) -> Bool) +//│ Type: ⊤ + +k("", if true then 1 else true) +//│ Type: Bool ∨ Int + +fun k: ((Int, Int) -> Int) & ((Bool, Bool) -> Bool) +//│ Type: ⊤ + +x => k(x, x) +//│ Type: ('x) ->{'eff} 'app +//│ Where: +//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ {0: 'x, 1: 'x}<:{0: Int, 1: Int} ∨ {0: Bool, 1: Bool} From bd53f6f871710cad34f9db7f8d924ae0729703f2 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:50:35 +0800 Subject: [PATCH 15/36] intersections wf check --- .../scala/hkmc2/bbml/ConstraintSolver.scala | 40 +++---- .../src/main/scala/hkmc2/bbml/bbML.scala | 19 ++- .../src/test/mlscript/logicsub/DisjSub.mls | 110 +++++++++++++++--- 3 files changed, 135 insertions(+), 34 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index cadc8917b5..1bc0ab8af2 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -117,27 +117,27 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, k.foreach(k => constrainImpl(um(k), wm(k))) else cctx.err case (Inter(S(u: RcdType)), Union(f, Nil, rs@(RcdType(w) :: _))) => - val um = u.fields.toMap val k = w.keys.toSet - if k.subsetOf(um.keySet) then - val r = RcdType(um.filterKeys(k(_)).toList) - rs.filter(w => Type.disjoint(w, r).isEmpty) match - case Nil => cctx.err - case w :: Nil => constrainImpl(u, w) - case ws@(RcdType(w) :: RcdType(z) :: _) => - val (wm, zm) = (w.toMap, z.toMap) - k.filter(k => Type.disjoint(wm(k), zm(k)) === S(Set.empty)).toList match - case Nil => ??? - case k :: Nil => - val (ku, i) = ws.foldLeft((Bot: Type, RcdType(Nil))): - case ((ku, i), RcdType(w)) => - val (a :: _, b) = w.partition(_._1 === k) - (ku | a._2, i & RcdType(b)) - constrainImpl(um(k), ku) - constrainImpl(u, i) - case _ => - constrainImpl(u, ws.reduce(_ & _)) - else cctx.err + val r = RcdType(u.fields.filter(p => k(p._1))) + val ws = rs.foldLeft(Nil): (x, w) => + val d = Type.disjoint(w, r) + if d === S(Set.empty) then x else Ls(d -> w) ++ x + ws match + case Nil => cctx.err + case (_, w) :: Nil => constrainImpl(u, w) + case ((_, RcdType(w)) :: (_, RcdType(z)) :: _) => + val (wm, zm) = (w.toMap, z.toMap) + val dk = k.find(k => Type.disjoint(wm(k), zm(k)) === S(Set.empty)).get + val ku = ws.foldLeft(Bot: Type): + case (ku, (_, w)) => ku | w.fields.find(_._1 === dk).get._2 + ws.foreach: + case (S(k), w) => k.foreach: k => + DisjSub(mutable.LinkedHashSet.from(k), Nil, Ls(u -> RcdType(w.fields.filter(_._1 =/= k)))).commit() + case _ => + constrainImpl(r.fields.find(_._1 === dk).get._2, ku) + ws.foreach: + case (N, w) => constrainImpl(u, RcdType(w.fields.filter(_._1 =/= dk))) + case _ => case (Inter(S(fs: Ls[FunType])), Union(S(FunType(args2, ret2, eff2)), Nil, Nil)) => val k = args2.flatMap(x => Type.disjoint(x, x)) if k.forall(_.nonEmpty) then diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index 2447365810..09a3d370ca 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -162,7 +162,24 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case Neg(rhs) => mono(rhs, !pol).! case CompType(lhs, rhs, pol) => - Type.mkComposedType(typeMonoType(lhs), typeMonoType(rhs), pol) + val (l, r) = (typeMonoType(lhs), typeMonoType(rhs)) + if !pol then + val lfa = l.toDnf.conjs.flatMap(_.i.v).collect: + case (f :: fs) => + val fd = Type.discriminant(f.args)._1 + fs.foldLeft(fd: Type, fd.fields.keys.toSet): (x, y) => + val d = Type.discriminant(y.args)._1 + (x._1 | d, x._2 & d.fields.keys.toSet) + val rfa = r.toDnf.conjs.flatMap(_.i.v).collect: + case (f :: fs) => + val fd = Type.discriminant(f.args)._1 + fs.foldLeft(fd: Type, fd.fields.keys.toSet): (x, y) => + val d = Type.discriminant(y.args)._1 + (x._1 | d, x._2 & d.fields.keys.toSet) + val d = lfa.iterator.flatMap(x => rfa.iterator.map(y => (x, y))).exists: + case ((x, u), (y, w)) => (u & w).isEmpty || Type.disjoint(x, y) =/= S(Set.empty) + if d then error(msg"Ill-formed functions intersection" -> ty.toLoc :: Nil) + Type.mkComposedType(l, r, pol) case _ => ty.symbol.flatMap(_.asTpe) match case S(cls: (ClassSymbol | TypeAliasSymbol)) => typeAndSubstType(Term.TyApp(ty, Nil), pol) diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index 2b4752b65e..28b97509aa 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -114,12 +114,15 @@ new Pair(1, 2) :todo // WF check on intersection types :e fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) +//│ ╔══[ERROR] Ill-formed functions intersection +//│ ║ l.116: fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ :e idIIBB(new Pair(1, 2)) //│ ╔══[ERROR] Type error in application -//│ ║ l.120: idIIBB(new Pair(1, 2)) +//│ ║ l.123: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] ∧ ¬⊥ @@ -127,7 +130,7 @@ idIIBB(new Pair(1, 2)) //│ ╟── because: cannot constrain 'A <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) //│ ╔══[ERROR] Type error in application -//│ ║ l.120: idIIBB(new Pair(1, 2)) +//│ ║ l.123: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] ∧ ¬⊥ @@ -139,7 +142,7 @@ idIIBB(new Pair(1, 2)) :e idIIBB(new Pair(1, true)) //│ ╔══[ERROR] Type error in application -//│ ║ l.140: idIIBB(new Pair(1, true)) +//│ ║ l.143: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Int, in ⊥ out Int] ∧ ¬⊥ @@ -147,7 +150,7 @@ idIIBB(new Pair(1, true)) //│ ╟── because: cannot constrain 'B <: ¬(¬{Int}) //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in application -//│ ║ l.140: idIIBB(new Pair(1, true)) +//│ ║ l.143: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] ∧ ¬⊥ @@ -161,7 +164,7 @@ idIIBB(new Pair(1, true)) :todo fun foo: ["x": Int, "y": Int] //│ ╔══[ERROR] Invalid type -//│ ║ l.162: fun foo: ["x": Int, "y": Int] +//│ ║ l.165: fun foo: ["x": Int, "y": Int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -198,11 +201,14 @@ k(idIB)(true, 1) :e k(idIB)("true", 1) //│ ╔══[ERROR] Type error in string literal with expected type 'x -//│ ║ l.199: k(idIB)("true", 1) +//│ ║ l.202: k(idIB)("true", 1) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Str <: 'x //│ ╟── because: cannot constrain Str <: 'x -//│ ╙── because: cannot constrain {0: 'x} <: {0: Int} ∨ {0: Bool} +//│ ╟── because: cannot constrain {0: 'x} <: {0: Int} ∨ {0: Bool} +//│ ╟── because: cannot constrain 'x <: Bool ∨ Int +//│ ╟── because: cannot constrain 'x <: ¬(¬{Int ∨ Bool}) +//│ ╙── because: cannot constrain Str <: ¬(¬{Int ∨ Bool}) //│ Type: {a: ⊥, b: Int} (x => x.x + idIB(x.y)) of (x:0, y:1) @@ -248,29 +254,29 @@ map(cons(1, cons(true, nil())))(idIB) let x = cons(1, cons(true, nil())) in map(cons(x, x))(idIB) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.249: map(cons(x, x))(idIB) +//│ ║ l.255: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} -//│ ╟── because: cannot constrain 'A <: Int ∨ Bool +//│ ╟── because: cannot constrain 'A <: Bool ∨ Int //│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.249: map(cons(x, x))(idIB) +//│ ║ l.255: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} -//│ ╟── because: cannot constrain 'A <: Int ∨ Bool +//│ ╟── because: cannot constrain 'A <: Bool ∨ Int //│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) //│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) //│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.249: map(cons(x, x))(idIB) +//│ ║ l.255: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} -//│ ╟── because: cannot constrain 'A <: Int ∨ Bool +//│ ╟── because: cannot constrain 'A <: Bool ∨ Int //│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) //│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) //│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) @@ -293,3 +299,81 @@ x => k(x, x) //│ Type: ('x) ->{'eff} 'app //│ Where: //│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ {0: 'x, 1: 'x}<:{0: Int, 1: Int} ∨ {0: Bool, 1: Bool} + +:e +fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) +//│ ╔══[ERROR] Ill-formed functions intersection +//│ ║ l.304: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ + +:e +fun id: [A] -> (A -> A) & (Int -> Int) +//│ ╔══[ERROR] Ill-formed functions intersection +//│ ║ l.311: fun id: [A] -> (A -> A) & (Int -> Int) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ + +fun fst: [A] -> (Pair[A, Int] -> Pair[A, Int]) & (Ls[A] -> A) +//│ Type: ⊤ + +fst(new Pair(true, 1)) +//│ Type: Pair[out Bool, out Int] + +fst(cons(1, nil())) +//│ Type: Int + +:e +fun idInt: (Int -> Int) & (Int -> Int) +//│ ╔══[ERROR] Ill-formed functions intersection +//│ ║ l.327: fun idInt: (Int -> Int) & (Int -> Int) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ + +fun wf: ((Int | Bool -> Int) | (Bool -> Bool)) & (Str -> Str) +//│ Type: ⊤ + +wf("") +//│ Type: Str + +wf(true) +//│ Type: Bool ∨ Int + +:e +wf(1) +//│ ╔══[ERROR] Type error in application +//│ ║ l.343: wf(1) +//│ ║ ^^^^^ +//│ ╟── because: cannot constrain (((Int ∨ Bool) -> Int) ∨ (Bool -> Bool)) ∧ (Str -> Str) <: Int ->{'eff} 'app +//│ ╙── because: cannot constrain {0: Int} <: {0: Bool} ∨ {0: Str} +//│ Type: Int + +class + Z() + S() +//│ Type: ⊤ + +fun wf: ((Z, Z) -> Z) & ((Z, S) -> S) & ((S, Z | S) -> S) +//│ Type: ⊤ + +let zs = if true then new Z() else new S() +zs +//│ Type: Z ∨ S + +:e +wf(zs, zs) +//│ ╔══[ERROR] Type error in application +//│ ║ l.364: wf(zs, zs) +//│ ║ ^^^^^^^^^^ +//│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: (Z ∨ S, Z ∨ S) ->{'eff} 'app +//│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} +//│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: {1: S} +//│ ╙── because: cannot constrain Z ∨ S <: S +//│ ╔══[ERROR] Type error in application +//│ ║ l.364: wf(zs, zs) +//│ ║ ^^^^^^^^^^ +//│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: (Z ∨ S, Z ∨ S) ->{'eff} 'app +//│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} +//│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: {1: Z} +//│ ╙── because: cannot constrain Z ∨ S <: Z +//│ Type: S ∨ Z From 92dc44a190c0f6296cc8fd4a70aae434a45df097 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 27 Mar 2025 03:00:17 +0800 Subject: [PATCH 16/36] fix nested record wf check --- .../src/main/scala/hkmc2/bbml/bbML.scala | 87 ++++++++++--------- .../src/main/scala/hkmc2/bbml/types.scala | 7 +- .../src/test/mlscript/logicsub/DisjSub.mls | 82 ++++++++++------- .../src/test/mlscript/logicsub/Records.mls | 84 ++++++++++++++++++ 4 files changed, 190 insertions(+), 70 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/logicsub/Records.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index 09a3d370ca..53b450efc1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -159,6 +159,13 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): ClassLikeType(tpeSym, ts) case N => error(msg"Not a valid class: ${cls.describe}" -> cls.toLoc :: Nil) + case Term.Tup(fields) => + // TODO + // denote record type by Tup for now + val u = fields.map: + case Fld(_, Lit(StrLit(a)), S(t)) => (a, typeMonoType(t)) + case _ => ??? + RcdType(u) case Neg(rhs) => mono(rhs, !pol).! case CompType(lhs, rhs, pol) => @@ -430,7 +437,37 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case ft: PolyFunType => ft.monoOr(error(msg"Expected a monomorphic type or an instantiable type here, but ${ty.show} found" -> sc.toLoc :: Nil)) case ty: Type => ty - + + def goStats(stats: Ls[Statement])(using ctx: BbCtx, scope: Scope, cctx: CCtx, effBuff: ListBuffer[Type]): Unit = stats match + case Nil => () + case (term: Term) :: stats => + effBuff += typeCheck(term)._2 + goStats(stats) + case LetDecl(sym, _) :: DefineVar(sym2, rhs) :: stats => + require(sym2 is sym) + val (rhsTy, eff) = typeCheck(rhs) + effBuff += eff + ctx += sym -> rhsTy + goStats(stats) + case TermDefinition(_, Fun, sym, ps :: Nil, _, sig, S(body), _, _, _) :: stats => + typeFunDef(sym, Term.Lam(ps, body), sig, ctx) + goStats(stats) + case TermDefinition(_, Fun, sym, Nil, _, sig, S(body), _, _, _) :: stats => + typeFunDef(sym, body, sig, ctx) // * may be a case expressions + goStats(stats) + case TermDefinition(_, Fun, sym1, _, _, S(sig), None, _, _, _) :: (td @ TermDefinition(_, Fun, sym2, _, _, _, S(body), _, _, _)) :: stats + if sym1 === sym2 => goStats(td :: stats) // * avoid type check signatures twice + case TermDefinition(_, Fun, sym, _, _, S(sig), None, _, _, _) :: stats => + ctx += sym -> typeType(sig) + goStats(stats) + case (clsDef: ClassDef) :: stats => + goStats(stats) + case (modDef: ModuleDef) :: stats => + goStats(stats) + case Import(sym, pth) :: stats => + goStats(stats) // TODO: + case stat :: _ => + TODO(stat) private def typeCheck(t: Term)(using ctx: BbCtx, scope: Scope): (GeneralType, Type) = trace[(GeneralType, Type)](s"${ctx.lvl}. Typing ${t.showDbg}", res => s": (${res._1.showDbg}, ${res._2.showDbg})"): given CCtx = CCtx.init(t, N) @@ -447,38 +484,8 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): (error(msg"Variable not found: ${sym.nme}" -> t.toLoc :: Nil), Bot) case Blk(stats, res) => - val effBuff = ListBuffer.empty[Type] - def goStats(stats: Ls[Statement]): Unit = stats match - case Nil => () - case (term: Term) :: stats => - effBuff += typeCheck(term)._2 - goStats(stats) - case LetDecl(sym, _) :: DefineVar(sym2, rhs) :: stats => - require(sym2 is sym) - val (rhsTy, eff) = typeCheck(rhs) - effBuff += eff - ctx += sym -> rhsTy - goStats(stats) - case TermDefinition(_, Fun, sym, ps :: Nil, _, sig, S(body), _, _, _) :: stats => - typeFunDef(sym, Term.Lam(ps, body), sig, ctx) - goStats(stats) - case TermDefinition(_, Fun, sym, Nil, _, sig, S(body), _, _, _) :: stats => - typeFunDef(sym, body, sig, ctx) // * may be a case expressions - goStats(stats) - case TermDefinition(_, Fun, sym1, _, _, S(sig), None, _, _, _) :: (td @ TermDefinition(_, Fun, sym2, _, _, _, S(body), _, _, _)) :: stats - if sym1 === sym2 => goStats(td :: stats) // * avoid type check signatures twice - case TermDefinition(_, Fun, sym, _, _, S(sig), None, _, _, _) :: stats => - ctx += sym -> typeType(sig) - goStats(stats) - case (clsDef: ClassDef) :: stats => - goStats(stats) - case (modDef: ModuleDef) :: stats => - goStats(stats) - case Import(sym, pth) :: stats => - goStats(stats) // TODO: - case stat :: _ => - TODO(stat) - goStats(stats) + val effBuff: ListBuffer[Type] = ListBuffer.empty + goStats(stats)(using effBuff = effBuff) val (ty, eff) = typeCheck(res) (ty, effBuff.foldLeft(eff)((res, e) => res | e)) case UnitVal() => (Top, Bot) @@ -597,19 +604,19 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): (Bot, eff) case Term.Error => (Bot, Bot) // TODO: error type? - case Rcd(fields@((_: RcdField) :: _)) => - val u = fields.collect: - case RcdField(Lit(StrLit(a)), t) => (a, t, typeCheck(t)) - val (w, e) = u.foldRight((Nil: Ls[Str -> Type], Bot: Type)): - case ((a, t, (ty, e)), (w, e0)) => ((a -> tryMkMono(ty, t) :: w), e | e0) - (RcdType(w), e) case Rcd(stats) => // TODO RcdSpread val (s, r) = stats.partitionMap: k => k match case RcdField(Lit(_: StrLit), _) => R(k) case _ => L(k) - typeCheck(Blk(s, Rcd(r))) + val effBuff: ListBuffer[Type] = ListBuffer.empty + goStats(s)(using effBuff = effBuff) + val u = r.map: + case RcdField(Lit(StrLit(a)), t) => (a, t, typeCheck(t)) + val (w, eff) = u.foldRight((Nil: Ls[Str -> Type], Bot: Type)): + case ((a, t, (ty, e)), (w, e0)) => ((a -> tryMkMono(ty, t) :: w), e | e0) + (RcdType(w), effBuff.foldLeft(eff)((res, e) => res | e)) case Term.Sel(u, Ident(a)) => val (ty, e) = typeCheck(u) val v = freshVar(new TempSymbol(S(t), "sel")) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 249b80d3fb..0e9fa6d974 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -273,6 +273,11 @@ case class RcdType(fields: Ls[Str -> Type]) extends BasicType with CachedNorm[Rc RcdType(fields.mapValues(_.subst)) def & (that: RcdType): RcdType = RcdType((fields ++ that.fields).groupMapReduce(_._1)(_._2)(_ & _).toList) + def flatten: RcdType = + RcdType(fields.flatMap: u => + (u._1, u._2.toBasic.simp.toBasic) match + case (a, r: RcdType) => r.flatten.fields.map(u => (s"$a.${u._1}", u._2)) + case u => Ls(u)) case class ComposedType(lhs: Type, rhs: Type, pol: Bool) extends BasicType: // * Positive -> union override def subst(using map: Map[Uid[InfVar], InfVar]): ThisType = @@ -296,7 +301,7 @@ object Type: else lhs & rhs def mkNegType(ty: Type): Type = ty.! def discriminant(a: Ls[Type]): (RcdType, RcdType) = - discriminantRcd(RcdType(a.zipWithIndex.map(u => (s"${u._2}", u._1.toBasic)))) + discriminantRcd(RcdType(a.zipWithIndex.map(u => (s"${u._2}", u._1.toBasic))).flatten) def discriminantRcd(a: RcdType): (RcdType, RcdType) = val (u, w) = (a.fields.map: case (a, t) => diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index 28b97509aa..35d6030f09 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -58,7 +58,6 @@ ap1(idIB) ap(idIB)(1) //│ Type: Int -:todo x => idIB(x) //│ Type: ('x) ->{'eff} 'app //│ Where: @@ -80,17 +79,17 @@ forward(true) :todo // BbML fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╔══[ERROR] General type is not allowed here. -//│ ║ l.81: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) +//│ ║ l.80: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╙── ^^^ //│ ╔══[ERROR] General type is not allowed here. -//│ ║ l.81: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) +//│ ║ l.80: fun idIIBB: ([Int, Int] -> Int) & ([Bool, Bool] -> Bool) //│ ╙── ^^^^ //│ Type: ⊤ :todo // BbML idIIBB([1, 2]) //│ ╔══[ERROR] Term shape not yet supported by BbML: Tup(List(Fld(‹›,Lit(IntLit(1)),None), Fld(‹›,Lit(IntLit(2)),None))) -//│ ║ l.91: idIIBB([1, 2]) +//│ ║ l.90: idIIBB([1, 2]) //│ ╙── ^^^^^^ //│ Type: ⊥ @@ -111,29 +110,29 @@ new Pair(1, 2) //│ Int <: 'A //│ Int <: 'B -:todo // WF check on intersection types +// WF check on intersection types :e fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.116: fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) +//│ ║ l.115: fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ :e idIIBB(new Pair(1, 2)) //│ ╔══[ERROR] Type error in application -//│ ║ l.123: idIIBB(new Pair(1, 2)) +//│ ║ l.122: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app -//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] ∧ ¬⊥ +//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] //│ ╟── because: cannot constrain 'A <: Bool //│ ╟── because: cannot constrain 'A <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) //│ ╔══[ERROR] Type error in application -//│ ║ l.123: idIIBB(new Pair(1, 2)) +//│ ║ l.122: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app -//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] ∧ ¬⊥ +//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] //│ ╟── because: cannot constrain 'B <: Bool //│ ╟── because: cannot constrain 'B <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) @@ -142,18 +141,18 @@ idIIBB(new Pair(1, 2)) :e idIIBB(new Pair(1, true)) //│ ╔══[ERROR] Type error in application -//│ ║ l.143: idIIBB(new Pair(1, true)) +//│ ║ l.142: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app -//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Int, in ⊥ out Int] ∧ ¬⊥ +//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Int, in ⊥ out Int] //│ ╟── because: cannot constrain 'B <: Int //│ ╟── because: cannot constrain 'B <: ¬(¬{Int}) //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in application -//│ ║ l.143: idIIBB(new Pair(1, true)) +//│ ║ l.142: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app -//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] ∧ ¬⊥ +//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] //│ ╟── because: cannot constrain 'A <: Bool //│ ╟── because: cannot constrain 'A <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) @@ -163,13 +162,10 @@ idIIBB(new Pair(1, true)) :todo fun foo: ["x": Int, "y": Int] -//│ ╔══[ERROR] Invalid type -//│ ║ l.165: fun foo: ["x": Int, "y": Int] -//│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ foo -//│ Type: ⊥ +//│ Type: {x: Int, y: Int} :todo fun foo(x) = if x is @@ -177,7 +173,7 @@ fun foo(x) = if x is [false, false] then 2 //│ /!!!\ Uncaught error: scala.MatchError: Tuple(2,false) (of class hkmc2.semantics.Pattern$Tuple) -{x:1, y:true} +{x: 1, y:true} //│ Type: {x: Int, y: Bool} fun k(f) = @@ -201,7 +197,7 @@ k(idIB)(true, 1) :e k(idIB)("true", 1) //│ ╔══[ERROR] Type error in string literal with expected type 'x -//│ ║ l.202: k(idIB)("true", 1) +//│ ║ l.198: k(idIB)("true", 1) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Str <: 'x //│ ╟── because: cannot constrain Str <: 'x @@ -254,7 +250,7 @@ map(cons(1, cons(true, nil())))(idIB) let x = cons(1, cons(true, nil())) in map(cons(x, x))(idIB) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.255: map(cons(x, x))(idIB) +//│ ║ l.251: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -262,7 +258,7 @@ let x = cons(1, cons(true, nil())) in //│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.255: map(cons(x, x))(idIB) +//│ ║ l.251: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -272,7 +268,7 @@ let x = cons(1, cons(true, nil())) in //│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.255: map(cons(x, x))(idIB) +//│ ║ l.251: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -303,14 +299,14 @@ x => k(x, x) :e fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.304: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) +//│ ║ l.300: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ :e fun id: [A] -> (A -> A) & (Int -> Int) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.311: fun id: [A] -> (A -> A) & (Int -> Int) +//│ ║ l.307: fun id: [A] -> (A -> A) & (Int -> Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -326,7 +322,7 @@ fst(cons(1, nil())) :e fun idInt: (Int -> Int) & (Int -> Int) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.327: fun idInt: (Int -> Int) & (Int -> Int) +//│ ║ l.323: fun idInt: (Int -> Int) & (Int -> Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -342,7 +338,7 @@ wf(true) :e wf(1) //│ ╔══[ERROR] Type error in application -//│ ║ l.343: wf(1) +//│ ║ l.339: wf(1) //│ ║ ^^^^^ //│ ╟── because: cannot constrain (((Int ∨ Bool) -> Int) ∨ (Bool -> Bool)) ∧ (Str -> Str) <: Int ->{'eff} 'app //│ ╙── because: cannot constrain {0: Int} <: {0: Bool} ∨ {0: Str} @@ -363,17 +359,45 @@ zs :e wf(zs, zs) //│ ╔══[ERROR] Type error in application -//│ ║ l.364: wf(zs, zs) +//│ ║ l.360: wf(zs, zs) //│ ║ ^^^^^^^^^^ //│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: (Z ∨ S, Z ∨ S) ->{'eff} 'app //│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} //│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: {1: S} //│ ╙── because: cannot constrain Z ∨ S <: S //│ ╔══[ERROR] Type error in application -//│ ║ l.364: wf(zs, zs) +//│ ║ l.360: wf(zs, zs) //│ ║ ^^^^^^^^^^ //│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: (Z ∨ S, Z ∨ S) ->{'eff} 'app //│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} //│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: {1: Z} //│ ╙── because: cannot constrain Z ∨ S <: Z //│ Type: S ∨ Z + +:e +fun ill: + (([a: Int, b:Int]) -> Int) & + (([b: Bool, c: Bool]) -> Bool) & + (([a: Str, c: Str]) -> Str) +//│ ╔══[ERROR] Ill-formed functions intersection +//│ ║ l.379: (([a: Int, b:Int]) -> Int) & +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.380: (([b: Bool, c: Bool]) -> Bool) & +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.381: (([a: Str, c: Str]) -> Str) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ + +:e +fun nested: + (([tag: [a: Int, b:Int]]) -> Int) & + (([tag: [b: Bool, c: Bool]]) -> Bool) & + (([tag: [a: Str, c: Str]]) -> Str) +//│ ╔══[ERROR] Ill-formed functions intersection +//│ ║ l.393: (([tag: [a: Int, b:Int]]) -> Int) & +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.394: (([tag: [b: Bool, c: Bool]]) -> Bool) & +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.395: (([tag: [a: Str, c: Str]]) -> Str) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/logicsub/Records.mls b/hkmc2/shared/src/test/mlscript/logicsub/Records.mls new file mode 100644 index 0000000000..b86a11a3bd --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/logicsub/Records.mls @@ -0,0 +1,84 @@ +:bbml +//│ Type: ⊤ + +//│ Type: ⊤ + +{} +//│ Type: ⊤ + +let r = {} +//│ Type: ⊤ + +{1} +//│ Type: Int + +{1, 2} +//│ Type: Int + +{foo: 1} +//│ Type: {foo: Int} + +let rcd = { foo: 1, bar: "..." } +//│ Type: ⊤ + +:todo +[rcd.foo, rcd.bar] +//│ ╔══[ERROR] Term shape not yet supported by BbML: Tup(List(Fld(‹›,Sel(Ref(rcd),Ident(foo)),None), Fld(‹›,Sel(Ref(rcd),Ident(bar)),None))) +//│ ║ l.25: [rcd.foo, rcd.bar] +//│ ╙── ^^^^^^^^^^^^^^^^^^ +//│ Type: ⊥ + +:todo // IntLit as label? +"0": rcd.foo +"1": rcd.bar +//│ Type: {0: Int, 1: Str} + +fun id(x) = x +//│ Type: ⊤ + +id of (x: 1) +//│ Type: {x: Int} + +:todo +id of { x: 1 } +//│ Type: Str + +id of ({ x: 1 }) +//│ Type: {x: Int} + +id of ({ x: 1, y: 2 }) +//│ Type: {x: Int, y: Int} + +id of (x: 1, y: 2) +//│ Type: {x: Int, y: Int} + +// * FIXME: handling of record arguments in resolver/checker +:fixme +id of { x: 1, y: 2 } +//│ ╔══[ERROR] Incorrect number of arguments +//│ ║ l.57: id of { x: 1, y: 2 } +//│ ╙── ^^^^^^^^^^^^^^^^^^ +//│ Type: ⊥ + +:todo +fun f(x) = + x: x.a + y: x.b +f of (a: 1, b: true) +//│ ╔══[ERROR] Type error in record with expected type 'x +//│ ║ l.67: f of (a: 1, b: true) +//│ ║ ^^^^^^^ +//│ ╟── because: cannot constrain {a: Int, b: Bool} <: 'x +//│ ╟── because: cannot constrain {a: Int, b: Bool} <: 'x +//│ ╟── because: cannot constrain {a: Int, b: Bool} <: ¬¬{a: 'sel} +//│ ╟── because: cannot constrain Int <: 'sel +//│ ╟── because: cannot constrain Int <: 'sel +//│ ╙── because: cannot constrain Int <: ¬¬{b: 'sel1} +//│ Type: {x: Int, y: ⊥} + +x: 1 +y: x +//│ Type: {x: Int, y: Int} + +(x => (x: 1, y: x))("") +//│ Type: {x: Int, y: Int} From 69bcc5ae1080d80178aaedc2960c907259275e10 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sat, 29 Mar 2025 02:07:50 +0800 Subject: [PATCH 17/36] wip refined if --- .../scala/hkmc2/bbml/ConstraintSolver.scala | 2 +- .../src/main/scala/hkmc2/bbml/bbML.scala | 162 ++++++++++-------- .../src/main/scala/hkmc2/bbml/types.scala | 23 ++- .../src/test/mlscript/bbml/bbBasics.mls | 22 ++- .../src/test/mlscript/bbml/bbExtrude.mls | 35 ++-- .../shared/src/test/mlscript/bbml/bbGPCE.mls | 28 ++- hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls | 64 +++---- .../src/test/mlscript/logicsub/DisjSub.mls | 90 +++++++--- .../test/mlscript/logicsub/MarlowWadler97.mls | 21 ++- 9 files changed, 263 insertions(+), 184 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index 1bc0ab8af2..5a6f40fd1e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -97,7 +97,7 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, cctx.nest(bd -> v) givenIn: v.state.lowerBounds ::= bd v.state.upperBounds.foreach(ub => constrainImpl(bd, ub)) - v.state.disjsub.iterator.flatMap(_.check(v)).foreach: + v.state.disjsub.toList.flatMap(_.check(v)).foreach: case (a, b) => constrainImpl(a, b) case Conj(i, u, Nil) => (conj.i, conj.u) match case (_, Union(N, Nil, Nil)) => diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index 53b450efc1..02234dbb92 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -2,7 +2,7 @@ package hkmc2 package bbml -import scala.collection.mutable.{HashSet, HashMap, ListBuffer} +import scala.collection.mutable.{HashSet, HashMap, ListBuffer, LinkedHashSet} import scala.annotation.tailrec import mlscript.utils.*, shorthands.* @@ -205,7 +205,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): lb.foreach(lb => tv.state.lowerBounds ::= typeMonoType(lb)) val lbty = tv.state.lowerBounds.foldLeft[Type](Bot)(_ | _) val ubty = tv.state.upperBounds.foldLeft[Type](Top)(_ & _) - constrain(lbty, ubty) + solver.constrain(lbty, ubty) PolyType(bds.map(_._1), S(outer), body) private def typeMonoType(ty: Term)(using ctx: BbCtx, cctx: CCtx): Type = monoOrErr(typeType(ty), ty) @@ -222,10 +222,14 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case pf @ PolyFunType(args, ret, eff) => PolyFunType(args.map(extrude(_)(using ctx, !pol)), extrude(ret), solver.extrude(eff)(using ctx.lvl, pol, HashMap.empty)) - private def constrain(lhs: Type, rhs: Type)(using ctx: BbCtx, cctx: CCtx): Unit = - solver.constrain(lhs, rhs) + trait ConstraintHandler: + def constrain(lhs: Type, rhs: Type)(using ctx: BbCtx, cctx: CCtx): Unit + def commit(ds: DisjSub): Unit - private def typeCode(code: Term)(using ctx: BbCtx, scope: Scope): (Type, Type, Type) = + private def constrain(lhs: Type, rhs: Type)(using ctx: BbCtx, cctx: CCtx, c: ConstraintHandler): Unit = + c.constrain(lhs, rhs) + + private def typeCode(code: Term)(using ctx: BbCtx, scope: Scope, c: ConstraintHandler): (Type, Type, Type) = given CCtx = CCtx.init(code, N) code match case UnitVal() => (Top, Bot, Bot) @@ -291,7 +295,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case _ => (error(msg"Cannot quote ${code.toString}" -> code.toLoc :: Nil), Bot, Bot) - private def typeFunDef(sym: Symbol, lam: Term, sig: Opt[Term], pctx: BbCtx)(using ctx: BbCtx, cctx: CCtx, scope: Scope) = lam match + private def typeFunDef(sym: Symbol, lam: Term, sig: Opt[Term], pctx: BbCtx)(using ctx: BbCtx, cctx: CCtx, scope: Scope, c: ConstraintHandler) = lam match case Term.Lam(params, body) => sig match case S(sig) => val sigTy = typeType(sig)(using ctx) @@ -311,38 +315,58 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case _ => error(msg"Function definition shape not yet supported for ${sym.nme}" -> lam.toLoc :: Nil) private def typeSplit - (split: Split, sign: Opt[GeneralType])(using ctx: BbCtx)(using CCtx, Scope) + (split: Split, sign: Opt[GeneralType])(using ctx: BbCtx, c: ConstraintHandler)(using CCtx, Scope) : (GeneralType, Type) = split match case Split.Cons(Branch(scrutinee, pattern, cons), alts) => val (scrutineeTy, scrutineeEff) = typeCheck(scrutinee) - val nestCtx1 = ctx.nest - val nestCtx2 = ctx.nest - val patTy = pattern match - case Pattern.ClassLike(sym, _, _, _) => - val (clsTy, tv, emptyTy) = sym.asCls.flatMap(_.defn) match - case S(cls) => - (ClassLikeType(sym, cls.tparams.map(_ => freshWildcard(sym))), (freshVar(new TempSymbol(S(scrutinee), "scrut"))), ClassLikeType(sym, cls.tparams.map(_ => Wildcard.empty))) - case _ => - error(msg"Cannot match ${scrutinee.toString} as ${sym.toString}" -> split.toLoc :: Nil) - (Bot, Bot, Bot) - scrutinee match // * refine - case Ref(sym: LocalSymbol) => - nestCtx1 += sym -> clsTy - nestCtx2 += sym -> tv - case _ => () // TODO: refine all variables holding this value? - clsTy | (tv & Type.mkNegType(emptyTy)) - case Pattern.Lit(lit) => lit match - case _: Tree.BoolLit => BbCtx.boolTy - case _: Tree.IntLit => BbCtx.intTy - case _: Tree.DecLit => BbCtx.numTy - case _: Tree.StrLit => BbCtx.strTy - case _: Tree.UnitLit => Top - constrain(tryMkMono(scrutineeTy, scrutinee), patTy) - val (consTy, consEff) = typeSplit(cons, sign)(using nestCtx1) - val (altsTy, altsEff) = typeSplit(alts, sign)(using nestCtx2) - val allEff = scrutineeEff | (consEff | altsEff) - (sign.getOrElse(tryMkMono(consTy, cons) | tryMkMono(altsTy, alts)), allEff) + pattern match + case Pattern.ClassLike(sym, _, _, _) => + sym.asCls.flatMap(_.defn) match + case S(cls) => + val nestCtx1 = ctx.nest + val nestCtx2 = ctx.nest + val clsTy = ClassLikeType(sym, cls.tparams.map(_ => Wildcard.empty)) + val ctv = freshVar(new TempSymbol(S(scrutinee), "scrut")) + val atv = freshVar(new TempSymbol(S(scrutinee), "scrut")) + scrutinee match // * refine + case Ref(sym: LocalSymbol) => + nestCtx1 += sym -> ctv + nestCtx2 += sym -> atv + case _ => () // TODO: refine all variables holding this value? + constrain(tryMkMono(scrutineeTy, scrutinee), (clsTy & ctv) | (clsTy.! & atv)) + val (consTy, consEff) = Type.disjoint(clsTy, ctv) match + case N => typeSplit(cons, sign)(using nestCtx1) + case S(k) => + if k.isEmpty then (Bot, Bot) + else + val cs = ListBuffer.empty[Type -> Type] + val dss = ListBuffer.empty[DisjSub] + val nc = new ConstraintHandler: + def constrain(lhs: Type, rhs: Type)(using ctx: BbCtx, cctx: CCtx) = + cs += lhs -> rhs + def commit(ds: DisjSub) = dss += ds + val eff = freshVar(new TempSymbol(N, "eff")) + val (t, e) = typeSplit(cons, sign.orElse(S(freshVar(new TempSymbol(N, "cons")))))(using nestCtx1, nc) + k.foreach(k => c.commit(DisjSub(LinkedHashSet.from(k), dss.toList, (e, eff) :: cs.toList))) + (t, eff) + val (altsTy, altsEff) = typeSplit(alts, sign)(using nestCtx2) + val allEff = scrutineeEff | (consEff | altsEff) + (sign.getOrElse(tryMkMono(consTy, cons) | tryMkMono(altsTy, alts)), allEff) + case _ => + error(msg"Cannot match ${scrutinee.toString} as ${sym.toString}" -> split.toLoc :: Nil) + (Bot, Bot) + case Pattern.Lit(lit) => + constrain(tryMkMono(scrutineeTy, scrutinee), lit match + case _: Tree.BoolLit => BbCtx.boolTy + case _: Tree.IntLit => BbCtx.intTy + case _: Tree.DecLit => BbCtx.numTy + case _: Tree.StrLit => BbCtx.strTy + case _: Tree.UnitLit => Top) + val (consTy, consEff) = typeSplit(cons, sign) + val (altsTy, altsEff) = typeSplit(alts, sign) + val allEff = scrutineeEff | (consEff | altsEff) + (sign.getOrElse(tryMkMono(consTy, cons) | tryMkMono(altsTy, alts)), allEff) case Split.Let(name, term, tail) => val nestCtx = ctx.nest given BbCtx = nestCtx @@ -357,7 +381,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case Split.End => (Bot, Bot) // * Note: currently, the returned type is not used or useful, but it could be in the future - private def ascribe(lhs: Term, rhs: GeneralType)(using ctx: BbCtx, scope: Scope): (GeneralType, Type) = + private def ascribe(lhs: Term, rhs: GeneralType)(using ctx: BbCtx, scope: Scope, c: ConstraintHandler): (GeneralType, Type) = trace[(GeneralType, Type)](s"${ctx.lvl}. Ascribing ${lhs.showDbg} : ${rhs.showDbg}", res => s"! ${res._2.showDbg}"): given CCtx = CCtx.init(lhs, S(rhs)) (lhs, rhs) match @@ -398,7 +422,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): // TODO: t -> loc when toLoc is implemented private def app(lhs: (GeneralType, Type), rhs: Ls[Elem], t: Term) - (using ctx: BbCtx)(using CCtx, Scope) + (using ctx: BbCtx, c: ConstraintHandler)(using CCtx, Scope) : (GeneralType, Type) = lhs match case (PolyFunType(params, ret, eff), lhsEff) => @@ -438,39 +462,39 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): ft.monoOr(error(msg"Expected a monomorphic type or an instantiable type here, but ${ty.show} found" -> sc.toLoc :: Nil)) case ty: Type => ty - def goStats(stats: Ls[Statement])(using ctx: BbCtx, scope: Scope, cctx: CCtx, effBuff: ListBuffer[Type]): Unit = stats match - case Nil => () - case (term: Term) :: stats => - effBuff += typeCheck(term)._2 - goStats(stats) - case LetDecl(sym, _) :: DefineVar(sym2, rhs) :: stats => - require(sym2 is sym) - val (rhsTy, eff) = typeCheck(rhs) - effBuff += eff - ctx += sym -> rhsTy - goStats(stats) - case TermDefinition(_, Fun, sym, ps :: Nil, _, sig, S(body), _, _, _) :: stats => - typeFunDef(sym, Term.Lam(ps, body), sig, ctx) - goStats(stats) - case TermDefinition(_, Fun, sym, Nil, _, sig, S(body), _, _, _) :: stats => - typeFunDef(sym, body, sig, ctx) // * may be a case expressions - goStats(stats) - case TermDefinition(_, Fun, sym1, _, _, S(sig), None, _, _, _) :: (td @ TermDefinition(_, Fun, sym2, _, _, _, S(body), _, _, _)) :: stats - if sym1 === sym2 => goStats(td :: stats) // * avoid type check signatures twice - case TermDefinition(_, Fun, sym, _, _, S(sig), None, _, _, _) :: stats => - ctx += sym -> typeType(sig) - goStats(stats) - case (clsDef: ClassDef) :: stats => - goStats(stats) - case (modDef: ModuleDef) :: stats => - goStats(stats) - case Import(sym, pth) :: stats => - goStats(stats) // TODO: - case stat :: _ => - TODO(stat) - private def typeCheck(t: Term)(using ctx: BbCtx, scope: Scope): (GeneralType, Type) = + private def typeCheck(t: Term)(using ctx: BbCtx, scope: Scope, c: ConstraintHandler): (GeneralType, Type) = trace[(GeneralType, Type)](s"${ctx.lvl}. Typing ${t.showDbg}", res => s": (${res._1.showDbg}, ${res._2.showDbg})"): given CCtx = CCtx.init(t, N) + def goStats(stats: Ls[Statement])(using effBuff: ListBuffer[Type]): Unit = stats match + case Nil => () + case (term: Term) :: stats => + effBuff += typeCheck(term)._2 + goStats(stats) + case LetDecl(sym, _) :: DefineVar(sym2, rhs) :: stats => + require(sym2 is sym) + val (rhsTy, eff) = typeCheck(rhs) + effBuff += eff + ctx += sym -> rhsTy + goStats(stats) + case TermDefinition(_, Fun, sym, ps :: Nil, _, sig, S(body), _, _, _) :: stats => + typeFunDef(sym, Term.Lam(ps, body), sig, ctx) + goStats(stats) + case TermDefinition(_, Fun, sym, Nil, _, sig, S(body), _, _, _) :: stats => + typeFunDef(sym, body, sig, ctx) // * may be a case expressions + goStats(stats) + case TermDefinition(_, Fun, sym1, _, _, S(sig), None, _, _, _) :: (td @ TermDefinition(_, Fun, sym2, _, _, _, S(body), _, _, _)) :: stats + if sym1 === sym2 => goStats(td :: stats) // * avoid type check signatures twice + case TermDefinition(_, Fun, sym, _, _, S(sig), None, _, _, _) :: stats => + ctx += sym -> typeType(sig) + goStats(stats) + case (clsDef: ClassDef) :: stats => + goStats(stats) + case (modDef: ModuleDef) :: stats => + goStats(stats) + case Import(sym, pth) :: stats => + goStats(stats) // TODO: + case stat :: _ => + TODO(stat) t match case Term.Annotated(Annot.Untyped, _) => (Bot, Bot) case sel @ Term.SynthSel(Ref(_: TopLevelSymbol), nme) @@ -626,6 +650,10 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): (error(msg"Term shape not yet supported by BbML: ${t.toString}" -> t.toLoc :: Nil), Bot) def typePurely(t: Term)(using BbCtx, Scope): GeneralType = + given ConstraintHandler = new ConstraintHandler: + def constrain(lhs: Type, rhs: Type)(using ctx: BbCtx, cctx: CCtx) = + solver.constrain(lhs, rhs) + def commit(ds: DisjSub) = ds.commit() val (ty, eff) = typeCheck(t) given CCtx = CCtx.init(t, N) constrain(eff, Bot) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 0e9fa6d974..64310bce1d 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -358,17 +358,26 @@ object Type: val u = disjointImpl(a, p.toBasic)(prev) val w = disjointImpl(a, q.toBasic)(prev) u.flatMap(u => w.map(u ++ _)) - case (a: InfVar, b: InfVar) if a.uid =/= b.uid => N + case (ComposedType(p, q, false), _) => + (disjointImpl(p.toBasic, b)(prev), disjointImpl(q.toBasic, b)(prev)) match + case (N, w) => w + case (u, N) => u + case (S(u), S(w)) => S(u.flatMap(u => w.map(u ++ _))) + case (_, ComposedType(p, q, false)) => + (disjointImpl(a, p.toBasic)(prev), disjointImpl(a, q.toBasic)(prev)) match + case (N, w) => w + case (u, N) => u + case (S(u), S(w)) => S(u.flatMap(u => w.map(u ++ _))) case (v: InfVar, _) => val p = prev + (v -> b) val k = v.state.lowerBounds.map(lb => disjointImpl(lb.toBasic, b)(p)) if k.exists(_.isEmpty) then N - else S((k.flatten.flatten.toSet + Set.empty).map(_ + (v -> b))) + else S(k.flatten.flatten.toSet + Set(v -> b)) case (_, v: InfVar) => val p = prev + (a -> v) val k = v.state.lowerBounds.map(lb => disjointImpl(a, lb.toBasic)(p)) if k.exists(_.isEmpty) then N - else S((k.flatten.flatten.toSet + Set.empty).map(_ + (v -> a))) + else S(k.flatten.flatten.toSet + Set(v -> a)) case _ => N }) else S(Set.empty) def disjoint(a: Type, b: Type): Opt[Set[Set[InfVar->BasicType]]] = @@ -502,11 +511,10 @@ case class DisjSub(disjoint: LinkedHashSet[InfVar -> BasicType], dss: Ls[DisjSub case N => disjoint -= u N - case S(k) => if k.nonEmpty then S(k) else N + case k => k if disjoint.isEmpty then dss.flatMap(_.checkAndCommit()) ++ cs else - disjoint.keys.foreach(_.state.disjsub += this) if d.nonEmpty then commit() d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => @@ -520,12 +528,11 @@ case class DisjSub(disjoint: LinkedHashSet[InfVar -> BasicType], dss: Ls[DisjSub case N => disjoint -= u N - case S(k) => if k.nonEmpty then S(k) else N + case k => k if disjoint.isEmpty then dss.flatMap(_.checkAndCommit()) ++ cs else - if disjoint.exists(_._1.uid === v.uid) then v.state.disjsub += this - else if d.nonEmpty then + if d.nonEmpty then d.foldLeft(Set(w))((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => DisjSub(LinkedHashSet.from(k), dss, cs).commit() Nil diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index c134b13674..c40957a188 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -149,7 +149,12 @@ fun foofoo(x) = if x is Int then let t = x + 1 in "foo" foofoo -//│ Type: (¬Int ∨ Int) -> Str +//│ Type: ['x, 'scrut, 'eff, 'cons] -> 'x ->{'eff} 'cons +//│ Where: +//│ 'x <: ¬Int ∨ Int +//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ 'scrut<:Int ∧ Int<:Int ∧ Str<:'cons +//│ Int ∧ 'x <: 'scrut +//│ 'scrut#Int ∨ ∧ ⊥<:'eff ∧ 'scrut<:Int ∧ Int<:Int ∧ Str<:'cons fun foofoo(x) = let t = x + 1 in "foo" @@ -175,7 +180,7 @@ f().Printer#f(42) :e f().Printer#f("oops") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.176: f().Printer#f("oops") +//│ ║ l.181: f().Printer#f("oops") //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -194,7 +199,7 @@ let ip = new Printer(foofoo) in ip.Printer#f(42) :e let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.195: let ip = new Printer(foofoo) in ip.Printer#f("42") +//│ ║ l.200: let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ║ ^^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -225,7 +230,7 @@ let tf = new TFun(inc) in tf.TFun#f(1) :e let tf = new TFun(inc) in tf.TFun#f("1") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.226: let tf = new TFun(inc) in tf.TFun#f("1") +//│ ║ l.231: let tf = new TFun(inc) in tf.TFun#f("1") //│ ║ ^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -281,7 +286,12 @@ if 1 is Foo then 0 else 1 fun test(x) = if x is Int then x + 1 else 0 test -//│ Type: (¬Int ∨ Int) -> Int +//│ Type: ['x, 'scrut, 'eff, 'cons] -> 'x ->{'eff} ('cons ∨ Int) +//│ Where: +//│ 'x <: ¬Int ∨ Int +//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ 'scrut<:Int ∧ Int<:Int ∧ Int<:'cons +//│ Int ∧ 'x <: 'scrut +//│ 'scrut#Int ∨ ∧ ⊥<:'eff ∧ 'scrut<:Int ∧ Int<:Int ∧ Int<:'cons test(1) //│ Type: Int @@ -352,7 +362,7 @@ throw new Error("oops") :e throw 42 //│ ╔══[ERROR] Type error in throw -//│ ║ l.353: throw 42 +//│ ║ l.363: throw 42 //│ ║ ^^ //│ ╙── because: cannot constrain Int <: Error //│ Type: ⊥ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls index d7acc55c98..e95eca5dcc 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls @@ -46,18 +46,13 @@ y `=> (let t = run(x `=> x `+ y) in y) //│ ╙── because: cannot constrain y <: ¬() //│ Type: CodeBase[out 'y -> 'y, ⊥, ?] //│ Where: -//│ 'y <: Int -//│ 'x#Int ∨ 'cde1#Int ∨ 'y#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ -//│ 'cde1#Int ∨ 'y#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ -//│ 'x2 <: ¬(¬{Int}) +//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'x2 <: 'x -//│ 'x <: ¬(¬{Int}) -//│ 'x#Int ∨ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'x <: 'cde1 -//│ 'cde1 <: ¬(¬{Int}) -//│ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'y <: 'cde2 -//│ 'cde2 <: ¬(¬{Int}) //│ 'cde <: 'cde3 //│ 'app <: ¬(¬'cde) @@ -75,7 +70,9 @@ g f(g) -//│ Type: ((¬C[?] ∨ C[in Int out ⊥]) ∧ (¬C[?] ∨ C[?])) ->{⊥} Int +//│ Type: ('A) ->{⊥} Int +//│ Where: +//│ 'A#C[out B] ∨ 'A#'A ∨ ( 'A#C[?] ∨ ∧ 'D<:B ∧ ⊥<:⊥ ∧ C[out B] ∧ 'A<:C[in Int out 'D]) ∧ {0: C[out B] ∧ 'A}<:{0: C[?]} fun foo: C[in Int out Nothing] foo @@ -91,16 +88,18 @@ f(g)(foo) :fixme // ??? f(g)(bar) //│ ╔══[ERROR] Type error in reference with expected type 'A -//│ ║ l.92: f(g)(bar) +//│ ║ l.89: f(g)(bar) //│ ║ ^^^ //│ ╟── because: cannot constrain C[Int] <: 'A //│ ╟── because: cannot constrain C[in Int out Int] <: 'A -//│ ╟── because: cannot constrain C[in Int out Int] <: ¬C[in ⊥ out ¬⊥ ∧ 'B] ∨ C[in Int out ¬⊥ ∧ 'D] -//│ ╟── because: cannot constrain (Int) ∧ ('B) <: ¬⊥ ∧ 'D -//│ ╟── because: cannot constrain Int ∧ 'B <: 'D -//│ ╟── because: cannot constrain Int ∧ 'B <: 'B1 -//│ ╟── because: cannot constrain Int ∧ 'B <: 'B1 -//│ ╟── because: cannot constrain Int ∧ 'B <: ¬() -//│ ╟── because: cannot constrain 'B <: ¬(Int) +//│ ╟── because: cannot constrain C[out B] ∧ 'A <: C[in Int out 'D] +//│ ╟── because: cannot constrain 'A <: ¬C[in ⊥ out ¬⊥ ∧ 'B1] ∨ C[in Int out ¬⊥ ∧ 'D1] +//│ ╟── because: cannot constrain C[in Int out Int] <: ¬C[in ⊥ out ¬⊥ ∧ 'B1] ∨ C[in Int out ¬⊥ ∧ 'D1] +//│ ╟── because: cannot constrain (Int) ∧ ('B1) <: ¬⊥ ∧ 'D1 +//│ ╟── because: cannot constrain Int ∧ 'B1 <: 'D1 +//│ ╟── because: cannot constrain Int ∧ 'B1 <: 'B2 +//│ ╟── because: cannot constrain Int ∧ 'B1 <: 'B2 +//│ ╟── because: cannot constrain Int ∧ 'B1 <: ¬() +//│ ╟── because: cannot constrain 'B1 <: ¬(Int) //│ ╙── because: cannot constrain <: ¬(Int) //│ Type: Int diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls index 2d0d93f1a2..d43e4009e6 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls @@ -17,7 +17,7 @@ fun id(x) = x run(x `=> id(x) `* x) -//│ Type: Int -> ⊥ +//│ Type: ⊤ -> ⊥ fun assertNotZero: [C] -> CodeBase[out Num, out C, out Any] -> CodeBase[out Num, out C, out Any] @@ -25,7 +25,7 @@ fun assertNotZero(x) = `if (x `== `0.0) then `error else x let checkedDiv = x `=> y `=> x `/. (assertNotZero(y)) run(checkedDiv) -//│ Type: Num -> (Num -> ⊥) +//│ Type: ⊤ -> (Num -> ⊥) @@ -38,29 +38,25 @@ show fun inc(dbg) = x `=> let c = x `+ `1 in let t = dbg(c) in c inc -//│ Type: ['x, 'cde, 'app, 'app1, 'eff, 'cde1, 'x1] -> (CodeBase[out 'app1, ?, ?] ->{'eff} ⊤) ->{'eff} CodeBase[out 'x -> 'cde1, ⊥, ?] +//│ Type: ['x, 'cde, 'cde1, 'app, 'app1, 'eff, 'cde2, 'x1] -> (CodeBase[out 'app1, ?, ?] ->{'eff} ⊤) ->{'eff} CodeBase[out 'x -> 'cde2, ⊥, ?] //│ Where: -//│ 'x <: Int //│ 'x <: 'x1 -//│ 'x1 <: Int -//│ 'x1#Int ∨ 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'x1#'cde ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde, 1: 'cde1}<:{0: Int, 1: Int} //│ 'x1 <: 'cde -//│ 'cde <: Int -//│ 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ -//│ 'cde1 <: ⊤ -//│ 'app <: 'cde1 +//│ 'cde#'cde ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde, 1: 'cde1}<:{0: Int, 1: Int} +//│ Int <: 'cde1 +//│ 'cde2 <: ⊤ +//│ 'app <: 'cde2 //│ 'app <: 'app1 inc(c => log(show(c))) //│ Type: CodeBase[out 'x -> 'cde, ⊥, ?] //│ Where: -//│ 'x1 <: Int //│ 'x1 <: 'x -//│ 'x <: Int -//│ 'x#Int ∨ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'x#'cde1 ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'x <: 'cde1 -//│ 'cde1 <: Int -//│ 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'cde1#'cde1 ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ Int <: 'cde2 //│ 'cde <: ⊤ //│ 'app <: 'cde //│ 'app <: 'app1 @@ -87,7 +83,7 @@ fun body(x, y) = case 1 then y n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] //│ ╔══[ERROR] Type error in application with expected type CodeBase[out Int, out G, ?] -//│ ║ l.88: n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] +//│ ║ l.84: n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain CodeBase[out 'cde, out 'ctx ∨ 'ctx1, ?] <: CodeBase[out Int, out G, ?] //│ ╟── because: cannot constrain 'ctx ∨ 'ctx1 <: G diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls index 06e4f7eab4..f313647169 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls @@ -43,53 +43,41 @@ f `=> x `=> f`(x) x `=> y `=> x `+ y //│ Type: CodeBase[out 'x -> ('y -> 'cde), ⊥, ?] //│ Where: -//│ 'x <: Int -//│ 'x#Int ∨ 'cde1#Int ∨ 'y1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ -//│ 'x#Int ∨ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ -//│ 'x <: 'cde1 -//│ 'cde1 <: ¬(¬{Int}) -//│ 'cde1#Int ∨ 'y1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ -//│ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ -//│ 'y <: Int +//│ 'x#'cde1 ∨ 'y1#'cde2 ∨ ( 'x#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'y <: 'y1 -//│ 'y1 <: ¬(¬{Int}) +//│ 'cde1#'cde1 ∨ 'y1#'cde2 ∨ ( 'x#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x <: 'cde1 +//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'y1 <: 'cde2 -//│ 'cde2 <: ¬(¬{Int}) //│ 'cde3 <: 'cde //│ 'app <: ¬(¬'cde3) (x, y) `=> x `+ y -//│ Type: CodeBase[out ('x, 'y) -> 'cde, ⊥, ?] +//│ Type: CodeBase[out ('x, 'x) -> 'cde, ⊥, ?] //│ Where: -//│ 'x <: Int -//│ 'x#Int ∨ 'cde1#Int ∨ 'y#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ -//│ 'x#Int ∨ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'x <: 'cde1 -//│ 'cde1 <: ¬(¬{Int}) -//│ 'cde1#Int ∨ 'y#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ -//│ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ -//│ 'y <: Int +//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'y <: 'cde2 -//│ 'cde2 <: ¬(¬{Int}) //│ 'app <: ¬(¬'cde) (x, y, z) `=> x `+ y `+ z -//│ Type: CodeBase[out ('x, 'y, 'z) -> 'cde, ⊥, ?] +//│ Type: CodeBase[out ('x, 'x, 'z) -> 'cde, ⊥, ?] //│ Where: -//│ 'x <: Int -//│ 'x#Int ∨ 'cde1#Int ∨ 'y#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ -//│ 'x#Int ∨ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ +//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'x <: 'cde1 -//│ 'cde1 <: ¬(¬{Int}) -//│ 'cde1#Int ∨ 'y#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ -//│ 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥ -//│ 'y <: Int +//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'y <: 'cde2 -//│ 'cde2 <: ¬(¬{Int}) -//│ 'cde3#'cde3 ∨ ( 'cde3#Int ∨ 'z#Int ∨ 'cde4#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥) ∧ ( 'cde3#Int ∨ 'cde4#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥) ∧ {0: 'cde3, 1: 'cde4}<:{0: Int, 1: Int} +//│ 'cde3#'cde3 ∨ 'z#'cde4 ∨ ( 'cde3#Int ∨ 'z#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥) ∧ ( 'cde3#Int ∨ 'cde4#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥) ∧ {0: 'cde3, 1: 'cde4}<:{0: Int, 1: Int} +//│ 'cde3#'cde3 ∨ 'cde4#'cde4 ∨ ( 'cde3#Int ∨ 'z#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥) ∧ ( 'cde3#Int ∨ 'cde4#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥) ∧ {0: 'cde3, 1: 'cde4}<:{0: Int, 1: Int} //│ 'z <: 'cde4 //│ 'app1 <: ¬(¬'cde) //│ 'app <: ¬(¬'cde3) @@ -103,15 +91,15 @@ f `=> x `=> y `=> f`(x, y) :e `let x = 42 `in x //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.104: `let x = 42 `in x -//│ ║ ^^ +//│ ║ l.92: `let x = 42 `in x +//│ ║ ^^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'cde, out 'ctx, ?] //│ Type: CodeBase[⊥, ⊥, ?] :e `let x = `0 `in 1 //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.112: `let x = `0 `in 1 +//│ ║ l.100: `let x = `0 `in 1 //│ ║ ^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'cde, out 'ctx, ?] //│ Type: CodeBase[⊥, ⊥, ?] @@ -126,9 +114,9 @@ f `=> x `=> y `=> f`(x, y) x `=> `if x `== `0.0 then `1.0 else x //│ Type: CodeBase[out 'x -> ('x ∨ Num), ⊥, ?] //│ Where: -//│ 'x#⊤ ∨ 'cde#⊤ ∨ ∧ Bool<:'app ∧ ⊥<:⊥ ∧ 'cde<:'T ∧ 'cde1<:'T +//│ 'x#'cde ∨ ( 'x#⊤ ∨ ∧ Bool<:'app ∧ ⊥<:⊥ ∧ 'cde<:'T ∧ 'cde1<:'T) ∧ ( 'cde#⊤ ∨ ∧ Bool<:'app ∧ ⊥<:⊥ ∧ 'cde<:'T ∧ 'cde1<:'T) ∧ {0: 'cde, 1: 'cde1}<:{0: ⊤, 1: ⊤} //│ 'x <: 'cde -//│ 'cde#⊤ ∨ ∧ Bool<:'app ∧ ⊥<:⊥ ∧ 'cde<:'T ∧ 'cde1<:'T +//│ 'cde#'cde ∨ ( 'x#⊤ ∨ ∧ Bool<:'app ∧ ⊥<:⊥ ∧ 'cde<:'T ∧ 'cde1<:'T) ∧ ( 'cde#⊤ ∨ ∧ Bool<:'app ∧ ⊥<:⊥ ∧ 'cde<:'T ∧ 'cde1<:'T) ∧ {0: 'cde, 1: 'cde1}<:{0: ⊤, 1: ⊤} //│ Num <: 'cde1 //│ 'cde2 <: ¬(¬{Bool}) //│ 'app <: ¬(¬'cde2) @@ -140,7 +128,7 @@ run(`1) :e run(1) //│ ╔══[ERROR] Type error in integer literal with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.141: run(1) +//│ ║ l.129: run(1) //│ ║ ^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'T, ⊥, ?] //│ Type: ⊥ @@ -148,7 +136,7 @@ run(1) :e x `=> run(x) //│ ╔══[ERROR] Type error in reference with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.149: x `=> run(x) +//│ ║ l.137: x `=> run(x) //│ ║ ^ //│ ╟── because: cannot constrain CodeBase['x, x, ⊥] <: CodeBase[out 'T, ⊥, ?] //│ ╙── because: cannot constrain x <: ⊥ @@ -157,12 +145,12 @@ x `=> run(x) :e `let x = `42 `in run(x) //│ ╔══[ERROR] Type error in reference with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.158: `let x = `42 `in run(x) +//│ ║ l.146: `let x = `42 `in run(x) //│ ║ ^ //│ ╟── because: cannot constrain CodeBase['cde, x, ⊥] <: CodeBase[out 'T, ⊥, ?] //│ ╙── because: cannot constrain x <: ⊥ //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.158: `let x = `42 `in run(x) +//│ ║ l.146: `let x = `42 `in run(x) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain 'T <: CodeBase[out 'cde1, out 'ctx, ?] //│ ╟── because: cannot constrain 'T <: ¬(¬{CodeBase[out 'cde1, out 'ctx, ?]}) diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index 35d6030f09..91d98e9bd8 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -97,7 +97,12 @@ idIIBB([1, 2]) x => if x is Int then 0 Bool then 0 -//│ Type: (((¬Bool ∨ Int) ∨ Bool) ∧ (¬Int ∨ Int)) ->{⊥} Int +//│ Type: ('x) ->{'eff ∨ 'eff1} 'cons ∨ 'cons1 +//│ Where: +//│ 'x <: (¬Bool ∨ Int) ∨ Bool +//│ 'x <: ¬Int ∨ Int +//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int<:'cons +//│ 'x#Bool ∨ ∧ ⊥<:'eff1 ∧ Int<:'cons1 @@ -114,14 +119,14 @@ new Pair(1, 2) :e fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.115: fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) +//│ ║ l.120: fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ :e idIIBB(new Pair(1, 2)) //│ ╔══[ERROR] Type error in application -//│ ║ l.122: idIIBB(new Pair(1, 2)) +//│ ║ l.127: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] @@ -129,7 +134,7 @@ idIIBB(new Pair(1, 2)) //│ ╟── because: cannot constrain 'A <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) //│ ╔══[ERROR] Type error in application -//│ ║ l.122: idIIBB(new Pair(1, 2)) +//│ ║ l.127: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] @@ -141,7 +146,7 @@ idIIBB(new Pair(1, 2)) :e idIIBB(new Pair(1, true)) //│ ╔══[ERROR] Type error in application -//│ ║ l.142: idIIBB(new Pair(1, true)) +//│ ║ l.147: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Int, in ⊥ out Int] @@ -149,7 +154,7 @@ idIIBB(new Pair(1, true)) //│ ╟── because: cannot constrain 'B <: ¬(¬{Int}) //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in application -//│ ║ l.142: idIIBB(new Pair(1, true)) +//│ ║ l.147: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] @@ -160,7 +165,7 @@ idIIBB(new Pair(1, true)) -:todo + fun foo: ["x": Int, "y": Int] //│ Type: ⊤ @@ -197,7 +202,7 @@ k(idIB)(true, 1) :e k(idIB)("true", 1) //│ ╔══[ERROR] Type error in string literal with expected type 'x -//│ ║ l.198: k(idIB)("true", 1) +//│ ║ l.203: k(idIB)("true", 1) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Str <: 'x //│ ╟── because: cannot constrain Str <: 'x @@ -250,7 +255,7 @@ map(cons(1, cons(true, nil())))(idIB) let x = cons(1, cons(true, nil())) in map(cons(x, x))(idIB) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.251: map(cons(x, x))(idIB) +//│ ║ l.256: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -258,7 +263,7 @@ let x = cons(1, cons(true, nil())) in //│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.251: map(cons(x, x))(idIB) +//│ ║ l.256: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -268,7 +273,7 @@ let x = cons(1, cons(true, nil())) in //│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.251: map(cons(x, x))(idIB) +//│ ║ l.256: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -299,14 +304,14 @@ x => k(x, x) :e fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.300: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) +//│ ║ l.305: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ :e fun id: [A] -> (A -> A) & (Int -> Int) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.307: fun id: [A] -> (A -> A) & (Int -> Int) +//│ ║ l.312: fun id: [A] -> (A -> A) & (Int -> Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -322,7 +327,7 @@ fst(cons(1, nil())) :e fun idInt: (Int -> Int) & (Int -> Int) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.323: fun idInt: (Int -> Int) & (Int -> Int) +//│ ║ l.328: fun idInt: (Int -> Int) & (Int -> Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -338,7 +343,7 @@ wf(true) :e wf(1) //│ ╔══[ERROR] Type error in application -//│ ║ l.339: wf(1) +//│ ║ l.344: wf(1) //│ ║ ^^^^^ //│ ╟── because: cannot constrain (((Int ∨ Bool) -> Int) ∨ (Bool -> Bool)) ∧ (Str -> Str) <: Int ->{'eff} 'app //│ ╙── because: cannot constrain {0: Int} <: {0: Bool} ∨ {0: Str} @@ -359,14 +364,14 @@ zs :e wf(zs, zs) //│ ╔══[ERROR] Type error in application -//│ ║ l.360: wf(zs, zs) +//│ ║ l.365: wf(zs, zs) //│ ║ ^^^^^^^^^^ //│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: (Z ∨ S, Z ∨ S) ->{'eff} 'app //│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} //│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: {1: S} //│ ╙── because: cannot constrain Z ∨ S <: S //│ ╔══[ERROR] Type error in application -//│ ║ l.360: wf(zs, zs) +//│ ║ l.365: wf(zs, zs) //│ ║ ^^^^^^^^^^ //│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: (Z ∨ S, Z ∨ S) ->{'eff} 'app //│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} @@ -380,11 +385,11 @@ fun ill: (([b: Bool, c: Bool]) -> Bool) & (([a: Str, c: Str]) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.379: (([a: Int, b:Int]) -> Int) & +//│ ║ l.384: (([a: Int, b:Int]) -> Int) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.380: (([b: Bool, c: Bool]) -> Bool) & +//│ ║ l.385: (([b: Bool, c: Bool]) -> Bool) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.381: (([a: Str, c: Str]) -> Str) +//│ ║ l.386: (([a: Str, c: Str]) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -394,10 +399,49 @@ fun nested: (([tag: [b: Bool, c: Bool]]) -> Bool) & (([tag: [a: Str, c: Str]]) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.393: (([tag: [a: Int, b:Int]]) -> Int) & +//│ ║ l.398: (([tag: [a: Int, b:Int]]) -> Int) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.394: (([tag: [b: Bool, c: Bool]]) -> Bool) & +//│ ║ l.399: (([tag: [b: Bool, c: Bool]]) -> Bool) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.395: (([tag: [a: Str, c: Str]]) -> Str) +//│ ║ l.400: (([tag: [a: Str, c: Str]]) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ + +if 0 is + Bool then "" + Int then true + Str then 0 +//│ Type: Bool + +fun not: Bool -> Bool +//│ Type: ⊤ + +fun foorec(x, y, r) = if + x is Int and y is Int then x + y + x is Str then not(y) + y is Str then r(y, x, r) +//│ Type: ⊤ + +fun foo(x, y) = foorec(x, y, foorec) +//│ Type: ⊤ + +foo(true, "") +//│ Type: Bool + +foo(1, 2) +//│ Type: Int + +foo as (Int, Int) -> Int +//│ Type: (Int, Int) ->{⊥} Int + +(x => foo(x, true)) as Str -> Bool +//│ Type: (Str) ->{⊥} Bool + +(x => foo(x, "")) as Bool -> Bool +//│ Type: (Bool) ->{⊥} Bool + +(x => foo(x, "")) as Int -> Bool +//│ Type: (Int) ->{⊥} Bool + +foo(1, "") +//│ Type: Bool diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index 32219d5e7a..53a4532383 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -36,33 +36,40 @@ test //│ > x is Fls then fls#666 //│ > y is Fls then fls#666 //│ = [function test] -//│ Type: (((¬Fls ∨ Fls) ∨ Tru) ∧ (¬Tru ∨ Tru), (¬Fls ∨ Fls) ∧ (¬Tru ∨ Tru)) -> (Tru ∨ Fls) +//│ Type: ['x, 'y, 'eff, 'cons, 'scrut, 'scrut1, 'eff1, 'eff2, 'cons1, 'eff3, 'cons2] -> ('x, 'y) ->{('eff ∨ 'eff2) ∨ 'eff3} (('cons ∨ 'cons1) ∨ 'cons2) +//│ Where: +//│ 'x <: (¬Fls ∨ Fls) ∨ Tru +//│ 'x <: ¬Tru ∨ Tru +//│ 'x#Tru ∨ ( 'scrut#Tru ∨ ∧ ⊥<:'eff ∧ Tru<:'cons) ∧ 'eff<:'eff1 ∧ 'y<:(Tru ∧ 'scrut) ∨ (¬Tru ∧ 'scrut1) +//│ 'x#Fls ∨ ∧ ⊥<:'eff2 ∧ Fls<:'cons1 +//│ 'y <: ¬Fls ∨ Fls +//│ 'y#Fls ∨ ∧ ⊥<:'eff3 ∧ Fls<:'cons2 test(tru, tru) //│ = Tru() -//│ Type: Tru ∨ Fls +//│ Type: Tru test(tru, fls) //│ = Fls() -//│ Type: Tru ∨ Fls +//│ Type: Fls test(fls, tru) //│ = Fls() -//│ Type: Tru ∨ Fls +//│ Type: Fls test(fls, fls) //│ = Fls() -//│ Type: Tru ∨ Fls +//│ Type: Fls test("hi", fls) //│ = Fls() -//│ Type: Tru ∨ Fls +//│ Type: Fls :todo :e test(true, false) //│ ═══[RUNTIME ERROR] Error: match error -//│ Type: Tru ∨ Fls +//│ Type: ⊥ From 081de12a50dfc4d9afaee37e2b47f9f527039607 Mon Sep 17 00:00:00 2001 From: auht <101095686+auht@users.noreply.github.com> Date: Sat, 29 Mar 2025 02:08:39 +0800 Subject: [PATCH 18/36] Update hkmc2/shared/src/test/mlscript/logicsub/Records.mls Co-authored-by: Lionel Parreaux --- hkmc2/shared/src/test/mlscript/logicsub/Records.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript/logicsub/Records.mls b/hkmc2/shared/src/test/mlscript/logicsub/Records.mls index b86a11a3bd..c03e36d222 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/Records.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/Records.mls @@ -28,7 +28,7 @@ let rcd = { foo: 1, bar: "..." } //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ Type: ⊥ -:todo // IntLit as label? +// TODO: IntLit as label? "0": rcd.foo "1": rcd.bar //│ Type: {0: Int, 1: Str} From 55b906635c202b0bbacb6802f85d36c671b3fe0a Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Wed, 2 Apr 2025 16:09:17 +0800 Subject: [PATCH 19/36] wip fix --- .../scala/hkmc2/bbml/ConstraintSolver.scala | 23 ++-- .../src/main/scala/hkmc2/bbml/bbML.scala | 25 +++-- .../src/main/scala/hkmc2/bbml/types.scala | 12 +-- .../src/test/mlscript/bbml/bbBasics.mls | 23 ++-- .../src/test/mlscript/bbml/bbExtrude.mls | 8 +- .../shared/src/test/mlscript/bbml/bbGPCE.mls | 41 +++++-- hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls | 28 ++--- .../src/test/mlscript/logicsub/DisjSub.mls | 100 +++++++++++++----- .../test/mlscript/logicsub/MarlowWadler97.mls | 11 +- 9 files changed, 168 insertions(+), 103 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index 5a6f40fd1e..c738150e6e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -70,6 +70,11 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, else v.state.lowerBounds ::= nv nv.state.upperBounds = v.state.upperBounds.map(extrude) // * propagate + nv.state.disjsub ++= v.state.disjsub.map: + case DisjSub(ds, dss, cs) => + val d = ds.mapKeys(v0 => if v === v0 then nv else v0) + DisjSub(mutable.LinkedHashSet.from(d), dss, cs) + nv.state.disjsub.foreach(_.commit()) nv }) case ft @ FunType(args, ret, eff) => @@ -117,16 +122,15 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, k.foreach(k => constrainImpl(um(k), wm(k))) else cctx.err case (Inter(S(u: RcdType)), Union(f, Nil, rs@(RcdType(w) :: _))) => - val k = w.keys.toSet - val r = RcdType(u.fields.filter(p => k(p._1))) val ws = rs.foldLeft(Nil): (x, w) => - val d = Type.disjoint(w, r) + val d = Type.disjoint(w, u) if d === S(Set.empty) then x else Ls(d -> w) ++ x ws match case Nil => cctx.err case (_, w) :: Nil => constrainImpl(u, w) case ((_, RcdType(w)) :: (_, RcdType(z)) :: _) => val (wm, zm) = (w.toMap, z.toMap) + val k = wm.keySet & zm.keySet val dk = k.find(k => Type.disjoint(wm(k), zm(k)) === S(Set.empty)).get val ku = ws.foldLeft(Bot: Type): case (ku, (_, w)) => ku | w.fields.find(_._1 === dk).get._2 @@ -134,7 +138,7 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, case (S(k), w) => k.foreach: k => DisjSub(mutable.LinkedHashSet.from(k), Nil, Ls(u -> RcdType(w.fields.filter(_._1 =/= k)))).commit() case _ => - constrainImpl(r.fields.find(_._1 === dk).get._2, ku) + constrainImpl(u.fields.find(_._1 === dk).get._2, ku) ws.foreach: case (N, w) => constrainImpl(u, RcdType(w.fields.filter(_._1 =/= dk))) case _ => @@ -149,16 +153,9 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, constrainImpl(f.ret, ret2) constrainImpl(f.eff, eff2) else - val dargs = f.map(x => Type.discriminant(x.args)) - val ks = if f.nonEmpty then - dargs.iterator.map(_._1.fields.keys.toSet).reduce(_ & _) - else Set.empty - val args = dargs.map: - case (u, w) => - val (q, p) = u.fields.partition(x => ks(x._1)) - (RcdType(q), RcdType(p) & w) + val args = f.map(x => Type.discriminant(x.args)) val args2r = args2.zipWithIndex.map(u => (s"${u._2}", u._1)) - val args2q = RcdType(args2r.filter(x => ks(x._1))) + val args2q = RcdType(args2r) val (cs, dss) = (args.iterator.zip(f).map: case ((q, r), f) => val rm = r.fields.toMap diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index 02234dbb92..f9fd1d3f3a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -327,16 +327,20 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): val nestCtx1 = ctx.nest val nestCtx2 = ctx.nest val clsTy = ClassLikeType(sym, cls.tparams.map(_ => Wildcard.empty)) - val ctv = freshVar(new TempSymbol(S(scrutinee), "scrut")) - val atv = freshVar(new TempSymbol(S(scrutinee), "scrut")) + val sty = tryMkMono(scrutineeTy, scrutinee) + val res = sign.orElse(S(freshVar(new TempSymbol(N, "res")))) + // val ctv = freshVar(new TempSymbol(S(scrutinee), "scrut")) + // val atv = freshVar(new TempSymbol(S(scrutinee), "scrut")) scrutinee match // * refine case Ref(sym: LocalSymbol) => - nestCtx1 += sym -> ctv - nestCtx2 += sym -> atv + nestCtx1 += sym -> (clsTy & sty) + nestCtx2 += sym -> sty + // nestCtx1 += sym -> ctv + // nestCtx2 += sym -> atv case _ => () // TODO: refine all variables holding this value? - constrain(tryMkMono(scrutineeTy, scrutinee), (clsTy & ctv) | (clsTy.! & atv)) - val (consTy, consEff) = Type.disjoint(clsTy, ctv) match - case N => typeSplit(cons, sign)(using nestCtx1) + // constrain(sty, (clsTy & ctv) | (clsTy.! & atv)) + val (consTy, consEff) = Type.disjoint(clsTy, sty) match + case N => typeSplit(cons, res)(using nestCtx1) case S(k) => if k.isEmpty then (Bot, Bot) else @@ -347,12 +351,13 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): cs += lhs -> rhs def commit(ds: DisjSub) = dss += ds val eff = freshVar(new TempSymbol(N, "eff")) - val (t, e) = typeSplit(cons, sign.orElse(S(freshVar(new TempSymbol(N, "cons")))))(using nestCtx1, nc) + val (t, e) = typeSplit(cons, res)(using nestCtx1, nc) k.foreach(k => c.commit(DisjSub(LinkedHashSet.from(k), dss.toList, (e, eff) :: cs.toList))) (t, eff) - val (altsTy, altsEff) = typeSplit(alts, sign)(using nestCtx2) + val (altsTy, altsEff) = typeSplit(alts, res)(using nestCtx2) val allEff = scrutineeEff | (consEff | altsEff) - (sign.getOrElse(tryMkMono(consTy, cons) | tryMkMono(altsTy, alts)), allEff) + // (sign.getOrElse(tryMkMono(consTy, cons) | tryMkMono(altsTy, alts)), allEff) + (res.get, allEff) case _ => error(msg"Cannot match ${scrutinee.toString} as ${sym.toString}" -> split.toLoc :: Nil) (Bot, Bot) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 64310bce1d..e0f8303bb4 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -326,12 +326,6 @@ object Type: if !prev.contains(a -> b) then c.getOrElseUpdate(a -> b, { (a.simp.toBasic, b.simp.toBasic) match case (Bot, _) | (_, Bot) => S(Set.empty) - case (NegType(t),_) => t.!.simp.toBasic match - case NegType(_) => N - case a => disjointImpl(a, b)(prev) - case (_, NegType(t)) => t.!.simp.toBasic match - case NegType(_) => N - case a => disjointImpl(a, b)(prev) case (ClassLikeType(a, _), ClassLikeType(b, _)) if a.uid =/= b.uid => S(Set.empty) case (RcdType(u), RcdType(w)) if u.nonEmpty && w.nonEmpty => val um = u.toMap @@ -378,6 +372,12 @@ object Type: val k = v.state.lowerBounds.map(lb => disjointImpl(a, lb.toBasic)(p)) if k.exists(_.isEmpty) then N else S(k.flatten.flatten.toSet + Set(v -> a)) + case (NegType(t),_) => t.!.simp.toBasic match + case NegType(_) => N + case a => disjointImpl(a, b)(prev) + case (_, NegType(t)) => t.!.simp.toBasic match + case NegType(_) => N + case a => disjointImpl(a, b)(prev) case _ => N }) else S(Set.empty) def disjoint(a: Type, b: Type): Opt[Set[Set[InfVar->BasicType]]] = diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index c40957a188..2ab9cf6b96 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -149,12 +149,9 @@ fun foofoo(x) = if x is Int then let t = x + 1 in "foo" foofoo -//│ Type: ['x, 'scrut, 'eff, 'cons] -> 'x ->{'eff} 'cons +//│ Type: ['x, 'res, 'eff] -> 'x ->{'eff} 'res //│ Where: -//│ 'x <: ¬Int ∨ Int -//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ 'scrut<:Int ∧ Int<:Int ∧ Str<:'cons -//│ Int ∧ 'x <: 'scrut -//│ 'scrut#Int ∨ ∧ ⊥<:'eff ∧ 'scrut<:Int ∧ Int<:Int ∧ Str<:'cons +//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Str<:'res fun foofoo(x) = let t = x + 1 in "foo" @@ -180,7 +177,7 @@ f().Printer#f(42) :e f().Printer#f("oops") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.181: f().Printer#f("oops") +//│ ║ l.178: f().Printer#f("oops") //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -199,7 +196,7 @@ let ip = new Printer(foofoo) in ip.Printer#f(42) :e let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.200: let ip = new Printer(foofoo) in ip.Printer#f("42") +//│ ║ l.197: let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ║ ^^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -230,7 +227,7 @@ let tf = new TFun(inc) in tf.TFun#f(1) :e let tf = new TFun(inc) in tf.TFun#f("1") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.231: let tf = new TFun(inc) in tf.TFun#f("1") +//│ ║ l.228: let tf = new TFun(inc) in tf.TFun#f("1") //│ ║ ^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -286,12 +283,10 @@ if 1 is Foo then 0 else 1 fun test(x) = if x is Int then x + 1 else 0 test -//│ Type: ['x, 'scrut, 'eff, 'cons] -> 'x ->{'eff} ('cons ∨ Int) +//│ Type: ['x, 'res, 'eff] -> 'x ->{'eff} 'res //│ Where: -//│ 'x <: ¬Int ∨ Int -//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ 'scrut<:Int ∧ Int<:Int ∧ Int<:'cons -//│ Int ∧ 'x <: 'scrut -//│ 'scrut#Int ∨ ∧ ⊥<:'eff ∧ 'scrut<:Int ∧ Int<:Int ∧ Int<:'cons +//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Int<:'res +//│ Int <: 'res test(1) //│ Type: Int @@ -362,7 +357,7 @@ throw new Error("oops") :e throw 42 //│ ╔══[ERROR] Type error in throw -//│ ║ l.363: throw 42 +//│ ║ l.358: throw 42 //│ ║ ^^ //│ ╙── because: cannot constrain Int <: Error //│ Type: ⊥ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls index e95eca5dcc..8008a4dff2 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls @@ -48,13 +48,15 @@ y `=> (let t = run(x `=> x `+ y) in y) //│ Where: //│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'x2 <: 'x -//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x2#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x2#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'x <: 'cde1 //│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'y <: 'cde2 +//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'cde <: 'cde3 //│ 'app <: ¬(¬'cde) +//│ 'x2 <: 'x data class C[A](m: A, n: A -> Int) //│ Type: ⊤ @@ -88,7 +90,7 @@ f(g)(foo) :fixme // ??? f(g)(bar) //│ ╔══[ERROR] Type error in reference with expected type 'A -//│ ║ l.89: f(g)(bar) +//│ ║ l.91: f(g)(bar) //│ ║ ^^^ //│ ╟── because: cannot constrain C[Int] <: 'A //│ ╟── because: cannot constrain C[in Int out Int] <: 'A diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls index d43e4009e6..241479ad73 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls @@ -17,7 +17,20 @@ fun id(x) = x run(x `=> id(x) `* x) -//│ Type: ⊤ -> ⊥ +//│ Type: 'x -> 'cde +//│ Where: +//│ 'x#'cde1 ∨ 'x#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'x#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x <: 'x1 +//│ 'x1#'cde1 ∨ 'x1#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'x1#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x1 <: 'cde1 +//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x1 <: 'cde2 +//│ 'cde3 <: 'cde +//│ 'app <: ¬(¬'cde3) fun assertNotZero: [C] -> CodeBase[out Num, out C, out Any] -> CodeBase[out Num, out C, out Any] @@ -25,7 +38,17 @@ fun assertNotZero(x) = `if (x `== `0.0) then `error else x let checkedDiv = x `=> y `=> x `/. (assertNotZero(y)) run(checkedDiv) -//│ Type: ⊤ -> (Num -> ⊥) +//│ Type: 'x -> (Num -> 'cde) +//│ Where: +//│ 'x#'cde1 ∨ ( 'x1#Num ∨ ∧ Num<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Num ∨ ∧ Num<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Num, 1: Num} +//│ 'x <: 'x1 +//│ 'x1#'cde1 ∨ ( 'x1#Num ∨ ∧ Num<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Num ∨ ∧ Num<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Num, 1: Num} +//│ 'x1 <: 'cde1 +//│ 'cde1#'cde1 ∨ ( 'x1#Num ∨ ∧ Num<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Num ∨ ∧ Num<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Num, 1: Num} +//│ Num <: 'cde2 +//│ 'cde3 <: 'cde +//│ 'cde4 <: 'cde3 +//│ 'app <: ¬(¬'cde4) @@ -40,26 +63,28 @@ fun inc(dbg) = inc //│ Type: ['x, 'cde, 'cde1, 'app, 'app1, 'eff, 'cde2, 'x1] -> (CodeBase[out 'app1, ?, ?] ->{'eff} ⊤) ->{'eff} CodeBase[out 'x -> 'cde2, ⊥, ?] //│ Where: -//│ 'x <: 'x1 -//│ 'x1#'cde ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde, 1: 'cde1}<:{0: Int, 1: Int} +//│ 'x#'cde ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde, 1: 'cde1}<:{0: Int, 1: Int} //│ 'x1 <: 'cde //│ 'cde#'cde ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde, 1: 'cde1}<:{0: Int, 1: Int} //│ Int <: 'cde1 //│ 'cde2 <: ⊤ //│ 'app <: 'cde2 //│ 'app <: 'app1 +//│ 'x <: 'x1 +//│ 'x1#'cde ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde, 1: 'cde1}<:{0: Int, 1: Int} inc(c => log(show(c))) //│ Type: CodeBase[out 'x -> 'cde, ⊥, ?] //│ Where: -//│ 'x1 <: 'x -//│ 'x#'cde1 ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x1#'cde1 ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'x <: 'cde1 //│ 'cde1#'cde1 ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ Int <: 'cde2 //│ 'cde <: ⊤ //│ 'app <: 'cde //│ 'app <: 'app1 +//│ 'x1 <: 'x +//│ 'x#'cde1 ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} fun body: [T, C] -> (CodeBase[out Int, out T, out Any], CodeBase[out Int, out C, out Any]) -> Int -> CodeBase[out Int, out T | C, out Any] @@ -83,8 +108,8 @@ fun body(x, y) = case 1 then y n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] //│ ╔══[ERROR] Type error in application with expected type CodeBase[out Int, out G, ?] -//│ ║ l.84: n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.109: n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain CodeBase[out 'cde, out 'ctx ∨ 'ctx1, ?] <: CodeBase[out Int, out G, ?] //│ ╟── because: cannot constrain 'ctx ∨ 'ctx1 <: G //│ ╟── because: cannot constrain 'ctx1 <: ¬(¬G) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls index f313647169..9199e9ddc1 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls @@ -41,17 +41,19 @@ f `=> x `=> f`(x) x `=> y `=> x `+ y -//│ Type: CodeBase[out 'x -> ('y -> 'cde), ⊥, ?] +//│ Type: CodeBase[out 'x -> ('x -> 'cde), ⊥, ?] //│ Where: -//│ 'x#'cde1 ∨ 'y1#'cde2 ∨ ( 'x#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'y <: 'y1 -//│ 'cde1#'cde1 ∨ 'y1#'cde2 ∨ ( 'x#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'y1#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y1#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} //│ 'x <: 'cde1 -//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'y1 <: 'cde2 +//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'y <: 'cde2 //│ 'cde3 <: 'cde //│ 'app <: ¬(¬'cde3) +//│ 'y1 <: 'y @@ -91,7 +93,7 @@ f `=> x `=> y `=> f`(x, y) :e `let x = 42 `in x //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.92: `let x = 42 `in x +//│ ║ l.94: `let x = 42 `in x //│ ║ ^^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'cde, out 'ctx, ?] //│ Type: CodeBase[⊥, ⊥, ?] @@ -99,7 +101,7 @@ f `=> x `=> y `=> f`(x, y) :e `let x = `0 `in 1 //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.100: `let x = `0 `in 1 +//│ ║ l.102: `let x = `0 `in 1 //│ ║ ^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'cde, out 'ctx, ?] //│ Type: CodeBase[⊥, ⊥, ?] @@ -128,7 +130,7 @@ run(`1) :e run(1) //│ ╔══[ERROR] Type error in integer literal with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.129: run(1) +//│ ║ l.131: run(1) //│ ║ ^ //│ ╙── because: cannot constrain Int <: CodeBase[out 'T, ⊥, ?] //│ Type: ⊥ @@ -136,7 +138,7 @@ run(1) :e x `=> run(x) //│ ╔══[ERROR] Type error in reference with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.137: x `=> run(x) +//│ ║ l.139: x `=> run(x) //│ ║ ^ //│ ╟── because: cannot constrain CodeBase['x, x, ⊥] <: CodeBase[out 'T, ⊥, ?] //│ ╙── because: cannot constrain x <: ⊥ @@ -145,12 +147,12 @@ x `=> run(x) :e `let x = `42 `in run(x) //│ ╔══[ERROR] Type error in reference with expected type CodeBase[out 'T, ⊥, ?] -//│ ║ l.146: `let x = `42 `in run(x) +//│ ║ l.148: `let x = `42 `in run(x) //│ ║ ^ //│ ╟── because: cannot constrain CodeBase['cde, x, ⊥] <: CodeBase[out 'T, ⊥, ?] //│ ╙── because: cannot constrain x <: ⊥ //│ ╔══[ERROR] Type error in unquoted term -//│ ║ l.146: `let x = `42 `in run(x) +//│ ║ l.148: `let x = `42 `in run(x) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain 'T <: CodeBase[out 'cde1, out 'ctx, ?] //│ ╟── because: cannot constrain 'T <: ¬(¬{CodeBase[out 'cde1, out 'ctx, ?]}) diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index 91d98e9bd8..6cf30f36ee 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -97,12 +97,10 @@ idIIBB([1, 2]) x => if x is Int then 0 Bool then 0 -//│ Type: ('x) ->{'eff ∨ 'eff1} 'cons ∨ 'cons1 +//│ Type: ('x) ->{'eff ∨ 'eff1} 'res //│ Where: -//│ 'x <: (¬Bool ∨ Int) ∨ Bool -//│ 'x <: ¬Int ∨ Int -//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int<:'cons -//│ 'x#Bool ∨ ∧ ⊥<:'eff1 ∧ Int<:'cons1 +//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int<:'res +//│ 'x#Bool ∨ ∧ ⊥<:'eff1 ∧ Int<:'res @@ -119,14 +117,14 @@ new Pair(1, 2) :e fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.120: fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) +//│ ║ l.118: fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ :e idIIBB(new Pair(1, 2)) //│ ╔══[ERROR] Type error in application -//│ ║ l.127: idIIBB(new Pair(1, 2)) +//│ ║ l.125: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] @@ -134,7 +132,7 @@ idIIBB(new Pair(1, 2)) //│ ╟── because: cannot constrain 'A <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) //│ ╔══[ERROR] Type error in application -//│ ║ l.127: idIIBB(new Pair(1, 2)) +//│ ║ l.125: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] @@ -146,7 +144,7 @@ idIIBB(new Pair(1, 2)) :e idIIBB(new Pair(1, true)) //│ ╔══[ERROR] Type error in application -//│ ║ l.147: idIIBB(new Pair(1, true)) +//│ ║ l.145: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Int, in ⊥ out Int] @@ -154,7 +152,7 @@ idIIBB(new Pair(1, true)) //│ ╟── because: cannot constrain 'B <: ¬(¬{Int}) //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in application -//│ ║ l.147: idIIBB(new Pair(1, true)) +//│ ║ l.145: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] @@ -202,7 +200,7 @@ k(idIB)(true, 1) :e k(idIB)("true", 1) //│ ╔══[ERROR] Type error in string literal with expected type 'x -//│ ║ l.203: k(idIB)("true", 1) +//│ ║ l.201: k(idIB)("true", 1) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Str <: 'x //│ ╟── because: cannot constrain Str <: 'x @@ -255,7 +253,7 @@ map(cons(1, cons(true, nil())))(idIB) let x = cons(1, cons(true, nil())) in map(cons(x, x))(idIB) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.256: map(cons(x, x))(idIB) +//│ ║ l.254: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -263,7 +261,7 @@ let x = cons(1, cons(true, nil())) in //│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.256: map(cons(x, x))(idIB) +//│ ║ l.254: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -273,7 +271,7 @@ let x = cons(1, cons(true, nil())) in //│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.256: map(cons(x, x))(idIB) +//│ ║ l.254: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -304,14 +302,14 @@ x => k(x, x) :e fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.305: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) +//│ ║ l.303: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ :e fun id: [A] -> (A -> A) & (Int -> Int) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.312: fun id: [A] -> (A -> A) & (Int -> Int) +//│ ║ l.310: fun id: [A] -> (A -> A) & (Int -> Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -327,7 +325,7 @@ fst(cons(1, nil())) :e fun idInt: (Int -> Int) & (Int -> Int) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.328: fun idInt: (Int -> Int) & (Int -> Int) +//│ ║ l.326: fun idInt: (Int -> Int) & (Int -> Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -343,7 +341,7 @@ wf(true) :e wf(1) //│ ╔══[ERROR] Type error in application -//│ ║ l.344: wf(1) +//│ ║ l.342: wf(1) //│ ║ ^^^^^ //│ ╟── because: cannot constrain (((Int ∨ Bool) -> Int) ∨ (Bool -> Bool)) ∧ (Str -> Str) <: Int ->{'eff} 'app //│ ╙── because: cannot constrain {0: Int} <: {0: Bool} ∨ {0: Str} @@ -364,14 +362,14 @@ zs :e wf(zs, zs) //│ ╔══[ERROR] Type error in application -//│ ║ l.365: wf(zs, zs) +//│ ║ l.363: wf(zs, zs) //│ ║ ^^^^^^^^^^ //│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: (Z ∨ S, Z ∨ S) ->{'eff} 'app //│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} //│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: {1: S} //│ ╙── because: cannot constrain Z ∨ S <: S //│ ╔══[ERROR] Type error in application -//│ ║ l.365: wf(zs, zs) +//│ ║ l.363: wf(zs, zs) //│ ║ ^^^^^^^^^^ //│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: (Z ∨ S, Z ∨ S) ->{'eff} 'app //│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} @@ -385,11 +383,11 @@ fun ill: (([b: Bool, c: Bool]) -> Bool) & (([a: Str, c: Str]) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.384: (([a: Int, b:Int]) -> Int) & +//│ ║ l.382: (([a: Int, b:Int]) -> Int) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.385: (([b: Bool, c: Bool]) -> Bool) & +//│ ║ l.383: (([b: Bool, c: Bool]) -> Bool) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.386: (([a: Str, c: Str]) -> Str) +//│ ║ l.384: (([a: Str, c: Str]) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -399,11 +397,11 @@ fun nested: (([tag: [b: Bool, c: Bool]]) -> Bool) & (([tag: [a: Str, c: Str]]) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.398: (([tag: [a: Int, b:Int]]) -> Int) & +//│ ║ l.396: (([tag: [a: Int, b:Int]]) -> Int) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.399: (([tag: [b: Bool, c: Bool]]) -> Bool) & +//│ ║ l.397: (([tag: [b: Bool, c: Bool]]) -> Bool) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.400: (([tag: [a: Str, c: Str]]) -> Str) +//│ ║ l.398: (([tag: [a: Str, c: Str]]) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -434,14 +432,58 @@ foo(1, 2) foo as (Int, Int) -> Int //│ Type: (Int, Int) ->{⊥} Int +foo as (Str, Bool) -> Bool +//│ Type: (Str, Bool) ->{⊥} Bool + (x => foo(x, true)) as Str -> Bool //│ Type: (Str) ->{⊥} Bool (x => foo(x, "")) as Bool -> Bool //│ Type: (Bool) ->{⊥} Bool -(x => foo(x, "")) as Int -> Bool -//│ Type: (Int) ->{⊥} Bool - +:e foo(1, "") +//│ ╔══[ERROR] Type error in string literal with expected type 'y +//│ ║ l.445: foo(1, "") +//│ ║ ^^ +//│ ╟── because: cannot constrain Str <: 'y +//│ ╟── because: cannot constrain Str <: 'y +//│ ╟── because: cannot constrain 'r <: (Str ∧ 'y1, 'x, 'r) ->{'eff} 'app +//│ ╟── because: cannot constrain 'r <: ¬(¬{(Str ∧ 'y1, 'x, 'r) ->{'eff} 'app}) +//│ ╟── because: cannot constrain ((¬⊥ ∧ 'x1, ¬⊥ ∧ 'y2, ¬⊥ ∧ 'r1) ->{((¬⊥ ∧ 'eff1) ∨ (¬⊥ ∧ 'eff2)) ∨ (¬⊥ ∧ 'eff3)} (¬⊥ ∧ 'res)) ∧ ¬⊥ <: ¬(¬{(Str ∧ 'y1, 'x, 'r) ->{'eff} 'app}) +//│ ╟── because: cannot constrain 'x <: 'y2 +//│ ╟── because: cannot constrain 'x <: 'y2 +//│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain ¬⊥ ∧ 'x2 <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Bool}) +//│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) //│ Type: Bool + +fun intstr: Int | Str +//│ Type: ⊤ + +fun rev: Str -> Str +fun increv(x) = if x is + Int then x + 1 + else + rev(x) +//│ Type: ⊤ + +fun increv'(x) = if x is + Int then x + 1 + Str then rev(x) +//│ Type: ⊤ + +increv'(intstr) +//│ Type: Str ∨ Int + +:todo +increv(intstr) +//│ ╔══[ERROR] Type error in reference with expected type 'x +//│ ║ l.482: increv(intstr) +//│ ║ ^^^^^^ +//│ ╟── because: cannot constrain Int ∨ Str <: 'x +//│ ╟── because: cannot constrain Int <: 'x +//│ ╙── because: cannot constrain Int <: ¬¬Str +//│ Type: Int ∨ Str diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index 53a4532383..2acd752f31 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -36,14 +36,11 @@ test //│ > x is Fls then fls#666 //│ > y is Fls then fls#666 //│ = [function test] -//│ Type: ['x, 'y, 'eff, 'cons, 'scrut, 'scrut1, 'eff1, 'eff2, 'cons1, 'eff3, 'cons2] -> ('x, 'y) ->{('eff ∨ 'eff2) ∨ 'eff3} (('cons ∨ 'cons1) ∨ 'cons2) +//│ Type: ['x, 'y, 'res, 'eff, 'eff1, 'eff2, 'eff3] -> ('x, 'y) ->{('eff ∨ 'eff2) ∨ 'eff3} 'res //│ Where: -//│ 'x <: (¬Fls ∨ Fls) ∨ Tru -//│ 'x <: ¬Tru ∨ Tru -//│ 'x#Tru ∨ ( 'scrut#Tru ∨ ∧ ⊥<:'eff ∧ Tru<:'cons) ∧ 'eff<:'eff1 ∧ 'y<:(Tru ∧ 'scrut) ∨ (¬Tru ∧ 'scrut1) -//│ 'x#Fls ∨ ∧ ⊥<:'eff2 ∧ Fls<:'cons1 -//│ 'y <: ¬Fls ∨ Fls -//│ 'y#Fls ∨ ∧ ⊥<:'eff3 ∧ Fls<:'cons2 +//│ 'x#Tru ∨ ( 'y#Tru ∨ ∧ ⊥<:'eff ∧ Tru<:'res) ∧ 'eff<:'eff1 +//│ 'x#Fls ∨ ∧ ⊥<:'eff2 ∧ Fls<:'res +//│ 'y#Fls ∨ ∧ ⊥<:'eff3 ∧ Fls<:'res test(tru, tru) //│ = Tru() From d99f3afcd821c2883fedb83b584896a57fda83f9 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sat, 5 Apr 2025 00:16:51 +0800 Subject: [PATCH 20/36] wip else branch disjointness --- .../src/main/scala/hkmc2/bbml/bbML.scala | 95 +++++++++---- .../src/main/scala/hkmc2/bbml/types.scala | 134 ++++++++++-------- .../src/test/mlscript/bbml/bbBasics.mls | 13 +- .../src/test/mlscript/logicsub/DisjSub.mls | 71 ++++++---- .../test/mlscript/logicsub/MarlowWadler97.mls | 84 ++++++++++- 5 files changed, 277 insertions(+), 120 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index f9fd1d3f3a..3aabd1c1c5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -2,7 +2,7 @@ package hkmc2 package bbml -import scala.collection.mutable.{HashSet, HashMap, ListBuffer, LinkedHashSet} +import scala.collection.mutable.{HashSet, HashMap, ListBuffer, LinkedHashSet, LinkedHashMap} import scala.annotation.tailrec import mlscript.utils.*, shorthands.* @@ -226,6 +226,15 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): def constrain(lhs: Type, rhs: Type)(using ctx: BbCtx, cctx: CCtx): Unit def commit(ds: DisjSub): Unit + private def constraintCollector = + val cs = ListBuffer.empty[Type -> Type] + val dss = ListBuffer.empty[DisjSub] + val nc = new ConstraintHandler: + def constrain(lhs: Type, rhs: Type)(using ctx: BbCtx, cctx: CCtx) = + cs += lhs -> rhs + def commit(ds: DisjSub) = dss += ds + (nc, dss, cs) + private def constrain(lhs: Type, rhs: Type)(using ctx: BbCtx, cctx: CCtx, c: ConstraintHandler): Unit = c.constrain(lhs, rhs) @@ -314,8 +323,32 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): pctx += sym -> PolyType.generalize(funTy, S(outer), 1) case _ => error(msg"Function definition shape not yet supported for ${sym.nme}" -> lam.toLoc :: Nil) + private def typeSplitBr(split: Split, sign: GeneralType, isElse: Bool)(using ctx: BbCtx, c: ConstraintHandler)(using CCtx, Scope): (Type, Ls[Ls[Type -> ClassLikeType]]) = split match + case Split.Cons(Branch(Ref(sym), c: Pattern.ClassLike, cons), alts) => + val sty = tryMkMono(ctx.get(sym).get, sym) + val cls = ClassLikeType(c.sym, Nil) + val ctx1 = ctx.nest + ctx1 += sym -> (cls & sty) + val (ce, p0) = typeSplitBr(cons, sign, false)(using ctx1) + val (ae, p1) = typeSplitBr(alts, sign, true) + val p = if p1.isEmpty then + if isElse then Nil else Ls(sty -> cls) :: p0 + else + (Ls(sty -> cls) :: p0).flatMap(u => p1.map(u ++ _)) + (ce | ae, p) + case Split.Let(name, term, tail) => + val nestCtx = ctx.nest + given BbCtx = nestCtx + val (termTy, termEff) = typeCheck(term) + val sk = freshSkolem(name) + nestCtx += name -> termTy + val (tailEff, p) = typeSplitBr(tail, sign, isElse)(using nestCtx) + (termEff | tailEff, p) + case Split.Else(alts) => (ascribe(alts, sign)._2, Nil) + case Split.End => (Bot, Nil) + private def typeSplit - (split: Split, sign: Opt[GeneralType])(using ctx: BbCtx, c: ConstraintHandler)(using CCtx, Scope) + (split: Split, sign: Opt[GeneralType], path: Ls[Ls[Type -> ClassLikeType]] = Ls(Nil))(using ctx: BbCtx, c: ConstraintHandler)(using CCtx, Scope) : (GeneralType, Type) = split match case Split.Cons(Branch(scrutinee, pattern, cons), alts) => @@ -329,34 +362,23 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): val clsTy = ClassLikeType(sym, cls.tparams.map(_ => Wildcard.empty)) val sty = tryMkMono(scrutineeTy, scrutinee) val res = sign.orElse(S(freshVar(new TempSymbol(N, "res")))) - // val ctv = freshVar(new TempSymbol(S(scrutinee), "scrut")) - // val atv = freshVar(new TempSymbol(S(scrutinee), "scrut")) scrutinee match // * refine case Ref(sym: LocalSymbol) => nestCtx1 += sym -> (clsTy & sty) nestCtx2 += sym -> sty - // nestCtx1 += sym -> ctv - // nestCtx2 += sym -> atv case _ => () // TODO: refine all variables holding this value? - // constrain(sty, (clsTy & ctv) | (clsTy.! & atv)) - val (consTy, consEff) = Type.disjoint(clsTy, sty) match - case N => typeSplit(cons, res)(using nestCtx1) + val (consEff, p) = Type.disjoint(clsTy, sty) match + case N => typeSplitBr(cons, res.get, false)(using nestCtx1) case S(k) => - if k.isEmpty then (Bot, Bot) + if k.isEmpty then (Bot, Ls(Nil)) else - val cs = ListBuffer.empty[Type -> Type] - val dss = ListBuffer.empty[DisjSub] - val nc = new ConstraintHandler: - def constrain(lhs: Type, rhs: Type)(using ctx: BbCtx, cctx: CCtx) = - cs += lhs -> rhs - def commit(ds: DisjSub) = dss += ds + val (nc, dss, cs) = constraintCollector val eff = freshVar(new TempSymbol(N, "eff")) - val (t, e) = typeSplit(cons, res)(using nestCtx1, nc) + val (e, p) = typeSplitBr(cons, res.get, false)(using nestCtx1, nc) k.foreach(k => c.commit(DisjSub(LinkedHashSet.from(k), dss.toList, (e, eff) :: cs.toList))) - (t, eff) - val (altsTy, altsEff) = typeSplit(alts, res)(using nestCtx2) + (eff, p) + val (altsTy, altsEff) = typeSplit(alts, res, (Ls(sty -> clsTy) :: p).flatMap(u => path.map(u ++ _)))(using nestCtx2) val allEff = scrutineeEff | (consEff | altsEff) - // (sign.getOrElse(tryMkMono(consTy, cons) | tryMkMono(altsTy, alts)), allEff) (res.get, allEff) case _ => error(msg"Cannot match ${scrutinee.toString} as ${sym.toString}" -> split.toLoc :: Nil) @@ -380,10 +402,35 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): nestCtx += name -> termTy val (tailTy, tailEff) = typeSplit(tail, sign)(using nestCtx) (tailTy, termEff | tailEff) - case Split.Else(alts) => sign match - case S(sign) => ascribe(alts, sign) - case _ => typeCheck(alts) - case Split.End => (Bot, Bot) + case Split.Else(alts) => + val p = path.map: u => + val m = LinkedHashMap.empty[Type, Type] + u.foreach { case (t, c) => m.updateWith(t)(_.map(_ | c).orElse(S(c))) } + m.flatMap { case (t, c) => Type.disjoint(NegType(c), t) }.toList + if p.exists(_.isEmpty) then + sign match + case S(sign) => ascribe(alts, sign) + case _ => typeCheck(alts) + else + val (nc, dss, cs) = constraintCollector + val res = sign.orElse(S(freshVar(new TempSymbol(N, "res")))).get + val eff = freshVar(new TempSymbol(N, "eff")) + val (_, e) = ascribe(alts, res)(using c = nc) + p.foreach(_.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => + c.commit(DisjSub(LinkedHashSet.from(k), dss.toList, (e, eff) :: cs.toList))) + (res, e) + case Split.End => + val ss = path.flatMap(_.map(_._1 -> Bot)) + val p = path.map: u => + val m = LinkedHashMap.empty[Type, Type] + u.foreach { case (t, c) => m.updateWith(t)(_.map(_ | c).orElse(S(c))) } + m.flatMap { case (t, c) => Type.disjoint(NegType(c), t) }.toList + if p.exists(_.isEmpty) then + ss.foreach { case (x, y) => constrain(x, y) } + else + p.foreach(_.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => + c.commit(DisjSub(LinkedHashSet.from(k), Nil, ss))) + (Bot, Bot) // * Note: currently, the returned type is not used or useful, but it could be in the future private def ascribe(lhs: Term, rhs: GeneralType)(using ctx: BbCtx, scope: Scope, c: ConstraintHandler): (GeneralType, Type) = diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index e0f8303bb4..c65ff3a24d 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -320,68 +320,90 @@ object Type: val (q, p) = discriminant(r.toBasic) ((u & q).toBasic, (w & p).toBasic) case a => (Top, a) + def in(a: BasicType, b: BasicType)(prev: Set[BasicType -> BasicType]) + (using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]) + : Opt[Set[Set[InfVar->BasicType]]] = (a.simp.toBasic, b.simp.toBasic) match + case (a, NegType(b)) => disjointImpl(a, b.toBasic)(prev) + case (v: InfVar, b) => + val p = prev + (v -> NegType(b)) + val k = v.state.lowerBounds.map(lb => in(lb.toBasic, b)(p)) + if k.exists(_.isEmpty) then N + else S(k.flatten.flatten.toSet + Set(v -> NegType(b))) + case (ComposedType(p, q, true), b) => + val u = in(p.toBasic, b)(prev) + val w = in(q.toBasic, b)(prev) + u.flatMap(u => w.map(u ++ _)) + case (ComposedType(p, q, false), b) => + (in(p.toBasic, b)(prev), in(q.toBasic, b)(prev)) match + case (N, w) => w + case (u, N) => u + case (S(u), S(w)) => S(u.flatMap(u => w.map(u ++ _))) + case (a: ClassLikeType, b: ClassLikeType) if a.name.uid === b.name.uid => S(Set.empty) + case (a: ClassLikeType, ComposedType(p, q, true)) => + (in(a, p.toBasic)(prev), in(a, q.toBasic)(prev)) match + case (N, w) => w + case (u, N) => u + case (S(u), S(w)) => S(u.flatMap(u => w.map(u ++ _))) + case _ => N def disjointImpl(a: BasicType, b: BasicType)(prev: Set[BasicType -> BasicType]) (using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]) : Opt[Set[Set[InfVar->BasicType]]] = if !prev.contains(a -> b) then c.getOrElseUpdate(a -> b, { - (a.simp.toBasic, b.simp.toBasic) match - case (Bot, _) | (_, Bot) => S(Set.empty) - case (ClassLikeType(a, _), ClassLikeType(b, _)) if a.uid =/= b.uid => S(Set.empty) - case (RcdType(u), RcdType(w)) if u.nonEmpty && w.nonEmpty => - val um = u.toMap - val wm = w.toMap - val k = um.keySet & wm.keySet - val ur = RcdType((um -- k).toList) - val wr = RcdType((wm -- k).toList) - val ud = disjointImpl(ur, ur)(prev) - val wd = disjointImpl(wr, wr)(prev) - if ud.exists(_.isEmpty) || wd.exists(_.isEmpty) then - S(Set.empty) - else - val d = k.flatMap(k => disjointImpl(um(k).toBasic, wm(k).toBasic)(prev)) ++ Ls(ud, wd).flatten - if d.isEmpty then N - else if d.exists(_.isEmpty) then S(Set.empty) - else S(d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y)))) - case (_: RcdType, _: FunType) | (_: FunType, _: RcdType) => S(Set.empty) - case (_: ClassLikeType, _: FunType) | (_: FunType, _: ClassLikeType) => S(Set.empty) - case (ComposedType(p, q, true), _) => - val u = disjointImpl(p.toBasic, b)(prev) - val w = disjointImpl(q.toBasic, b)(prev) - u.flatMap(u => w.map(u ++ _)) - case (_, ComposedType(p, q, true)) => - val u = disjointImpl(a, p.toBasic)(prev) - val w = disjointImpl(a, q.toBasic)(prev) - u.flatMap(u => w.map(u ++ _)) - case (ComposedType(p, q, false), _) => - (disjointImpl(p.toBasic, b)(prev), disjointImpl(q.toBasic, b)(prev)) match - case (N, w) => w - case (u, N) => u - case (S(u), S(w)) => S(u.flatMap(u => w.map(u ++ _))) - case (_, ComposedType(p, q, false)) => - (disjointImpl(a, p.toBasic)(prev), disjointImpl(a, q.toBasic)(prev)) match - case (N, w) => w - case (u, N) => u - case (S(u), S(w)) => S(u.flatMap(u => w.map(u ++ _))) - case (v: InfVar, _) => - val p = prev + (v -> b) - val k = v.state.lowerBounds.map(lb => disjointImpl(lb.toBasic, b)(p)) - if k.exists(_.isEmpty) then N - else S(k.flatten.flatten.toSet + Set(v -> b)) - case (_, v: InfVar) => - val p = prev + (a -> v) - val k = v.state.lowerBounds.map(lb => disjointImpl(a, lb.toBasic)(p)) - if k.exists(_.isEmpty) then N - else S(k.flatten.flatten.toSet + Set(v -> a)) - case (NegType(t),_) => t.!.simp.toBasic match - case NegType(_) => N - case a => disjointImpl(a, b)(prev) - case (_, NegType(t)) => t.!.simp.toBasic match - case NegType(_) => N - case a => disjointImpl(a, b)(prev) - case _ => N + (a, b) match + case (NegType(a), b) => in(b, a.toBasic)(prev) + case (a, NegType(b)) => in(a, b.toBasic)(prev) + case _ => (a.simp.toBasic, b.simp.toBasic) match + case (Bot, _) | (_, Bot) => S(Set.empty) + case (ClassLikeType(a, _), ClassLikeType(b, _)) if a.uid =/= b.uid => S(Set.empty) + case (RcdType(u), RcdType(w)) if u.nonEmpty && w.nonEmpty => + val um = u.toMap + val wm = w.toMap + val k = um.keySet & wm.keySet + val ur = RcdType((um -- k).toList) + val wr = RcdType((wm -- k).toList) + val ud = disjointImpl(ur, ur)(prev) + val wd = disjointImpl(wr, wr)(prev) + if ud.exists(_.isEmpty) || wd.exists(_.isEmpty) then + S(Set.empty) + else + val d = k.flatMap(k => disjointImpl(um(k).toBasic, wm(k).toBasic)(prev)) ++ Ls(ud, wd).flatten + if d.isEmpty then N + else if d.exists(_.isEmpty) then S(Set.empty) + else S(d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y)))) + case (_: RcdType, _: FunType) | (_: FunType, _: RcdType) => S(Set.empty) + case (_: ClassLikeType, _: FunType) | (_: FunType, _: ClassLikeType) => S(Set.empty) + case (ComposedType(p, q, true), b) => + val u = disjointImpl(p.toBasic, b)(prev) + val w = disjointImpl(q.toBasic, b)(prev) + u.flatMap(u => w.map(u ++ _)) + case (a, ComposedType(p, q, true)) => + val u = disjointImpl(a, p.toBasic)(prev) + val w = disjointImpl(a, q.toBasic)(prev) + u.flatMap(u => w.map(u ++ _)) + case (ComposedType(p, q, false), b) => + (disjointImpl(p.toBasic, b)(prev), disjointImpl(q.toBasic, b)(prev)) match + case (N, w) => w + case (u, N) => u + case (S(u), S(w)) => S(u.flatMap(u => w.map(u ++ _))) + case (a, ComposedType(p, q, false)) => + (disjointImpl(a, p.toBasic)(prev), disjointImpl(a, q.toBasic)(prev)) match + case (N, w) => w + case (u, N) => u + case (S(u), S(w)) => S(u.flatMap(u => w.map(u ++ _))) + case (v: InfVar, b) => + val p = prev + (v -> b) + val k = v.state.lowerBounds.map(lb => disjointImpl(lb.toBasic, b)(p)) + if k.exists(_.isEmpty) then N + else S(k.flatten.flatten.toSet + Set(v -> b)) + case (a, v: InfVar) => + val p = prev + (a -> v) + val k = v.state.lowerBounds.map(lb => disjointImpl(a, lb.toBasic)(p)) + if k.exists(_.isEmpty) then N + else S(k.flatten.flatten.toSet + Set(v -> a)) + case _ => N }) else S(Set.empty) def disjoint(a: Type, b: Type): Opt[Set[Set[InfVar->BasicType]]] = - disjointImpl(a.simp.toBasic, b.simp.toBasic)(Set.empty)(using c = MutMap.empty) + disjointImpl(a.toBasic, b.toBasic)(Set.empty)(using c = MutMap.empty) // * Poly types can not be used as type arguments diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index 2ab9cf6b96..e3bacb57ca 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -152,6 +152,7 @@ foofoo //│ Type: ['x, 'res, 'eff] -> 'x ->{'eff} 'res //│ Where: //│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Str<:'res +//│ 'x#¬Int ∨ ∧ 'x<:⊥ fun foofoo(x) = let t = x + 1 in "foo" @@ -177,7 +178,7 @@ f().Printer#f(42) :e f().Printer#f("oops") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.178: f().Printer#f("oops") +//│ ║ l.179: f().Printer#f("oops") //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -196,7 +197,7 @@ let ip = new Printer(foofoo) in ip.Printer#f(42) :e let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.197: let ip = new Printer(foofoo) in ip.Printer#f("42") +//│ ║ l.198: let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ║ ^^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -227,7 +228,7 @@ let tf = new TFun(inc) in tf.TFun#f(1) :e let tf = new TFun(inc) in tf.TFun#f("1") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.228: let tf = new TFun(inc) in tf.TFun#f("1") +//│ ║ l.229: let tf = new TFun(inc) in tf.TFun#f("1") //│ ║ ^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T @@ -283,10 +284,10 @@ if 1 is Foo then 0 else 1 fun test(x) = if x is Int then x + 1 else 0 test -//│ Type: ['x, 'res, 'eff] -> 'x ->{'eff} 'res +//│ Type: ['x, 'res, 'eff, 'eff1] -> 'x ->{'eff} 'res //│ Where: //│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Int<:'res -//│ Int <: 'res +//│ 'x#¬Int ∨ ∧ ⊥<:'eff1 ∧ Int<:'res test(1) //│ Type: Int @@ -357,7 +358,7 @@ throw new Error("oops") :e throw 42 //│ ╔══[ERROR] Type error in throw -//│ ║ l.358: throw 42 +//│ ║ l.359: throw 42 //│ ║ ^^ //│ ╙── because: cannot constrain Int <: Error //│ Type: ⊥ diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index 6cf30f36ee..ee7f95cf9e 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -101,6 +101,7 @@ x => if x is //│ Where: //│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int<:'res //│ 'x#Bool ∨ ∧ ⊥<:'eff1 ∧ Int<:'res +//│ 'x#¬(Bool ∨ Int) ∨ ∧ 'x<:⊥ ∧ 'x<:⊥ @@ -117,14 +118,14 @@ new Pair(1, 2) :e fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.118: fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) +//│ ║ l.119: fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ :e idIIBB(new Pair(1, 2)) //│ ╔══[ERROR] Type error in application -//│ ║ l.125: idIIBB(new Pair(1, 2)) +//│ ║ l.126: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] @@ -132,7 +133,7 @@ idIIBB(new Pair(1, 2)) //│ ╟── because: cannot constrain 'A <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) //│ ╔══[ERROR] Type error in application -//│ ║ l.125: idIIBB(new Pair(1, 2)) +//│ ║ l.126: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] @@ -144,7 +145,7 @@ idIIBB(new Pair(1, 2)) :e idIIBB(new Pair(1, true)) //│ ╔══[ERROR] Type error in application -//│ ║ l.145: idIIBB(new Pair(1, true)) +//│ ║ l.146: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Int, in ⊥ out Int] @@ -152,7 +153,7 @@ idIIBB(new Pair(1, true)) //│ ╟── because: cannot constrain 'B <: ¬(¬{Int}) //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in application -//│ ║ l.145: idIIBB(new Pair(1, true)) +//│ ║ l.146: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] @@ -200,7 +201,7 @@ k(idIB)(true, 1) :e k(idIB)("true", 1) //│ ╔══[ERROR] Type error in string literal with expected type 'x -//│ ║ l.201: k(idIB)("true", 1) +//│ ║ l.202: k(idIB)("true", 1) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Str <: 'x //│ ╟── because: cannot constrain Str <: 'x @@ -253,7 +254,7 @@ map(cons(1, cons(true, nil())))(idIB) let x = cons(1, cons(true, nil())) in map(cons(x, x))(idIB) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.254: map(cons(x, x))(idIB) +//│ ║ l.255: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -261,7 +262,7 @@ let x = cons(1, cons(true, nil())) in //│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.254: map(cons(x, x))(idIB) +//│ ║ l.255: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -271,7 +272,7 @@ let x = cons(1, cons(true, nil())) in //│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.254: map(cons(x, x))(idIB) +//│ ║ l.255: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -302,14 +303,14 @@ x => k(x, x) :e fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.303: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) +//│ ║ l.304: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ :e fun id: [A] -> (A -> A) & (Int -> Int) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.310: fun id: [A] -> (A -> A) & (Int -> Int) +//│ ║ l.311: fun id: [A] -> (A -> A) & (Int -> Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -325,7 +326,7 @@ fst(cons(1, nil())) :e fun idInt: (Int -> Int) & (Int -> Int) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.326: fun idInt: (Int -> Int) & (Int -> Int) +//│ ║ l.327: fun idInt: (Int -> Int) & (Int -> Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -341,7 +342,7 @@ wf(true) :e wf(1) //│ ╔══[ERROR] Type error in application -//│ ║ l.342: wf(1) +//│ ║ l.343: wf(1) //│ ║ ^^^^^ //│ ╟── because: cannot constrain (((Int ∨ Bool) -> Int) ∨ (Bool -> Bool)) ∧ (Str -> Str) <: Int ->{'eff} 'app //│ ╙── because: cannot constrain {0: Int} <: {0: Bool} ∨ {0: Str} @@ -362,14 +363,14 @@ zs :e wf(zs, zs) //│ ╔══[ERROR] Type error in application -//│ ║ l.363: wf(zs, zs) +//│ ║ l.364: wf(zs, zs) //│ ║ ^^^^^^^^^^ //│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: (Z ∨ S, Z ∨ S) ->{'eff} 'app //│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} //│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: {1: S} //│ ╙── because: cannot constrain Z ∨ S <: S //│ ╔══[ERROR] Type error in application -//│ ║ l.363: wf(zs, zs) +//│ ║ l.364: wf(zs, zs) //│ ║ ^^^^^^^^^^ //│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: (Z ∨ S, Z ∨ S) ->{'eff} 'app //│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} @@ -383,11 +384,11 @@ fun ill: (([b: Bool, c: Bool]) -> Bool) & (([a: Str, c: Str]) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.382: (([a: Int, b:Int]) -> Int) & +//│ ║ l.383: (([a: Int, b:Int]) -> Int) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.383: (([b: Bool, c: Bool]) -> Bool) & +//│ ║ l.384: (([b: Bool, c: Bool]) -> Bool) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.384: (([a: Str, c: Str]) -> Str) +//│ ║ l.385: (([a: Str, c: Str]) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -397,11 +398,11 @@ fun nested: (([tag: [b: Bool, c: Bool]]) -> Bool) & (([tag: [a: Str, c: Str]]) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.396: (([tag: [a: Int, b:Int]]) -> Int) & +//│ ║ l.397: (([tag: [a: Int, b:Int]]) -> Int) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.397: (([tag: [b: Bool, c: Bool]]) -> Bool) & +//│ ║ l.398: (([tag: [b: Bool, c: Bool]]) -> Bool) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.398: (([tag: [a: Str, c: Str]]) -> Str) +//│ ║ l.399: (([tag: [a: Str, c: Str]]) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -444,7 +445,7 @@ foo as (Str, Bool) -> Bool :e foo(1, "") //│ ╔══[ERROR] Type error in string literal with expected type 'y -//│ ║ l.445: foo(1, "") +//│ ║ l.446: foo(1, "") //│ ║ ^^ //│ ╟── because: cannot constrain Str <: 'y //│ ╟── because: cannot constrain Str <: 'y @@ -458,7 +459,7 @@ foo(1, "") //│ ╟── because: cannot constrain ¬⊥ ∧ 'x2 <: ¬(¬{Bool}) //│ ╟── because: cannot constrain 'x2 <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) -//│ Type: Bool +//│ Type: Bool ∨ Int fun intstr: Int | Str //│ Type: ⊤ @@ -468,12 +469,22 @@ fun increv(x) = if x is Int then x + 1 else rev(x) -//│ Type: ⊤ +increv +//│ Type: ['x, 'res, 'eff, 'eff1] -> 'x ->{'eff} 'res +//│ Where: +//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Int<:'res +//│ 'x#¬Int ∨ ∧ ⊥<:'eff1 ∧ 'x<:Str ∧ Str<:'res fun increv'(x) = if x is Int then x + 1 Str then rev(x) -//│ Type: ⊤ +increv' +//│ Type: ['x, 'res, 'eff, 'eff1] -> 'x ->{'eff ∨ 'eff1} 'res +//│ Where: +//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Int<:'res +//│ 'x#Str ∨ ∧ ⊥<:'eff1 ∧ Str ∧ 'x<:Str ∧ Str<:'res +//│ 'x#¬(Str ∨ Int) ∨ ∧ 'x<:⊥ ∧ 'x<:⊥ + increv'(intstr) //│ Type: Str ∨ Int @@ -481,9 +492,11 @@ increv'(intstr) :todo increv(intstr) //│ ╔══[ERROR] Type error in reference with expected type 'x -//│ ║ l.482: increv(intstr) +//│ ║ l.493: increv(intstr) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Int ∨ Str <: 'x -//│ ╟── because: cannot constrain Int <: 'x -//│ ╙── because: cannot constrain Int <: ¬¬Str -//│ Type: Int ∨ Str +//│ ╟── because: cannot constrain Str <: 'x +//│ ╟── because: cannot constrain 'x <: Str +//│ ╟── because: cannot constrain 'x <: ¬(¬{Str}) +//│ ╙── because: cannot constrain Int <: ¬(¬{Str}) +//│ Type: Str ∨ Int diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index 2acd752f31..1fab59a904 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -36,11 +36,13 @@ test //│ > x is Fls then fls#666 //│ > y is Fls then fls#666 //│ = [function test] -//│ Type: ['x, 'y, 'res, 'eff, 'eff1, 'eff2, 'eff3] -> ('x, 'y) ->{('eff ∨ 'eff2) ∨ 'eff3} 'res +//│ Type: ['x, 'y, 'res, 'eff, 'eff1, 'eff2] -> ('x, 'y) ->{('eff ∨ 'eff1) ∨ 'eff2} 'res //│ Where: -//│ 'x#Tru ∨ ( 'y#Tru ∨ ∧ ⊥<:'eff ∧ Tru<:'res) ∧ 'eff<:'eff1 -//│ 'x#Fls ∨ ∧ ⊥<:'eff2 ∧ Fls<:'res -//│ 'y#Fls ∨ ∧ ⊥<:'eff3 ∧ Fls<:'res +//│ 'x#Tru ∨ ∧ ⊥<:'eff ∧ Tru<:'res +//│ 'x#Fls ∨ ∧ ⊥<:'eff1 ∧ Fls<:'res +//│ 'y#¬Fls ∨ 'x#¬(Fls ∨ Tru) ∨ ∧ 'y<:⊥ ∧ 'x<:⊥ ∧ 'x<:⊥ ∧ 'y<:⊥ ∧ 'x<:⊥ ∧ 'y<:⊥ +//│ 'y#¬(Fls ∨ Tru) ∨ 'x#¬Fls ∨ ∧ 'y<:⊥ ∧ 'x<:⊥ ∧ 'x<:⊥ ∧ 'y<:⊥ ∧ 'x<:⊥ ∧ 'y<:⊥ +//│ 'y#Fls ∨ ∧ ⊥<:'eff2 ∧ Fls<:'res test(tru, tru) //│ = Tru() @@ -48,7 +50,7 @@ test(tru, tru) test(tru, fls) //│ = Fls() -//│ Type: Fls +//│ Type: Fls ∨ Tru test(fls, tru) //│ = Fls() @@ -67,6 +69,78 @@ test("hi", fls) :e test(true, false) //│ ═══[RUNTIME ERROR] Error: match error +//│ ╔══[ERROR] Type error in boolean literal with expected type 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain 'y <: ⊥ +//│ ╟── because: cannot constrain 'y <: ¬() +//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╔══[ERROR] Type error in boolean literal with expected type 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain 'x <: ⊥ +//│ ╟── because: cannot constrain 'x <: ¬() +//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╔══[ERROR] Type error in boolean literal with expected type 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain 'x <: ⊥ +//│ ╟── because: cannot constrain 'x <: ¬() +//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╔══[ERROR] Type error in boolean literal with expected type 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain 'y <: ⊥ +//│ ╟── because: cannot constrain 'y <: ¬() +//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╔══[ERROR] Type error in boolean literal with expected type 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain 'x <: ⊥ +//│ ╟── because: cannot constrain 'x <: ¬() +//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╔══[ERROR] Type error in boolean literal with expected type 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain 'y <: ⊥ +//│ ╟── because: cannot constrain 'y <: ¬() +//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╔══[ERROR] Type error in boolean literal with expected type 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain 'y <: ⊥ +//│ ╟── because: cannot constrain 'y <: ¬() +//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╔══[ERROR] Type error in boolean literal with expected type 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain 'x <: ⊥ +//│ ╟── because: cannot constrain 'x <: ¬() +//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╔══[ERROR] Type error in boolean literal with expected type 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain 'x <: ⊥ +//│ ╟── because: cannot constrain 'x <: ¬() +//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╔══[ERROR] Type error in boolean literal with expected type 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain 'y <: ⊥ +//│ ╟── because: cannot constrain 'y <: ¬() +//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╔══[ERROR] Type error in boolean literal with expected type 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain 'x <: ⊥ +//│ ╟── because: cannot constrain 'x <: ¬() +//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╔══[ERROR] Type error in boolean literal with expected type 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain Bool <: 'y +//│ ╟── because: cannot constrain 'y <: ⊥ +//│ ╟── because: cannot constrain 'y <: ¬() +//│ ╙── because: cannot constrain Bool <: ¬() //│ Type: ⊥ From 93d7ff64a462db0b8001e5a3cab36a649cb21058 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sun, 6 Apr 2025 15:04:37 +0800 Subject: [PATCH 21/36] fix if disjsub --- hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala | 13 +++++++++++-- hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls | 2 +- .../src/test/mlscript/logicsub/MarlowWadler97.mls | 10 +++++----- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index 3aabd1c1c5..46de4f22c5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -323,13 +323,22 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): pctx += sym -> PolyType.generalize(funTy, S(outer), 1) case _ => error(msg"Function definition shape not yet supported for ${sym.nme}" -> lam.toLoc :: Nil) - private def typeSplitBr(split: Split, sign: GeneralType, isElse: Bool)(using ctx: BbCtx, c: ConstraintHandler)(using CCtx, Scope): (Type, Ls[Ls[Type -> ClassLikeType]]) = split match + private def typeSplitBr(split: Split, sign: GeneralType, isElse: Bool)(using ctx: BbCtx, ch: ConstraintHandler)(using CCtx, Scope): (Type, Ls[Ls[Type -> ClassLikeType]]) = split match case Split.Cons(Branch(Ref(sym), c: Pattern.ClassLike, cons), alts) => val sty = tryMkMono(ctx.get(sym).get, sym) val cls = ClassLikeType(c.sym, Nil) val ctx1 = ctx.nest ctx1 += sym -> (cls & sty) - val (ce, p0) = typeSplitBr(cons, sign, false)(using ctx1) + val (ce, p0) = Type.disjoint(cls, sty) match + case N => typeSplitBr(cons, sign, false)(using ctx1) + case S(k) => + if k.isEmpty then (Bot, Ls(Nil)) + else + val (nc, dss, cs) = constraintCollector + val eff = freshVar(new TempSymbol(N, "eff")) + val (e, p) = typeSplitBr(cons, sign, false)(using ctx1, nc) + k.foreach(k => ch.commit(DisjSub(LinkedHashSet.from(k), dss.toList, (e, eff) :: cs.toList))) + (eff, p) val (ae, p1) = typeSplitBr(alts, sign, true) val p = if p1.isEmpty then if isElse then Nil else Ls(sty -> cls) :: p0 diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index ee7f95cf9e..cfa4964b4f 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -459,7 +459,7 @@ foo(1, "") //│ ╟── because: cannot constrain ¬⊥ ∧ 'x2 <: ¬(¬{Bool}) //│ ╟── because: cannot constrain 'x2 <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) -//│ Type: Bool ∨ Int +//│ Type: Bool fun intstr: Int | Str //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index 1fab59a904..04dbcb09e3 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -36,13 +36,13 @@ test //│ > x is Fls then fls#666 //│ > y is Fls then fls#666 //│ = [function test] -//│ Type: ['x, 'y, 'res, 'eff, 'eff1, 'eff2] -> ('x, 'y) ->{('eff ∨ 'eff1) ∨ 'eff2} 'res +//│ Type: ['x, 'y, 'res, 'eff, 'eff1, 'eff2, 'eff3] -> ('x, 'y) ->{('eff ∨ 'eff2) ∨ 'eff3} 'res //│ Where: -//│ 'x#Tru ∨ ∧ ⊥<:'eff ∧ Tru<:'res -//│ 'x#Fls ∨ ∧ ⊥<:'eff1 ∧ Fls<:'res +//│ 'x#Tru ∨ ( 'y#Tru ∨ ∧ ⊥<:'eff ∧ Tru<:'res) ∧ 'eff<:'eff1 +//│ 'x#Fls ∨ ∧ ⊥<:'eff2 ∧ Fls<:'res //│ 'y#¬Fls ∨ 'x#¬(Fls ∨ Tru) ∨ ∧ 'y<:⊥ ∧ 'x<:⊥ ∧ 'x<:⊥ ∧ 'y<:⊥ ∧ 'x<:⊥ ∧ 'y<:⊥ //│ 'y#¬(Fls ∨ Tru) ∨ 'x#¬Fls ∨ ∧ 'y<:⊥ ∧ 'x<:⊥ ∧ 'x<:⊥ ∧ 'y<:⊥ ∧ 'x<:⊥ ∧ 'y<:⊥ -//│ 'y#Fls ∨ ∧ ⊥<:'eff2 ∧ Fls<:'res +//│ 'y#Fls ∨ ∧ ⊥<:'eff3 ∧ Fls<:'res test(tru, tru) //│ = Tru() @@ -50,7 +50,7 @@ test(tru, tru) test(tru, fls) //│ = Fls() -//│ Type: Fls ∨ Tru +//│ Type: Fls test(fls, tru) //│ = Fls() From 3cd0f966440edb87c37c6d77fa3a7ce17aaaebcf Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Tue, 8 Apr 2025 23:35:44 +0800 Subject: [PATCH 22/36] wip if --- .../src/main/scala/hkmc2/bbml/bbML.scala | 175 +++++++---------- .../src/main/scala/hkmc2/bbml/types.scala | 32 ++-- .../src/test/mlscript/bbml/bbBasics.mls | 14 +- .../src/test/mlscript/bbml/bbCodeGen.mls | 3 + .../src/test/mlscript/bbml/bbGetters.mls | 2 +- .../src/test/mlscript/logicsub/DisjSub.mls | 173 ++++------------- .../shared/src/test/mlscript/logicsub/If.mls | 180 ++++++++++++++++++ .../test/mlscript/logicsub/MarlowWadler97.mls | 68 ++----- 8 files changed, 332 insertions(+), 315 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/logicsub/If.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index 46de4f22c5..11b5b5c114 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -323,123 +323,90 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): pctx += sym -> PolyType.generalize(funTy, S(outer), 1) case _ => error(msg"Function definition shape not yet supported for ${sym.nme}" -> lam.toLoc :: Nil) - private def typeSplitBr(split: Split, sign: GeneralType, isElse: Bool)(using ctx: BbCtx, ch: ConstraintHandler)(using CCtx, Scope): (Type, Ls[Ls[Type -> ClassLikeType]]) = split match - case Split.Cons(Branch(Ref(sym), c: Pattern.ClassLike, cons), alts) => - val sty = tryMkMono(ctx.get(sym).get, sym) - val cls = ClassLikeType(c.sym, Nil) - val ctx1 = ctx.nest - ctx1 += sym -> (cls & sty) - val (ce, p0) = Type.disjoint(cls, sty) match - case N => typeSplitBr(cons, sign, false)(using ctx1) + private def typeSplitImpl(split: Split, sign: GeneralType, eff: Type, br: Bool, path: Ls[LinkedHashMap[Ref, Type]]) + (using ctx: BbCtx, c: ConstraintHandler, sv: HashMap[Ref, InfVar])(using CCtx, Scope) + : Ls[LinkedHashMap[Ref, Type]] = split match + case Split.Cons(Branch(s: Ref, cp: Pattern.ClassLike, cons), alts) => + val sty = tryMkMono(typeCheck(s)._1, s) + val cls = ClassLikeType(cp.sym, Nil) + sv.updateWith(s)(_.orElse(S(freshVar(new TempSymbol(S(s), s.sym.nme))))) + val (ctx1, ctx2) = (ctx.nest, ctx.nest) + ctx1 += s.sym -> (cls & sty) + val p0 = LinkedHashMap(s -> cls) :: (Type.disjoint(cls, sty) match + case N => typeSplitImpl(cons, sign, eff, true, Ls(LinkedHashMap.empty))(using ctx1) case S(k) => - if k.isEmpty then (Bot, Ls(Nil)) + if k.isEmpty then Nil else val (nc, dss, cs) = constraintCollector - val eff = freshVar(new TempSymbol(N, "eff")) - val (e, p) = typeSplitBr(cons, sign, false)(using ctx1, nc) - k.foreach(k => ch.commit(DisjSub(LinkedHashSet.from(k), dss.toList, (e, eff) :: cs.toList))) - (eff, p) - val (ae, p1) = typeSplitBr(alts, sign, true) - val p = if p1.isEmpty then - if isElse then Nil else Ls(sty -> cls) :: p0 - else - (Ls(sty -> cls) :: p0).flatMap(u => p1.map(u ++ _)) - (ce | ae, p) + val p = typeSplitImpl(cons, sign, eff, true, Ls(LinkedHashMap.empty))(using ctx1, nc) + k.foreach(k => c.commit(DisjSub(LinkedHashSet.from(k), dss.toList, cs.toList))) + p) + p0.flatMap(_.keysIterator).distinct.foreach(s => ctx2 += s.sym -> sv(s)) + val p = p0.flatMap(x => path.map: y => + val m = y.clone() + x.foreachEntry((s, t) => m.updateWith(s)(_.map(_ | t).orElse(S(t)))) + m) + val (nc, dss, cs) = constraintCollector + val p1 = typeSplitImpl(alts, sign, eff, br, p)(using ctx2, nc) + p.foreach: p => + val ds = p.map { case (s, t) => Type.disjoint(NegType(t), tryMkMono(typeCheck(s)._1, s)) }.flatten + val scs = sv.toList.map: + case (s, v) => p.get(s) match + case N => (tryMkMono(typeCheck(s)._1, s), v) + case S(t) => (t.! & tryMkMono(typeCheck(s)._1, s), v) + if ds.isEmpty then + dss.foreach(c.commit(_)) + (scs ++ cs).foreach(u => constrain(u._1, u._2)) + else + ds.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => + c.commit(DisjSub(LinkedHashSet.from(k), dss.toList, scs ++ cs)) + if br then + p1.flatMap(x => p.map: y => + val m = y.clone() + x.foreachEntry((s, t) => m.updateWith(s)(_.map(_ | t).orElse(S(t)))) + m) + else Nil + case Split.Cons(Branch(s: Ref, Pattern.Lit(lit), cons), alts) => + constrain(tryMkMono(typeCheck(s)._1, s), lit match + case _: Tree.BoolLit => BbCtx.boolTy + case _: Tree.IntLit => BbCtx.intTy + case _: Tree.DecLit => BbCtx.numTy + case _: Tree.StrLit => BbCtx.strTy + case _: Tree.UnitLit => Top) + val p0 = typeSplitImpl(cons, sign, eff, true, List(LinkedHashMap.empty)) + val p = p0.flatMap(x => path.map: y => + val m = y.clone() + x.foreachEntry((s, t) => m.updateWith(s)(_.map(_ | t).orElse(S(t)))) + m) + val p1 = typeSplitImpl(alts, sign, eff, br, p) + if br then + p1.flatMap(x => p.map: y => + val m = y.clone() + x.foreachEntry((s, t) => m.updateWith(s)(_.map(_ | t).orElse(S(t)))) + m) + else Nil case Split.Let(name, term, tail) => val nestCtx = ctx.nest given BbCtx = nestCtx val (termTy, termEff) = typeCheck(term) val sk = freshSkolem(name) nestCtx += name -> termTy - val (tailEff, p) = typeSplitBr(tail, sign, isElse)(using nestCtx) - (termEff | tailEff, p) - case Split.Else(alts) => (ascribe(alts, sign)._2, Nil) - case Split.End => (Bot, Nil) + constrain(termEff, eff) + typeSplitImpl(tail, sign, eff, br, path) + case Split.Else(e) => + constrain(ascribe(e, sign)._2, eff) + Nil + case Split.End => + if !br then constrain(Top, Bot) + Ls(LinkedHashMap.empty) private def typeSplit (split: Split, sign: Opt[GeneralType], path: Ls[Ls[Type -> ClassLikeType]] = Ls(Nil))(using ctx: BbCtx, c: ConstraintHandler)(using CCtx, Scope) : (GeneralType, Type) = - split match - case Split.Cons(Branch(scrutinee, pattern, cons), alts) => - val (scrutineeTy, scrutineeEff) = typeCheck(scrutinee) - pattern match - case Pattern.ClassLike(sym, _, _, _) => - sym.asCls.flatMap(_.defn) match - case S(cls) => - val nestCtx1 = ctx.nest - val nestCtx2 = ctx.nest - val clsTy = ClassLikeType(sym, cls.tparams.map(_ => Wildcard.empty)) - val sty = tryMkMono(scrutineeTy, scrutinee) - val res = sign.orElse(S(freshVar(new TempSymbol(N, "res")))) - scrutinee match // * refine - case Ref(sym: LocalSymbol) => - nestCtx1 += sym -> (clsTy & sty) - nestCtx2 += sym -> sty - case _ => () // TODO: refine all variables holding this value? - val (consEff, p) = Type.disjoint(clsTy, sty) match - case N => typeSplitBr(cons, res.get, false)(using nestCtx1) - case S(k) => - if k.isEmpty then (Bot, Ls(Nil)) - else - val (nc, dss, cs) = constraintCollector - val eff = freshVar(new TempSymbol(N, "eff")) - val (e, p) = typeSplitBr(cons, res.get, false)(using nestCtx1, nc) - k.foreach(k => c.commit(DisjSub(LinkedHashSet.from(k), dss.toList, (e, eff) :: cs.toList))) - (eff, p) - val (altsTy, altsEff) = typeSplit(alts, res, (Ls(sty -> clsTy) :: p).flatMap(u => path.map(u ++ _)))(using nestCtx2) - val allEff = scrutineeEff | (consEff | altsEff) - (res.get, allEff) - case _ => - error(msg"Cannot match ${scrutinee.toString} as ${sym.toString}" -> split.toLoc :: Nil) - (Bot, Bot) - case Pattern.Lit(lit) => - constrain(tryMkMono(scrutineeTy, scrutinee), lit match - case _: Tree.BoolLit => BbCtx.boolTy - case _: Tree.IntLit => BbCtx.intTy - case _: Tree.DecLit => BbCtx.numTy - case _: Tree.StrLit => BbCtx.strTy - case _: Tree.UnitLit => Top) - val (consTy, consEff) = typeSplit(cons, sign) - val (altsTy, altsEff) = typeSplit(alts, sign) - val allEff = scrutineeEff | (consEff | altsEff) - (sign.getOrElse(tryMkMono(consTy, cons) | tryMkMono(altsTy, alts)), allEff) - case Split.Let(name, term, tail) => - val nestCtx = ctx.nest - given BbCtx = nestCtx - val (termTy, termEff) = typeCheck(term) - val sk = freshSkolem(name) - nestCtx += name -> termTy - val (tailTy, tailEff) = typeSplit(tail, sign)(using nestCtx) - (tailTy, termEff | tailEff) - case Split.Else(alts) => - val p = path.map: u => - val m = LinkedHashMap.empty[Type, Type] - u.foreach { case (t, c) => m.updateWith(t)(_.map(_ | c).orElse(S(c))) } - m.flatMap { case (t, c) => Type.disjoint(NegType(c), t) }.toList - if p.exists(_.isEmpty) then - sign match - case S(sign) => ascribe(alts, sign) - case _ => typeCheck(alts) - else - val (nc, dss, cs) = constraintCollector - val res = sign.orElse(S(freshVar(new TempSymbol(N, "res")))).get - val eff = freshVar(new TempSymbol(N, "eff")) - val (_, e) = ascribe(alts, res)(using c = nc) - p.foreach(_.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - c.commit(DisjSub(LinkedHashSet.from(k), dss.toList, (e, eff) :: cs.toList))) - (res, e) - case Split.End => - val ss = path.flatMap(_.map(_._1 -> Bot)) - val p = path.map: u => - val m = LinkedHashMap.empty[Type, Type] - u.foreach { case (t, c) => m.updateWith(t)(_.map(_ | c).orElse(S(c))) } - m.flatMap { case (t, c) => Type.disjoint(NegType(c), t) }.toList - if p.exists(_.isEmpty) then - ss.foreach { case (x, y) => constrain(x, y) } - else - p.foreach(_.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - c.commit(DisjSub(LinkedHashSet.from(k), Nil, ss))) - (Bot, Bot) + val res = sign.orElse(S(freshVar(new TempSymbol(N, "res")))).get + val eff = freshVar(new TempSymbol(N, "eff")) + typeSplitImpl(split, res, eff, false, Ls(LinkedHashMap.empty))(using sv = HashMap.empty) + (res, eff) // * Note: currently, the returned type is not used or useful, but it could be in the future private def ascribe(lhs: Term, rhs: GeneralType)(using ctx: BbCtx, scope: Scope, c: ConstraintHandler): (GeneralType, Type) = diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index c65ff3a24d..e5cde853ed 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -527,21 +527,23 @@ class VarState: case class DisjSub(disjoint: LinkedHashSet[InfVar -> BasicType], dss: Ls[DisjSub], cs: Ls[Type -> Type]): def commit() = disjoint.keys.foreach(_.state.disjsub += this) def checkAndCommit()(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]): Ls[Type -> Type] = - disjoint.keys.foreach(_.state.disjsub -= this) - val d = disjoint.flatMap: u => - Type.disjointImpl(u._2, u._1)(Set.empty) match - case N => - disjoint -= u - N - case k => k - if disjoint.isEmpty then - dss.flatMap(_.checkAndCommit()) ++ cs - else - if d.nonEmpty then - commit() - d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - DisjSub(LinkedHashSet.from(k), dss, cs).commit() - Nil + if disjoint.nonEmpty then + disjoint.keys.foreach(_.state.disjsub -= this) + val d = disjoint.flatMap: u => + Type.disjointImpl(u._2, u._1)(Set.empty) match + case N => + disjoint -= u + N + case k => k + if disjoint.isEmpty then + dss.flatMap(_.checkAndCommit()) ++ cs + else + if d.nonEmpty then + commit() + d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => + DisjSub(LinkedHashSet.from(k), dss, cs).commit() + Nil + else Nil def checkImpl(v: InfVar)(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]) = v.state.disjsub -= this val (u, w) = disjoint.toList.partition(_._1.uid === v.uid) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index e3bacb57ca..defe1a6edd 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -149,10 +149,10 @@ fun foofoo(x) = if x is Int then let t = x + 1 in "foo" foofoo -//│ Type: ['x, 'res, 'eff] -> 'x ->{'eff} 'res +//│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Str<:'res -//│ 'x#¬Int ∨ ∧ 'x<:⊥ +//│ 'x#Int ∨ ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Str<:'res ∧ ⊥<:'eff +//│ 'x#¬Int ∨ ∧ ¬Int ∧ 'x<:'x1 ∧ ⊤<:⊥ fun foofoo(x) = let t = x + 1 in "foo" @@ -270,7 +270,7 @@ if 1 < 2 then 1 else 0 if false then 1 else "1" -//│ Type: Int ∨ Str +//│ Type: Str ∨ Int if 1 is Int then 1 else 0 @@ -284,10 +284,10 @@ if 1 is Foo then 0 else 1 fun test(x) = if x is Int then x + 1 else 0 test -//│ Type: ['x, 'res, 'eff, 'eff1] -> 'x ->{'eff} 'res +//│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Int<:'res -//│ 'x#¬Int ∨ ∧ ⊥<:'eff1 ∧ Int<:'res +//│ 'x#Int ∨ ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Int<:'res ∧ ⊥<:'eff +//│ 'x#¬Int ∨ ∧ ¬Int ∧ 'x<:'x1 ∧ Int<:'res ∧ ⊥<:'eff test(1) //│ Type: Int diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbCodeGen.mls b/hkmc2/shared/src/test/mlscript/bbml/bbCodeGen.mls index 7ff168e31f..c4c9aca8a9 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbCodeGen.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbCodeGen.mls @@ -169,6 +169,7 @@ fun pow(x) = case :sjs +:fixme fun not = case true then false false then true @@ -187,6 +188,8 @@ fun not = case //│ }); //│ return lambda1 //│ }; +//│ ╔══[ERROR] Type error in `if` expression +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls index 81e3a81e0d..7961b9dfff 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls @@ -37,7 +37,7 @@ fun test2() = 0 then 0 n then funny(n - 1) + 1 funny -//│ ╔══[ERROR] Expected a monomorphic type or an instantiable type here, but () ->{⊥} [outer, 'caseScrut, 'eff] -> 'caseScrut ->{'eff} Int found +//│ ╔══[ERROR] Expected a monomorphic type or an instantiable type here, but () ->{⊥} [outer, 'caseScrut, 'res, 'eff] -> 'caseScrut ->{'eff} 'res found //│ ║ l.38: n then funny(n - 1) + 1 //│ ║ ^^^^^^^^^^^^^^^^ //│ ║ l.39: funny diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index cfa4964b4f..2df4a622db 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -93,18 +93,6 @@ idIIBB([1, 2]) //│ ╙── ^^^^^^ //│ Type: ⊥ - -x => if x is - Int then 0 - Bool then 0 -//│ Type: ('x) ->{'eff ∨ 'eff1} 'res -//│ Where: -//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int<:'res -//│ 'x#Bool ∨ ∧ ⊥<:'eff1 ∧ Int<:'res -//│ 'x#¬(Bool ∨ Int) ∨ ∧ 'x<:⊥ ∧ 'x<:⊥ - - - class Pair[out A, out B](fst: A, snd: B) //│ Type: ⊤ @@ -118,14 +106,14 @@ new Pair(1, 2) :e fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.119: fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) +//│ ║ l.107: fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ :e idIIBB(new Pair(1, 2)) //│ ╔══[ERROR] Type error in application -//│ ║ l.126: idIIBB(new Pair(1, 2)) +//│ ║ l.114: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] @@ -133,7 +121,7 @@ idIIBB(new Pair(1, 2)) //│ ╟── because: cannot constrain 'A <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) //│ ╔══[ERROR] Type error in application -//│ ║ l.126: idIIBB(new Pair(1, 2)) +//│ ║ l.114: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] @@ -145,7 +133,7 @@ idIIBB(new Pair(1, 2)) :e idIIBB(new Pair(1, true)) //│ ╔══[ERROR] Type error in application -//│ ║ l.146: idIIBB(new Pair(1, true)) +//│ ║ l.134: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Int, in ⊥ out Int] @@ -153,7 +141,7 @@ idIIBB(new Pair(1, true)) //│ ╟── because: cannot constrain 'B <: ¬(¬{Int}) //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in application -//│ ║ l.146: idIIBB(new Pair(1, true)) +//│ ║ l.134: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] @@ -175,7 +163,7 @@ foo fun foo(x) = if x is [true, true] then 1 [false, false] then 2 -//│ /!!!\ Uncaught error: scala.MatchError: Tuple(2,false) (of class hkmc2.semantics.Pattern$Tuple) +//│ /!!!\ Uncaught error: scala.MatchError: Cons(Branch(Ref(x),Tuple(2,false),Let($first0,SynthSel(Ref(x),Ident(0)),Let($first1,SynthSel(Ref(x),Ident(1)),Cons(Branch(Ref($first0),Lit(BoolLit(true)),Cons(Branch(Ref($first1),Lit(BoolLit(true)),Else(Lit(IntLit(1)))),End)),End)))),Cons(Branch(Ref(x),Tuple(2,false),Let($first0,SynthSel(Ref(x),Ident(0)),Let($first1,SynthSel(Ref(x),Ident(1)),Cons(Branch(Ref($first0),Lit(BoolLit(false)),Cons(Branch(Ref($first1),Lit(BoolLit(false)),Else(Lit(IntLit(2)))),End)),End)))),End)) (of class hkmc2.semantics.Split$Cons) {x: 1, y:true} //│ Type: {x: Int, y: Bool} @@ -201,7 +189,7 @@ k(idIB)(true, 1) :e k(idIB)("true", 1) //│ ╔══[ERROR] Type error in string literal with expected type 'x -//│ ║ l.202: k(idIB)("true", 1) +//│ ║ l.190: k(idIB)("true", 1) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Str <: 'x //│ ╟── because: cannot constrain Str <: 'x @@ -254,7 +242,7 @@ map(cons(1, cons(true, nil())))(idIB) let x = cons(1, cons(true, nil())) in map(cons(x, x))(idIB) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.255: map(cons(x, x))(idIB) +//│ ║ l.243: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -262,7 +250,7 @@ let x = cons(1, cons(true, nil())) in //│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.255: map(cons(x, x))(idIB) +//│ ║ l.243: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -272,7 +260,7 @@ let x = cons(1, cons(true, nil())) in //│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) //│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.255: map(cons(x, x))(idIB) +//│ ║ l.243: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} @@ -303,14 +291,14 @@ x => k(x, x) :e fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.304: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) +//│ ║ l.292: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ :e fun id: [A] -> (A -> A) & (Int -> Int) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.311: fun id: [A] -> (A -> A) & (Int -> Int) +//│ ║ l.299: fun id: [A] -> (A -> A) & (Int -> Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -326,7 +314,7 @@ fst(cons(1, nil())) :e fun idInt: (Int -> Int) & (Int -> Int) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.327: fun idInt: (Int -> Int) & (Int -> Int) +//│ ║ l.315: fun idInt: (Int -> Int) & (Int -> Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -342,7 +330,7 @@ wf(true) :e wf(1) //│ ╔══[ERROR] Type error in application -//│ ║ l.343: wf(1) +//│ ║ l.331: wf(1) //│ ║ ^^^^^ //│ ╟── because: cannot constrain (((Int ∨ Bool) -> Int) ∨ (Bool -> Bool)) ∧ (Str -> Str) <: Int ->{'eff} 'app //│ ╙── because: cannot constrain {0: Int} <: {0: Bool} ∨ {0: Str} @@ -358,24 +346,28 @@ fun wf: ((Z, Z) -> Z) & ((Z, S) -> S) & ((S, Z | S) -> S) let zs = if true then new Z() else new S() zs -//│ Type: Z ∨ S +//│ Type: S ∨ Z :e wf(zs, zs) //│ ╔══[ERROR] Type error in application -//│ ║ l.364: wf(zs, zs) +//│ ║ l.352: wf(zs, zs) //│ ║ ^^^^^^^^^^ -//│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: (Z ∨ S, Z ∨ S) ->{'eff} 'app -//│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} -//│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: {1: S} -//│ ╙── because: cannot constrain Z ∨ S <: S +//│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: ('res, 'res) ->{'eff} 'app +//│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} +//│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: {1: S} +//│ ╟── because: cannot constrain 'res <: S +//│ ╟── because: cannot constrain 'res <: ¬(¬{S}) +//│ ╙── because: cannot constrain Z <: ¬(¬{S}) //│ ╔══[ERROR] Type error in application -//│ ║ l.364: wf(zs, zs) +//│ ║ l.352: wf(zs, zs) //│ ║ ^^^^^^^^^^ -//│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: (Z ∨ S, Z ∨ S) ->{'eff} 'app -//│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} -//│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: {1: Z} -//│ ╙── because: cannot constrain Z ∨ S <: Z +//│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: ('res, 'res) ->{'eff} 'app +//│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} +//│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: {1: Z} +//│ ╟── because: cannot constrain 'res <: Z +//│ ╟── because: cannot constrain 'res <: ¬(¬{Z}) +//│ ╙── because: cannot constrain S <: ¬(¬{Z}) //│ Type: S ∨ Z :e @@ -384,11 +376,11 @@ fun ill: (([b: Bool, c: Bool]) -> Bool) & (([a: Str, c: Str]) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.383: (([a: Int, b:Int]) -> Int) & +//│ ║ l.375: (([a: Int, b:Int]) -> Int) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.384: (([b: Bool, c: Bool]) -> Bool) & +//│ ║ l.376: (([b: Bool, c: Bool]) -> Bool) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.385: (([a: Str, c: Str]) -> Str) +//│ ║ l.377: (([a: Str, c: Str]) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -398,105 +390,10 @@ fun nested: (([tag: [b: Bool, c: Bool]]) -> Bool) & (([tag: [a: Str, c: Str]]) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.397: (([tag: [a: Int, b:Int]]) -> Int) & +//│ ║ l.389: (([tag: [a: Int, b:Int]]) -> Int) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.398: (([tag: [b: Bool, c: Bool]]) -> Bool) & +//│ ║ l.390: (([tag: [b: Bool, c: Bool]]) -> Bool) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.399: (([tag: [a: Str, c: Str]]) -> Str) +//│ ║ l.391: (([tag: [a: Str, c: Str]]) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ - -if 0 is - Bool then "" - Int then true - Str then 0 -//│ Type: Bool - -fun not: Bool -> Bool -//│ Type: ⊤ - -fun foorec(x, y, r) = if - x is Int and y is Int then x + y - x is Str then not(y) - y is Str then r(y, x, r) -//│ Type: ⊤ - -fun foo(x, y) = foorec(x, y, foorec) -//│ Type: ⊤ - -foo(true, "") -//│ Type: Bool - -foo(1, 2) -//│ Type: Int - -foo as (Int, Int) -> Int -//│ Type: (Int, Int) ->{⊥} Int - -foo as (Str, Bool) -> Bool -//│ Type: (Str, Bool) ->{⊥} Bool - -(x => foo(x, true)) as Str -> Bool -//│ Type: (Str) ->{⊥} Bool - -(x => foo(x, "")) as Bool -> Bool -//│ Type: (Bool) ->{⊥} Bool - -:e -foo(1, "") -//│ ╔══[ERROR] Type error in string literal with expected type 'y -//│ ║ l.446: foo(1, "") -//│ ║ ^^ -//│ ╟── because: cannot constrain Str <: 'y -//│ ╟── because: cannot constrain Str <: 'y -//│ ╟── because: cannot constrain 'r <: (Str ∧ 'y1, 'x, 'r) ->{'eff} 'app -//│ ╟── because: cannot constrain 'r <: ¬(¬{(Str ∧ 'y1, 'x, 'r) ->{'eff} 'app}) -//│ ╟── because: cannot constrain ((¬⊥ ∧ 'x1, ¬⊥ ∧ 'y2, ¬⊥ ∧ 'r1) ->{((¬⊥ ∧ 'eff1) ∨ (¬⊥ ∧ 'eff2)) ∨ (¬⊥ ∧ 'eff3)} (¬⊥ ∧ 'res)) ∧ ¬⊥ <: ¬(¬{(Str ∧ 'y1, 'x, 'r) ->{'eff} 'app}) -//│ ╟── because: cannot constrain 'x <: 'y2 -//│ ╟── because: cannot constrain 'x <: 'y2 -//│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain ¬⊥ ∧ 'x2 <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Bool}) -//│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) -//│ Type: Bool - -fun intstr: Int | Str -//│ Type: ⊤ - -fun rev: Str -> Str -fun increv(x) = if x is - Int then x + 1 - else - rev(x) -increv -//│ Type: ['x, 'res, 'eff, 'eff1] -> 'x ->{'eff} 'res -//│ Where: -//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Int<:'res -//│ 'x#¬Int ∨ ∧ ⊥<:'eff1 ∧ 'x<:Str ∧ Str<:'res - -fun increv'(x) = if x is - Int then x + 1 - Str then rev(x) -increv' -//│ Type: ['x, 'res, 'eff, 'eff1] -> 'x ->{'eff ∨ 'eff1} 'res -//│ Where: -//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Int<:'res -//│ 'x#Str ∨ ∧ ⊥<:'eff1 ∧ Str ∧ 'x<:Str ∧ Str<:'res -//│ 'x#¬(Str ∨ Int) ∨ ∧ 'x<:⊥ ∧ 'x<:⊥ - - -increv'(intstr) -//│ Type: Str ∨ Int - -:todo -increv(intstr) -//│ ╔══[ERROR] Type error in reference with expected type 'x -//│ ║ l.493: increv(intstr) -//│ ║ ^^^^^^ -//│ ╟── because: cannot constrain Int ∨ Str <: 'x -//│ ╟── because: cannot constrain Str <: 'x -//│ ╟── because: cannot constrain 'x <: Str -//│ ╟── because: cannot constrain 'x <: ¬(¬{Str}) -//│ ╙── because: cannot constrain Int <: ¬(¬{Str}) -//│ Type: Str ∨ Int diff --git a/hkmc2/shared/src/test/mlscript/logicsub/If.mls b/hkmc2/shared/src/test/mlscript/logicsub/If.mls new file mode 100644 index 0000000000..b70779413b --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/logicsub/If.mls @@ -0,0 +1,180 @@ +:bbml +//│ Type: ⊤ + +//│ Type: ⊤ + +fun ib: Int | Bool +fun si: Str | Int +fun sib: Str | Int | Bool +fun rev: Str -> Str +fun not: Bool -> Bool +//│ Type: ⊤ + +fun f(x) = if x is + Int then 0 + Bool then x +f +//│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res +//│ Where: +//│ 'x#Int ∨ ∧ Int<:'res ∧ ⊥<:'eff +//│ 'x#¬Int ∨ ( 'x1#Bool ∨ ∧ Bool ∧ 'x1<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Int ∨ Bool) ∨ ∧ (¬Int ∧ ¬Bool) ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ¬Int ∧ 'x<:'x1 + +f(ib) as Int | Bool +//│ Type: Int ∨ Bool + +f(f(ib)) as Int | Bool +f(f(ib)) +//│ Type: Int ∨ ((Bool ∧ ¬Int) ∧ 'x) +//│ Where: +//│ Int <: 'x +//│ Bool ∧ ¬Int <: 'x +//│ 'x#¬(Int ∨ Bool) ∨ ∧ (¬Int ∧ ¬Bool) ∧ 'x1<:'x1 ∧ ⊤<:⊥ +//│ ¬{Int} ∧ 'x <: 'x1 +//│ Int <: 'res +//│ (Bool ∧ ¬Int) ∧ 'x <: 'res +//│ 'x1 <: ¬(Bool ∧ ¬'res) +//│ 'x1#¬(Int ∨ Bool) ∨ ∧ (¬Int ∧ ¬Bool) ∧ 'x1<:'x1 ∧ ⊤<:⊥ + +:e +f(si) +//│ ╔══[ERROR] Type error in reference with expected type 'x +//│ ║ l.39: f(si) +//│ ║ ^^ +//│ ╟── because: cannot constrain Str ∨ Int <: 'x +//│ ╟── because: cannot constrain Str <: 'x +//│ ╟── because: cannot constrain ¬Int ∧ 'x <: 'x1 +//│ ╟── because: cannot constrain ¬{Int} ∧ 'x <: 'x1 +//│ ╙── because: cannot constrain ⊤ <: ⊥ +//│ Type: Int + + +// order dependent + +fun f(x, y) = if + x is Int then 1 + y is Str then "" +f(1, "") +//│ Type: Int + +fun f(x, y) = if + y is Str then "" + x is Int then 1 +f(1, "") +//│ Type: Str + +f(1, sib) +//│ Type: Int ∨ Str + + +fun foorec(x, y, r) = if + x is Int and y is Int then x + y + x is Str then not(y) + y is Str then r(y, x, r) +//│ Type: ⊤ + +fun foo(x, y) = foorec(x, y, foorec) +//│ Type: ⊤ + +foo(true, "") +foo(1, 2) +foo as (Int, Int) -> Int +foo as (Str, Bool) -> Bool +(x => foo(x, true)) as Str -> Bool +(x => foo(x, "")) as Bool -> Bool +//│ Type: (Bool) ->{⊥} Bool + +:e +foo(1, "") +//│ ╔══[ERROR] Type error in string literal with expected type 'y +//│ ║ l.87: foo(1, "") +//│ ║ ^^ +//│ ╟── because: cannot constrain Str <: 'y +//│ ╟── because: cannot constrain Str <: 'y +//│ ╟── because: cannot constrain ¬Int ∧ 'y1 <: 'y2 +//│ ╟── because: cannot constrain ¬{Int} ∧ 'y1 <: 'y2 +//│ ╟── because: cannot constrain 'r <: (Str ∧ 'y2, 'x, 'r) ->{'eff} 'app +//│ ╟── because: cannot constrain 'r <: ¬(¬{(Str ∧ 'y2, 'x, 'r) ->{'eff} 'app}) +//│ ╟── because: cannot constrain ((¬⊥ ∧ 'x1, ¬⊥ ∧ 'y3, ¬⊥ ∧ 'r1) ->{¬⊥ ∧ 'eff1} (¬⊥ ∧ 'res)) ∧ ¬⊥ <: ¬(¬{(Str ∧ 'y2, 'x, 'r) ->{'eff} 'app}) +//│ ╟── because: cannot constrain 'x <: 'y3 +//│ ╟── because: cannot constrain 'x <: 'y3 +//│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain ¬⊥ ∧ 'x3 <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain 'x3 <: ¬(¬{Bool}) +//│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) +//│ ╔══[ERROR] Type error in string literal with expected type 'y +//│ ║ l.87: foo(1, "") +//│ ║ ^^ +//│ ╟── because: cannot constrain Str <: 'y +//│ ╟── because: cannot constrain Str <: 'y +//│ ╟── because: cannot constrain Int ∧ 'x2 <: 'x +//│ ╟── because: cannot constrain Int ∧ 'x2 <: 'x +//│ ╟── because: cannot constrain Int ∧ 'x2 <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain 'x2 <: ¬(Int ∧ ¬{Bool}) +//│ ╟── because: cannot constrain ¬⊥ ∧ 'x3 <: ¬(Int ∧ ¬{Bool}) +//│ ╟── because: cannot constrain 'x3 <: ¬(Int ∧ ¬{Bool}) +//│ ╙── because: cannot constrain Int <: ¬(Int ∧ ¬{Bool}) +//│ Type: Bool + +fun increv(x) = if x is + Int then x + 1 + else + rev(x) +increv +//│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res +//│ Where: +//│ 'x#Int ∨ ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Int<:'res ∧ ⊥<:'eff +//│ 'x#¬Int ∨ ∧ ¬Int ∧ 'x<:'x1 ∧ 'x1<:Str ∧ Str<:'res ∧ ⊥<:'eff + +fun increv'(x) = if x is + Int then x + 1 + Str then rev(x) +increv' +//│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res +//│ Where: +//│ 'x#Int ∨ ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Int<:'res ∧ ⊥<:'eff +//│ 'x#¬Int ∨ ( 'x1#Str ∨ ∧ Str ∧ 'x1<:Str ∧ Str<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Int ∨ Str) ∨ ∧ (¬Int ∧ ¬Str) ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ¬Int ∧ 'x<:'x1 + +:e +increv(sib) +//│ ╔══[ERROR] Type error in reference with expected type 'x +//│ ║ l.141: increv(sib) +//│ ║ ^^^ +//│ ╟── because: cannot constrain (Str ∨ Int) ∨ Bool <: 'x +//│ ╟── because: cannot constrain Bool <: 'x +//│ ╙── because: cannot constrain Bool <: ¬(¬{Str ∨ Int}) +//│ Type: Int ∨ Str + +:e +increv'(sib) +//│ ╔══[ERROR] Type error in reference with expected type 'x +//│ ║ l.151: increv'(sib) +//│ ║ ^^^ +//│ ╟── because: cannot constrain (Str ∨ Int) ∨ Bool <: 'x +//│ ╟── because: cannot constrain Bool <: 'x +//│ ╙── because: cannot constrain ⊤ <: ⊥ +//│ Type: Int ∨ Str + +increv(si) +//│ Type: Int ∨ Str + +increv'(si) +//│ Type: Int ∨ Str + +fun f(x, y) = if + x is Int and y is Int then 1 + x is Bool then y +//│ Type: ⊤ + +// literal matching not yet implemented + +:todo +x => if x is + true then 0 + false then 0 +//│ ╔══[ERROR] Type error in `if` expression +//│ ╙── because: cannot constrain ⊤ <: ⊥ +//│ Type: (Bool) ->{⊥} Int + diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index 04dbcb09e3..af804f4ec7 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -36,13 +36,11 @@ test //│ > x is Fls then fls#666 //│ > y is Fls then fls#666 //│ = [function test] -//│ Type: ['x, 'y, 'res, 'eff, 'eff1, 'eff2, 'eff3] -> ('x, 'y) ->{('eff ∨ 'eff2) ∨ 'eff3} 'res +//│ Type: ['x, 'y, 'res, 'eff, 'x1, 'y1] -> ('x, 'x) ->{'eff} 'res //│ Where: -//│ 'x#Tru ∨ ( 'y#Tru ∨ ∧ ⊥<:'eff ∧ Tru<:'res) ∧ 'eff<:'eff1 -//│ 'x#Fls ∨ ∧ ⊥<:'eff2 ∧ Fls<:'res -//│ 'y#¬Fls ∨ 'x#¬(Fls ∨ Tru) ∨ ∧ 'y<:⊥ ∧ 'x<:⊥ ∧ 'x<:⊥ ∧ 'y<:⊥ ∧ 'x<:⊥ ∧ 'y<:⊥ -//│ 'y#¬(Fls ∨ Tru) ∨ 'x#¬Fls ∨ ∧ 'y<:⊥ ∧ 'x<:⊥ ∧ 'x<:⊥ ∧ 'y<:⊥ ∧ 'x<:⊥ ∧ 'y<:⊥ -//│ 'y#Fls ∨ ∧ ⊥<:'eff3 ∧ Fls<:'res +//│ 'x#Tru ∨ ( 'y#Tru ∨ ∧ Tru<:'res ∧ ⊥<:'eff) ∧ ( 'y#¬Tru ∨ ∧ ¬Tru ∧ 'y<:'y1 ∧ Tru ∧ 'x<:'x1) +//│ 'x#¬Tru ∨ ( 'x1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ ¬Fls ∧ 'y1<:'y1 ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ¬Fls ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ 'y1<:'y1 ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ ¬Fls ∧ 'y1<:'y1 ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ¬Fls ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ¬Tru ∧ 'y1<:'y1 ∧ ¬Fls ∧ 'x1<:'x1) ∧ 'y<:'y1 ∧ ¬Tru ∧ 'x<:'x1 +//│ 'y#¬Tru ∨ ( 'x1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ ¬Fls ∧ 'y1<:'y1 ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ¬Fls ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ 'y1<:'y1 ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ ¬Fls ∧ 'y1<:'y1 ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ¬Fls ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ¬Tru ∧ 'y1<:'y1 ∧ ¬Fls ∧ 'x1<:'x1) ∧ ¬Tru ∧ 'y<:'y1 ∧ 'x<:'x1 test(tru, tru) //│ = Tru() @@ -72,75 +70,45 @@ test(true, false) //│ ╔══[ERROR] Type error in boolean literal with expected type 'y //│ ╟── because: cannot constrain Bool <: 'y //│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain 'y <: ⊥ -//│ ╟── because: cannot constrain 'y <: ¬() -//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ ╔══[ERROR] Type error in boolean literal with expected type 'y //│ ╟── because: cannot constrain Bool <: 'y //│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain 'x <: ⊥ -//│ ╟── because: cannot constrain 'x <: ¬() -//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ ╔══[ERROR] Type error in boolean literal with expected type 'y //│ ╟── because: cannot constrain Bool <: 'y //│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain 'x <: ⊥ -//│ ╟── because: cannot constrain 'x <: ¬() -//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ ╔══[ERROR] Type error in boolean literal with expected type 'y //│ ╟── because: cannot constrain Bool <: 'y //│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain 'y <: ⊥ -//│ ╟── because: cannot constrain 'y <: ¬() -//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ ╔══[ERROR] Type error in boolean literal with expected type 'y //│ ╟── because: cannot constrain Bool <: 'y //│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain 'x <: ⊥ -//│ ╟── because: cannot constrain 'x <: ¬() -//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╟── because: cannot constrain ¬Tru ∧ 'y <: 'y1 +//│ ╟── because: cannot constrain ¬{Tru} ∧ 'y <: 'y1 +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ ╔══[ERROR] Type error in boolean literal with expected type 'y //│ ╟── because: cannot constrain Bool <: 'y //│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain 'y <: ⊥ -//│ ╟── because: cannot constrain 'y <: ¬() -//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╟── because: cannot constrain ¬Tru ∧ 'y <: 'y1 +//│ ╟── because: cannot constrain ¬{Tru} ∧ 'y <: 'y1 +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ ╔══[ERROR] Type error in boolean literal with expected type 'y //│ ╟── because: cannot constrain Bool <: 'y //│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain 'y <: ⊥ -//│ ╟── because: cannot constrain 'y <: ¬() -//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ ╔══[ERROR] Type error in boolean literal with expected type 'y //│ ╟── because: cannot constrain Bool <: 'y //│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain 'x <: ⊥ -//│ ╟── because: cannot constrain 'x <: ¬() -//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ ╔══[ERROR] Type error in boolean literal with expected type 'y //│ ╟── because: cannot constrain Bool <: 'y //│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain 'x <: ⊥ -//│ ╟── because: cannot constrain 'x <: ¬() -//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ ╔══[ERROR] Type error in boolean literal with expected type 'y //│ ╟── because: cannot constrain Bool <: 'y //│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain 'y <: ⊥ -//│ ╟── because: cannot constrain 'y <: ¬() -//│ ╙── because: cannot constrain Bool <: ¬() -//│ ╔══[ERROR] Type error in boolean literal with expected type 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain 'x <: ⊥ -//│ ╟── because: cannot constrain 'x <: ¬() -//│ ╙── because: cannot constrain Bool <: ¬() -//│ ╔══[ERROR] Type error in boolean literal with expected type 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain 'y <: ⊥ -//│ ╟── because: cannot constrain 'y <: ¬() -//│ ╙── because: cannot constrain Bool <: ¬() +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: ⊥ - - From 3928da007ddb37873703a8d08592125b5fd1565e Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Tue, 8 Apr 2025 23:45:27 +0800 Subject: [PATCH 23/36] test --- .../shared/src/test/mlscript/logicsub/If.mls | 26 +++++++++---------- .../test/mlscript/logicsub/MarlowWadler97.mls | 6 ++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/logicsub/If.mls b/hkmc2/shared/src/test/mlscript/logicsub/If.mls index b70779413b..9f3cdc4194 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/If.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/If.mls @@ -90,17 +90,17 @@ foo(1, "") //│ ║ ^^ //│ ╟── because: cannot constrain Str <: 'y //│ ╟── because: cannot constrain Str <: 'y -//│ ╟── because: cannot constrain ¬Int ∧ 'y1 <: 'y2 -//│ ╟── because: cannot constrain ¬{Int} ∧ 'y1 <: 'y2 -//│ ╟── because: cannot constrain 'r <: (Str ∧ 'y2, 'x, 'r) ->{'eff} 'app -//│ ╟── because: cannot constrain 'r <: ¬(¬{(Str ∧ 'y2, 'x, 'r) ->{'eff} 'app}) -//│ ╟── because: cannot constrain ((¬⊥ ∧ 'x1, ¬⊥ ∧ 'y3, ¬⊥ ∧ 'r1) ->{¬⊥ ∧ 'eff1} (¬⊥ ∧ 'res)) ∧ ¬⊥ <: ¬(¬{(Str ∧ 'y2, 'x, 'r) ->{'eff} 'app}) -//│ ╟── because: cannot constrain 'x <: 'y3 -//│ ╟── because: cannot constrain 'x <: 'y3 +//│ ╟── because: cannot constrain 'x <: 'x1 +//│ ╟── because: cannot constrain 'x <: 'x1 +//│ ╟── because: cannot constrain 'r <: (Str ∧ 'y1, 'x1, 'r) ->{'eff} 'app +//│ ╟── because: cannot constrain 'r <: ¬(¬{(Str ∧ 'y1, 'x1, 'r) ->{'eff} 'app}) +//│ ╟── because: cannot constrain ((¬⊥ ∧ 'x2, ¬⊥ ∧ 'y2, ¬⊥ ∧ 'r1) ->{¬⊥ ∧ 'eff1} (¬⊥ ∧ 'res)) ∧ ¬⊥ <: ¬(¬{(Str ∧ 'y1, 'x1, 'r) ->{'eff} 'app}) +//│ ╟── because: cannot constrain 'x1 <: 'y2 +//│ ╟── because: cannot constrain 'x1 <: 'y2 +//│ ╟── because: cannot constrain 'x1 <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain 'x1 <: ¬(¬{Bool}) //│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) //│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Bool}) //│ ╟── because: cannot constrain ¬⊥ ∧ 'x3 <: ¬(¬{Bool}) //│ ╟── because: cannot constrain 'x3 <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) @@ -109,10 +109,10 @@ foo(1, "") //│ ║ ^^ //│ ╟── because: cannot constrain Str <: 'y //│ ╟── because: cannot constrain Str <: 'y -//│ ╟── because: cannot constrain Int ∧ 'x2 <: 'x -//│ ╟── because: cannot constrain Int ∧ 'x2 <: 'x -//│ ╟── because: cannot constrain Int ∧ 'x2 <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain 'x2 <: ¬(Int ∧ ¬{Bool}) +//│ ╟── because: cannot constrain Int ∧ 'x <: 'x1 +//│ ╟── because: cannot constrain Int ∧ 'x <: 'x1 +//│ ╟── because: cannot constrain Int ∧ 'x <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain 'x <: ¬(Int ∧ ¬{Bool}) //│ ╟── because: cannot constrain ¬⊥ ∧ 'x3 <: ¬(Int ∧ ¬{Bool}) //│ ╟── because: cannot constrain 'x3 <: ¬(Int ∧ ¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(Int ∧ ¬{Bool}) diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index af804f4ec7..4ab737ac67 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -38,9 +38,9 @@ test //│ = [function test] //│ Type: ['x, 'y, 'res, 'eff, 'x1, 'y1] -> ('x, 'x) ->{'eff} 'res //│ Where: -//│ 'x#Tru ∨ ( 'y#Tru ∨ ∧ Tru<:'res ∧ ⊥<:'eff) ∧ ( 'y#¬Tru ∨ ∧ ¬Tru ∧ 'y<:'y1 ∧ Tru ∧ 'x<:'x1) -//│ 'x#¬Tru ∨ ( 'x1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ ¬Fls ∧ 'y1<:'y1 ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ¬Fls ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ 'y1<:'y1 ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ ¬Fls ∧ 'y1<:'y1 ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ¬Fls ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ¬Tru ∧ 'y1<:'y1 ∧ ¬Fls ∧ 'x1<:'x1) ∧ 'y<:'y1 ∧ ¬Tru ∧ 'x<:'x1 -//│ 'y#¬Tru ∨ ( 'x1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ ¬Fls ∧ 'y1<:'y1 ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ¬Fls ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ 'y1<:'y1 ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ ¬Fls ∧ 'y1<:'y1 ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ¬Fls ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ¬Tru ∧ 'y1<:'y1 ∧ ¬Fls ∧ 'x1<:'x1) ∧ ¬Tru ∧ 'y<:'y1 ∧ 'x<:'x1 +//│ 'x#Tru ∨ ( 'y#Tru ∨ ∧ Tru<:'res ∧ ⊥<:'eff) ∧ ( 'y#¬Tru ∨ ∧ Tru ∧ 'x<:'x1 ∧ ¬Tru ∧ 'y<:'y1) +//│ 'x#¬Tru ∨ ( 'x1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ¬Fls ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ ¬Fls ∧ 'x1<:'x1 ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ 'y1<:'y1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ¬Fls ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ ¬Fls ∧ 'x1<:'x1 ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ ¬Fls ∧ 'x1<:'x1 ∧ ¬Tru ∧ 'y1<:'y1) ∧ ¬Tru ∧ 'x<:'x1 ∧ 'y<:'y1 +//│ 'y#¬Tru ∨ ( 'x1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ¬Fls ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ ¬Fls ∧ 'x1<:'x1 ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ 'y1<:'y1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ¬Fls ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ ¬Fls ∧ 'x1<:'x1 ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ ¬Fls ∧ 'x1<:'x1 ∧ ¬Tru ∧ 'y1<:'y1) ∧ 'x<:'x1 ∧ ¬Tru ∧ 'y<:'y1 test(tru, tru) //│ = Tru() From 88e351888e41cc675dea388c6be48c93c5cffd23 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 11 Apr 2025 14:55:52 +0800 Subject: [PATCH 24/36] Pretty printer changes from meeting --- .../main/scala/hkmc2/bbml/PrettyPrinter.scala | 2 +- .../src/main/scala/hkmc2/bbml/types.scala | 4 +- .../src/test/mlscript/bbml/bbBasics.mls | 18 ++-- .../src/test/mlscript/bbml/bbBorrowing.mls | 6 +- .../src/test/mlscript/bbml/bbBorrowing2.mls | 4 +- .../src/test/mlscript/bbml/bbBounds.mls | 10 +- .../shared/src/test/mlscript/bbml/bbCheck.mls | 10 +- .../test/mlscript/bbml/bbCyclicExtrude.mls | 4 +- .../src/test/mlscript/bbml/bbDisjoint.mls | 20 ++-- .../src/test/mlscript/bbml/bbExtrude.mls | 26 ++--- .../shared/src/test/mlscript/bbml/bbGPCE.mls | 38 ++++---- .../test/mlscript/bbml/bbLetRegEncoding.mls | 18 ++-- .../shared/src/test/mlscript/bbml/bbList.mls | 18 ++-- .../src/test/mlscript/bbml/bbOption.mls | 2 +- .../shared/src/test/mlscript/bbml/bbPoly.mls | 2 +- hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls | 38 ++++---- hkmc2/shared/src/test/mlscript/bbml/bbRec.mls | 4 +- hkmc2/shared/src/test/mlscript/bbml/bbRef.mls | 22 ++--- hkmc2/shared/src/test/mlscript/bbml/bbSeq.mls | 14 +-- .../src/test/mlscript/bbml/bbVariance.mls | 4 +- .../src/test/mlscript/logicsub/DisjSub.mls | 94 +++++++++---------- .../shared/src/test/mlscript/logicsub/If.mls | 88 ++++++++--------- .../test/mlscript/logicsub/MarlowWadler97.mls | 32 ++++++- 23 files changed, 252 insertions(+), 226 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala index 95d9a293a6..1a8219c947 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/PrettyPrinter.scala @@ -8,7 +8,7 @@ class PrettyPrinter(output: String => Unit)(using Scope): case DisjSub(d, dss, cs) => val g = d.iterator.map { case (x, y) => s"${x.show}#${y.show} ∨ " }.mkString val h = dss.iterator.map("(" + showDisjSub(_) + ")").mkString(" ∧ ") - val b = cs.map { case (x, y) => s" ∧ ${x.simp.show}<:${y.simp.show}"}.mkString + val b = cs.iterator.map{ case (x, y) => s"${x.simp.show} <: ${y.simp.show}" }.mkString(" ∧ ") s" $g$h$b" def print(ty: GeneralType): Unit = output(s"Type: ${ty.show}") diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index e5cde853ed..1693fe1b38 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -176,7 +176,7 @@ sealed abstract class BasicType extends Type: case FunType(arg :: Nil, ret, eff) => s"${arg.paren} ->${printEff(eff)} ${ret.paren}" case FunType(args, ret, eff) => s"(${args.map(_.show).mkString(", ")}) ->${printEff(eff)} ${ret.paren}" case RcdType(fields) => s"{${fields.map { case (l, t) => s"$l: ${t.show}" }.mkString(", ")}}" - case ComposedType(lhs, rhs, pol) => s"${lhs.paren} ${if pol then "∨" else "∧"} ${rhs.paren}" + case ComposedType(lhs, rhs, pol) => s"${lhs.paren} ${if pol then "|" else "&"} ${rhs.paren}" case NegType(ty) => s"¬${ty.paren}" case Top => "⊤" case Bot => "⊥" @@ -190,7 +190,7 @@ sealed abstract class BasicType extends Type: case FunType(arg :: Nil, ret, eff) => s"${arg.parenDbg} ->{${eff.showDbg}} ${ret.parenDbg}" case FunType(args, ret, eff) => s"(${args.map(_.showDbg).mkString(", ")}) ->{${eff.showDbg}} ${ret.parenDbg}" case RcdType(fields) => s"{${fields.map { case (l, t) => s"$l: ${t.showDbg}" }.mkString(", ")}}" - case ComposedType(lhs, rhs, pol) => s"${lhs.parenDbg} ${if pol then "∨" else "∧"} ${rhs.parenDbg}" + case ComposedType(lhs, rhs, pol) => s"${lhs.parenDbg} ${if pol then "|" else "&"} ${rhs.parenDbg}" case NegType(ty) => s"¬${ty.parenDbg}" case Top => "⊤" case Bot => "⊥" diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index defe1a6edd..e1c6629e01 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -151,8 +151,8 @@ fun foofoo(x) = foofoo //│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Str<:'res ∧ ⊥<:'eff -//│ 'x#¬Int ∨ ∧ ¬Int ∧ 'x<:'x1 ∧ ⊤<:⊥ +//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Str <: 'res ∧ ⊥ <: 'eff +//│ 'x#¬Int ∨ ¬Int & 'x <: 'x1 ∧ ⊤ <: ⊥ fun foofoo(x) = let t = x + 1 in "foo" @@ -169,7 +169,7 @@ fun f() = new Printer(foofoo) f //│ Type: ['T, 'x] -> () -> Printer['T] //│ Where: -//│ 'T#'T ∨ ( 'T#⊤ ∨ ∧ Str<:Str ∧ ⊥<:⊥ ∧ 'T<:'x) ∧ {0: 'T}<:{0: ⊤} +//│ 'T#'T ∨ ( 'T#⊤ ∨ Str <: Str ∧ ⊥ <: ⊥ ∧ 'T <: 'x){0: 'T} <: {0: ⊤} //│ 'x <: Int f().Printer#f(42) @@ -219,7 +219,7 @@ fun inc(x) = x + 1 new TFun(inc) //│ Type: TFun['T] //│ Where: -//│ 'T#'T ∨ ( 'T#⊤ ∨ ∧ Int<:'T ∧ ⊥<:⊥ ∧ 'T<:'x) ∧ {0: 'T}<:{0: ⊤} +//│ 'T#'T ∨ ( 'T#⊤ ∨ Int <: 'T ∧ ⊥ <: ⊥ ∧ 'T <: 'x){0: 'T} <: {0: ⊤} //│ 'x <: ¬¬Int let tf = new TFun(inc) in tf.TFun#f(1) @@ -239,7 +239,7 @@ let tf = new TFun(inc) in tf.TFun#f("1") //│ ╟── because: cannot constrain 'T <: ¬¬Int //│ ╟── because: cannot constrain 'T <: ¬(¬{Int}) //│ ╙── because: cannot constrain Str <: ¬(¬{Int}) -//│ Type: Int ∨ Str +//│ Type: Int | Str data class Pair[A, B](fst: A, snd: B) //│ Type: ⊤ @@ -270,7 +270,7 @@ if 1 < 2 then 1 else 0 if false then 1 else "1" -//│ Type: Str ∨ Int +//│ Type: Str | Int if 1 is Int then 1 else 0 @@ -286,8 +286,8 @@ fun test(x) = test //│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Int<:'res ∧ ⊥<:'eff -//│ 'x#¬Int ∨ ∧ ¬Int ∧ 'x<:'x1 ∧ Int<:'res ∧ ⊥<:'eff +//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#¬Int ∨ ¬Int & 'x <: 'x1 ∧ Int <: 'res ∧ ⊥ <: 'eff test(1) //│ Type: Int @@ -345,7 +345,7 @@ f f(x => x).Foo#x //│ Type: ('A) ->{⊥} 'A //│ Where: -//│ 'A#'A ∨ ( 'A#⊤ ∨ ∧ 'x<:'A ∧ ⊥<:⊥ ∧ 'A<:'x) ∧ {0: 'A}<:{0: ⊤} +//│ 'A#'A ∨ ( 'A#⊤ ∨ 'x <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'x){0: 'A} <: {0: ⊤} g => (new Foo(g)).Foo#x //│ Type: ('A -> 'A) ->{⊥} ('A) ->{⊥} 'A diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBorrowing.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBorrowing.mls index ba89c19e39..fd43e6fb09 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBorrowing.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBorrowing.mls @@ -92,7 +92,7 @@ letreg of r => //│ ║ ^^^^^ //│ ╟── because: cannot constrain 'E <: ⊥ //│ ╟── because: cannot constrain 'E <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ ¬'Rg <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & ¬'Rg <: ¬() //│ ╟── because: cannot constrain <: 'Rg //│ ╙── because: cannot constrain <: ¬() //│ Type: ⊥ @@ -128,7 +128,7 @@ letreg of r => //│ ║ ^^^ //│ ╟── because: cannot constrain 'E <: ⊥ //│ ╟── because: cannot constrain 'E <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ 'Rg <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & 'Rg <: ¬() //│ ╟── because: cannot constrain 'Rg <: ¬() //│ ╙── because: cannot constrain <: ¬() //│ Type: Reg[?, 'E] @@ -172,7 +172,7 @@ letreg of r => //│ ║ ^^^ //│ ╟── because: cannot constrain 'E <: ⊥ //│ ╟── because: cannot constrain 'E <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ 'Rg <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & 'Rg <: ¬() //│ ╟── because: cannot constrain 'Rg <: ¬() //│ ╙── because: cannot constrain <: ¬() //│ Type: Reg[?, 'E] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBorrowing2.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBorrowing2.mls index 260bc778f5..4661590c23 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBorrowing2.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBorrowing2.mls @@ -49,7 +49,7 @@ letreg of r => //│ ║ ^^^^^^^^^^ //│ ╟── because: cannot constrain 'E <: ⊥ //│ ╟── because: cannot constrain 'E <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ 'Rg <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & 'Rg <: ¬() //│ ╟── because: cannot constrain 'Rg <: ¬() //│ ╙── because: cannot constrain <: ¬() //│ Type: Int @@ -88,7 +88,7 @@ letreg of r => //│ ║ ^^^^^^^^^^ //│ ╟── because: cannot constrain 'E <: ⊥ //│ ╟── because: cannot constrain 'E <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ 'Rg <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & 'Rg <: ¬() //│ ╟── because: cannot constrain 'Rg <: ¬() //│ ╙── because: cannot constrain <: ¬() //│ Type: Int diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls index 78d5bc8677..78718a4eee 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls @@ -56,7 +56,7 @@ fun bar: Foo[in Num out Int] //│ Type: ⊤ foo(bar) -//│ Type: Foo[in Num out Int] ∨ Foo[in Num] +//│ Type: Foo[in Num out Int] | Foo[in Num] :e fun badfoo: [A extends Str restricts Int] -> A -> A @@ -87,7 +87,7 @@ bazbaz //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#⊤ ∨ ∧ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A) ∧ {0: 'A}<:{0: ⊤} +//│ 'A#'A ∨ ( 'A#⊤ ∨ 'A <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'A){0: 'A} <: {0: ⊤} bazbaz(42)(x => x + 1) //│ Type: Int @@ -98,7 +98,7 @@ cc //│ Where: //│ 'A -> 'A <: 'B //│ 'B <: 'A -> 'A -//│ 'B#'B ∨ ( 'B#⊤ ∨ ∧ 'B<:'B ∧ ⊥<:⊥ ∧ 'B<:'B) ∧ {0: 'B}<:{0: ⊤} +//│ 'B#'B ∨ ( 'B#⊤ ∨ 'B <: 'B ∧ ⊥ <: ⊥ ∧ 'B <: 'B){0: 'B} <: {0: ⊤} //│ 'B -> 'B <: 'A //│ 'A <: 'B -> 'B @@ -119,14 +119,14 @@ bazbaz as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#⊤ ∨ ∧ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A) ∧ {0: 'A}<:{0: ⊤} +//│ 'A#'A ∨ ( 'A#⊤ ∨ 'A <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'A){0: 'A} <: {0: ⊤} (x => f => bazbaz(x)(f)) as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> A //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#⊤ ∨ ∧ 'A<:'A ∧ ⊥<:⊥ ∧ 'A<:'A) ∧ {0: 'A}<:{0: ⊤} +//│ 'A#'A ∨ ( 'A#⊤ ∨ 'A <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'A){0: 'A} <: {0: ⊤} h(x => f => bazbaz(x)(f))(42) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbCheck.mls b/hkmc2/shared/src/test/mlscript/bbml/bbCheck.mls index c2be44ba59..48d8e46554 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbCheck.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbCheck.mls @@ -151,14 +151,14 @@ id as [A] -> A -> A //│ Type: ['A] -> ('A) ->{⊥} 'A 42 as Int | Num -//│ Type: Int ∨ Num +//│ Type: Int | Num 42 as [A] -> Int //│ Type: Int 42 as [A] -> Int | Num -//│ Type: Int ∨ Num +//│ Type: Int | Num fun foo: Int -> Int foo @@ -215,14 +215,14 @@ f fun f: ([A] -> ([B] -> A | B -> B | A) -> A) -> ([A] -> ([B] -> A | B -> B | A) -> A) f -//│ Type: (['A] -> (['B] -> ('A ∨ 'B) ->{⊥} 'B ∨ 'A) ->{⊥} 'A) ->{⊥} ['A] -> (['B] -> ('A ∨ 'B) ->{⊥} 'B ∨ 'A) ->{⊥} 'A +//│ Type: (['A] -> (['B] -> ('A | 'B) ->{⊥} 'B | 'A) ->{⊥} 'A) ->{⊥} ['A] -> (['B] -> ('A | 'B) ->{⊥} 'B | 'A) ->{⊥} 'A fun f: [A] -> [B] -> ([C] -> A | B -> B | C -> A | C) -> B f -//│ Type: ['A] -> (['C] -> ('A) ->{⊥} ('C) ->{⊥} 'A ∨ 'C) ->{⊥} ⊥ +//│ Type: ['A] -> (['C] -> ('A) ->{⊥} ('C) ->{⊥} 'A | 'C) ->{⊥} ⊥ fun f: [A, B] -> ([C] -> A | B -> B | C -> A | B | C) -> B f -//│ Type: ['A, 'B] -> (['C] -> ('A ∨ 'B) ->{⊥} ('B ∨ 'C) ->{⊥} ('A ∨ 'B) ∨ 'C) ->{⊥} 'B +//│ Type: ['A, 'B] -> (['C] -> ('A | 'B) ->{⊥} ('B | 'C) ->{⊥} ('A | 'B) | 'C) ->{⊥} 'B diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbCyclicExtrude.mls b/hkmc2/shared/src/test/mlscript/bbml/bbCyclicExtrude.mls index 677547e7bf..9b923f445f 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbCyclicExtrude.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbCyclicExtrude.mls @@ -46,8 +46,8 @@ fun foo(f) = (f(x => x(x)) as [A] -> A -> A) f => (let g = x => x(x) in let tmp = g(g) in f(g)) as [A] -> A -> A -//│ Type: (((('x ∨ ('x ->{'eff} 'app)) -> 'app) ->{'eff} 'app) -> (⊤ -> ⊥)) ->{⊥} ['A] -> ('A) ->{⊥} 'A +//│ Type: (((('x | ('x ->{'eff} 'app)) -> 'app) ->{'eff} 'app) -> (⊤ -> ⊥)) ->{⊥} ['A] -> ('A) ->{⊥} 'A //│ Where: -//│ 'x <: ('x ∨ ('x ->{'eff} 'app)) -> 'app +//│ 'x <: ('x | ('x ->{'eff} 'app)) -> 'app diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls b/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls index eab472c8cb..54b385de67 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls @@ -9,7 +9,7 @@ data class Pair[P, Q](fst: P, snd: Q) fun fork: [A, B extends ~A, T1, T2] -> (Any ->{A} T1, Any ->{B} T2) ->{A | B} Pair[out T1, out T2] fork -//│ Type: ['A, 'B, 'T1, 'T2] -> ((⊤) ->{'A} 'T1, (⊤) ->{'B} 'T2) ->{'A ∨ 'B} Pair[out 'T1, out 'T2] +//│ Type: ['A, 'B, 'T1, 'T2] -> ((⊤) ->{'A} 'T1, (⊤) ->{'B} 'T2) ->{'A | 'B} Pair[out 'T1, out 'T2] //│ Where: //│ 'B <: ¬'A @@ -63,8 +63,8 @@ region x in //│ ║ l.61: naive_helper(x) //│ ║ ^ //│ ╟── because: cannot constrain Region[x] <: 'r1 -//│ ╟── because: cannot constrain Region[in ¬⊥ ∧ 'x1 out ¬⊥ ∧ 'x2] ∧ ¬⊥ <: 'r1 -//│ ╟── because: cannot constrain Region[in ¬⊥ ∧ 'x1 out ¬⊥ ∧ 'x2] ∧ ¬⊥ <: Region[in 'reg out 'reg1] +//│ ╟── because: cannot constrain Region[in ¬⊥ & 'x1 out ¬⊥ & 'x2] & ¬⊥ <: 'r1 +//│ ╟── because: cannot constrain Region[in ¬⊥ & 'x1 out ¬⊥ & 'x2] & ¬⊥ <: Region[in 'reg out 'reg1] //│ ╟── because: cannot constrain 'x2 <: 'reg1 //│ ╟── because: cannot constrain 'x2 <: ¬(¬'reg1) //│ ╟── because: cannot constrain <: ¬(¬'reg1) @@ -74,8 +74,8 @@ region x in //│ ║ l.61: naive_helper(x) //│ ║ ^ //│ ╟── because: cannot constrain Region[x] <: 'r1 -//│ ╟── because: cannot constrain Region[in ¬⊥ ∧ 'x1 out ¬⊥ ∧ 'x2] ∧ ¬⊥ <: 'r1 -//│ ╟── because: cannot constrain Region[in ¬⊥ ∧ 'x1 out ¬⊥ ∧ 'x2] ∧ ¬⊥ <: Region[in 'reg out 'reg1] +//│ ╟── because: cannot constrain Region[in ¬⊥ & 'x1 out ¬⊥ & 'x2] & ¬⊥ <: 'r1 +//│ ╟── because: cannot constrain Region[in ¬⊥ & 'x1 out ¬⊥ & 'x2] & ¬⊥ <: Region[in 'reg out 'reg1] //│ ╟── because: cannot constrain 'x2 <: 'reg1 //│ ╟── because: cannot constrain 'x2 <: ¬(¬'reg1) //│ ╟── because: cannot constrain <: ¬(¬'reg1) @@ -88,7 +88,7 @@ region x in //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'eff <: ⊥ //│ ╟── because: cannot constrain 'eff <: ¬() -//│ ╟── because: cannot constrain (¬⊥ ∧ 'eff1) ∧ ¬'x3 <: ¬() +//│ ╟── because: cannot constrain (¬⊥ & 'eff1) & ¬'x3 <: ¬() //│ ╟── because: cannot constrain 'eff1 <: 'x3 //│ ╟── because: cannot constrain 'eff1 <: ¬() //│ ╟── because: cannot constrain 'eff1 <: ¬() @@ -137,13 +137,13 @@ region x in //│ ╟── because: cannot constrain x <: 'reg1 //│ ╟── because: cannot constrain x <: 'env //│ ╟── because: cannot constrain x <: 'env -//│ ╙── because: cannot constrain x <: outer ∨ y +//│ ╙── because: cannot constrain x <: outer | y //│ ╔══[ERROR] Type error in region expression with expected type [outer, 'A] -> Int //│ ║ l.129: (region y in let t = helper(x) in 42) as [A] -> Int //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'eff <: ⊥ //│ ╟── because: cannot constrain 'eff <: ¬() -//│ ╟── because: cannot constrain (¬⊥ ∧ ¬'y1) ∧ x <: ¬() +//│ ╟── because: cannot constrain (¬⊥ & ¬'y1) & x <: ¬() //│ ╟── because: cannot constrain x <: 'y1 //│ ╙── because: cannot constrain x <: ¬() //│ Type: Int @@ -195,7 +195,7 @@ fun annohelper(r1) = region r2 in fork((_ => r1.ref 1), (_ => r2.ref 2)) annohelper -//│ Type: [outer, 'T] -> (Region['T ∧ outer]) ->{'T ∧ outer} Pair[out Ref[Int, out 'T ∧ outer], out Ref[Int, out ¬outer]] +//│ Type: [outer, 'T] -> (Region['T & outer]) ->{'T & outer} Pair[out Ref[Int, out 'T & outer], out Ref[Int, out ¬outer]] region x in @@ -231,7 +231,7 @@ fun foo(r1) = //│ ╟── because: cannot constrain 'r21 <: ¬(¬'reg1) //│ ╟── because: cannot constrain ¬outer <: ¬(¬'reg1) //│ ╟── because: cannot constrain ¬outer <: 'reg1 -//│ ╟── because: cannot constrain ¬outer <: ¬'r22 ∨ outer +//│ ╟── because: cannot constrain ¬outer <: ¬'r22 | outer //│ ╟── because: cannot constrain 'r22 <: ¬(¬outer) //│ ╙── because: cannot constrain ¬outer <: ¬(¬outer) //│ ╔══[ERROR] Type error in function literal diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls index 8008a4dff2..df1b40e056 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls @@ -41,19 +41,19 @@ y `=> (let t = run(x `=> x `+ y) in y) //│ ╟── because: cannot constrain CodeBase[out 'x -> 'cde, out 'ctx, ?] <: CodeBase[out 'T, ⊥, ?] //│ ╟── because: cannot constrain 'ctx <: ⊥ //│ ╟── because: cannot constrain 'ctx <: ¬() -//│ ╟── because: cannot constrain (¬⊥ ∧ ¬'x1) ∧ y <: ¬() +//│ ╟── because: cannot constrain (¬⊥ & ¬'x1) & y <: ¬() //│ ╟── because: cannot constrain y <: 'x1 //│ ╙── because: cannot constrain y <: ¬() //│ Type: CodeBase[out 'y -> 'y, ⊥, ?] //│ Where: -//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'x2#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'x2#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x2#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x2#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x <: 'cde1 -//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'y <: 'cde2 -//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'cde <: 'cde3 //│ 'app <: ¬(¬'cde) //│ 'x2 <: 'x @@ -64,7 +64,7 @@ data class C[A](m: A, n: A -> Int) fun f: [A] -> ([B] -> (C[out B] & A) -> B) -> A -> Int f -//│ Type: ['A] -> (['B] -> (C[out 'B] ∧ 'A) ->{⊥} 'B) ->{⊥} ('A) ->{⊥} Int +//│ Type: ['A] -> (['B] -> (C[out 'B] & 'A) ->{⊥} 'B) ->{⊥} ('A) ->{⊥} Int fun g: [D] -> C[in Int out D] -> D g @@ -74,7 +74,7 @@ g f(g) //│ Type: ('A) ->{⊥} Int //│ Where: -//│ 'A#C[out B] ∨ 'A#'A ∨ ( 'A#C[?] ∨ ∧ 'D<:B ∧ ⊥<:⊥ ∧ C[out B] ∧ 'A<:C[in Int out 'D]) ∧ {0: C[out B] ∧ 'A}<:{0: C[?]} +//│ 'A#C[out B] ∨ 'A#'A ∨ ( 'A#C[?] ∨ 'D <: B ∧ ⊥ <: ⊥ ∧ C[out B] & 'A <: C[in Int out 'D]){0: C[out B] & 'A} <: {0: C[?]} fun foo: C[in Int out Nothing] foo @@ -94,10 +94,10 @@ f(g)(bar) //│ ║ ^^^ //│ ╟── because: cannot constrain C[Int] <: 'A //│ ╟── because: cannot constrain C[in Int out Int] <: 'A -//│ ╟── because: cannot constrain C[out B] ∧ 'A <: C[in Int out 'D] -//│ ╟── because: cannot constrain 'A <: ¬C[in ⊥ out ¬⊥ ∧ 'B1] ∨ C[in Int out ¬⊥ ∧ 'D1] -//│ ╟── because: cannot constrain C[in Int out Int] <: ¬C[in ⊥ out ¬⊥ ∧ 'B1] ∨ C[in Int out ¬⊥ ∧ 'D1] -//│ ╟── because: cannot constrain (Int) ∧ ('B1) <: ¬⊥ ∧ 'D1 +//│ ╟── because: cannot constrain C[out B] & 'A <: C[in Int out 'D] +//│ ╟── because: cannot constrain 'A <: ¬C[in ⊥ out ¬⊥ & 'B1] | C[in Int out ¬⊥ & 'D1] +//│ ╟── because: cannot constrain C[in Int out Int] <: ¬C[in ⊥ out ¬⊥ & 'B1] | C[in Int out ¬⊥ & 'D1] +//│ ╟── because: cannot constrain (Int) & ('B1) <: ¬⊥ & 'D1 //│ ╟── because: cannot constrain Int ∧ 'B1 <: 'D1 //│ ╟── because: cannot constrain Int ∧ 'B1 <: 'B2 //│ ╟── because: cannot constrain Int ∧ 'B1 <: 'B2 diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls index 241479ad73..3758e4ba25 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls @@ -19,15 +19,15 @@ fun id(x) = x run(x `=> id(x) `* x) //│ Type: 'x -> 'cde //│ Where: -//│ 'x#'cde1 ∨ 'x#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'cde1#'cde1 ∨ 'x#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'x#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'x#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x <: 'x1 -//│ 'x1#'cde1 ∨ 'x1#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'cde1#'cde1 ∨ 'x1#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'x1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x1#'cde1 ∨ 'x1#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'x1#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x1 <: 'cde1 -//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x1 <: 'cde2 //│ 'cde3 <: 'cde //│ 'app <: ¬(¬'cde3) @@ -40,11 +40,11 @@ let checkedDiv = x `=> y `=> x `/. (assertNotZero(y)) run(checkedDiv) //│ Type: 'x -> (Num -> 'cde) //│ Where: -//│ 'x#'cde1 ∨ ( 'x1#Num ∨ ∧ Num<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Num ∨ ∧ Num<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Num, 1: Num} +//│ 'x#'cde1 ∨ ( 'x1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Num, 1: Num} //│ 'x <: 'x1 -//│ 'x1#'cde1 ∨ ( 'x1#Num ∨ ∧ Num<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Num ∨ ∧ Num<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Num, 1: Num} +//│ 'x1#'cde1 ∨ ( 'x1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Num, 1: Num} //│ 'x1 <: 'cde1 -//│ 'cde1#'cde1 ∨ ( 'x1#Num ∨ ∧ Num<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Num ∨ ∧ Num<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Num, 1: Num} +//│ 'cde1#'cde1 ∨ ( 'x1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Num, 1: Num} //│ Num <: 'cde2 //│ 'cde3 <: 'cde //│ 'cde4 <: 'cde3 @@ -63,28 +63,28 @@ fun inc(dbg) = inc //│ Type: ['x, 'cde, 'cde1, 'app, 'app1, 'eff, 'cde2, 'x1] -> (CodeBase[out 'app1, ?, ?] ->{'eff} ⊤) ->{'eff} CodeBase[out 'x -> 'cde2, ⊥, ?] //│ Where: -//│ 'x#'cde ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde, 1: 'cde1}<:{0: Int, 1: Int} +//│ 'x#'cde ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde, 1: 'cde1} <: {0: Int, 1: Int} //│ 'x1 <: 'cde -//│ 'cde#'cde ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde, 1: 'cde1}<:{0: Int, 1: Int} +//│ 'cde#'cde ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde, 1: 'cde1} <: {0: Int, 1: Int} //│ Int <: 'cde1 //│ 'cde2 <: ⊤ //│ 'app <: 'cde2 //│ 'app <: 'app1 //│ 'x <: 'x1 -//│ 'x1#'cde ∨ ( 'x1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde, 1: 'cde1}<:{0: Int, 1: Int} +//│ 'x1#'cde ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde, 1: 'cde1} <: {0: Int, 1: Int} inc(c => log(show(c))) //│ Type: CodeBase[out 'x -> 'cde, ⊥, ?] //│ Where: -//│ 'x1#'cde1 ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x1#'cde1 ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x <: 'cde1 -//│ 'cde1#'cde1 ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ Int <: 'cde2 //│ 'cde <: ⊤ //│ 'app <: 'cde //│ 'app <: 'app1 //│ 'x1 <: 'x -//│ 'x#'cde1 ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} fun body: [T, C] -> (CodeBase[out Int, out T, out Any], CodeBase[out Int, out C, out Any]) -> Int -> CodeBase[out Int, out T | C, out Any] @@ -99,7 +99,7 @@ let gn5 = run(gib_naive(5)) fun bind(rhs, k) = `let x = rhs `in k(x) bind -//│ Type: ['cde, 'ctx, 'cde1, 'eff, 'cde2, 'ctx1] -> (CodeBase[out 'cde, out 'ctx, ?], CodeBase[in 'cde1 out 'cde1 ∨ 'cde, ?, ⊥] ->{'eff} CodeBase[out 'cde2, out 'ctx1, ?]) ->{'eff} CodeBase[out 'cde2, out 'ctx ∨ 'ctx1, ?] +//│ Type: ['cde, 'ctx, 'cde1, 'eff, 'cde2, 'ctx1] -> (CodeBase[out 'cde, out 'ctx, ?], CodeBase[in 'cde1 out 'cde1 | 'cde, ?, ⊥] ->{'eff} CodeBase[out 'cde2, out 'ctx1, ?]) ->{'eff} CodeBase[out 'cde2, out 'ctx | 'ctx1, ?] :e fun body: [G] -> (CodeBase[out Int, out G, out Any], CodeBase[out Int, out G, out Any]) -> Int -> CodeBase[out Int, out G, out Any] @@ -110,7 +110,7 @@ fun body(x, y) = case //│ ╔══[ERROR] Type error in application with expected type CodeBase[out Int, out G, ?] //│ ║ l.109: n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain CodeBase[out 'cde, out 'ctx ∨ 'ctx1, ?] <: CodeBase[out Int, out G, ?] +//│ ╟── because: cannot constrain CodeBase[out 'cde, out 'ctx | 'ctx1, ?] <: CodeBase[out Int, out G, ?] //│ ╟── because: cannot constrain 'ctx ∨ 'ctx1 <: G //│ ╟── because: cannot constrain 'ctx1 <: ¬(¬G) //│ ╟── because: cannot constrain 'ctx2 <: ¬(¬G) @@ -121,7 +121,7 @@ fun body(x, y) = case fun bind: [G] -> (CodeBase[out Int, out G, out Any], [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out Int, out C | G, out Any]) -> CodeBase[out Int, out G, out Any] fun bind(rhs, k) = `let x = rhs `in k(x) bind -//│ Type: ['G] -> (CodeBase[out Int, out 'G, ?], ['C] -> (CodeBase[out Int, out 'C, ?]) ->{⊥} CodeBase[out Int, out 'C ∨ 'G, ?]) ->{⊥} CodeBase[out Int, out 'G, ?] +//│ Type: ['G] -> (CodeBase[out Int, out 'G, ?], ['C] -> (CodeBase[out Int, out 'C, ?]) ->{⊥} CodeBase[out Int, out 'C | 'G, ?]) ->{⊥} CodeBase[out Int, out 'G, ?] fun body: [G] -> (CodeBase[out Int, out G, out Any], CodeBase[out Int, out G, out Any]) -> Int -> CodeBase[out Int, out G, out Any] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbLetRegEncoding.mls b/hkmc2/shared/src/test/mlscript/bbml/bbLetRegEncoding.mls index fd6a13fb37..330cf1e639 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbLetRegEncoding.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbLetRegEncoding.mls @@ -8,7 +8,7 @@ fun letreg: [E,Res] -> ([R] -> Region[R] ->{E | R} Res) ->{E} Res //│ Type: ⊤ letreg -//│ Type: ['E, 'Res] -> (['R] -> (Region['R]) ->{'E ∨ 'R} 'Res) ->{'E} 'Res +//│ Type: ['E, 'Res] -> (['R] -> (Region['R]) ->{'E | 'R} 'Res) ->{'E} 'Res letreg(r => r) //│ Type: Region[?] @@ -20,7 +20,7 @@ letreg(r => r).ref 1 //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'Res <: Region['reg] //│ ╟── because: cannot constrain 'Res <: ¬(¬{Region['reg]}) -//│ ╟── because: cannot constrain Region[in ¬⊥ ∧ 'R out ¬⊥ ∧ 'R1] ∧ ¬⊥ <: ¬(¬{Region['reg]}) +//│ ╟── because: cannot constrain Region[in ¬⊥ & 'R out ¬⊥ & 'R1] & ¬⊥ <: ¬(¬{Region['reg]}) //│ ╟── because: cannot constrain 'R1 <: 'reg //│ ╟── because: cannot constrain 'R1 <: 'reg //│ ╟── because: cannot constrain 'R1 <: ¬(¬'R) @@ -31,7 +31,7 @@ letreg(r => r).ref 1 //│ ╔══[ERROR] Type error in block //│ ║ l.17: letreg(r => r).ref 1 //│ ║ ^^^^^^^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain 'reg ∨ 'E <: ⊥ +//│ ╟── because: cannot constrain 'reg | 'E <: ⊥ //│ ╟── because: cannot constrain 'reg <: ¬() //│ ╟── because: cannot constrain 'R1 <: ¬() //│ ╟── because: cannot constrain 'R1 <: ¬() @@ -49,11 +49,11 @@ letreg(r => !(r.ref 1)) //│ ╔══[ERROR] Type error in block //│ ║ l.48: !letreg(r => r.ref 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain 'reg ∨ 'E <: ⊥ +//│ ╟── because: cannot constrain 'reg | 'E <: ⊥ //│ ╟── because: cannot constrain 'reg <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ 'R <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & 'R <: ¬() //│ ╟── because: cannot constrain 'R <: ¬() //│ ╙── because: cannot constrain <: ¬() //│ Type: Int @@ -75,11 +75,11 @@ letreg(r => arg => r.ref arg)(0) //│ ╔══[ERROR] Type error in block //│ ║ l.74: letreg(r => arg => r.ref arg)(0) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain 'eff ∨ 'E <: ⊥ +//│ ╟── because: cannot constrain 'eff | 'E <: ⊥ //│ ╟── because: cannot constrain 'eff <: ¬() //│ ╟── because: cannot constrain 'reg <: ¬() //│ ╟── because: cannot constrain 'reg <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ 'R <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & 'R <: ¬() //│ ╟── because: cannot constrain 'R <: ¬() //│ ╙── because: cannot constrain <: ¬() //│ Type: Ref['arg, ?] @@ -108,7 +108,7 @@ letreg(r => !(r.ref 1)) //│ ╔══[ERROR] Type error in function literal with expected type (Region[R]) ->{⊥} 'Res //│ ║ l.107: letreg(r => !(r.ref 1)) //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain 'reg ∨ 'reg1 <: ⊥ +//│ ╟── because: cannot constrain 'reg | 'reg1 <: ⊥ //│ ╟── because: cannot constrain 'reg <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() @@ -116,7 +116,7 @@ letreg(r => !(r.ref 1)) //│ ╔══[ERROR] Type error in function literal with expected type (Region[R]) ->{⊥} 'Res //│ ║ l.107: letreg(r => !(r.ref 1)) //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain 'reg ∨ 'reg1 <: ⊥ +//│ ╟── because: cannot constrain 'reg | 'reg1 <: ⊥ //│ ╟── because: cannot constrain 'reg1 <: ¬() //│ ╙── because: cannot constrain R <: ¬() //│ Type: Int diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbList.mls b/hkmc2/shared/src/test/mlscript/bbml/bbList.mls index df5d2659c6..932fe99491 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbList.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbList.mls @@ -63,9 +63,9 @@ fun mapi = s => //│ ╟── because: cannot constrain 'f ->{'E1} List[out 'B] <: ((Int, A) ->{E} A) ->{E} List[out A] //│ ╟── because: cannot constrain 'E1 <: E //│ ╟── because: cannot constrain 'E1 <: ¬(¬E) -//│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) +//│ ╟── because: cannot constrain ¬⊥ & 'reg <: ¬(¬E) //│ ╟── because: cannot constrain 'reg <: ¬(¬E) -//│ ╟── because: cannot constrain (¬⊥ ∧ 'r) ∧ ¬outer <: ¬(¬E) +//│ ╟── because: cannot constrain (¬⊥ & 'r) & ¬outer <: ¬(¬E) //│ ╟── because: cannot constrain 'r <: ¬(¬E ∧ ¬outer) //│ ╙── because: cannot constrain ¬outer <: ¬(¬E ∧ ¬outer) //│ ╔══[ERROR] Type error in region expression with expected type ((Int, A) ->{E} A) ->{E} List[out A] @@ -80,9 +80,9 @@ fun mapi = s => //│ ╟── because: cannot constrain 'f ->{'E1} List[out 'B] <: ((Int, A) ->{E} A) ->{E} List[out A] //│ ╟── because: cannot constrain 'E1 <: E //│ ╟── because: cannot constrain 'E1 <: ¬(¬E) -//│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) +//│ ╟── because: cannot constrain ¬⊥ & 'reg <: ¬(¬E) //│ ╟── because: cannot constrain 'reg <: ¬(¬E) -//│ ╟── because: cannot constrain (¬⊥ ∧ 'r) ∧ ¬outer <: ¬(¬E) +//│ ╟── because: cannot constrain (¬⊥ & 'r) & ¬outer <: ¬(¬E) //│ ╟── because: cannot constrain 'r <: ¬(¬E ∧ ¬outer) //│ ╙── because: cannot constrain ¬outer <: ¬(¬E ∧ ¬outer) //│ ╔══[ERROR] Type error in region expression with expected type ((Int, A) ->{E} A) ->{E} List[out A] @@ -97,9 +97,9 @@ fun mapi = s => //│ ╟── because: cannot constrain 'f ->{'E1} List[out 'B] <: ((Int, A) ->{E} A) ->{E} List[out A] //│ ╟── because: cannot constrain 'E1 <: E //│ ╟── because: cannot constrain 'E1 <: ¬(¬E) -//│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) +//│ ╟── because: cannot constrain ¬⊥ & 'reg <: ¬(¬E) //│ ╟── because: cannot constrain 'reg <: ¬(¬E) -//│ ╟── because: cannot constrain (¬⊥ ∧ 'r) ∧ ¬outer <: ¬(¬E) +//│ ╟── because: cannot constrain (¬⊥ & 'r) & ¬outer <: ¬(¬E) //│ ╟── because: cannot constrain 'r <: ¬(¬E ∧ ¬outer) //│ ╙── because: cannot constrain ¬outer <: ¬(¬E ∧ ¬outer) //│ Type: ⊤ @@ -129,7 +129,7 @@ region r in //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'eff <: ⊥ //│ ╟── because: cannot constrain 'eff <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ ¬'r <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & ¬'r <: ¬() //│ ╟── because: cannot constrain <: 'r //│ ╙── because: cannot constrain <: ¬() //│ ╔══[ERROR] Type error in block @@ -143,7 +143,7 @@ region r in //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'eff <: ⊥ //│ ╟── because: cannot constrain 'eff <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ ¬'r1 <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & ¬'r1 <: ¬() //│ ╟── because: cannot constrain <: 'r1 //│ ╙── because: cannot constrain <: ¬() //│ ╔══[ERROR] Type error in block @@ -157,7 +157,7 @@ region r in //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'eff <: ⊥ //│ ╟── because: cannot constrain 'eff <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ ¬'r2 <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & ¬'r2 <: ¬() //│ ╟── because: cannot constrain <: 'r2 //│ ╙── because: cannot constrain <: ¬() //│ Type: Int diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbOption.mls b/hkmc2/shared/src/test/mlscript/bbml/bbOption.mls index 12253e77c7..a9d59cb42c 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbOption.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbOption.mls @@ -28,6 +28,6 @@ opt => opt as Option[out Int] //│ Type: (Option[out Int]) ->{⊥} Option[out Int] opt => (opt as Option[Int]) as Option[Int | Str] -//│ Type: (Option[out Int ∨ Str] ∧ Option[out Int]) ->{⊥} Option[out Int ∨ Str] +//│ Type: (Option[out Int | Str] & Option[out Int]) ->{⊥} Option[out Int | Str] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbPoly.mls b/hkmc2/shared/src/test/mlscript/bbml/bbPoly.mls index a66aa7ec02..661630a0d4 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbPoly.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbPoly.mls @@ -136,7 +136,7 @@ new Some((x => x) as [A] -> A -> A) //│ 'x -> 'x <: 'A let s = new Some((x => x) as [A] -> A -> A) in let t = s.Some#value(42) in s.Some#value(false) -//│ Type: Bool ∨ Int +//│ Type: Bool | Int fun gen: Int -> [A] -> A -> A fun gen(x) = diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls index 9199e9ddc1..0064707468 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls @@ -43,13 +43,13 @@ f `=> x `=> f`(x) x `=> y `=> x `+ y //│ Type: CodeBase[out 'x -> ('x -> 'cde), ⊥, ?] //│ Where: -//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'x#'cde1 ∨ 'y1#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'cde1#'cde1 ∨ 'y1#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'y1#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y1#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x <: 'cde1 -//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'y <: 'cde2 //│ 'cde3 <: 'cde //│ 'app <: ¬(¬'cde3) @@ -60,11 +60,11 @@ x `=> y `=> x `+ y (x, y) `=> x `+ y //│ Type: CodeBase[out ('x, 'x) -> 'cde, ⊥, ?] //│ Where: -//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x <: 'cde1 -//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'y <: 'cde2 //│ 'app <: ¬(¬'cde) @@ -72,14 +72,14 @@ x `=> y `=> x `+ y (x, y, z) `=> x `+ y `+ z //│ Type: CodeBase[out ('x, 'x, 'z) -> 'cde, ⊥, ?] //│ Where: -//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} -//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x <: 'cde1 -//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ ∧ Int<:'app ∧ ⊥<:⊥) ∧ {0: 'cde1, 1: 'cde2}<:{0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'y <: 'cde2 -//│ 'cde3#'cde3 ∨ 'z#'cde4 ∨ ( 'cde3#Int ∨ 'z#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥) ∧ ( 'cde3#Int ∨ 'cde4#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥) ∧ {0: 'cde3, 1: 'cde4}<:{0: Int, 1: Int} -//│ 'cde3#'cde3 ∨ 'cde4#'cde4 ∨ ( 'cde3#Int ∨ 'z#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥) ∧ ( 'cde3#Int ∨ 'cde4#Int ∨ ∧ Int<:'app1 ∧ ⊥<:⊥) ∧ {0: 'cde3, 1: 'cde4}<:{0: Int, 1: Int} +//│ 'cde3#'cde3 ∨ 'z#'cde4 ∨ ( 'cde3#Int ∨ 'z#Int ∨ Int <: 'app1 ∧ ⊥ <: ⊥) ∧ ( 'cde3#Int ∨ 'cde4#Int ∨ Int <: 'app1 ∧ ⊥ <: ⊥){0: 'cde3, 1: 'cde4} <: {0: Int, 1: Int} +//│ 'cde3#'cde3 ∨ 'cde4#'cde4 ∨ ( 'cde3#Int ∨ 'z#Int ∨ Int <: 'app1 ∧ ⊥ <: ⊥) ∧ ( 'cde3#Int ∨ 'cde4#Int ∨ Int <: 'app1 ∧ ⊥ <: ⊥){0: 'cde3, 1: 'cde4} <: {0: Int, 1: Int} //│ 'z <: 'cde4 //│ 'app1 <: ¬(¬'cde) //│ 'app <: ¬(¬'cde3) @@ -114,11 +114,11 @@ f `=> x `=> y `=> f`(x, y) x `=> `if x `== `0.0 then `1.0 else x -//│ Type: CodeBase[out 'x -> ('x ∨ Num), ⊥, ?] +//│ Type: CodeBase[out 'x -> ('x | Num), ⊥, ?] //│ Where: -//│ 'x#'cde ∨ ( 'x#⊤ ∨ ∧ Bool<:'app ∧ ⊥<:⊥ ∧ 'cde<:'T ∧ 'cde1<:'T) ∧ ( 'cde#⊤ ∨ ∧ Bool<:'app ∧ ⊥<:⊥ ∧ 'cde<:'T ∧ 'cde1<:'T) ∧ {0: 'cde, 1: 'cde1}<:{0: ⊤, 1: ⊤} +//│ 'x#'cde ∨ ( 'x#⊤ ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T) ∧ ( 'cde#⊤ ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T){0: 'cde, 1: 'cde1} <: {0: ⊤, 1: ⊤} //│ 'x <: 'cde -//│ 'cde#'cde ∨ ( 'x#⊤ ∨ ∧ Bool<:'app ∧ ⊥<:⊥ ∧ 'cde<:'T ∧ 'cde1<:'T) ∧ ( 'cde#⊤ ∨ ∧ Bool<:'app ∧ ⊥<:⊥ ∧ 'cde<:'T ∧ 'cde1<:'T) ∧ {0: 'cde, 1: 'cde1}<:{0: ⊤, 1: ⊤} +//│ 'cde#'cde ∨ ( 'x#⊤ ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T) ∧ ( 'cde#⊤ ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T){0: 'cde, 1: 'cde1} <: {0: ⊤, 1: ⊤} //│ Num <: 'cde1 //│ 'cde2 <: ¬(¬{Bool}) //│ 'app <: ¬(¬'cde2) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls index 469aa33f31..75030f7e5b 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls @@ -37,7 +37,7 @@ fun f(x) = f(x) f //│ Type: ['x, 'eff, 'app] -> 'x ->{'eff} 'app //│ Where: -//│ 'x#'x ∨ ( 'x#⊤ ∨ ∧ 'app<:'app ∧ 'eff<:'eff ∧ 'x<:'x) ∧ {0: 'x}<:{0: ⊤} +//│ 'x#'x ∨ ( 'x#⊤ ∨ 'app <: 'app ∧ 'eff <: 'eff ∧ 'x <: 'x){0: 'x} <: {0: ⊤} fun f(x) = f(x.a) @@ -70,7 +70,7 @@ fun f(x) = f(x.Foo#a) f //│ Type: ['x, 'A, 'eff, 'app] -> Foo[out 'A] ->{'eff} 'app //│ Where: -//│ 'A#'A ∨ ( 'A#⊤ ∨ ∧ 'app<:'app ∧ 'eff<:'eff ∧ 'A<:'x) ∧ {0: 'A}<:{0: ⊤} +//│ 'A#'A ∨ ( 'A#⊤ ∨ 'app <: 'app ∧ 'eff <: 'eff ∧ 'A <: 'x){0: 'A} <: {0: ⊤} //│ 'x <: Foo[out 'A] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbRef.mls b/hkmc2/shared/src/test/mlscript/bbml/bbRef.mls index 22701e863c..2dffe478c4 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbRef.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbRef.mls @@ -25,11 +25,11 @@ let r = region x in x.ref 42 //│ ║ ^^^^^^^^ //│ ║ l.22: !r //│ ║ ^^ -//│ ╟── because: cannot constrain 'reg ∨ 'eff <: ⊥ +//│ ╟── because: cannot constrain 'reg | 'eff <: ⊥ //│ ╟── because: cannot constrain 'reg <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ 'x <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & 'x <: ¬() //│ ╟── because: cannot constrain 'x <: ¬() //│ ╙── because: cannot constrain <: ¬() //│ Type: Int @@ -54,7 +54,7 @@ let t = region x in x in t.ref 42 //│ ╔══[ERROR] Type error in block //│ ║ l.42: let t = region x in x in t.ref 42 //│ ║ ^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain 'reg ∨ 'eff <: ⊥ +//│ ╟── because: cannot constrain 'reg | 'eff <: ⊥ //│ ╟── because: cannot constrain 'reg <: ¬() //│ ╟── because: cannot constrain 'x1 <: ¬() //│ ╟── because: cannot constrain 'x1 <: ¬() @@ -75,11 +75,11 @@ in t := 0 //│ ║ ^^^^^^^^ //│ ║ l.72: in t := 0 //│ ║ ^^^^^^^^^ -//│ ╟── because: cannot constrain 'reg ∨ 'eff <: ⊥ +//│ ╟── because: cannot constrain 'reg | 'eff <: ⊥ //│ ╟── because: cannot constrain 'reg <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ 'x <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & 'x <: ¬() //│ ╟── because: cannot constrain 'x <: ¬() //│ ╙── because: cannot constrain <: ¬() //│ Type: Int @@ -98,11 +98,11 @@ in !t //│ ║ ^^^^^^^^ //│ ║ l.95: in !t //│ ║ ^^^^^ -//│ ╟── because: cannot constrain 'reg ∨ 'eff <: ⊥ +//│ ╟── because: cannot constrain 'reg | 'eff <: ⊥ //│ ╟── because: cannot constrain 'reg <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() //│ ╟── because: cannot constrain 'reg1 <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ 'x <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & 'x <: ¬() //│ ╟── because: cannot constrain 'x <: ¬() //│ ╙── because: cannot constrain <: ¬() //│ Type: Int @@ -144,12 +144,12 @@ in t(42) //│ ║ ^^^^^^^^^^^^ //│ ║ l.141: in t(42) //│ ║ ^^^^^^^^ -//│ ╟── because: cannot constrain 'reg ∨ 'eff <: ⊥ +//│ ╟── because: cannot constrain 'reg | 'eff <: ⊥ //│ ╟── because: cannot constrain 'reg <: ¬() -//│ ╟── because: cannot constrain ¬⊥ ∧ 'x <: ¬() +//│ ╟── because: cannot constrain ¬⊥ & 'x <: ¬() //│ ╟── because: cannot constrain 'x <: ¬() //│ ╙── because: cannot constrain <: ¬() -//│ Type: Ref[in 'y out 'y ∨ Int, ?] +//│ Type: Ref[in 'y out 'y | Int, ?] fun foo: [A] -> Int ->{A} Int fun foo(x) = @@ -172,7 +172,7 @@ foo //│ 'A <: Int region x in x.ref foo -//│ Type: Ref[in 'A -> ('A ∧ Int) out ('A ∧ Int) -> 'A, ?] +//│ Type: Ref[in 'A -> ('A & Int) out ('A & Int) -> 'A, ?] fun bar: ([A] -> A -> A) -> Int fun bar(f) = f(42) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbSeq.mls b/hkmc2/shared/src/test/mlscript/bbml/bbSeq.mls index b0cb998168..32b9809f84 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbSeq.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbSeq.mls @@ -47,9 +47,9 @@ fun mapi = s => f => //│ ╟── because: cannot constrain Seq[out 'B, out 'E1] <: Seq[out A, out E] //│ ╟── because: cannot constrain 'E1 <: E //│ ╟── because: cannot constrain 'E1 <: ¬(¬E) -//│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) +//│ ╟── because: cannot constrain ¬⊥ & 'reg <: ¬(¬E) //│ ╟── because: cannot constrain 'reg <: ¬(¬E) -//│ ╟── because: cannot constrain (¬⊥ ∧ 'r) ∧ ¬outer <: ¬(¬E) +//│ ╟── because: cannot constrain (¬⊥ & 'r) & ¬outer <: ¬(¬E) //│ ╟── because: cannot constrain 'r <: ¬(¬E ∧ ¬outer) //│ ╙── because: cannot constrain ¬outer <: ¬(¬E ∧ ¬outer) //│ ╔══[ERROR] Type error in region expression with expected type Seq[out A, out E] @@ -64,9 +64,9 @@ fun mapi = s => f => //│ ╟── because: cannot constrain Seq[out 'B, out 'E1] <: Seq[out A, out E] //│ ╟── because: cannot constrain 'E1 <: E //│ ╟── because: cannot constrain 'E1 <: ¬(¬E) -//│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) +//│ ╟── because: cannot constrain ¬⊥ & 'reg <: ¬(¬E) //│ ╟── because: cannot constrain 'reg <: ¬(¬E) -//│ ╟── because: cannot constrain (¬⊥ ∧ 'r) ∧ ¬outer <: ¬(¬E) +//│ ╟── because: cannot constrain (¬⊥ & 'r) & ¬outer <: ¬(¬E) //│ ╟── because: cannot constrain 'r <: ¬(¬E ∧ ¬outer) //│ ╙── because: cannot constrain ¬outer <: ¬(¬E ∧ ¬outer) //│ ╔══[ERROR] Type error in region expression with expected type Seq[out A, out E] @@ -81,9 +81,9 @@ fun mapi = s => f => //│ ╟── because: cannot constrain Seq[out 'B, out 'E1] <: Seq[out A, out E] //│ ╟── because: cannot constrain 'E1 <: E //│ ╟── because: cannot constrain 'E1 <: ¬(¬E) -//│ ╟── because: cannot constrain ¬⊥ ∧ 'reg <: ¬(¬E) +//│ ╟── because: cannot constrain ¬⊥ & 'reg <: ¬(¬E) //│ ╟── because: cannot constrain 'reg <: ¬(¬E) -//│ ╟── because: cannot constrain (¬⊥ ∧ 'r) ∧ ¬outer <: ¬(¬E) +//│ ╟── because: cannot constrain (¬⊥ & 'r) & ¬outer <: ¬(¬E) //│ ╟── because: cannot constrain 'r <: ¬(¬E ∧ ¬outer) //│ ╙── because: cannot constrain ¬outer <: ¬(¬E ∧ ¬outer) //│ Type: ⊤ @@ -96,7 +96,7 @@ fun mapi = s => f => i := !i + 1 f(!i, x) mapi -//│ Type: [outer, 'A, 'E, 'app, 'eff] -> Seq[out 'A, out 'E] -> (((Int, 'A) ->{'eff} 'app) -> Seq[out 'app, out (¬outer ∨ 'eff) ∨ 'E]) +//│ Type: [outer, 'A, 'E, 'app, 'eff] -> Seq[out 'A, out 'E] -> (((Int, 'A) ->{'eff} 'app) -> Seq[out 'app, out (¬outer | 'eff) | 'E]) // * This version is correct as it keeps the mutation encapsulated within the region fun mapi_force: [A, E] -> Seq[out A, out E] -> ((Int, A) ->{E} A) ->{E} Seq[out A, Nothing] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbVariance.mls b/hkmc2/shared/src/test/mlscript/bbml/bbVariance.mls index 62e56acddf..75a466abc0 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbVariance.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbVariance.mls @@ -7,13 +7,13 @@ class Foo[out A] //│ Type: ⊤ (x: Foo[Int]) => (x as Foo[Int | Str]) -//│ Type: (Foo[out Int]) ->{⊥} Foo[out Int ∨ Str] +//│ Type: (Foo[out Int]) ->{⊥} Foo[out Int | Str] class Foo[in A] //│ Type: ⊤ (x: Foo[Int]) => (x as Foo[Int & Str]) -//│ Type: (Foo[in Int]) ->{⊥} Foo[in Int ∧ Str] +//│ Type: (Foo[in Int]) ->{⊥} Foo[in Int & Str] diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index 2df4a622db..f640b7648d 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -28,7 +28,7 @@ idIB(true) //│ Type: Bool idIB(if true then 1 else true) -//│ Type: Bool ∨ Int +//│ Type: Bool | Int x => let y = x+1 @@ -36,7 +36,7 @@ x => //│ Type: ('x) ->{'eff} 'app //│ Where: //│ 'x <: Int -//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ {0: 'x}<:{0: Int} ∨ {0: Bool} +//│ 'x#'x ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: 'eff) ∧ ( 'x#Bool ∨ Bool <: 'app ∧ ⊥ <: 'eff){0: 'x} <: {0: Int} | {0: Bool} (x: Int) => let y = x + 1 @@ -61,13 +61,13 @@ ap(idIB)(1) x => idIB(x) //│ Type: ('x) ->{'eff} 'app //│ Where: -//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ {0: 'x}<:{0: Int} ∨ {0: Bool} +//│ 'x#'x ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: 'eff) ∧ ( 'x#Bool ∨ Bool <: 'app ∧ ⊥ <: 'eff){0: 'x} <: {0: Int} | {0: Bool} fun forward(x) = idIB(x) forward //│ Type: ['x, 'eff, 'app] -> 'x ->{'eff} 'app //│ Where: -//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ {0: 'x}<:{0: Int} ∨ {0: Bool} +//│ 'x#'x ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: 'eff) ∧ ( 'x#Bool ∨ Bool <: 'app ∧ ⊥ <: 'eff){0: 'x} <: {0: Int} | {0: Bool} forward(1) //│ Type: Int @@ -115,7 +115,7 @@ idIIBB(new Pair(1, 2)) //│ ╔══[ERROR] Type error in application //│ ║ l.114: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app +//│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) & (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] //│ ╟── because: cannot constrain 'A <: Bool //│ ╟── because: cannot constrain 'A <: ¬(¬{Bool}) @@ -123,19 +123,19 @@ idIIBB(new Pair(1, 2)) //│ ╔══[ERROR] Type error in application //│ ║ l.114: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app +//│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) & (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] //│ ╟── because: cannot constrain 'B <: Bool //│ ╟── because: cannot constrain 'B <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) -//│ Type: Bool ∨ Int +//│ Type: Bool | Int :e idIIBB(new Pair(1, true)) //│ ╔══[ERROR] Type error in application //│ ║ l.134: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app +//│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) & (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Int, in ⊥ out Int] //│ ╟── because: cannot constrain 'B <: Int //│ ╟── because: cannot constrain 'B <: ¬(¬{Int}) @@ -143,12 +143,12 @@ idIIBB(new Pair(1, true)) //│ ╔══[ERROR] Type error in application //│ ║ l.134: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) ∧ (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app +//│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) & (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app //│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] //│ ╟── because: cannot constrain 'A <: Bool //│ ╟── because: cannot constrain 'A <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) -//│ Type: Bool ∨ Int +//│ Type: Bool | Int @@ -172,7 +172,7 @@ fun k(f) = a: f(0) b: f(true) k -//│ Type: ['eff, 'app, 'eff1, 'app1] -> ((Bool ->{'eff1} 'app1) ∧ (Int ->{'eff} 'app)) ->{'eff ∨ 'eff1} {a: 'app, b: 'app1} +//│ Type: ['eff, 'app, 'eff1, 'app1] -> ((Bool ->{'eff1} 'app1) & (Int ->{'eff} 'app)) ->{'eff | 'eff1} {a: 'app, b: 'app1} k(idIB) //│ Type: {a: Int, b: Bool} @@ -181,7 +181,7 @@ fun k(f) = (x, y) => a: f(x) b: f(y) k -//│ Type: ['x, 'y, 'eff, 'app, 'eff1, 'app1] -> (('y ->{'eff1} 'app1) ∧ ('x ->{'eff} 'app)) -> (('x, 'y) ->{'eff ∨ 'eff1} {a: 'app, b: 'app1}) +//│ Type: ['x, 'y, 'eff, 'app, 'eff1, 'app1] -> (('y ->{'eff1} 'app1) & ('x ->{'eff} 'app)) -> (('x, 'y) ->{'eff | 'eff1} {a: 'app, b: 'app1}) k(idIB)(true, 1) //│ Type: {a: Bool, b: Int} @@ -193,10 +193,10 @@ k(idIB)("true", 1) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Str <: 'x //│ ╟── because: cannot constrain Str <: 'x -//│ ╟── because: cannot constrain {0: 'x} <: {0: Int} ∨ {0: Bool} -//│ ╟── because: cannot constrain 'x <: Bool ∨ Int -//│ ╟── because: cannot constrain 'x <: ¬(¬{Int ∨ Bool}) -//│ ╙── because: cannot constrain Str <: ¬(¬{Int ∨ Bool}) +//│ ╟── because: cannot constrain {0: 'x} <: {0: Int} | {0: Bool} +//│ ╟── because: cannot constrain 'x <: Bool | Int +//│ ╟── because: cannot constrain 'x <: ¬(¬{Int | Bool}) +//│ ╙── because: cannot constrain Str <: ¬(¬{Int | Bool}) //│ Type: {a: ⊥, b: Int} (x => x.x + idIB(x.y)) of (x:0, y:1) @@ -219,7 +219,7 @@ fun map = x => f => x.Ls#prim(() => nil(), (a, b) => cons(f(a), map(b)(f))) x => map(x)(idIB) //│ Type: (Ls['A]) ->{⊥} Ls['B] //│ Where: -//│ 'A#'A ∨ ( 'A#Int ∨ ∧ Int<:'B ∧ ⊥<:⊥) ∧ ( 'A#Bool ∨ ∧ Bool<:'B ∧ ⊥<:⊥) ∧ {0: 'A}<:{0: Int} ∨ {0: Bool} +//│ 'A#'A ∨ ( 'A#Int ∨ Int <: 'B ∧ ⊥ <: ⊥) ∧ ( 'A#Bool ∨ Bool <: 'B ∧ ⊥ <: ⊥){0: 'A} <: {0: Int} | {0: Bool} map(nil())(idIB) //│ Type: Ls['B] @@ -244,31 +244,31 @@ let x = cons(1, cons(true, nil())) in //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B //│ ║ l.243: map(cons(x, x))(idIB) //│ ║ ^^^^ -//│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B -//│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} -//│ ╟── because: cannot constrain 'A <: Bool ∨ Int -//│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) -//│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) +//│ ╟── because: cannot constrain (Int -> Int) & (Bool -> Bool) <: 'A -> 'B +//│ ╟── because: cannot constrain {0: 'A} <: {0: Int} | {0: Bool} +//│ ╟── because: cannot constrain 'A <: Bool | Int +//│ ╟── because: cannot constrain 'A <: ¬(¬{Int | Bool}) +//│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int | Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B //│ ║ l.243: map(cons(x, x))(idIB) //│ ║ ^^^^ -//│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B -//│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} -//│ ╟── because: cannot constrain 'A <: Bool ∨ Int -//│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) -//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) -//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) -//│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) +//│ ╟── because: cannot constrain (Int -> Int) & (Bool -> Bool) <: 'A -> 'B +//│ ╟── because: cannot constrain {0: 'A} <: {0: Int} | {0: Bool} +//│ ╟── because: cannot constrain 'A <: Bool | Int +//│ ╟── because: cannot constrain 'A <: ¬(¬{Int | Bool}) +//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int | Bool}) +//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int | Bool}) +//│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int | Bool}) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B //│ ║ l.243: map(cons(x, x))(idIB) //│ ║ ^^^^ -//│ ╟── because: cannot constrain (Int -> Int) ∧ (Bool -> Bool) <: 'A -> 'B -//│ ╟── because: cannot constrain {0: 'A} <: {0: Int} ∨ {0: Bool} -//│ ╟── because: cannot constrain 'A <: Bool ∨ Int -//│ ╟── because: cannot constrain 'A <: ¬(¬{Int ∨ Bool}) -//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) -//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int ∨ Bool}) -//│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int ∨ Bool}) +//│ ╟── because: cannot constrain (Int -> Int) & (Bool -> Bool) <: 'A -> 'B +//│ ╟── because: cannot constrain {0: 'A} <: {0: Int} | {0: Bool} +//│ ╟── because: cannot constrain 'A <: Bool | Int +//│ ╟── because: cannot constrain 'A <: ¬(¬{Int | Bool}) +//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int | Bool}) +//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int | Bool}) +//│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int | Bool}) //│ Type: Ls['B] //│ Where: //│ Bool <: 'B @@ -278,7 +278,7 @@ fun k: ((Int | Str, Int) -> Int) & ((Bool | Str, Bool) -> Bool) //│ Type: ⊤ k("", if true then 1 else true) -//│ Type: Bool ∨ Int +//│ Type: Bool | Int fun k: ((Int, Int) -> Int) & ((Bool, Bool) -> Bool) //│ Type: ⊤ @@ -286,7 +286,7 @@ fun k: ((Int, Int) -> Int) & ((Bool, Bool) -> Bool) x => k(x, x) //│ Type: ('x) ->{'eff} 'app //│ Where: -//│ 'x#'x ∨ ( 'x#Int ∨ ∧ Int<:'app ∧ ⊥<:'eff) ∧ ( 'x#Bool ∨ ∧ Bool<:'app ∧ ⊥<:'eff) ∧ {0: 'x, 1: 'x}<:{0: Int, 1: Int} ∨ {0: Bool, 1: Bool} +//│ 'x#'x ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: 'eff) ∧ ( 'x#Bool ∨ Bool <: 'app ∧ ⊥ <: 'eff){0: 'x, 1: 'x} <: {0: Int, 1: Int} | {0: Bool, 1: Bool} :e fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) @@ -325,15 +325,15 @@ wf("") //│ Type: Str wf(true) -//│ Type: Bool ∨ Int +//│ Type: Bool | Int :e wf(1) //│ ╔══[ERROR] Type error in application //│ ║ l.331: wf(1) //│ ║ ^^^^^ -//│ ╟── because: cannot constrain (((Int ∨ Bool) -> Int) ∨ (Bool -> Bool)) ∧ (Str -> Str) <: Int ->{'eff} 'app -//│ ╙── because: cannot constrain {0: Int} <: {0: Bool} ∨ {0: Str} +//│ ╟── because: cannot constrain (((Int | Bool) -> Int) | (Bool -> Bool)) & (Str -> Str) <: Int ->{'eff} 'app +//│ ╙── because: cannot constrain {0: Int} <: {0: Bool} | {0: Str} //│ Type: Int class @@ -346,15 +346,15 @@ fun wf: ((Z, Z) -> Z) & ((Z, S) -> S) & ((S, Z | S) -> S) let zs = if true then new Z() else new S() zs -//│ Type: S ∨ Z +//│ Type: S | Z :e wf(zs, zs) //│ ╔══[ERROR] Type error in application //│ ║ l.352: wf(zs, zs) //│ ║ ^^^^^^^^^^ -//│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: ('res, 'res) ->{'eff} 'app -//│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} +//│ ╟── because: cannot constrain (((Z, Z) -> Z) & ((Z, S) -> S)) & ((S, Z | S) -> S) <: ('res, 'res) ->{'eff} 'app +//│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: ({0: Z, 1: Z} | {0: Z, 1: S}) | {0: S, 1: Z | S} //│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: {1: S} //│ ╟── because: cannot constrain 'res <: S //│ ╟── because: cannot constrain 'res <: ¬(¬{S}) @@ -362,13 +362,13 @@ wf(zs, zs) //│ ╔══[ERROR] Type error in application //│ ║ l.352: wf(zs, zs) //│ ║ ^^^^^^^^^^ -//│ ╟── because: cannot constrain (((Z, Z) -> Z) ∧ ((Z, S) -> S)) ∧ ((S, Z ∨ S) -> S) <: ('res, 'res) ->{'eff} 'app -//│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: ({0: Z, 1: Z} ∨ {0: Z, 1: S}) ∨ {0: S, 1: Z ∨ S} +//│ ╟── because: cannot constrain (((Z, Z) -> Z) & ((Z, S) -> S)) & ((S, Z | S) -> S) <: ('res, 'res) ->{'eff} 'app +//│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: ({0: Z, 1: Z} | {0: Z, 1: S}) | {0: S, 1: Z | S} //│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: {1: Z} //│ ╟── because: cannot constrain 'res <: Z //│ ╟── because: cannot constrain 'res <: ¬(¬{Z}) //│ ╙── because: cannot constrain S <: ¬(¬{Z}) -//│ Type: S ∨ Z +//│ Type: S | Z :e fun ill: diff --git a/hkmc2/shared/src/test/mlscript/logicsub/If.mls b/hkmc2/shared/src/test/mlscript/logicsub/If.mls index 9f3cdc4194..6fbe47ff55 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/If.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/If.mls @@ -16,39 +16,39 @@ fun f(x) = if x is f //│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ ∧ Int<:'res ∧ ⊥<:'eff -//│ 'x#¬Int ∨ ( 'x1#Bool ∨ ∧ Bool ∧ 'x1<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Int ∨ Bool) ∨ ∧ (¬Int ∧ ¬Bool) ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ¬Int ∧ 'x<:'x1 +//│ 'x#Int ∨ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#¬Int ∨ ( 'x1#Bool ∨ Bool & 'x1 <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Int | Bool) ∨ (¬Int & ¬Bool) & 'x1 <: 'x1 ∧ ⊤ <: ⊥)¬Int & 'x <: 'x1 f(ib) as Int | Bool -//│ Type: Int ∨ Bool +//│ Type: Int | Bool f(f(ib)) as Int | Bool f(f(ib)) -//│ Type: Int ∨ ((Bool ∧ ¬Int) ∧ 'x) +//│ Type: Int | ((Bool & ¬Int) & 'x) //│ Where: //│ Int <: 'x -//│ Bool ∧ ¬Int <: 'x -//│ 'x#¬(Int ∨ Bool) ∨ ∧ (¬Int ∧ ¬Bool) ∧ 'x1<:'x1 ∧ ⊤<:⊥ +//│ Bool & ¬Int <: 'x +//│ 'x#¬(Int | Bool) ∨ (¬Int & ¬Bool) & 'x1 <: 'x1 ∧ ⊤ <: ⊥ //│ ¬{Int} ∧ 'x <: 'x1 //│ Int <: 'res -//│ (Bool ∧ ¬Int) ∧ 'x <: 'res +//│ (Bool & ¬Int) & 'x <: 'res //│ 'x1 <: ¬(Bool ∧ ¬'res) -//│ 'x1#¬(Int ∨ Bool) ∨ ∧ (¬Int ∧ ¬Bool) ∧ 'x1<:'x1 ∧ ⊤<:⊥ +//│ 'x1#¬(Int | Bool) ∨ (¬Int & ¬Bool) & 'x1 <: 'x1 ∧ ⊤ <: ⊥ :e f(si) //│ ╔══[ERROR] Type error in reference with expected type 'x //│ ║ l.39: f(si) //│ ║ ^^ -//│ ╟── because: cannot constrain Str ∨ Int <: 'x +//│ ╟── because: cannot constrain Str | Int <: 'x //│ ╟── because: cannot constrain Str <: 'x -//│ ╟── because: cannot constrain ¬Int ∧ 'x <: 'x1 +//│ ╟── because: cannot constrain ¬Int & 'x <: 'x1 //│ ╟── because: cannot constrain ¬{Int} ∧ 'x <: 'x1 //│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: Int -// order dependent +// order-dependent (expected) fun f(x, y) = if x is Int then 1 @@ -56,6 +56,9 @@ fun f(x, y) = if f(1, "") //│ Type: Int +f(1, sib) +//│ Type: Int + fun f(x, y) = if y is Str then "" x is Int then 1 @@ -63,7 +66,7 @@ f(1, "") //│ Type: Str f(1, sib) -//│ Type: Int ∨ Str +//│ Type: Int | Str fun foorec(x, y, r) = if @@ -86,34 +89,34 @@ foo as (Str, Bool) -> Bool :e foo(1, "") //│ ╔══[ERROR] Type error in string literal with expected type 'y -//│ ║ l.87: foo(1, "") +//│ ║ l.90: foo(1, "") //│ ║ ^^ //│ ╟── because: cannot constrain Str <: 'y //│ ╟── because: cannot constrain Str <: 'y -//│ ╟── because: cannot constrain 'x <: 'x1 -//│ ╟── because: cannot constrain 'x <: 'x1 -//│ ╟── because: cannot constrain 'r <: (Str ∧ 'y1, 'x1, 'r) ->{'eff} 'app -//│ ╟── because: cannot constrain 'r <: ¬(¬{(Str ∧ 'y1, 'x1, 'r) ->{'eff} 'app}) -//│ ╟── because: cannot constrain ((¬⊥ ∧ 'x2, ¬⊥ ∧ 'y2, ¬⊥ ∧ 'r1) ->{¬⊥ ∧ 'eff1} (¬⊥ ∧ 'res)) ∧ ¬⊥ <: ¬(¬{(Str ∧ 'y1, 'x1, 'r) ->{'eff} 'app}) -//│ ╟── because: cannot constrain 'x1 <: 'y2 -//│ ╟── because: cannot constrain 'x1 <: 'y2 -//│ ╟── because: cannot constrain 'x1 <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain 'x1 <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain ¬Int & 'y1 <: 'y2 +//│ ╟── because: cannot constrain ¬{Int} ∧ 'y1 <: 'y2 +//│ ╟── because: cannot constrain 'r <: (Str & 'y2, 'x, 'r) ->{'eff} 'app +//│ ╟── because: cannot constrain 'r <: ¬(¬{(Str & 'y2, 'x, 'r) ->{'eff} 'app}) +//│ ╟── because: cannot constrain ((¬⊥ & 'x1, ¬⊥ & 'y3, ¬⊥ & 'r1) ->{¬⊥ & 'eff1} (¬⊥ & 'res)) & ¬⊥ <: ¬(¬{(Str & 'y2, 'x, 'r) ->{'eff} 'app}) +//│ ╟── because: cannot constrain 'x <: 'y3 +//│ ╟── because: cannot constrain 'x <: 'y3 //│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) //│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain ¬⊥ ∧ 'x3 <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain ¬⊥ & 'x3 <: ¬(¬{Bool}) //│ ╟── because: cannot constrain 'x3 <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) //│ ╔══[ERROR] Type error in string literal with expected type 'y -//│ ║ l.87: foo(1, "") +//│ ║ l.90: foo(1, "") //│ ║ ^^ //│ ╟── because: cannot constrain Str <: 'y //│ ╟── because: cannot constrain Str <: 'y -//│ ╟── because: cannot constrain Int ∧ 'x <: 'x1 -//│ ╟── because: cannot constrain Int ∧ 'x <: 'x1 -//│ ╟── because: cannot constrain Int ∧ 'x <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain 'x <: ¬(Int ∧ ¬{Bool}) -//│ ╟── because: cannot constrain ¬⊥ ∧ 'x3 <: ¬(Int ∧ ¬{Bool}) +//│ ╟── because: cannot constrain Int & 'x2 <: 'x +//│ ╟── because: cannot constrain Int ∧ 'x2 <: 'x +//│ ╟── because: cannot constrain Int ∧ 'x2 <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain 'x2 <: ¬(Int ∧ ¬{Bool}) +//│ ╟── because: cannot constrain ¬⊥ & 'x3 <: ¬(Int ∧ ¬{Bool}) //│ ╟── because: cannot constrain 'x3 <: ¬(Int ∧ ¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(Int ∧ ¬{Bool}) //│ Type: Bool @@ -125,8 +128,8 @@ fun increv(x) = if x is increv //│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Int<:'res ∧ ⊥<:'eff -//│ 'x#¬Int ∨ ∧ ¬Int ∧ 'x<:'x1 ∧ 'x1<:Str ∧ Str<:'res ∧ ⊥<:'eff +//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#¬Int ∨ ¬Int & 'x <: 'x1 ∧ 'x1 <: Str ∧ Str <: 'res ∧ ⊥ <: 'eff fun increv'(x) = if x is Int then x + 1 @@ -134,34 +137,34 @@ fun increv'(x) = if x is increv' //│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ ∧ Int ∧ 'x<:Int ∧ Int<:Int ∧ Int<:'res ∧ ⊥<:'eff -//│ 'x#¬Int ∨ ( 'x1#Str ∨ ∧ Str ∧ 'x1<:Str ∧ Str<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Int ∨ Str) ∨ ∧ (¬Int ∧ ¬Str) ∧ 'x1<:'x1 ∧ ⊤<:⊥) ∧ ¬Int ∧ 'x<:'x1 +//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#¬Int ∨ ( 'x1#Str ∨ Str & 'x1 <: Str ∧ Str <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Int | Str) ∨ (¬Int & ¬Str) & 'x1 <: 'x1 ∧ ⊤ <: ⊥)¬Int & 'x <: 'x1 :e increv(sib) //│ ╔══[ERROR] Type error in reference with expected type 'x -//│ ║ l.141: increv(sib) +//│ ║ l.144: increv(sib) //│ ║ ^^^ -//│ ╟── because: cannot constrain (Str ∨ Int) ∨ Bool <: 'x +//│ ╟── because: cannot constrain (Str | Int) | Bool <: 'x //│ ╟── because: cannot constrain Bool <: 'x -//│ ╙── because: cannot constrain Bool <: ¬(¬{Str ∨ Int}) -//│ Type: Int ∨ Str +//│ ╙── because: cannot constrain Bool <: ¬(¬{Str | Int}) +//│ Type: Int | Str :e increv'(sib) //│ ╔══[ERROR] Type error in reference with expected type 'x -//│ ║ l.151: increv'(sib) +//│ ║ l.154: increv'(sib) //│ ║ ^^^ -//│ ╟── because: cannot constrain (Str ∨ Int) ∨ Bool <: 'x +//│ ╟── because: cannot constrain (Str | Int) | Bool <: 'x //│ ╟── because: cannot constrain Bool <: 'x //│ ╙── because: cannot constrain ⊤ <: ⊥ -//│ Type: Int ∨ Str +//│ Type: Int | Str increv(si) -//│ Type: Int ∨ Str +//│ Type: Int | Str increv'(si) -//│ Type: Int ∨ Str +//│ Type: Int | Str fun f(x, y) = if x is Int and y is Int then 1 @@ -178,3 +181,4 @@ x => if x is //│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: (Bool) ->{⊥} Int + diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index 4ab737ac67..3fef940e4a 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -38,9 +38,9 @@ test //│ = [function test] //│ Type: ['x, 'y, 'res, 'eff, 'x1, 'y1] -> ('x, 'x) ->{'eff} 'res //│ Where: -//│ 'x#Tru ∨ ( 'y#Tru ∨ ∧ Tru<:'res ∧ ⊥<:'eff) ∧ ( 'y#¬Tru ∨ ∧ Tru ∧ 'x<:'x1 ∧ ¬Tru ∧ 'y<:'y1) -//│ 'x#¬Tru ∨ ( 'x1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ¬Fls ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ ¬Fls ∧ 'x1<:'x1 ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ 'y1<:'y1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ¬Fls ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ ¬Fls ∧ 'x1<:'x1 ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ ¬Fls ∧ 'x1<:'x1 ∧ ¬Tru ∧ 'y1<:'y1) ∧ ¬Tru ∧ 'x<:'x1 ∧ 'y<:'y1 -//│ 'y#¬Tru ∨ ( 'x1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ¬Fls ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ ¬Fls ∧ 'x1<:'x1 ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ 'y1<:'y1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ ∧ Fls<:'res ∧ ⊥<:'eff) ∧ ( 'x1#¬(Tru ∨ Fls) ∨ 'y1#¬Fls ∨ ∧ (¬Tru ∧ ¬Fls) ∧ 'x1<:'x1 ∧ ¬Fls ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ ( 'y1#¬(Tru ∨ Fls) ∨ 'x1#¬Fls ∨ ∧ ¬Fls ∧ 'x1<:'x1 ∧ (¬Tru ∧ ¬Fls) ∧ 'y1<:'y1 ∧ ⊤<:⊥) ∧ ¬Fls ∧ 'x1<:'x1 ∧ ¬Tru ∧ 'y1<:'y1) ∧ 'x<:'x1 ∧ ¬Tru ∧ 'y<:'y1 +//│ 'x#Tru ∨ ( 'y#Tru ∨ Tru <: 'res ∧ ⊥ <: 'eff) ∧ ( 'y#¬Tru ∨ Tru & 'x <: 'x1 ∧ ¬Tru & 'y <: 'y1) +//│ 'x#¬Tru ∨ ( 'x1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Tru | Fls) ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Tru | Fls) ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬(Tru | Fls) ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)(¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ 'y1 <: 'y1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Tru | Fls) ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬(Tru | Fls) ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)¬Fls & 'x1 <: 'x1 ∧ ¬Tru & 'y1 <: 'y1)¬Tru & 'x <: 'x1 ∧ 'y <: 'y1 +//│ 'y#¬Tru ∨ ( 'x1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Tru | Fls) ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Tru | Fls) ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬(Tru | Fls) ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)(¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ 'y1 <: 'y1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Tru | Fls) ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬(Tru | Fls) ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)¬Fls & 'x1 <: 'x1 ∧ ¬Tru & 'y1 <: 'y1)'x <: 'x1 ∧ ¬Tru & 'y <: 'y1 test(tru, tru) //│ = Tru() @@ -86,13 +86,13 @@ test(true, false) //│ ╔══[ERROR] Type error in boolean literal with expected type 'y //│ ╟── because: cannot constrain Bool <: 'y //│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain ¬Tru ∧ 'y <: 'y1 +//│ ╟── because: cannot constrain ¬Tru & 'y <: 'y1 //│ ╟── because: cannot constrain ¬{Tru} ∧ 'y <: 'y1 //│ ╙── because: cannot constrain ⊤ <: ⊥ //│ ╔══[ERROR] Type error in boolean literal with expected type 'y //│ ╟── because: cannot constrain Bool <: 'y //│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain ¬Tru ∧ 'y <: 'y1 +//│ ╟── because: cannot constrain ¬Tru & 'y <: 'y1 //│ ╟── because: cannot constrain ¬{Tru} ∧ 'y <: 'y1 //│ ╙── because: cannot constrain ⊤ <: ⊥ //│ ╔══[ERROR] Type error in boolean literal with expected type 'y @@ -112,3 +112,25 @@ test(true, false) //│ ╟── because: cannot constrain Bool <: 'y //│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: ⊥ + + +// * Note: this version generates a large type + +fun test(x, y) = if + x is Tru and y is Tru then tru + x is Fls and y is Tru then fls + y is Fls then fls +// test +//│ Type: ⊤ + +// * Note: and this one even larger + +fun test(x, y) = if + x is Tru and y is Tru then tru + x is Fls and y is Tru then fls + y is Fls then fls + y is Fls then fls +// test +//│ Type: ⊤ + + From f77ddbb5fa8be57fb5f7fbe16cf964fbebda2c97 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Mon, 14 Apr 2025 22:09:45 +0800 Subject: [PATCH 25/36] dnf disjointness --- .../src/main/scala/hkmc2/bbml/types.scala | 124 ++++++------------ .../src/test/mlscript/bbml/bbBasics.mls | 6 +- .../src/test/mlscript/bbml/bbBounds.mls | 8 +- .../src/test/mlscript/bbml/bbExtrude.mls | 12 +- .../shared/src/test/mlscript/bbml/bbGPCE.mls | 24 ++-- hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls | 28 ++-- hkmc2/shared/src/test/mlscript/bbml/bbRec.mls | 4 +- .../shared/src/test/mlscript/logicsub/If.mls | 8 +- .../test/mlscript/logicsub/MarlowWadler97.mls | 4 +- 9 files changed, 84 insertions(+), 134 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 1693fe1b38..1bee9c20c7 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -320,90 +320,40 @@ object Type: val (q, p) = discriminant(r.toBasic) ((u & q).toBasic, (w & p).toBasic) case a => (Top, a) - def in(a: BasicType, b: BasicType)(prev: Set[BasicType -> BasicType]) - (using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]) - : Opt[Set[Set[InfVar->BasicType]]] = (a.simp.toBasic, b.simp.toBasic) match - case (a, NegType(b)) => disjointImpl(a, b.toBasic)(prev) - case (v: InfVar, b) => - val p = prev + (v -> NegType(b)) - val k = v.state.lowerBounds.map(lb => in(lb.toBasic, b)(p)) - if k.exists(_.isEmpty) then N - else S(k.flatten.flatten.toSet + Set(v -> NegType(b))) - case (ComposedType(p, q, true), b) => - val u = in(p.toBasic, b)(prev) - val w = in(q.toBasic, b)(prev) - u.flatMap(u => w.map(u ++ _)) - case (ComposedType(p, q, false), b) => - (in(p.toBasic, b)(prev), in(q.toBasic, b)(prev)) match - case (N, w) => w - case (u, N) => u - case (S(u), S(w)) => S(u.flatMap(u => w.map(u ++ _))) - case (a: ClassLikeType, b: ClassLikeType) if a.name.uid === b.name.uid => S(Set.empty) - case (a: ClassLikeType, ComposedType(p, q, true)) => - (in(a, p.toBasic)(prev), in(a, q.toBasic)(prev)) match - case (N, w) => w - case (u, N) => u - case (S(u), S(w)) => S(u.flatMap(u => w.map(u ++ _))) + def disjointIU(i: Inter, u: Union)(using TL): Opt[Set[Set[InfVar -> BasicType]]] = (i.v, u.cls) match + case (S(c: ClassLikeType), cs) if cs.exists(_.name.uid === c.name.uid) => S(Set.empty) + case (S(RcdType(u)), _) => + val kk = u.values.map(t => disjointDisj(t.toDnf)).toList + val k = kk.flatten.toList + if k.isEmpty then N + else if k.exists(_.isEmpty) then S(Set.empty) + else S(k.reduce((x, y) => y.flatMap(y => x.map(_ ++ y)))) case _ => N - def disjointImpl(a: BasicType, b: BasicType)(prev: Set[BasicType -> BasicType]) - (using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]) - : Opt[Set[Set[InfVar->BasicType]]] = - if !prev.contains(a -> b) then c.getOrElseUpdate(a -> b, { - (a, b) match - case (NegType(a), b) => in(b, a.toBasic)(prev) - case (a, NegType(b)) => in(a, b.toBasic)(prev) - case _ => (a.simp.toBasic, b.simp.toBasic) match - case (Bot, _) | (_, Bot) => S(Set.empty) - case (ClassLikeType(a, _), ClassLikeType(b, _)) if a.uid =/= b.uid => S(Set.empty) - case (RcdType(u), RcdType(w)) if u.nonEmpty && w.nonEmpty => - val um = u.toMap - val wm = w.toMap - val k = um.keySet & wm.keySet - val ur = RcdType((um -- k).toList) - val wr = RcdType((wm -- k).toList) - val ud = disjointImpl(ur, ur)(prev) - val wd = disjointImpl(wr, wr)(prev) - if ud.exists(_.isEmpty) || wd.exists(_.isEmpty) then - S(Set.empty) - else - val d = k.flatMap(k => disjointImpl(um(k).toBasic, wm(k).toBasic)(prev)) ++ Ls(ud, wd).flatten - if d.isEmpty then N - else if d.exists(_.isEmpty) then S(Set.empty) - else S(d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y)))) - case (_: RcdType, _: FunType) | (_: FunType, _: RcdType) => S(Set.empty) - case (_: ClassLikeType, _: FunType) | (_: FunType, _: ClassLikeType) => S(Set.empty) - case (ComposedType(p, q, true), b) => - val u = disjointImpl(p.toBasic, b)(prev) - val w = disjointImpl(q.toBasic, b)(prev) - u.flatMap(u => w.map(u ++ _)) - case (a, ComposedType(p, q, true)) => - val u = disjointImpl(a, p.toBasic)(prev) - val w = disjointImpl(a, q.toBasic)(prev) - u.flatMap(u => w.map(u ++ _)) - case (ComposedType(p, q, false), b) => - (disjointImpl(p.toBasic, b)(prev), disjointImpl(q.toBasic, b)(prev)) match - case (N, w) => w - case (u, N) => u - case (S(u), S(w)) => S(u.flatMap(u => w.map(u ++ _))) - case (a, ComposedType(p, q, false)) => - (disjointImpl(a, p.toBasic)(prev), disjointImpl(a, q.toBasic)(prev)) match - case (N, w) => w - case (u, N) => u - case (S(u), S(w)) => S(u.flatMap(u => w.map(u ++ _))) - case (v: InfVar, b) => - val p = prev + (v -> b) - val k = v.state.lowerBounds.map(lb => disjointImpl(lb.toBasic, b)(p)) - if k.exists(_.isEmpty) then N - else S(k.flatten.flatten.toSet + Set(v -> b)) - case (a, v: InfVar) => - val p = prev + (a -> v) - val k = v.state.lowerBounds.map(lb => disjointImpl(a, lb.toBasic)(p)) - if k.exists(_.isEmpty) then N - else S(k.flatten.flatten.toSet + Set(v -> a)) + def disjointConj(ty: Conj)(using TL): Opt[Set[Set[InfVar -> BasicType]]] = + val d = disjointIU(ty.i, ty.u) + if d.exists(_.isEmpty) then S(Set.empty) + else (ty.i.v, ty.u.cls, ty.vars.iterator.filter(_._2).keys.toList) match + case (_, _, Nil) => d + case (N, Nil, v :: Nil) => + val lb = v.state.lowerBounds.reduceOption(_ | _).orElse(S(Bot)).get + disjointDisj(lb.toDnf).map(_ + Set(v -> v)) + case (i, c, vs) => + val j = i match + case S(u: (ClassLikeType | RcdType)) => S(u) case _ => N - }) else S(Set.empty) - def disjoint(a: Type, b: Type): Opt[Set[Set[InfVar->BasicType]]] = - disjointImpl(a.toBasic, b.toBasic)(Set.empty)(using c = MutMap.empty) + val vd = vs.combinations(2).collect { case x :: y :: _ => Ls(x -> y, y -> x) }.flatten.toList + val ds = vs.flatMap(v => (j ++ c.reduceOption[Type](_ | _).map(_.!)).map(x => v -> x.toBasic)).toSet ++ vd + val lb = vs.flatMap(_.state.lowerBounds.reduceOption[Type](_ | _)).reduceOption(_ & _).orElse(S(Bot)).get + val t = lb & Conj(Inter(j), Union(N, c, Nil), Nil) + disjointDisj(t.toDnf).map(_ + ds) + def disjointDisj(t: Disj)(using TL): Opt[Set[Set[InfVar -> BasicType]]] = + if t.conjs.isEmpty then S(Set.empty) + else + val ds = t.conjs.map(disjointConj) + if ds.contains(N) then N + else S(ds.flatten.flatten.toSet) + def disjoint(a: Type, b: Type)(using TL): Opt[Set[Set[InfVar->BasicType]]] = + disjointDisj((a & b).toDnf) // * Poly types can not be used as type arguments @@ -526,11 +476,11 @@ class VarState: case class DisjSub(disjoint: LinkedHashSet[InfVar -> BasicType], dss: Ls[DisjSub], cs: Ls[Type -> Type]): def commit() = disjoint.keys.foreach(_.state.disjsub += this) - def checkAndCommit()(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]): Ls[Type -> Type] = + def checkAndCommit()(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]])(using TL): Ls[Type -> Type] = if disjoint.nonEmpty then disjoint.keys.foreach(_.state.disjsub -= this) val d = disjoint.flatMap: u => - Type.disjointImpl(u._2, u._1)(Set.empty) match + Type.disjoint(u._2, u._1) match case N => disjoint -= u N @@ -544,11 +494,11 @@ case class DisjSub(disjoint: LinkedHashSet[InfVar -> BasicType], dss: Ls[DisjSub DisjSub(LinkedHashSet.from(k), dss, cs).commit() Nil else Nil - def checkImpl(v: InfVar)(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]]) = + def checkImpl(v: InfVar)(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]])(using TL) = v.state.disjsub -= this val (u, w) = disjoint.toList.partition(_._1.uid === v.uid) val d = u.flatMap: u => - Type.disjointImpl(u._2, u._1)(Set.empty) match + Type.disjoint(u._2, u._1) match case N => disjoint -= u N @@ -560,7 +510,7 @@ case class DisjSub(disjoint: LinkedHashSet[InfVar -> BasicType], dss: Ls[DisjSub d.foldLeft(Set(w))((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => DisjSub(LinkedHashSet.from(k), dss, cs).commit() Nil - def check(v: InfVar) = checkImpl(v)(using c = MutMap.empty) + def check(v: InfVar)(using TL) = checkImpl(v)(using c = MutMap.empty) def children(): (Ls[Type], Ls[Type]) = val (p, n) = dss.map(_.children()).unzip (p.flatten ++ disjoint.keys ++ cs.keys, n.flatten ++ cs.values) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index e1c6629e01..fe5e642d1c 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -169,7 +169,7 @@ fun f() = new Printer(foofoo) f //│ Type: ['T, 'x] -> () -> Printer['T] //│ Where: -//│ 'T#'T ∨ ( 'T#⊤ ∨ Str <: Str ∧ ⊥ <: ⊥ ∧ 'T <: 'x){0: 'T} <: {0: ⊤} +//│ 'T#'T ∨ ( 'T#'T ∨ Str <: Str ∧ ⊥ <: ⊥ ∧ 'T <: 'x){0: 'T} <: {0: ⊤} //│ 'x <: Int f().Printer#f(42) @@ -219,7 +219,7 @@ fun inc(x) = x + 1 new TFun(inc) //│ Type: TFun['T] //│ Where: -//│ 'T#'T ∨ ( 'T#⊤ ∨ Int <: 'T ∧ ⊥ <: ⊥ ∧ 'T <: 'x){0: 'T} <: {0: ⊤} +//│ 'T#'T ∨ ( 'T#'T ∨ Int <: 'T ∧ ⊥ <: ⊥ ∧ 'T <: 'x){0: 'T} <: {0: ⊤} //│ 'x <: ¬¬Int let tf = new TFun(inc) in tf.TFun#f(1) @@ -345,7 +345,7 @@ f f(x => x).Foo#x //│ Type: ('A) ->{⊥} 'A //│ Where: -//│ 'A#'A ∨ ( 'A#⊤ ∨ 'x <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'x){0: 'A} <: {0: ⊤} +//│ 'A#'A ∨ ( 'A#'A ∨ 'x <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'x){0: 'A} <: {0: ⊤} g => (new Foo(g)).Foo#x //│ Type: ('A -> 'A) ->{⊥} ('A) ->{⊥} 'A diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls index 78718a4eee..59c286f6bc 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls @@ -87,7 +87,7 @@ bazbaz //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#⊤ ∨ 'A <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'A){0: 'A} <: {0: ⊤} +//│ 'A#'A ∨ ( 'A#'A ∨ 'A <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'A){0: 'A} <: {0: ⊤} bazbaz(42)(x => x + 1) //│ Type: Int @@ -98,7 +98,7 @@ cc //│ Where: //│ 'A -> 'A <: 'B //│ 'B <: 'A -> 'A -//│ 'B#'B ∨ ( 'B#⊤ ∨ 'B <: 'B ∧ ⊥ <: ⊥ ∧ 'B <: 'B){0: 'B} <: {0: ⊤} +//│ 'B#'B ∨ ( 'B#'B ∨ 'B <: 'B ∧ ⊥ <: ⊥ ∧ 'B <: 'B){0: 'B} <: {0: ⊤} //│ 'B -> 'B <: 'A //│ 'A <: 'B -> 'B @@ -119,14 +119,14 @@ bazbaz as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#⊤ ∨ 'A <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'A){0: 'A} <: {0: ⊤} +//│ 'A#'A ∨ ( 'A#'A ∨ 'A <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'A){0: 'A} <: {0: ⊤} (x => f => bazbaz(x)(f)) as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> A //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#⊤ ∨ 'A <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'A){0: 'A} <: {0: ⊤} +//│ 'A#'A ∨ ( 'A#'A ∨ 'A <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'A){0: 'A} <: {0: ⊤} h(x => f => bazbaz(x)(f))(42) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls index df1b40e056..21e14d4dfd 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls @@ -46,14 +46,14 @@ y `=> (let t = run(x `=> x `+ y) in y) //│ ╙── because: cannot constrain y <: ¬() //│ Type: CodeBase[out 'y -> 'y, ⊥, ?] //│ Where: -//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'x2#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'x2#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'x ∨ 'y#'y ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y#'y ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x2#'x ∨ 'y#'y ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x2#'x ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x <: 'cde1 //│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'y <: 'cde2 -//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'x ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'cde <: 'cde3 //│ 'app <: ¬(¬'cde) //│ 'x2 <: 'x @@ -74,7 +74,7 @@ g f(g) //│ Type: ('A) ->{⊥} Int //│ Where: -//│ 'A#C[out B] ∨ 'A#'A ∨ ( 'A#C[?] ∨ 'D <: B ∧ ⊥ <: ⊥ ∧ C[out B] & 'A <: C[in Int out 'D]){0: C[out B] & 'A} <: {0: C[?]} +//│ 'A#C[in ⊥ out B] ∨ ( 'A#C[in ⊥ out () & (B)] ∨ 'D <: B ∧ ⊥ <: ⊥ ∧ C[out B] & 'A <: C[in Int out 'D]){0: C[out B] & 'A} <: {0: C[?]} fun foo: C[in Int out Nothing] foo diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls index 3758e4ba25..53ed2221ee 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls @@ -19,13 +19,13 @@ fun id(x) = x run(x `=> id(x) `* x) //│ Type: 'x -> 'cde //│ Where: -//│ 'x#'cde1 ∨ 'x#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'cde1#'cde1 ∨ 'x#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'x1 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'x#'x1 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'x1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x <: 'x1 -//│ 'x1#'cde1 ∨ 'x1#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'cde1#'cde1 ∨ 'x1#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'x1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x1#'x1 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'x1#'x1 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x1#'x1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x1 <: 'cde1 //│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x1 <: 'cde2 @@ -40,9 +40,9 @@ let checkedDiv = x `=> y `=> x `/. (assertNotZero(y)) run(checkedDiv) //│ Type: 'x -> (Num -> 'cde) //│ Where: -//│ 'x#'cde1 ∨ ( 'x1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Num, 1: Num} +//│ 'x#'x1 ∨ ( 'x1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Num, 1: Num} //│ 'x <: 'x1 -//│ 'x1#'cde1 ∨ ( 'x1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Num, 1: Num} +//│ 'x1#'x1 ∨ ( 'x1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Num, 1: Num} //│ 'x1 <: 'cde1 //│ 'cde1#'cde1 ∨ ( 'x1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Num ∨ Num <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Num, 1: Num} //│ Num <: 'cde2 @@ -63,7 +63,7 @@ fun inc(dbg) = inc //│ Type: ['x, 'cde, 'cde1, 'app, 'app1, 'eff, 'cde2, 'x1] -> (CodeBase[out 'app1, ?, ?] ->{'eff} ⊤) ->{'eff} CodeBase[out 'x -> 'cde2, ⊥, ?] //│ Where: -//│ 'x#'cde ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde, 1: 'cde1} <: {0: Int, 1: Int} +//│ 'x#'x1 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde, 1: 'cde1} <: {0: Int, 1: Int} //│ 'x1 <: 'cde //│ 'cde#'cde ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde, 1: 'cde1} <: {0: Int, 1: Int} //│ Int <: 'cde1 @@ -71,12 +71,12 @@ inc //│ 'app <: 'cde2 //│ 'app <: 'app1 //│ 'x <: 'x1 -//│ 'x1#'cde ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde, 1: 'cde1} <: {0: Int, 1: Int} +//│ 'x1#'x1 ∨ ( 'x1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde, 1: 'cde1} <: {0: Int, 1: Int} inc(c => log(show(c))) //│ Type: CodeBase[out 'x -> 'cde, ⊥, ?] //│ Where: -//│ 'x1#'cde1 ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x1#'x ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x <: 'cde1 //│ 'cde1#'cde1 ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ Int <: 'cde2 @@ -84,7 +84,7 @@ inc(c => log(show(c))) //│ 'app <: 'cde //│ 'app <: 'app1 //│ 'x1 <: 'x -//│ 'x#'cde1 ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'x ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} fun body: [T, C] -> (CodeBase[out Int, out T, out Any], CodeBase[out Int, out C, out Any]) -> Int -> CodeBase[out Int, out T | C, out Any] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls index 0064707468..d17db1db7f 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls @@ -43,12 +43,12 @@ f `=> x `=> f`(x) x `=> y `=> x `+ y //│ Type: CodeBase[out 'x -> ('x -> 'cde), ⊥, ?] //│ Where: -//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'x#'cde1 ∨ 'y1#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'cde1#'cde1 ∨ 'y1#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'x ∨ 'y#'y ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'x ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'x ∨ 'y1#'y ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y1#'y ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x <: 'cde1 -//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y#'y ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'y <: 'cde2 //│ 'cde3 <: 'cde @@ -60,9 +60,9 @@ x `=> y `=> x `+ y (x, y) `=> x `+ y //│ Type: CodeBase[out ('x, 'x) -> 'cde, ⊥, ?] //│ Where: -//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'x ∨ 'y#'y ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'x ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y#'y ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x <: 'cde1 //│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'y <: 'cde2 @@ -72,13 +72,13 @@ x `=> y `=> x `+ y (x, y, z) `=> x `+ y `+ z //│ Type: CodeBase[out ('x, 'x, 'z) -> 'cde, ⊥, ?] //│ Where: -//│ 'x#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'x#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} -//│ 'cde1#'cde1 ∨ 'y#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'x ∨ 'y#'y ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'x ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ 'y#'y ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'x <: 'cde1 //│ 'cde1#'cde1 ∨ 'cde2#'cde2 ∨ ( 'x#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'y#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'x#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ 'cde2#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} //│ 'y <: 'cde2 -//│ 'cde3#'cde3 ∨ 'z#'cde4 ∨ ( 'cde3#Int ∨ 'z#Int ∨ Int <: 'app1 ∧ ⊥ <: ⊥) ∧ ( 'cde3#Int ∨ 'cde4#Int ∨ Int <: 'app1 ∧ ⊥ <: ⊥){0: 'cde3, 1: 'cde4} <: {0: Int, 1: Int} +//│ 'cde3#'cde3 ∨ 'z#'z ∨ ( 'cde3#Int ∨ 'z#Int ∨ Int <: 'app1 ∧ ⊥ <: ⊥) ∧ ( 'cde3#Int ∨ 'cde4#Int ∨ Int <: 'app1 ∧ ⊥ <: ⊥){0: 'cde3, 1: 'cde4} <: {0: Int, 1: Int} //│ 'cde3#'cde3 ∨ 'cde4#'cde4 ∨ ( 'cde3#Int ∨ 'z#Int ∨ Int <: 'app1 ∧ ⊥ <: ⊥) ∧ ( 'cde3#Int ∨ 'cde4#Int ∨ Int <: 'app1 ∧ ⊥ <: ⊥){0: 'cde3, 1: 'cde4} <: {0: Int, 1: Int} //│ 'z <: 'cde4 //│ 'app1 <: ¬(¬'cde) @@ -116,9 +116,9 @@ f `=> x `=> y `=> f`(x, y) x `=> `if x `== `0.0 then `1.0 else x //│ Type: CodeBase[out 'x -> ('x | Num), ⊥, ?] //│ Where: -//│ 'x#'cde ∨ ( 'x#⊤ ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T) ∧ ( 'cde#⊤ ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T){0: 'cde, 1: 'cde1} <: {0: ⊤, 1: ⊤} +//│ 'x#'x ∨ ( 'x#'x ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T) ∧ ( 'cde#'cde ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T){0: 'cde, 1: 'cde1} <: {0: ⊤, 1: ⊤} //│ 'x <: 'cde -//│ 'cde#'cde ∨ ( 'x#⊤ ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T) ∧ ( 'cde#⊤ ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T){0: 'cde, 1: 'cde1} <: {0: ⊤, 1: ⊤} +//│ 'cde#'cde ∨ ( 'x#'x ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T) ∧ ( 'cde#'cde ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T){0: 'cde, 1: 'cde1} <: {0: ⊤, 1: ⊤} //│ Num <: 'cde1 //│ 'cde2 <: ¬(¬{Bool}) //│ 'app <: ¬(¬'cde2) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls index 75030f7e5b..c203261a58 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls @@ -37,7 +37,7 @@ fun f(x) = f(x) f //│ Type: ['x, 'eff, 'app] -> 'x ->{'eff} 'app //│ Where: -//│ 'x#'x ∨ ( 'x#⊤ ∨ 'app <: 'app ∧ 'eff <: 'eff ∧ 'x <: 'x){0: 'x} <: {0: ⊤} +//│ 'x#'x ∨ ( 'x#'x ∨ 'app <: 'app ∧ 'eff <: 'eff ∧ 'x <: 'x){0: 'x} <: {0: ⊤} fun f(x) = f(x.a) @@ -70,7 +70,7 @@ fun f(x) = f(x.Foo#a) f //│ Type: ['x, 'A, 'eff, 'app] -> Foo[out 'A] ->{'eff} 'app //│ Where: -//│ 'A#'A ∨ ( 'A#⊤ ∨ 'app <: 'app ∧ 'eff <: 'eff ∧ 'A <: 'x){0: 'A} <: {0: ⊤} +//│ 'A#'A ∨ ( 'A#'A ∨ 'app <: 'app ∧ 'eff <: 'eff ∧ 'A <: 'x){0: 'A} <: {0: ⊤} //│ 'x <: Foo[out 'A] diff --git a/hkmc2/shared/src/test/mlscript/logicsub/If.mls b/hkmc2/shared/src/test/mlscript/logicsub/If.mls index 6fbe47ff55..33ad38abf8 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/If.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/If.mls @@ -17,7 +17,7 @@ f //│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: //│ 'x#Int ∨ Int <: 'res ∧ ⊥ <: 'eff -//│ 'x#¬Int ∨ ( 'x1#Bool ∨ Bool & 'x1 <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Int | Bool) ∨ (¬Int & ¬Bool) & 'x1 <: 'x1 ∧ ⊤ <: ⊥)¬Int & 'x <: 'x1 +//│ 'x#¬Int ∨ ( 'x1#Bool ∨ Bool & 'x1 <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Int & ¬Bool ∨ (¬Int & ¬Bool) & 'x1 <: 'x1 ∧ ⊤ <: ⊥)¬Int & 'x <: 'x1 f(ib) as Int | Bool //│ Type: Int | Bool @@ -28,12 +28,12 @@ f(f(ib)) //│ Where: //│ Int <: 'x //│ Bool & ¬Int <: 'x -//│ 'x#¬(Int | Bool) ∨ (¬Int & ¬Bool) & 'x1 <: 'x1 ∧ ⊤ <: ⊥ +//│ 'x#¬Int & ¬Bool ∨ (¬Int & ¬Bool) & 'x1 <: 'x1 ∧ ⊤ <: ⊥ //│ ¬{Int} ∧ 'x <: 'x1 //│ Int <: 'res //│ (Bool & ¬Int) & 'x <: 'res //│ 'x1 <: ¬(Bool ∧ ¬'res) -//│ 'x1#¬(Int | Bool) ∨ (¬Int & ¬Bool) & 'x1 <: 'x1 ∧ ⊤ <: ⊥ +//│ 'x1#¬Int & ¬Bool ∨ (¬Int & ¬Bool) & 'x1 <: 'x1 ∧ ⊤ <: ⊥ :e f(si) @@ -138,7 +138,7 @@ increv' //│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: //│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff -//│ 'x#¬Int ∨ ( 'x1#Str ∨ Str & 'x1 <: Str ∧ Str <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Int | Str) ∨ (¬Int & ¬Str) & 'x1 <: 'x1 ∧ ⊤ <: ⊥)¬Int & 'x <: 'x1 +//│ 'x#¬Int ∨ ( 'x1#Str ∨ Str & 'x1 <: Str ∧ Str <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Str & ¬Int ∨ (¬Int & ¬Str) & 'x1 <: 'x1 ∧ ⊤ <: ⊥)¬Int & 'x <: 'x1 :e increv(sib) diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index 3fef940e4a..6a2248085d 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -39,8 +39,8 @@ test //│ Type: ['x, 'y, 'res, 'eff, 'x1, 'y1] -> ('x, 'x) ->{'eff} 'res //│ Where: //│ 'x#Tru ∨ ( 'y#Tru ∨ Tru <: 'res ∧ ⊥ <: 'eff) ∧ ( 'y#¬Tru ∨ Tru & 'x <: 'x1 ∧ ¬Tru & 'y <: 'y1) -//│ 'x#¬Tru ∨ ( 'x1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Tru | Fls) ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Tru | Fls) ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬(Tru | Fls) ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)(¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ 'y1 <: 'y1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Tru | Fls) ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬(Tru | Fls) ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)¬Fls & 'x1 <: 'x1 ∧ ¬Tru & 'y1 <: 'y1)¬Tru & 'x <: 'x1 ∧ 'y <: 'y1 -//│ 'y#¬Tru ∨ ( 'x1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Tru | Fls) ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Tru | Fls) ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬(Tru | Fls) ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)(¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ 'y1 <: 'y1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬(Tru | Fls) ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬(Tru | Fls) ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)¬Fls & 'x1 <: 'x1 ∧ ¬Tru & 'y1 <: 'y1)'x <: 'x1 ∧ ¬Tru & 'y <: 'y1 +//│ 'x#¬Tru ∨ ( 'x1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Fls & ¬Tru ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Fls & ¬Tru ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬Fls & ¬Tru ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)(¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ 'y1 <: 'y1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Fls & ¬Tru ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬Fls & ¬Tru ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)¬Fls & 'x1 <: 'x1 ∧ ¬Tru & 'y1 <: 'y1)¬Tru & 'x <: 'x1 ∧ 'y <: 'y1 +//│ 'y#¬Tru ∨ ( 'x1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Fls & ¬Tru ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Fls & ¬Tru ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬Fls & ¬Tru ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)(¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ 'y1 <: 'y1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Fls & ¬Tru ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬Fls & ¬Tru ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)¬Fls & 'x1 <: 'x1 ∧ ¬Tru & 'y1 <: 'y1)'x <: 'x1 ∧ ¬Tru & 'y <: 'y1 test(tru, tru) //│ = Tru() From f0097116db7a79d59fe62cd66364eff8f1fbe1ba Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 17 Apr 2025 05:26:44 +0800 Subject: [PATCH 26/36] fix if --- .../scala/hkmc2/bbml/ConstraintSolver.scala | 5 +- .../src/main/scala/hkmc2/bbml/bbML.scala | 162 +++++++++++------- .../src/main/scala/hkmc2/bbml/types.scala | 43 ++--- .../src/test/mlscript/bbml/bbBasics.mls | 6 +- .../src/test/mlscript/bbml/bbCodeGen.mls | 3 - .../shared/src/test/mlscript/bbml/bbGPCE.mls | 10 +- .../src/test/mlscript/logicsub/DisjSub.mls | 45 +++-- .../shared/src/test/mlscript/logicsub/If.mls | 116 ++++++++----- .../test/mlscript/logicsub/MarlowWadler97.mls | 49 +----- 9 files changed, 221 insertions(+), 218 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index c738150e6e..8e6f44f6bd 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -102,8 +102,9 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, cctx.nest(bd -> v) givenIn: v.state.lowerBounds ::= bd v.state.upperBounds.foreach(ub => constrainImpl(bd, ub)) - v.state.disjsub.toList.flatMap(_.check(v)).foreach: - case (a, b) => constrainImpl(a, b) + val (dss, cs) = v.state.disjsub.toList.map(_.check(Map(v -> bd), false)).unzip + dss.flatten.foreach(_.commit()) + cs.flatten.foreach(u => constrainImpl(u._1, u._2)) case Conj(i, u, Nil) => (conj.i, conj.u) match case (_, Union(N, Nil, Nil)) => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} ∧ ¬⊥" -> N :: Nil)) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index 11b5b5c114..78bf2d6f1a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -323,49 +323,45 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): pctx += sym -> PolyType.generalize(funTy, S(outer), 1) case _ => error(msg"Function definition shape not yet supported for ${sym.nme}" -> lam.toLoc :: Nil) - private def typeSplitImpl(split: Split, sign: GeneralType, eff: Type, br: Bool, path: Ls[LinkedHashMap[Ref, Type]]) - (using ctx: BbCtx, c: ConstraintHandler, sv: HashMap[Ref, InfVar])(using CCtx, Scope) - : Ls[LinkedHashMap[Ref, Type]] = split match + private def typeSplitImpl(split: Split, sign: GeneralType, eff: Type, br: Bool, cons: Bool, path: Ls[Ls[Ref -> Type]]) + (using ctx: BbCtx, c: ConstraintHandler, sv: HashMap[Ref, Type])(using CCtx, Scope) + : Ls[Ls[Ref -> Type]] = split match case Split.Cons(Branch(s: Ref, cp: Pattern.ClassLike, cons), alts) => - val sty = tryMkMono(typeCheck(s)._1, s) val cls = ClassLikeType(cp.sym, Nil) - sv.updateWith(s)(_.orElse(S(freshVar(new TempSymbol(S(s), s.sym.nme))))) - val (ctx1, ctx2) = (ctx.nest, ctx.nest) - ctx1 += s.sym -> (cls & sty) - val p0 = LinkedHashMap(s -> cls) :: (Type.disjoint(cls, sty) match - case N => typeSplitImpl(cons, sign, eff, true, Ls(LinkedHashMap.empty))(using ctx1) - case S(k) => - if k.isEmpty then Nil - else - val (nc, dss, cs) = constraintCollector - val p = typeSplitImpl(cons, sign, eff, true, Ls(LinkedHashMap.empty))(using ctx1, nc) - k.foreach(k => c.commit(DisjSub(LinkedHashSet.from(k), dss.toList, cs.toList))) - p) - p0.flatMap(_.keysIterator).distinct.foreach(s => ctx2 += s.sym -> sv(s)) - val p = p0.flatMap(x => path.map: y => - val m = y.clone() - x.foreachEntry((s, t) => m.updateWith(s)(_.map(_ | t).orElse(S(t)))) - m) - val (nc, dss, cs) = constraintCollector - val p1 = typeSplitImpl(alts, sign, eff, br, p)(using ctx2, nc) - p.foreach: p => - val ds = p.map { case (s, t) => Type.disjoint(NegType(t), tryMkMono(typeCheck(s)._1, s)) }.flatten - val scs = sv.toList.map: - case (s, v) => p.get(s) match - case N => (tryMkMono(typeCheck(s)._1, s), v) - case S(t) => (t.! & tryMkMono(typeCheck(s)._1, s), v) - if ds.isEmpty then - dss.foreach(c.commit(_)) - (scs ++ cs).foreach(u => constrain(u._1, u._2)) - else - ds.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - c.commit(DisjSub(LinkedHashSet.from(k), dss.toList, scs ++ cs)) - if br then - p1.flatMap(x => p.map: y => - val m = y.clone() - x.foreachEntry((s, t) => m.updateWith(s)(_.map(_ | t).orElse(S(t)))) - m) - else Nil + val (r, sty) = sv.get(s) match + case N => + val t = tryMkMono(typeCheck(s)._1, s) + sv += s -> t + (false, t) + case S(t) => + (path.forall: p => + p.find(_._1 === s).fold(false): u => + Type.disjoint(u._2.!, cls).exists(_.isEmpty)) -> t + if r then typeSplitImpl(alts, sign, eff, br, false, path) + else + val ctx1 = ctx.nest + ctx1 += s.sym -> (cls & sty) + val p0 = Ls(s -> cls) :: (Type.disjoint(cls, sty) match + case N => typeSplitImpl(cons, sign, eff, true, true, path)(using ctx1) + case S(k) => + if k.isEmpty then Nil + else + val (nc, dss, cs) = constraintCollector + val p = typeSplitImpl(cons, sign, eff, true, true, path)(using ctx1, nc) + k.foreach: k => + val ks = LinkedHashSet.from(k) + dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) + if cs.nonEmpty then c.commit(DisjSub(ks, Nil, cs.toList)) + p) + val p = path.flatMap(x => p0.map: y => + val m = (x ++ y).groupMapReduce(_._1)(_._2)(_ | _) + (x.keys ++ y.keys).distinct.map(k => k -> m(k)).toList) + val p1 = typeSplitImpl(alts, sign, eff, br, false, p) + if br then + p1.flatMap(y => p0.map: x => + val m = (x ++ y).groupMapReduce(_._1)(_._2)(_ | _) + (x.keys ++ y.keys).distinct.map(k => k -> m(k)).toList) + else Nil case Split.Cons(Branch(s: Ref, Pattern.Lit(lit), cons), alts) => constrain(tryMkMono(typeCheck(s)._1, s), lit match case _: Tree.BoolLit => BbCtx.boolTy @@ -373,39 +369,89 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case _: Tree.DecLit => BbCtx.numTy case _: Tree.StrLit => BbCtx.strTy case _: Tree.UnitLit => Top) - val p0 = typeSplitImpl(cons, sign, eff, true, List(LinkedHashMap.empty)) - val p = p0.flatMap(x => path.map: y => - val m = y.clone() - x.foreachEntry((s, t) => m.updateWith(s)(_.map(_ | t).orElse(S(t)))) - m) - val p1 = typeSplitImpl(alts, sign, eff, br, p) + val p0 = typeSplitImpl(cons, sign, eff, true, true, path) + val p = path.flatMap(x => p0.map: y => + val m = (x ++ y).groupMapReduce(_._1)(_._2)(_ | _) + (x.keys ++ y.keys).distinct.map(k => k -> m(k)).toList) + val p1 = typeSplitImpl(alts, sign, eff, br, false, p) if br then - p1.flatMap(x => p.map: y => - val m = y.clone() - x.foreachEntry((s, t) => m.updateWith(s)(_.map(_ | t).orElse(S(t)))) - m) + p1.flatMap(y => p0.map: x => + val m = (x ++ y).groupMapReduce(_._1)(_._2)(_ | _) + (x.keys ++ y.keys).distinct.map(k => k -> m(k)).toList) else Nil case Split.Let(name, term, tail) => val nestCtx = ctx.nest given BbCtx = nestCtx - val (termTy, termEff) = typeCheck(term) + val (nc, dss, cs) = constraintCollector + val sv0 = HashMap.empty[Ref, InfVar] + sv.keys.foreach: s => + val v = freshVar(new TempSymbol(S(s), s.sym.nme)) + nestCtx += s.sym -> v + sv0 += s -> v + val (termTy, termEff) = typeCheck(term)(using c = nc) val sk = freshSkolem(name) nestCtx += name -> termTy - constrain(termEff, eff) - typeSplitImpl(tail, sign, eff, br, path) - case Split.Else(e) => + nc.constrain(termEff, eff) + path.foreach: p => + val m = p.toMap + val d = p.flatMap { case (s, t) => Type.disjoint(t.!, sv(s)) } + val sc = p.iterator.map { case (s, t) => (t.! & sv(s), sv0(s)) } + if d.isEmpty then + dss.foreach(c.commit(_)) + (sc ++ cs).foreach(u => constrain(u._1, u._2)) + else + val ds = d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => + val c0 = sc ++ cs + val ks = LinkedHashSet.from(k) + dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) + c.commit(DisjSub(ks, Nil, c0.toList)) + typeSplitImpl(tail, sign, eff, br, cons, path) + case Split.Else(e) if cons => constrain(ascribe(e, sign)._2, eff) Nil + case Split.Else(e) => + val (nc, dss, cs) = constraintCollector + val ctx1 = ctx.nest + val sv0 = HashMap.empty[Ref, InfVar] + sv.keys.foreach: s => + val v = freshVar(new TempSymbol(S(s), s.sym.nme)) + ctx1 += s.sym -> v + sv0 += s -> v + nc.constrain(ascribe(e, sign)(using ctx1, c = nc)._2, eff) + path.foreach: p => + val m = p.toMap + val d = p.flatMap { case (s, t) => Type.disjoint(t.!, sv(s)) } + val sc = p.map { case (s, t) => (t.! & sv(s), sv0(s)) } + if d.isEmpty then + dss.foreach(c.commit(_)) + (sc ++ cs).foreach(u => constrain(u._1, u._2)) + else + val ds = d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => + val c0 = sc ++ cs + val ks = LinkedHashSet.from(k) + dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) + c.commit(DisjSub(ks, Nil, c0.toList)) + Nil case Split.End => - if !br then constrain(Top, Bot) - Ls(LinkedHashMap.empty) + if !br then + path.foreach: p => + val m = p.toMap + val d = p.flatMap { case (s, t) => Type.disjoint(t.!, sv(s)) } + if d.isEmpty then + constrain(Top, Bot) + else + val ds = d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => + val c0 = Ls(Top -> Bot) + val ks = LinkedHashSet.from(k) + c.commit(DisjSub(ks, Nil, c0)) + Ls(Nil) private def typeSplit (split: Split, sign: Opt[GeneralType], path: Ls[Ls[Type -> ClassLikeType]] = Ls(Nil))(using ctx: BbCtx, c: ConstraintHandler)(using CCtx, Scope) : (GeneralType, Type) = val res = sign.orElse(S(freshVar(new TempSymbol(N, "res")))).get val eff = freshVar(new TempSymbol(N, "eff")) - typeSplitImpl(split, res, eff, false, Ls(LinkedHashMap.empty))(using sv = HashMap.empty) + typeSplitImpl(split, res, eff, false, true, Ls(Nil))(using sv = HashMap.empty) (res, eff) // * Note: currently, the returned type is not used or useful, but it could be in the future diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 1bee9c20c7..12ab0c4a2c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -476,41 +476,20 @@ class VarState: case class DisjSub(disjoint: LinkedHashSet[InfVar -> BasicType], dss: Ls[DisjSub], cs: Ls[Type -> Type]): def commit() = disjoint.keys.foreach(_.state.disjsub += this) - def checkAndCommit()(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]])(using TL): Ls[Type -> Type] = - if disjoint.nonEmpty then + def check(m: Map[InfVar, Type], subst: Bool)(using TL): (Ls[DisjSub], Ls[Type -> Type]) = + if disjoint.isEmpty then (Nil, Nil) + else disjoint.keys.foreach(_.state.disjsub -= this) - val d = disjoint.flatMap: u => - Type.disjoint(u._2, u._1) match - case N => - disjoint -= u - N - case k => k + val d = disjoint.toList.flatMap: u => + m.get(u._1).fold(S(Set(Set(u._1 -> u._2)))): t => + Type.disjoint(u._2, if subst then t else t | u._1).orElse { disjoint -= u; N } if disjoint.isEmpty then - dss.flatMap(_.checkAndCommit()) ++ cs + val (dss0, cs0) = dss.map(_.check(m, subst)).unzip + (dss0.flatten, cs0.flatten ++ cs) else - if d.nonEmpty then - commit() - d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - DisjSub(LinkedHashSet.from(k), dss, cs).commit() - Nil - else Nil - def checkImpl(v: InfVar)(using c: MutMap[BasicType -> BasicType, Opt[Set[Set[InfVar->BasicType]]]])(using TL) = - v.state.disjsub -= this - val (u, w) = disjoint.toList.partition(_._1.uid === v.uid) - val d = u.flatMap: u => - Type.disjoint(u._2, u._1) match - case N => - disjoint -= u - N - case k => k - if disjoint.isEmpty then - dss.flatMap(_.checkAndCommit()) ++ cs - else - if d.nonEmpty then - d.foldLeft(Set(w))((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - DisjSub(LinkedHashSet.from(k), dss, cs).commit() - Nil - def check(v: InfVar)(using TL) = checkImpl(v)(using c = MutMap.empty) + val dss1 = d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).map: k => + DisjSub(LinkedHashSet.from(k), dss, cs) + (dss1.toList, Nil) def children(): (Ls[Type], Ls[Type]) = val (p, n) = dss.map(_.children()).unzip (p.flatten ++ disjoint.keys ++ cs.keys, n.flatten ++ cs.values) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index fe5e642d1c..14871c9d06 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -149,10 +149,10 @@ fun foofoo(x) = if x is Int then let t = x + 1 in "foo" foofoo -//│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res +//│ Type: ['x, 'res, 'eff] -> 'x ->{'eff} 'res //│ Where: //│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Str <: 'res ∧ ⊥ <: 'eff -//│ 'x#¬Int ∨ ¬Int & 'x <: 'x1 ∧ ⊤ <: ⊥ +//│ 'x#¬Int ∨ ⊤ <: ⊥ fun foofoo(x) = let t = x + 1 in "foo" @@ -270,7 +270,7 @@ if 1 < 2 then 1 else 0 if false then 1 else "1" -//│ Type: Str | Int +//│ Type: Int if 1 is Int then 1 else 0 diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbCodeGen.mls b/hkmc2/shared/src/test/mlscript/bbml/bbCodeGen.mls index c4c9aca8a9..7ff168e31f 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbCodeGen.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbCodeGen.mls @@ -169,7 +169,6 @@ fun pow(x) = case :sjs -:fixme fun not = case true then false false then true @@ -188,8 +187,6 @@ fun not = case //│ }); //│ return lambda1 //│ }; -//│ ╔══[ERROR] Type error in `if` expression -//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls index 53ed2221ee..2dace72d3c 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls @@ -101,21 +101,13 @@ fun bind(rhs, k) = `let x = rhs `in k(x) bind //│ Type: ['cde, 'ctx, 'cde1, 'eff, 'cde2, 'ctx1] -> (CodeBase[out 'cde, out 'ctx, ?], CodeBase[in 'cde1 out 'cde1 | 'cde, ?, ⊥] ->{'eff} CodeBase[out 'cde2, out 'ctx1, ?]) ->{'eff} CodeBase[out 'cde2, out 'ctx | 'ctx1, ?] +:todo :e fun body: [G] -> (CodeBase[out Int, out G, out Any], CodeBase[out Int, out G, out Any]) -> Int -> CodeBase[out Int, out G, out Any] fun body(x, y) = case 0 then x 1 then y n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] -//│ ╔══[ERROR] Type error in application with expected type CodeBase[out Int, out G, ?] -//│ ║ l.109: n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain CodeBase[out 'cde, out 'ctx | 'ctx1, ?] <: CodeBase[out Int, out G, ?] -//│ ╟── because: cannot constrain 'ctx ∨ 'ctx1 <: G -//│ ╟── because: cannot constrain 'ctx1 <: ¬(¬G) -//│ ╟── because: cannot constrain 'ctx2 <: ¬(¬G) -//│ ╟── because: cannot constrain 'ctx2 <: ¬(¬G) -//│ ╙── because: cannot constrain <: ¬(¬G) //│ Type: ⊤ fun bind: [G] -> (CodeBase[out Int, out G, out Any], [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out Int, out C | G, out Any]) -> CodeBase[out Int, out G, out Any] diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index f640b7648d..f3f614476b 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -28,7 +28,7 @@ idIB(true) //│ Type: Bool idIB(if true then 1 else true) -//│ Type: Bool | Int +//│ Type: Int x => let y = x+1 @@ -278,7 +278,7 @@ fun k: ((Int | Str, Int) -> Int) & ((Bool | Str, Bool) -> Bool) //│ Type: ⊤ k("", if true then 1 else true) -//│ Type: Bool | Int +//│ Type: Int fun k: ((Int, Int) -> Int) & ((Bool, Bool) -> Bool) //│ Type: ⊤ @@ -344,30 +344,25 @@ class fun wf: ((Z, Z) -> Z) & ((Z, S) -> S) & ((S, Z | S) -> S) //│ Type: ⊤ -let zs = if true then new Z() else new S() -zs -//│ Type: S | Z +fun zs: Z | S +//│ Type: ⊤ :e wf(zs, zs) //│ ╔══[ERROR] Type error in application -//│ ║ l.352: wf(zs, zs) +//│ ║ l.351: wf(zs, zs) //│ ║ ^^^^^^^^^^ -//│ ╟── because: cannot constrain (((Z, Z) -> Z) & ((Z, S) -> S)) & ((S, Z | S) -> S) <: ('res, 'res) ->{'eff} 'app -//│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: ({0: Z, 1: Z} | {0: Z, 1: S}) | {0: S, 1: Z | S} -//│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: {1: S} -//│ ╟── because: cannot constrain 'res <: S -//│ ╟── because: cannot constrain 'res <: ¬(¬{S}) -//│ ╙── because: cannot constrain Z <: ¬(¬{S}) +//│ ╟── because: cannot constrain (((Z, Z) -> Z) & ((Z, S) -> S)) & ((S, Z | S) -> S) <: (Z | S, Z | S) ->{'eff} 'app +//│ ╟── because: cannot constrain {0: Z | S, 1: Z | S} <: ({0: Z, 1: Z} | {0: Z, 1: S}) | {0: S, 1: Z | S} +//│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: {1: S} +//│ ╙── because: cannot constrain Z ∨ S <: S //│ ╔══[ERROR] Type error in application -//│ ║ l.352: wf(zs, zs) +//│ ║ l.351: wf(zs, zs) //│ ║ ^^^^^^^^^^ -//│ ╟── because: cannot constrain (((Z, Z) -> Z) & ((Z, S) -> S)) & ((S, Z | S) -> S) <: ('res, 'res) ->{'eff} 'app -//│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: ({0: Z, 1: Z} | {0: Z, 1: S}) | {0: S, 1: Z | S} -//│ ╟── because: cannot constrain {0: 'res, 1: 'res} <: {1: Z} -//│ ╟── because: cannot constrain 'res <: Z -//│ ╟── because: cannot constrain 'res <: ¬(¬{Z}) -//│ ╙── because: cannot constrain S <: ¬(¬{Z}) +//│ ╟── because: cannot constrain (((Z, Z) -> Z) & ((Z, S) -> S)) & ((S, Z | S) -> S) <: (Z | S, Z | S) ->{'eff} 'app +//│ ╟── because: cannot constrain {0: Z | S, 1: Z | S} <: ({0: Z, 1: Z} | {0: Z, 1: S}) | {0: S, 1: Z | S} +//│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: {1: Z} +//│ ╙── because: cannot constrain Z ∨ S <: Z //│ Type: S | Z :e @@ -376,11 +371,11 @@ fun ill: (([b: Bool, c: Bool]) -> Bool) & (([a: Str, c: Str]) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.375: (([a: Int, b:Int]) -> Int) & +//│ ║ l.370: (([a: Int, b:Int]) -> Int) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.376: (([b: Bool, c: Bool]) -> Bool) & +//│ ║ l.371: (([b: Bool, c: Bool]) -> Bool) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.377: (([a: Str, c: Str]) -> Str) +//│ ║ l.372: (([a: Str, c: Str]) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -390,10 +385,10 @@ fun nested: (([tag: [b: Bool, c: Bool]]) -> Bool) & (([tag: [a: Str, c: Str]]) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.389: (([tag: [a: Int, b:Int]]) -> Int) & +//│ ║ l.384: (([tag: [a: Int, b:Int]]) -> Int) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.390: (([tag: [b: Bool, c: Bool]]) -> Bool) & +//│ ║ l.385: (([tag: [b: Bool, c: Bool]]) -> Bool) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.391: (([tag: [a: Str, c: Str]]) -> Str) +//│ ║ l.386: (([tag: [a: Str, c: Str]]) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/logicsub/If.mls b/hkmc2/shared/src/test/mlscript/logicsub/If.mls index 33ad38abf8..0ce69b3a0e 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/If.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/If.mls @@ -14,59 +14,55 @@ fun f(x) = if x is Int then 0 Bool then x f -//│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res +//│ Type: ['x, 'res, 'eff] -> 'x ->{'eff} 'res //│ Where: //│ 'x#Int ∨ Int <: 'res ∧ ⊥ <: 'eff -//│ 'x#¬Int ∨ ( 'x1#Bool ∨ Bool & 'x1 <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Int & ¬Bool ∨ (¬Int & ¬Bool) & 'x1 <: 'x1 ∧ ⊤ <: ⊥)¬Int & 'x <: 'x1 +//│ 'x#Bool ∨ Bool & 'x <: 'res ∧ ⊥ <: 'eff +//│ 'x#¬Int & ¬Bool ∨ ⊤ <: ⊥ f(ib) as Int | Bool //│ Type: Int | Bool f(f(ib)) as Int | Bool f(f(ib)) -//│ Type: Int | ((Bool & ¬Int) & 'x) +//│ Type: Int | (Bool & 'x) //│ Where: //│ Int <: 'x -//│ Bool & ¬Int <: 'x -//│ 'x#¬Int & ¬Bool ∨ (¬Int & ¬Bool) & 'x1 <: 'x1 ∧ ⊤ <: ⊥ -//│ ¬{Int} ∧ 'x <: 'x1 -//│ Int <: 'res -//│ (Bool & ¬Int) & 'x <: 'res -//│ 'x1 <: ¬(Bool ∧ ¬'res) -//│ 'x1#¬Int & ¬Bool ∨ (¬Int & ¬Bool) & 'x1 <: 'x1 ∧ ⊤ <: ⊥ +//│ Bool <: 'x +//│ 'x#¬Int & ¬Bool ∨ ⊤ <: ⊥ :e f(si) //│ ╔══[ERROR] Type error in reference with expected type 'x -//│ ║ l.39: f(si) +//│ ║ l.35: f(si) //│ ║ ^^ //│ ╟── because: cannot constrain Str | Int <: 'x //│ ╟── because: cannot constrain Str <: 'x -//│ ╟── because: cannot constrain ¬Int & 'x <: 'x1 -//│ ╟── because: cannot constrain ¬{Int} ∧ 'x <: 'x1 //│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: Int // order-dependent (expected) +// TODO: order-independent currently, bring order-dependence back + fun f(x, y) = if x is Int then 1 y is Str then "" f(1, "") -//│ Type: Int +//│ Type: Str | Int f(1, sib) -//│ Type: Int +//│ Type: Str | Int fun f(x, y) = if y is Str then "" x is Int then 1 f(1, "") -//│ Type: Str +//│ Type: Str | Int f(1, sib) -//│ Type: Int | Str +//│ Type: Str | Int fun foorec(x, y, r) = if @@ -89,36 +85,20 @@ foo as (Str, Bool) -> Bool :e foo(1, "") //│ ╔══[ERROR] Type error in string literal with expected type 'y -//│ ║ l.90: foo(1, "") +//│ ║ l.86: foo(1, "") //│ ║ ^^ //│ ╟── because: cannot constrain Str <: 'y //│ ╟── because: cannot constrain Str <: 'y -//│ ╟── because: cannot constrain ¬Int & 'y1 <: 'y2 -//│ ╟── because: cannot constrain ¬{Int} ∧ 'y1 <: 'y2 -//│ ╟── because: cannot constrain 'r <: (Str & 'y2, 'x, 'r) ->{'eff} 'app -//│ ╟── because: cannot constrain 'r <: ¬(¬{(Str & 'y2, 'x, 'r) ->{'eff} 'app}) -//│ ╟── because: cannot constrain ((¬⊥ & 'x1, ¬⊥ & 'y3, ¬⊥ & 'r1) ->{¬⊥ & 'eff1} (¬⊥ & 'res)) & ¬⊥ <: ¬(¬{(Str & 'y2, 'x, 'r) ->{'eff} 'app}) -//│ ╟── because: cannot constrain 'x <: 'y3 -//│ ╟── because: cannot constrain 'x <: 'y3 +//│ ╟── because: cannot constrain 'r <: (Str & 'y1, 'x, 'r) ->{'eff} 'app +//│ ╟── because: cannot constrain 'r <: ¬(¬{(Str & 'y1, 'x, 'r) ->{'eff} 'app}) +//│ ╟── because: cannot constrain ((¬⊥ & 'x1, ¬⊥ & 'y2, ¬⊥ & 'r1) ->{¬⊥ & 'eff1} (¬⊥ & 'res)) & ¬⊥ <: ¬(¬{(Str & 'y1, 'x, 'r) ->{'eff} 'app}) +//│ ╟── because: cannot constrain 'x <: 'y2 +//│ ╟── because: cannot constrain 'x <: 'y2 //│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) //│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain ¬⊥ & 'x2 <: ¬(¬{Bool}) //│ ╟── because: cannot constrain 'x2 <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain ¬⊥ & 'x3 <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain 'x3 <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) -//│ ╔══[ERROR] Type error in string literal with expected type 'y -//│ ║ l.90: foo(1, "") -//│ ║ ^^ -//│ ╟── because: cannot constrain Str <: 'y -//│ ╟── because: cannot constrain Str <: 'y -//│ ╟── because: cannot constrain Int & 'x2 <: 'x -//│ ╟── because: cannot constrain Int ∧ 'x2 <: 'x -//│ ╟── because: cannot constrain Int ∧ 'x2 <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain 'x2 <: ¬(Int ∧ ¬{Bool}) -//│ ╟── because: cannot constrain ¬⊥ & 'x3 <: ¬(Int ∧ ¬{Bool}) -//│ ╟── because: cannot constrain 'x3 <: ¬(Int ∧ ¬{Bool}) -//│ ╙── because: cannot constrain Int <: ¬(Int ∧ ¬{Bool}) //│ Type: Bool fun increv(x) = if x is @@ -135,15 +115,16 @@ fun increv'(x) = if x is Int then x + 1 Str then rev(x) increv' -//│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res +//│ Type: ['x, 'res, 'eff] -> 'x ->{'eff} 'res //│ Where: //│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff -//│ 'x#¬Int ∨ ( 'x1#Str ∨ Str & 'x1 <: Str ∧ Str <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Str & ¬Int ∨ (¬Int & ¬Str) & 'x1 <: 'x1 ∧ ⊤ <: ⊥)¬Int & 'x <: 'x1 +//│ 'x#Str ∨ Str & 'x <: Str ∧ Str <: 'res ∧ ⊥ <: 'eff +//│ 'x#¬Str & ¬Int ∨ ⊤ <: ⊥ :e increv(sib) //│ ╔══[ERROR] Type error in reference with expected type 'x -//│ ║ l.144: increv(sib) +//│ ║ l.125: increv(sib) //│ ║ ^^^ //│ ╟── because: cannot constrain (Str | Int) | Bool <: 'x //│ ╟── because: cannot constrain Bool <: 'x @@ -153,7 +134,7 @@ increv(sib) :e increv'(sib) //│ ╔══[ERROR] Type error in reference with expected type 'x -//│ ║ l.154: increv'(sib) +//│ ║ l.135: increv'(sib) //│ ║ ^^^ //│ ╟── because: cannot constrain (Str | Int) | Bool <: 'x //│ ╟── because: cannot constrain Bool <: 'x @@ -177,8 +158,51 @@ fun f(x, y) = if x => if x is true then 0 false then 0 -//│ ╔══[ERROR] Type error in `if` expression -//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: (Bool) ->{⊥} Int +fun f(x) = if + x is Int then x + 2 + x is Str then rev(x) + else + not(x) +f +//│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res +//│ Where: +//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#Str ∨ Str & 'x <: Str ∧ Str <: 'res ∧ ⊥ <: 'eff +//│ 'x#¬Str & ¬Int ∨ (¬Int & ¬Str) & 'x <: 'x1 ∧ 'x1 <: Bool ∧ Bool <: 'res ∧ ⊥ <: 'eff + +f(sib) +//│ Type: (Bool | Int) | Str + +fun f(x, y) = if + x is Int then y + y is Str then 1 + x is Str then y + 1 + else + not(x) +f +//│ Type: ['x, 'y, 'res, 'eff, 'y1, 'x1] -> ('x, 'y) ->{'eff} 'res +//│ Where: +//│ 'x#Int ∨ 'y <: 'res ∧ ⊥ <: 'eff +//│ 'x#Str ∨ 'y <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#¬Str & ¬Int ∨ 'y#¬Str ∨ (¬Int & ¬Str) & 'x <: 'x1 ∧ ¬Str & 'y <: 'y1 ∧ 'x1 <: Bool ∧ Bool <: 'res ∧ ⊥ <: 'eff +//│ 'y#Str ∨ Int <: 'res ∧ ⊥ <: 'eff + +f(ib, sib) +//│ Type: (((Bool | Int) | Bool) | Int) | Str +:ns +f(ib, ib) +//│ Type: 'res +//│ Where: +//│ Bool <: 'y +//│ Int <: 'y +//│ 'y#Str ∨ Int <: 'res ∧ ⊥ <: 'eff +//│ 'eff <: ¬() +//│ Bool <: 'res +//│ 'y <: 'res + +:todo +f(ib, ib) +//│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index 6a2248085d..af150cdd84 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -24,6 +24,8 @@ let // :ucs desugared :ucs normalized fun test(x, y) = if + x is Tru and y is Tru then tru + x is Tru and y is Tru then tru x is Tru and y is Tru then tru x is Fls then fls y is Fls then fls @@ -36,11 +38,14 @@ test //│ > x is Fls then fls#666 //│ > y is Fls then fls#666 //│ = [function test] -//│ Type: ['x, 'y, 'res, 'eff, 'x1, 'y1] -> ('x, 'x) ->{'eff} 'res +//│ Type: ['x, 'y, 'res, 'eff] -> ('x, 'y) ->{'eff} 'res //│ Where: -//│ 'x#Tru ∨ ( 'y#Tru ∨ Tru <: 'res ∧ ⊥ <: 'eff) ∧ ( 'y#¬Tru ∨ Tru & 'x <: 'x1 ∧ ¬Tru & 'y <: 'y1) -//│ 'x#¬Tru ∨ ( 'x1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Fls & ¬Tru ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Fls & ¬Tru ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬Fls & ¬Tru ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)(¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ 'y1 <: 'y1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Fls & ¬Tru ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬Fls & ¬Tru ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)¬Fls & 'x1 <: 'x1 ∧ ¬Tru & 'y1 <: 'y1)¬Tru & 'x <: 'x1 ∧ 'y <: 'y1 -//│ 'y#¬Tru ∨ ( 'x1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Fls & ¬Tru ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Fls & ¬Tru ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬Fls & ¬Tru ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)(¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ 'y1 <: 'y1) ∧ ( 'y1#¬Tru ∨ 'x1#¬Fls ∨ ( 'y1#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff) ∧ ( 'x1#¬Fls & ¬Tru ∨ 'y1#¬Fls ∨ (¬Tru & ¬Fls) & 'x1 <: 'x1 ∧ ¬Fls & 'y1 <: 'y1 ∧ ⊤ <: ⊥) ∧ ( 'y1#¬Fls & ¬Tru ∨ 'x1#¬Fls ∨ ¬Fls & 'x1 <: 'x1 ∧ (¬Tru & ¬Fls) & 'y1 <: 'y1 ∧ ⊤ <: ⊥)¬Fls & 'x1 <: 'x1 ∧ ¬Tru & 'y1 <: 'y1)'x <: 'x1 ∧ ¬Tru & 'y <: 'y1 +//│ 'x#Tru ∨ 'y#Tru ∨ Tru <: 'res ∧ ⊥ <: 'eff +//│ 'x#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff +//│ 'x#¬Fls & ¬Tru ∨ 'y#¬Fls ∨ ⊤ <: ⊥ +//│ 'x#¬Fls & ¬Tru ∨ 'y#¬Fls & ¬Tru ∨ ⊤ <: ⊥ +//│ 'y#¬Fls & ¬Tru ∨ 'x#¬Fls ∨ ⊤ <: ⊥ +//│ 'y#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff test(tru, tru) //│ = Tru() @@ -75,42 +80,6 @@ test(true, false) //│ ╟── because: cannot constrain Bool <: 'y //│ ╟── because: cannot constrain Bool <: 'y //│ ╙── because: cannot constrain ⊤ <: ⊥ -//│ ╔══[ERROR] Type error in boolean literal with expected type 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╙── because: cannot constrain ⊤ <: ⊥ -//│ ╔══[ERROR] Type error in boolean literal with expected type 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╙── because: cannot constrain ⊤ <: ⊥ -//│ ╔══[ERROR] Type error in boolean literal with expected type 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain ¬Tru & 'y <: 'y1 -//│ ╟── because: cannot constrain ¬{Tru} ∧ 'y <: 'y1 -//│ ╙── because: cannot constrain ⊤ <: ⊥ -//│ ╔══[ERROR] Type error in boolean literal with expected type 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain ¬Tru & 'y <: 'y1 -//│ ╟── because: cannot constrain ¬{Tru} ∧ 'y <: 'y1 -//│ ╙── because: cannot constrain ⊤ <: ⊥ -//│ ╔══[ERROR] Type error in boolean literal with expected type 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╙── because: cannot constrain ⊤ <: ⊥ -//│ ╔══[ERROR] Type error in boolean literal with expected type 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╙── because: cannot constrain ⊤ <: ⊥ -//│ ╔══[ERROR] Type error in boolean literal with expected type 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╙── because: cannot constrain ⊤ <: ⊥ -//│ ╔══[ERROR] Type error in boolean literal with expected type 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╟── because: cannot constrain Bool <: 'y -//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: ⊥ From fd21398ac78ff02fb8dcbeb9dce96027786a99b6 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Thu, 17 Apr 2025 07:09:57 +0800 Subject: [PATCH 27/36] fix if --- .../src/main/scala/hkmc2/bbml/bbML.scala | 17 +++--- .../src/test/mlscript/bbml/bbBasics.mls | 2 +- .../shared/src/test/mlscript/logicsub/If.mls | 58 +++++++++++++------ .../test/mlscript/logicsub/MarlowWadler97.mls | 10 +++- 4 files changed, 55 insertions(+), 32 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index 78bf2d6f1a..c234201d36 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -324,7 +324,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case _ => error(msg"Function definition shape not yet supported for ${sym.nme}" -> lam.toLoc :: Nil) private def typeSplitImpl(split: Split, sign: GeneralType, eff: Type, br: Bool, cons: Bool, path: Ls[Ls[Ref -> Type]]) - (using ctx: BbCtx, c: ConstraintHandler, sv: HashMap[Ref, Type])(using CCtx, Scope) + (using ctx: BbCtx, c: ConstraintHandler, sv: LinkedHashMap[Ref, Type])(using CCtx, Scope) : Ls[Ls[Ref -> Type]] = split match case Split.Cons(Branch(s: Ref, cp: Pattern.ClassLike, cons), alts) => val cls = ClassLikeType(cp.sym, Nil) @@ -341,6 +341,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): else val ctx1 = ctx.nest ctx1 += s.sym -> (cls & sty) + sv -= s val p0 = Ls(s -> cls) :: (Type.disjoint(cls, sty) match case N => typeSplitImpl(cons, sign, eff, true, true, path)(using ctx1) case S(k) => @@ -356,6 +357,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): val p = path.flatMap(x => p0.map: y => val m = (x ++ y).groupMapReduce(_._1)(_._2)(_ | _) (x.keys ++ y.keys).distinct.map(k => k -> m(k)).toList) + sv += s -> sty val p1 = typeSplitImpl(alts, sign, eff, br, false, p) if br then p1.flatMap(y => p0.map: x => @@ -394,8 +396,8 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): nc.constrain(termEff, eff) path.foreach: p => val m = p.toMap - val d = p.flatMap { case (s, t) => Type.disjoint(t.!, sv(s)) } - val sc = p.iterator.map { case (s, t) => (t.! & sv(s), sv0(s)) } + val d = p.flatMap { case (s, t) => sv.get(s).flatMap(st => Type.disjoint(t.!, st)) } + val sc = sv.map { case (s, t) => (m.getOrElse(s, Bot).! & t, sv0(s)) } if d.isEmpty then dss.foreach(c.commit(_)) (sc ++ cs).foreach(u => constrain(u._1, u._2)) @@ -406,9 +408,6 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) c.commit(DisjSub(ks, Nil, c0.toList)) typeSplitImpl(tail, sign, eff, br, cons, path) - case Split.Else(e) if cons => - constrain(ascribe(e, sign)._2, eff) - Nil case Split.Else(e) => val (nc, dss, cs) = constraintCollector val ctx1 = ctx.nest @@ -420,8 +419,8 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): nc.constrain(ascribe(e, sign)(using ctx1, c = nc)._2, eff) path.foreach: p => val m = p.toMap - val d = p.flatMap { case (s, t) => Type.disjoint(t.!, sv(s)) } - val sc = p.map { case (s, t) => (t.! & sv(s), sv0(s)) } + val d = p.flatMap { case (s, t) => sv.get(s).flatMap(st => Type.disjoint(t.!, st)) } + val sc = sv.map { case (s, t) => (m.getOrElse(s, Bot).! & t, sv0(s)) } if d.isEmpty then dss.foreach(c.commit(_)) (sc ++ cs).foreach(u => constrain(u._1, u._2)) @@ -451,7 +450,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): : (GeneralType, Type) = val res = sign.orElse(S(freshVar(new TempSymbol(N, "res")))).get val eff = freshVar(new TempSymbol(N, "eff")) - typeSplitImpl(split, res, eff, false, true, Ls(Nil))(using sv = HashMap.empty) + typeSplitImpl(split, res, eff, false, true, Ls(Nil))(using sv = LinkedHashMap.empty) (res, eff) // * Note: currently, the returned type is not used or useful, but it could be in the future diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index 14871c9d06..5143d35c9f 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -286,7 +286,7 @@ fun test(x) = test //│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff //│ 'x#¬Int ∨ ¬Int & 'x <: 'x1 ∧ Int <: 'res ∧ ⊥ <: 'eff test(1) diff --git a/hkmc2/shared/src/test/mlscript/logicsub/If.mls b/hkmc2/shared/src/test/mlscript/logicsub/If.mls index 0ce69b3a0e..267f879027 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/If.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/If.mls @@ -44,25 +44,23 @@ f(si) // order-dependent (expected) -// TODO: order-independent currently, bring order-dependence back - fun f(x, y) = if x is Int then 1 y is Str then "" f(1, "") -//│ Type: Str | Int +//│ Type: Int f(1, sib) -//│ Type: Str | Int +//│ Type: Int fun f(x, y) = if y is Str then "" x is Int then 1 f(1, "") -//│ Type: Str | Int +//│ Type: Str f(1, sib) -//│ Type: Str | Int +//│ Type: Int | Str fun foorec(x, y, r) = if @@ -85,7 +83,7 @@ foo as (Str, Bool) -> Bool :e foo(1, "") //│ ╔══[ERROR] Type error in string literal with expected type 'y -//│ ║ l.86: foo(1, "") +//│ ║ l.84: foo(1, "") //│ ║ ^^ //│ ╟── because: cannot constrain Str <: 'y //│ ╟── because: cannot constrain Str <: 'y @@ -96,9 +94,11 @@ foo(1, "") //│ ╟── because: cannot constrain 'x <: 'y2 //│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) //│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain ¬⊥ & 'x2 <: ¬(¬{Bool}) -//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Bool}) -//│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain ¬{Str} ∧ 'x2 <: ¬(¬{Bool}) +//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Str | Bool}) +//│ ╟── because: cannot constrain ¬⊥ & 'x3 <: ¬(¬{Str | Bool}) +//│ ╟── because: cannot constrain 'x3 <: ¬(¬{Str | Bool}) +//│ ╙── because: cannot constrain Int <: ¬(¬{Str | Bool}) //│ Type: Bool fun increv(x) = if x is @@ -108,7 +108,7 @@ fun increv(x) = if x is increv //│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff //│ 'x#¬Int ∨ ¬Int & 'x <: 'x1 ∧ 'x1 <: Str ∧ Str <: 'res ∧ ⊥ <: 'eff fun increv'(x) = if x is @@ -117,7 +117,7 @@ fun increv'(x) = if x is increv' //│ Type: ['x, 'res, 'eff] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff //│ 'x#Str ∨ Str & 'x <: Str ∧ Str <: 'res ∧ ⊥ <: 'eff //│ 'x#¬Str & ¬Int ∨ ⊤ <: ⊥ @@ -168,7 +168,7 @@ fun f(x) = if f //│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff //│ 'x#Str ∨ Str & 'x <: Str ∧ Str <: 'res ∧ ⊥ <: 'eff //│ 'x#¬Str & ¬Int ∨ (¬Int & ¬Str) & 'x <: 'x1 ∧ 'x1 <: Bool ∧ Bool <: 'res ∧ ⊥ <: 'eff @@ -182,12 +182,12 @@ fun f(x, y) = if else not(x) f -//│ Type: ['x, 'y, 'res, 'eff, 'y1, 'x1] -> ('x, 'y) ->{'eff} 'res +//│ Type: ['x, 'y, 'res, 'eff, 'x1, 'y1, 'y2, 'x2] -> ('x, 'y) ->{'eff} 'res //│ Where: //│ 'x#Int ∨ 'y <: 'res ∧ ⊥ <: 'eff -//│ 'x#Str ∨ 'y <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff -//│ 'x#¬Str & ¬Int ∨ 'y#¬Str ∨ (¬Int & ¬Str) & 'x <: 'x1 ∧ ¬Str & 'y <: 'y1 ∧ 'x1 <: Bool ∧ Bool <: 'res ∧ ⊥ <: 'eff -//│ 'y#Str ∨ Int <: 'res ∧ ⊥ <: 'eff +//│ 'y#Str ∨ 'x#¬Int ∨ ¬Int & 'x <: 'x1 ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#Str ∨ 'y#¬Str ∨ ¬Str & 'y <: 'y1 ∧ 'y1 <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#¬Str & ¬Int ∨ 'y#¬Str ∨ ¬Str & 'y <: 'y2 ∧ (¬Int & ¬Str) & 'x <: 'x2 ∧ 'x2 <: Bool ∧ Bool <: 'res ∧ ⊥ <: 'eff f(ib, sib) //│ Type: (((Bool | Int) | Bool) | Int) | Str @@ -198,11 +198,31 @@ f(ib, ib) //│ Where: //│ Bool <: 'y //│ Int <: 'y -//│ 'y#Str ∨ Int <: 'res ∧ ⊥ <: 'eff +//│ 'y#Str ∨ ¬Int & 'x <: 'x1 ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ Bool <: 'x +//│ Int <: 'x +//│ 'x <: ¬(¬{(Str | Int) | Bool}) +//│ 'x#Str ∨ ¬Str & 'y <: 'y1 ∧ 'y1 <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff //│ 'eff <: ¬() //│ Bool <: 'res //│ 'y <: 'res :todo f(ib, ib) -//│ Type: ⊤ +//│ Type: Bool | 'res +//│ Where: +//│ Bool <: 'res +//│ 'res <: 'res + +fun f(x, y) = if + x is Int then 1 + y is Int then not(x) +f +//│ Type: ['x, 'y, 'res, 'eff, 'x1] -> ('x, 'y) ->{'eff} 'res +//│ Where: +//│ 'x#Int ∨ Int <: 'res ∧ ⊥ <: 'eff +//│ 'y#Int ∨ 'x#¬Int ∨ ¬Int & 'x <: 'x1 ∧ 'x1 <: Bool ∧ Bool <: 'res ∧ ⊥ <: 'eff +//│ 'x#¬Int ∨ 'y#¬Int ∨ ⊤ <: ⊥ + +f(ib, 1) +//│ Type: Bool | Int diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index af150cdd84..f165935528 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -38,14 +38,18 @@ test //│ > x is Fls then fls#666 //│ > y is Fls then fls#666 //│ = [function test] -//│ Type: ['x, 'y, 'res, 'eff] -> ('x, 'y) ->{'eff} 'res +//│ Type: ['x, 'y, 'res, 'eff, 'y1, 'x1] -> ('x, 'y) ->{'eff} 'res //│ Where: //│ 'x#Tru ∨ 'y#Tru ∨ Tru <: 'res ∧ ⊥ <: 'eff -//│ 'x#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff +//│ 'x#Tru ∨ 'y#Tru ∨ Tru <: 'res ∧ ⊥ <: 'eff ∧ Tru <: 'res ∧ ⊥ <: 'eff +//│ 'x#Tru ∨ 'y#Tru ∨ Tru <: 'res ∧ ⊥ <: 'eff ∧ Tru <: 'res ∧ ⊥ <: 'eff ∧ Tru <: 'res ∧ ⊥ <: 'eff ∧ Tru <: 'res ∧ ⊥ <: 'eff +//│ 'x#Fls ∨ 'y#¬Tru ∨ ¬Tru & 'y <: 'y1 ∧ Fls <: 'res ∧ ⊥ <: 'eff +//│ 'x#Fls ∨ 'y <: 'y1 ∧ Fls <: 'res ∧ ⊥ <: 'eff +//│ 'y#Fls ∨ 'x#¬Fls & ¬Tru ∨ (¬Tru & ¬Fls) & 'x <: 'x1 ∧ Fls <: 'res ∧ ⊥ <: 'eff +//│ 'y#Fls ∨ 'x#¬Fls ∨ ¬Fls & 'x <: 'x1 ∧ Fls <: 'res ∧ ⊥ <: 'eff //│ 'x#¬Fls & ¬Tru ∨ 'y#¬Fls ∨ ⊤ <: ⊥ //│ 'x#¬Fls & ¬Tru ∨ 'y#¬Fls & ¬Tru ∨ ⊤ <: ⊥ //│ 'y#¬Fls & ¬Tru ∨ 'x#¬Fls ∨ ⊤ <: ⊥ -//│ 'y#Fls ∨ Fls <: 'res ∧ ⊥ <: 'eff test(tru, tru) //│ = Tru() From 4dc8cd7f91d05ecc1b588ea5561455efecd47b13 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Fri, 18 Apr 2025 21:10:23 +0800 Subject: [PATCH 28/36] fix missing constraints --- .../scala/hkmc2/bbml/ConstraintSolver.scala | 2 +- .../src/main/scala/hkmc2/bbml/bbML.scala | 34 +++-- .../src/main/scala/hkmc2/bbml/types.scala | 9 +- .../shared/src/test/mlscript/logicsub/If.mls | 10 +- .../src/test/mlscript/logicsub/List.mls | 124 ++++++++++++++++++ 5 files changed, 151 insertions(+), 28 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/logicsub/List.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index 8e6f44f6bd..ab1c13c35a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -102,7 +102,7 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, cctx.nest(bd -> v) givenIn: v.state.lowerBounds ::= bd v.state.upperBounds.foreach(ub => constrainImpl(bd, ub)) - val (dss, cs) = v.state.disjsub.toList.map(_.check(Map(v -> bd), false)).unzip + val (dss, cs) = v.state.disjsub.toList.map(_.check(Map(v -> bd))).unzip dss.flatten.foreach(_.commit()) cs.flatten.foreach(u => constrainImpl(u._1, u._2)) case Conj(i, u, Nil) => (conj.i, conj.u) match diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index c234201d36..010a0dbae1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -323,11 +323,11 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): pctx += sym -> PolyType.generalize(funTy, S(outer), 1) case _ => error(msg"Function definition shape not yet supported for ${sym.nme}" -> lam.toLoc :: Nil) - private def typeSplitImpl(split: Split, sign: GeneralType, eff: Type, br: Bool, cons: Bool, path: Ls[Ls[Ref -> Type]]) + private def typeSplitImpl(split: Split, sign: GeneralType, eff: Type, br: Bool, path: Ls[Ls[Ref -> Type]]) (using ctx: BbCtx, c: ConstraintHandler, sv: LinkedHashMap[Ref, Type])(using CCtx, Scope) : Ls[Ls[Ref -> Type]] = split match case Split.Cons(Branch(s: Ref, cp: Pattern.ClassLike, cons), alts) => - val cls = ClassLikeType(cp.sym, Nil) + val cls = ClassLikeType(cp.sym, cp.sym.asCls.flatMap(_.defn).get.tparams.map(_ => Wildcard.empty)) val (r, sty) = sv.get(s) match case N => val t = tryMkMono(typeCheck(s)._1, s) @@ -337,18 +337,18 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): (path.forall: p => p.find(_._1 === s).fold(false): u => Type.disjoint(u._2.!, cls).exists(_.isEmpty)) -> t - if r then typeSplitImpl(alts, sign, eff, br, false, path) + if r then typeSplitImpl(alts, sign, eff, br, path) else val ctx1 = ctx.nest ctx1 += s.sym -> (cls & sty) sv -= s val p0 = Ls(s -> cls) :: (Type.disjoint(cls, sty) match - case N => typeSplitImpl(cons, sign, eff, true, true, path)(using ctx1) + case N => typeSplitImpl(cons, sign, eff, true, path)(using ctx1) case S(k) => if k.isEmpty then Nil else val (nc, dss, cs) = constraintCollector - val p = typeSplitImpl(cons, sign, eff, true, true, path)(using ctx1, nc) + val p = typeSplitImpl(cons, sign, eff, true, path)(using ctx1, nc) k.foreach: k => val ks = LinkedHashSet.from(k) dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) @@ -358,7 +358,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): val m = (x ++ y).groupMapReduce(_._1)(_._2)(_ | _) (x.keys ++ y.keys).distinct.map(k => k -> m(k)).toList) sv += s -> sty - val p1 = typeSplitImpl(alts, sign, eff, br, false, p) + val p1 = typeSplitImpl(alts, sign, eff, br, p) if br then p1.flatMap(y => p0.map: x => val m = (x ++ y).groupMapReduce(_._1)(_._2)(_ | _) @@ -371,11 +371,11 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case _: Tree.DecLit => BbCtx.numTy case _: Tree.StrLit => BbCtx.strTy case _: Tree.UnitLit => Top) - val p0 = typeSplitImpl(cons, sign, eff, true, true, path) + val p0 = typeSplitImpl(cons, sign, eff, true, path) val p = path.flatMap(x => p0.map: y => val m = (x ++ y).groupMapReduce(_._1)(_._2)(_ | _) (x.keys ++ y.keys).distinct.map(k => k -> m(k)).toList) - val p1 = typeSplitImpl(alts, sign, eff, br, false, p) + val p1 = typeSplitImpl(alts, sign, eff, br, p) if br then p1.flatMap(y => p0.map: x => val m = (x ++ y).groupMapReduce(_._1)(_._2)(_ | _) @@ -397,17 +397,16 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): path.foreach: p => val m = p.toMap val d = p.flatMap { case (s, t) => sv.get(s).flatMap(st => Type.disjoint(t.!, st)) } - val sc = sv.map { case (s, t) => (m.getOrElse(s, Bot).! & t, sv0(s)) } + val sc = sv.toList.map { case (s, t) => (m.getOrElse(s, Bot).! & t, sv0(s)) } if d.isEmpty then dss.foreach(c.commit(_)) - (sc ++ cs).foreach(u => constrain(u._1, u._2)) + (sc ++ cs).distinct.foreach(u => constrain(u._1, u._2)) else val ds = d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - val c0 = sc ++ cs val ks = LinkedHashSet.from(k) dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) - c.commit(DisjSub(ks, Nil, c0.toList)) - typeSplitImpl(tail, sign, eff, br, cons, path) + c.commit(DisjSub(ks, Nil, (sc ++ cs).distinct)) + typeSplitImpl(tail, sign, eff, br, path) case Split.Else(e) => val (nc, dss, cs) = constraintCollector val ctx1 = ctx.nest @@ -420,16 +419,15 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): path.foreach: p => val m = p.toMap val d = p.flatMap { case (s, t) => sv.get(s).flatMap(st => Type.disjoint(t.!, st)) } - val sc = sv.map { case (s, t) => (m.getOrElse(s, Bot).! & t, sv0(s)) } + val sc = sv.toList.map { case (s, t) => (m.getOrElse(s, Bot).! & t, sv0(s)) } if d.isEmpty then dss.foreach(c.commit(_)) - (sc ++ cs).foreach(u => constrain(u._1, u._2)) + (sc ++ cs).distinct.foreach(u => constrain(u._1, u._2)) else val ds = d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - val c0 = sc ++ cs val ks = LinkedHashSet.from(k) dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) - c.commit(DisjSub(ks, Nil, c0.toList)) + c.commit(DisjSub(ks, Nil, (sc ++ cs).distinct)) Nil case Split.End => if !br then @@ -450,7 +448,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): : (GeneralType, Type) = val res = sign.orElse(S(freshVar(new TempSymbol(N, "res")))).get val eff = freshVar(new TempSymbol(N, "eff")) - typeSplitImpl(split, res, eff, false, true, Ls(Nil))(using sv = LinkedHashMap.empty) + typeSplitImpl(split, res, eff, false, Ls(Nil))(using sv = LinkedHashMap.empty) (res, eff) // * Note: currently, the returned type is not used or useful, but it could be in the future diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 12ab0c4a2c..444b194abc 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -339,7 +339,8 @@ object Type: disjointDisj(lb.toDnf).map(_ + Set(v -> v)) case (i, c, vs) => val j = i match - case S(u: (ClassLikeType | RcdType)) => S(u) + case S(ClassLikeType(c, _)) => S(ClassLikeType(c, Nil)) + case S(u: RcdType) => S(u) case _ => N val vd = vs.combinations(2).collect { case x :: y :: _ => Ls(x -> y, y -> x) }.flatten.toList val ds = vs.flatMap(v => (j ++ c.reduceOption[Type](_ | _).map(_.!)).map(x => v -> x.toBasic)).toSet ++ vd @@ -476,15 +477,15 @@ class VarState: case class DisjSub(disjoint: LinkedHashSet[InfVar -> BasicType], dss: Ls[DisjSub], cs: Ls[Type -> Type]): def commit() = disjoint.keys.foreach(_.state.disjsub += this) - def check(m: Map[InfVar, Type], subst: Bool)(using TL): (Ls[DisjSub], Ls[Type -> Type]) = + def check(m: Map[InfVar, Type])(using TL): (Ls[DisjSub], Ls[Type -> Type]) = if disjoint.isEmpty then (Nil, Nil) else disjoint.keys.foreach(_.state.disjsub -= this) val d = disjoint.toList.flatMap: u => m.get(u._1).fold(S(Set(Set(u._1 -> u._2)))): t => - Type.disjoint(u._2, if subst then t else t | u._1).orElse { disjoint -= u; N } + Type.disjoint(u._2, t | u._1).orElse { disjoint -= u; N } if disjoint.isEmpty then - val (dss0, cs0) = dss.map(_.check(m, subst)).unzip + val (dss0, cs0) = dss.map(_.check(m)).unzip (dss0.flatten, cs0.flatten ++ cs) else val dss1 = d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).map: k => diff --git a/hkmc2/shared/src/test/mlscript/logicsub/If.mls b/hkmc2/shared/src/test/mlscript/logicsub/If.mls index 267f879027..2bbbbd7da5 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/If.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/If.mls @@ -108,7 +108,7 @@ fun increv(x) = if x is increv //│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff //│ 'x#¬Int ∨ ¬Int & 'x <: 'x1 ∧ 'x1 <: Str ∧ Str <: 'res ∧ ⊥ <: 'eff fun increv'(x) = if x is @@ -117,7 +117,7 @@ fun increv'(x) = if x is increv' //│ Type: ['x, 'res, 'eff] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff //│ 'x#Str ∨ Str & 'x <: Str ∧ Str <: 'res ∧ ⊥ <: 'eff //│ 'x#¬Str & ¬Int ∨ ⊤ <: ⊥ @@ -168,7 +168,7 @@ fun f(x) = if f //│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff //│ 'x#Str ∨ Str & 'x <: Str ∧ Str <: 'res ∧ ⊥ <: 'eff //│ 'x#¬Str & ¬Int ∨ (¬Int & ¬Str) & 'x <: 'x1 ∧ 'x1 <: Bool ∧ Bool <: 'res ∧ ⊥ <: 'eff @@ -186,7 +186,7 @@ f //│ Where: //│ 'x#Int ∨ 'y <: 'res ∧ ⊥ <: 'eff //│ 'y#Str ∨ 'x#¬Int ∨ ¬Int & 'x <: 'x1 ∧ Int <: 'res ∧ ⊥ <: 'eff -//│ 'x#Str ∨ 'y#¬Str ∨ ¬Str & 'y <: 'y1 ∧ 'y1 <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#Str ∨ 'y#¬Str ∨ ¬Str & 'y <: 'y1 ∧ 'y1 <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff //│ 'x#¬Str & ¬Int ∨ 'y#¬Str ∨ ¬Str & 'y <: 'y2 ∧ (¬Int & ¬Str) & 'x <: 'x2 ∧ 'x2 <: Bool ∧ Bool <: 'res ∧ ⊥ <: 'eff f(ib, sib) @@ -202,7 +202,7 @@ f(ib, ib) //│ Bool <: 'x //│ Int <: 'x //│ 'x <: ¬(¬{(Str | Int) | Bool}) -//│ 'x#Str ∨ ¬Str & 'y <: 'y1 ∧ 'y1 <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#Str ∨ ¬Str & 'y <: 'y1 ∧ 'y1 <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff //│ 'eff <: ¬() //│ Bool <: 'res //│ 'y <: 'res diff --git a/hkmc2/shared/src/test/mlscript/logicsub/List.mls b/hkmc2/shared/src/test/mlscript/logicsub/List.mls new file mode 100644 index 0000000000..0b9c643943 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/logicsub/List.mls @@ -0,0 +1,124 @@ +:bbml +//│ Type: ⊤ + +//│ Type: ⊤ +class + Nil() + Cons[A, Tl](val hd: A, val tl: Tl) +//│ Type: ⊤ + +let nil = new Nil() +//│ Type: ⊤ + +let cons(hd, tl) = new Cons(hd, tl) +//│ Type: ⊤ + +cons(0, 0) +//│ Type: Cons['A, 'Tl] +//│ Where: +//│ Int <: 'A +//│ Int <: 'Tl + +cons +//│ Type: (⊤, ⊤) ->{⊥} Cons['A, 'Tl] +//│ Where: +//│ Int <: 'A +//│ Int <: 'Tl + +fun cons(hd, tl) = new Cons(hd, tl) +//│ Type: ⊤ + +fun map(xs, f) = + if xs is + Nil then nil + Cons then new Cons(f(xs.Cons#hd), map(xs.Cons#tl, f)) +//│ Type: ⊤ + +nil map(x => x) +//│ Type: Nil + +let c = cons(1, nil) +c map(x => x) +//│ Type: Nil | Cons['A, 'Tl] +//│ Where: +//│ Int <: 'A +//│ Nil <: 'res +//│ Cons['A, 'Tl] <: 'res +//│ 'res <: 'Tl + +:e +cons(1, 2) map(x => x) +//│ ╔══[ERROR] Type error in function literal with expected type 'f +//│ ║ l.50: cons(1, 2) map(x => x) +//│ ║ ^^^^^^ +//│ ╟── because: cannot constrain 'x -> 'x <: 'f +//│ ╟── because: cannot constrain ('x) ->{⊥} ('x) <: 'f +//│ ╟── because: cannot constrain 'Tl <: 'xs +//│ ╟── because: cannot constrain 'Tl <: ¬(¬'xs) +//│ ╟── because: cannot constrain Int <: ¬(¬'xs) +//│ ╟── because: cannot constrain Int <: 'xs +//│ ╙── because: cannot constrain ⊤ <: ⊥ +//│ Type: Cons['A, 'Tl1] +//│ Where: +//│ Int <: 'A +//│ Cons['A, 'Tl1] <: 'res +//│ 'res <: 'Tl1 + +cons(1, cons("", nil)) map(x => cons(x, true)) +//│ Type: Nil | Cons['A, 'Tl] +//│ Where: +//│ Str | Int <: 'A1 +//│ Bool <: 'Tl1 +//│ Cons['A1, 'Tl1] <: 'A +//│ Nil <: 'res +//│ Cons['A, 'Tl] <: 'res +//│ 'res <: 'Tl + + +fun maprec(xs, f, r) = + if xs is + Nil then nil + Cons then new Cons(f(xs.Cons#hd), r(xs.Cons#tl, f, r)) +fun map(xs, f) = maprec(xs, f, maprec) +//│ Type: ⊤ + + +nil map(x => x) +//│ Type: Nil + +let c = cons(1, nil) +c map(x => x) +//│ Type: Cons['A, 'Tl] +//│ Where: +//│ Int <: 'A +//│ Nil <: 'Tl + +:e +cons(1, 2) map(x => x) +//│ ╔══[ERROR] Type error in function literal with expected type 'f +//│ ║ l.97: cons(1, 2) map(x => x) +//│ ║ ^^^^^^ +//│ ╟── because: cannot constrain 'x -> 'x <: 'f +//│ ╟── because: cannot constrain ('x) ->{⊥} ('x) <: 'f +//│ ╟── because: cannot constrain 'Tl <: 'xs +//│ ╟── because: cannot constrain 'Tl <: 'xs +//│ ╙── because: cannot constrain ⊤ <: ⊥ +//│ Type: Cons['A, 'Tl1] +//│ Where: +//│ Int <: 'A + +let c = cons(nil, nil) +c map(x => x map(x => (a: x))) +//│ Type: Cons['A, 'Tl] +//│ Where: +//│ Nil <: 'A +//│ Nil <: 'Tl + +let c = cons(cons(nil, nil), nil) +c map(x => x map(x => (a: x))) +//│ Type: Cons['A, 'Tl] +//│ Where: +//│ {a: Nil} <: 'A1 +//│ Nil <: 'Tl1 +//│ Cons['A1, 'Tl1] <: 'A +//│ Nil <: 'Tl From 0ed746e5a5952924e31b7a6cfc66f5e456db6581 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Fri, 18 Apr 2025 21:12:21 +0800 Subject: [PATCH 29/36] test --- hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls | 2 +- hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index 5143d35c9f..14871c9d06 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -286,7 +286,7 @@ fun test(x) = test //│ Type: ['x, 'res, 'eff, 'x1] -> 'x ->{'eff} 'res //│ Where: -//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff +//│ 'x#Int ∨ Int & 'x <: Int ∧ Int <: Int ∧ Int <: 'res ∧ ⊥ <: 'eff //│ 'x#¬Int ∨ ¬Int & 'x <: 'x1 ∧ Int <: 'res ∧ ⊥ <: 'eff test(1) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls index 21e14d4dfd..59b28f83bb 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls @@ -74,7 +74,7 @@ g f(g) //│ Type: ('A) ->{⊥} Int //│ Where: -//│ 'A#C[in ⊥ out B] ∨ ( 'A#C[in ⊥ out () & (B)] ∨ 'D <: B ∧ ⊥ <: ⊥ ∧ C[out B] & 'A <: C[in Int out 'D]){0: C[out B] & 'A} <: {0: C[?]} +//│ 'A#C ∨ ( 'A#C ∨ 'D <: B ∧ ⊥ <: ⊥ ∧ C[out B] & 'A <: C[in Int out 'D]){0: C[out B] & 'A} <: {0: C[?]} fun foo: C[in Int out Nothing] foo From 836f3bbc05f53f2f92213461d19182d2652f4f46 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Sun, 20 Apr 2025 19:15:26 +0800 Subject: [PATCH 30/36] elim branches --- .../src/main/scala/hkmc2/bbml/bbML.scala | 41 ++++++++++--------- .../test/mlscript/logicsub/MarlowWadler97.mls | 3 -- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index 010a0dbae1..437c6c452f 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -332,38 +332,39 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case N => val t = tryMkMono(typeCheck(s)._1, s) sv += s -> t - (false, t) + (path, t) case S(t) => - (path.forall: p => + (path.filterNot: p => p.find(_._1 === s).fold(false): u => Type.disjoint(u._2.!, cls).exists(_.isEmpty)) -> t - if r then typeSplitImpl(alts, sign, eff, br, path) + if r.isEmpty then typeSplitImpl(alts, sign, eff, br, path) else val ctx1 = ctx.nest ctx1 += s.sym -> (cls & sty) sv -= s - val p0 = Ls(s -> cls) :: (Type.disjoint(cls, sty) match - case N => typeSplitImpl(cons, sign, eff, true, path)(using ctx1) - case S(k) => - if k.isEmpty then Nil - else - val (nc, dss, cs) = constraintCollector - val p = typeSplitImpl(cons, sign, eff, true, path)(using ctx1, nc) - k.foreach: k => + val (nc, dss, cs) = constraintCollector + val p0 = Ls(s -> cls) :: typeSplitImpl(cons, sign, eff, true, r)(using ctx1, nc) + sv += s -> sty + if p0.contains(Nil) then typeSplitImpl(alts, sign, eff, br, path) + else + Type.disjoint(cls, sty) match + case N => + dss.foreach(c.commit) + cs.foreach(u => constrain(u._1, u._2)) + case S(k) => + if k.nonEmpty then k.foreach: k => val ks = LinkedHashSet.from(k) dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) if cs.nonEmpty then c.commit(DisjSub(ks, Nil, cs.toList)) - p) - val p = path.flatMap(x => p0.map: y => - val m = (x ++ y).groupMapReduce(_._1)(_._2)(_ | _) - (x.keys ++ y.keys).distinct.map(k => k -> m(k)).toList) - sv += s -> sty - val p1 = typeSplitImpl(alts, sign, eff, br, p) - if br then - p1.flatMap(y => p0.map: x => + val p = path.flatMap(x => p0.map: y => val m = (x ++ y).groupMapReduce(_._1)(_._2)(_ | _) (x.keys ++ y.keys).distinct.map(k => k -> m(k)).toList) - else Nil + val p1 = typeSplitImpl(alts, sign, eff, br, p) + if br then + p1.flatMap(y => p0.map: x => + val m = (x ++ y).groupMapReduce(_._1)(_._2)(_ | _) + (x.keys ++ y.keys).distinct.map(k => k -> m(k)).toList) + else Nil case Split.Cons(Branch(s: Ref, Pattern.Lit(lit), cons), alts) => constrain(tryMkMono(typeCheck(s)._1, s), lit match case _: Tree.BoolLit => BbCtx.boolTy diff --git a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls index f165935528..febceb3a75 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/MarlowWadler97.mls @@ -41,14 +41,11 @@ test //│ Type: ['x, 'y, 'res, 'eff, 'y1, 'x1] -> ('x, 'y) ->{'eff} 'res //│ Where: //│ 'x#Tru ∨ 'y#Tru ∨ Tru <: 'res ∧ ⊥ <: 'eff -//│ 'x#Tru ∨ 'y#Tru ∨ Tru <: 'res ∧ ⊥ <: 'eff ∧ Tru <: 'res ∧ ⊥ <: 'eff -//│ 'x#Tru ∨ 'y#Tru ∨ Tru <: 'res ∧ ⊥ <: 'eff ∧ Tru <: 'res ∧ ⊥ <: 'eff ∧ Tru <: 'res ∧ ⊥ <: 'eff ∧ Tru <: 'res ∧ ⊥ <: 'eff //│ 'x#Fls ∨ 'y#¬Tru ∨ ¬Tru & 'y <: 'y1 ∧ Fls <: 'res ∧ ⊥ <: 'eff //│ 'x#Fls ∨ 'y <: 'y1 ∧ Fls <: 'res ∧ ⊥ <: 'eff //│ 'y#Fls ∨ 'x#¬Fls & ¬Tru ∨ (¬Tru & ¬Fls) & 'x <: 'x1 ∧ Fls <: 'res ∧ ⊥ <: 'eff //│ 'y#Fls ∨ 'x#¬Fls ∨ ¬Fls & 'x <: 'x1 ∧ Fls <: 'res ∧ ⊥ <: 'eff //│ 'x#¬Fls & ¬Tru ∨ 'y#¬Fls ∨ ⊤ <: ⊥ -//│ 'x#¬Fls & ¬Tru ∨ 'y#¬Fls & ¬Tru ∨ ⊤ <: ⊥ //│ 'y#¬Fls & ¬Tru ∨ 'x#¬Fls ∨ ⊤ <: ⊥ test(tru, tru) From a9c4221f35cce77037106440701c4ad8b99769ca Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:15:20 +0800 Subject: [PATCH 31/36] negtype and wip test --- .../src/main/scala/hkmc2/bbml/types.scala | 5 +- .../src/test/mlscript/logicsub/elixir.mls | 161 ++++++++++ .../src/test/mlscript/logicsub/popl22.mls | 298 ++++++++++++++++++ 3 files changed, 463 insertions(+), 1 deletion(-) create mode 100644 hkmc2/shared/src/test/mlscript/logicsub/elixir.mls create mode 100644 hkmc2/shared/src/test/mlscript/logicsub/popl22.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 444b194abc..24e1b0d643 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -314,11 +314,14 @@ object Type: case c@ClassLikeType(_, Nil) => (c, Top) case ClassLikeType(c, t) => (ClassLikeType(c, t.map(_ => Wildcard.empty)), a) case a@RcdType(_ :: _) => discriminantRcd(a) - case a@ComposedType(l, r, true) => ((discriminant(l.toBasic)._1 | discriminant(r.toBasic)._1).toBasic, a) + case a@ComposedType(l, r, true) => + val q = (discriminant(l.toBasic)._1 | discriminant(r.toBasic)._1).toBasic + (q, (a | q.!).toBasic) case ComposedType(l, r, false) => val (u, w) = discriminant(l.toBasic) val (q, p) = discriminant(r.toBasic) ((u & q).toBasic, (w & p).toBasic) + case NegType(t) => (a, Top) case a => (Top, a) def disjointIU(i: Inter, u: Union)(using TL): Opt[Set[Set[InfVar -> BasicType]]] = (i.v, u.cls) match case (S(c: ClassLikeType), cs) if cs.exists(_.name.uid === c.name.uid) => S(Set.empty) diff --git a/hkmc2/shared/src/test/mlscript/logicsub/elixir.mls b/hkmc2/shared/src/test/mlscript/logicsub/elixir.mls new file mode 100644 index 0000000000..766704149d --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/logicsub/elixir.mls @@ -0,0 +1,161 @@ +:bbml +//│ Type: ⊤ + +//│ Type: ⊤ +// The Design Principles of the Elixir Type System +// https://www.irif.fr/~gc/papers/elixir-type-design.pdf + +class + Nil() + Cons[A, B](val car: A, val cdr: B) + Tru() + Fls() +//│ Type: ⊤ + +let tru = new Tru +let fls = new Fls +fun not: Tru | Fls -> Tru | Fls +fun not(x) = if x is + Tru then fls + Fls then tru +fun car(x) = x.Cons#car +fun cdr(x) = x.Cons#cdr +//│ Type: ⊤ + + + +fun negate: Int -> Int +fun negate(x) = if x is + Int then 0 - x +//│ Type: ⊤ + +fun subtract: (Int, Int) -> Int +fun subtract(a, b) = if + a is Int and b is Int then a + negate(b) +//│ Type: ⊤ + +fun negate: Int | Tru | Fls -> Int | Tru | Fls +fun negate(x) = if x is + Int then 0 - x + Tru then not(x) + Fls then not(x) +//│ Type: ⊤ + +:e +fun subtract: (Int, Int) -> Int +fun subtract(a, b) = if + a is Int and b is Int then a + negate(b) +//│ ╔══[ERROR] Type error in `if` expression with expected type Int +//│ ║ l.47: a is Int and b is Int then a + negate(b) +//│ ║ ^^^ +//│ ╙── because: cannot constrain (Int | Tru) | Fls <: Int +//│ ╔══[ERROR] Type error in `if` expression with expected type Int +//│ ║ l.47: a is Int and b is Int then a + negate(b) +//│ ║ ^^^ +//│ ╙── because: cannot constrain (Int | Tru) | Fls <: Int +//│ Type: ⊤ + +// TODO impl +fun negate: (Int -> Int) & (Tru | Fls -> Tru | Fls) +//│ Type: ⊤ + +fun subtract: (Int, Int) -> Int +fun subtract(a, b) = if + a is Int and b is Int then a + negate(b) +//│ Type: ⊤ + +// fun negate: (Fls | Nil -> Tru) & (~(Fls | Nil) -> Fls) + + + +// type t = [a: Int | Str, b: Tru | Fls] +// type s = [a: Int, b: Tru | Fls] | [a: Str, b: Tru | Fls] +// s = t +// fun apply: (t -> t, s) -> s +fun apply: (([a: Int | Str, b: Tru | Fls]) -> [a: Int | Str, b: Tru | Fls], [a: Int, b: Tru | Fls] | [a: Str, b: Tru | Fls]) -> + [a: Int, b: Tru | Fls] | [a: Str, b: Tru | Fls] +fun apply(f, x) = f(x) +//│ Type: ⊤ + + + +data class Ls[A](prim: [R] -> (() -> R, (A, Ls[A]) -> R) -> R) +fun nil() = new Ls((n, _) => n()) +fun cons(p, q) = new Ls((n, r) => r(p, q)) +fun from(x) = x.Ls#prim(() => new Nil, (x, y) => new Cons(x, from(y))) +//│ Type: ⊤ + +fun _in(x) = if x is + Nil then nil() + Cons then cons(car(x), cdr(x)) +fun _out(x) = x.Ls#prim(() => new Nil, (x, y) => new Cons(x, y)) +//│ Type: ⊤ + +// fun map: [A, B] -> (Ls[A], A -> B) -> Ls[B] +fun map(xs, f) = + let x = _out(xs) + if x is + Cons then cons(f(car(x)), map(cdr(x), f)) + Nil then nil() +//│ Type: ⊤ + +// fun reduce: [A, B] -> (Ls[A], B, (A, B) -> B) -> B +fun reduce(xs, acc, f) = + let x = _out(xs) + if x is + Cons then reduce(cdr(x), f(car(x), acc), f) + Nil then acc +//│ Type: ⊤ + +let xs = cons(1, cons(4, nil())) +//│ Type: ⊤ + +xs map(negate) +//│ Type: Ls['A] | Ls['A1] +//│ Where: +//│ Int <: 'A1 +//│ 'A1 <: 'A +//│ 'A <: 'A1 + +fun map(xs, f) = if xs is + Cons then cons(f(car(xs)), map(_out(cdr(xs)), f)) + Nil then nil() +//│ Type: ⊤ + +fun reduce: [A, B] -> ((Cons[A, Ls[A]], B, (A, B) -> B) -> B) & ((Nil, B, Any) -> B) +fun reduce(xs, acc, f) = if xs is + Cons then reduce(_out(cdr(xs)), f(car(xs), acc), f) + Nil then acc +//│ Type: ⊤ + +reduce(new Nil, 1, "function") +//│ Type: Int + +let xs = cons(1, cons(4, nil())) +//│ Type: ⊤ + +xs _out() map(negate) +//│ Type: Ls['A] | Ls['A1] +//│ Where: +//│ Int <: 'A1 +//│ 'A1 <: 'A +//│ 'A <: 'A1 + + + +// TODO +// fun negate: (Int -> Int) & (Bool -> Bool) & (~(Int | Bool) -> ~(Int | Bool)) +fun negate(x) = if x is + Int then 0 - x + Tru then not(x) + Fls then not(x) + else + x +//│ Type: ⊤ + +negate as Int -> Int +negate as Bool -> Bool +negate as ~(Int | Bool) -> ~(Int | Bool) +//│ Type: (¬Int & ¬Bool) ->{⊥} ¬Int & ¬Bool + +// type tree(a) = (a and not list()) or [tree(a)] diff --git a/hkmc2/shared/src/test/mlscript/logicsub/popl22.mls b/hkmc2/shared/src/test/mlscript/logicsub/popl22.mls new file mode 100644 index 0000000000..6f91cf52ce --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/logicsub/popl22.mls @@ -0,0 +1,298 @@ +:bbml +//│ Type: ⊤ + +//│ Type: ⊤ +// On Type-Cases, Union Elimination, and Occurrence Typing +// https://www.irif.fr/~gc/papers/popl22.pdf + +fun f(x1, x2) = if + x1(x2) is Int then x2 + 1 + else + x1(x2).Str#concat(x2) +//│ Type: ⊤ + +fun id: (Int -> Int) & (Str -> Str) +//│ Type: ⊤ + +f(id, 1) +//│ Type: Int + +f(id, "") +//│ Type: Str + +:e +f as ((Int -> Int) & (Str -> Str), Int | Str) -> Int | Str +//│ ╔══[ERROR] Type error in reference with expected type ((Int -> Int) & (Str -> Str), Int | Str) ->{⊥} Int | Str +//│ ║ l.24: f as ((Int -> Int) & (Str -> Str), Int | Str) -> Int | Str +//│ ║ ^ +//│ ╟── because: cannot constrain ('x1, 'x2) ->{'eff} 'res <: ((Int -> Int) & (Str -> Str), Int | Str) -> (Int | Str) +//│ ╟── because: cannot constrain Int | Str <: 'x2 +//│ ╟── because: cannot constrain Str <: 'x2 +//│ ╙── because: cannot constrain Str <: ¬(¬{Int}) +//│ ╔══[ERROR] Type error in reference with expected type ((Int -> Int) & (Str -> Str), Int | Str) ->{⊥} Int | Str +//│ ║ l.24: f as ((Int -> Int) & (Str -> Str), Int | Str) -> Int | Str +//│ ║ ^ +//│ ╟── because: cannot constrain ('x1, 'x2) ->{'eff} 'res <: ((Int -> Int) & (Str -> Str), Int | Str) -> (Int | Str) +//│ ╟── because: cannot constrain Int | Str <: 'x2 +//│ ╟── because: cannot constrain Str <: 'x2 +//│ ╟── because: cannot constrain Str <: 'app +//│ ╟── because: cannot constrain Str <: 'app +//│ ╟── because: cannot constrain 'app1 <: Str +//│ ╟── because: cannot constrain 'app1 <: ¬(¬{Str}) +//│ ╙── because: cannot constrain Int <: ¬(¬{Str}) +//│ ╔══[ERROR] Type error in reference with expected type ((Int -> Int) & (Str -> Str), Int | Str) ->{⊥} Int | Str +//│ ║ l.24: f as ((Int -> Int) & (Str -> Str), Int | Str) -> Int | Str +//│ ║ ^ +//│ ╟── because: cannot constrain ('x1, 'x2) ->{'eff} 'res <: ((Int -> Int) & (Str -> Str), Int | Str) -> (Int | Str) +//│ ╟── because: cannot constrain Int | Str <: 'x2 +//│ ╟── because: cannot constrain Str <: 'x2 +//│ ╟── because: cannot constrain Str <: 'app +//│ ╟── because: cannot constrain Str <: 'app +//│ ╟── because: cannot constrain 'x2 <: Str +//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Str}) +//│ ╙── because: cannot constrain Int <: ¬(¬{Str}) +//│ ╔══[ERROR] Type error in reference with expected type ((Int -> Int) & (Str -> Str), Int | Str) ->{⊥} Int | Str +//│ ║ l.24: f as ((Int -> Int) & (Str -> Str), Int | Str) -> Int | Str +//│ ║ ^ +//│ ╟── because: cannot constrain ('x1, 'x2) ->{'eff} 'res <: ((Int -> Int) & (Str -> Str), Int | Str) -> (Int | Str) +//│ ╟── because: cannot constrain Int | Str <: 'x2 +//│ ╟── because: cannot constrain Str <: 'x2 +//│ ╟── because: cannot constrain {0: 'x2} <: {0: Str} +//│ ╟── because: cannot constrain 'x2 <: Str +//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Str}) +//│ ╙── because: cannot constrain Int <: ¬(¬{Str}) +//│ Type: ((Int -> Int) & (Str -> Str), Int | Str) ->{⊥} Int | Str + + +data class Prod[A, B](val fst: A, val snd: B) +//│ Type: ⊤ + +class + Tru() + Fls() + Z() +//│ Type: ⊤ + +let tru = new Tru() +let fls = new Fls() +//│ Type: ⊤ + +fun prod(p, q) = new Prod(p, q) +//│ Type: ⊤ + +fun y: Any -> Tru | Fls +//│ Type: ⊤ + +prod(y(x => x), y(x => x)) as Prod[Tru, Tru] | Prod[Fls, Fls] +//│ Type: Prod[Tru, Tru] | Prod[Fls, Fls] + +:e +{ fst: y(x => x), snd: y(x => x) } as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ] +//│ ╔══[ERROR] Type error in record with expected type {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} +//│ ║ l.90: { fst: y(x => x), snd: y(x => x) } as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain {fst: Tru | Fls, snd: Tru | Fls} <: {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} +//│ ╟── because: cannot constrain {fst: Tru ∨ Fls, snd: Tru ∨ Fls} <: {snd: Fls} +//│ ╙── because: cannot constrain Tru ∨ Fls <: Fls +//│ ╔══[ERROR] Type error in record with expected type {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} +//│ ║ l.90: { fst: y(x => x), snd: y(x => x) } as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain {fst: Tru | Fls, snd: Tru | Fls} <: {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} +//│ ╟── because: cannot constrain {fst: Tru ∨ Fls, snd: Tru ∨ Fls} <: {snd: Tru} +//│ ╙── because: cannot constrain Tru ∨ Fls <: Tru +//│ Type: {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} + + + +fun f(a, n) = if + a is Prod and + a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd + else a.Prod#snd + a(n) is Int then a(n) < 42 + else a(n) +//│ Type: ⊤ + +fun f(a, n) = if + a is Prod and + a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd + else a.Prod#snd + let x = a(n) + x is Int then x < 42 + else x +//│ Type: ⊤ + +fun a: (Int -> (Int | Bool)) | Prod[Int, Int | Bool] +fun n: Int +//│ Type: ⊤ + +f(a, n) +//│ Type: (((((Int & ¬Int) | (Bool & ¬Int)) | Bool) | Int) | Bool) | Bool + + +fun is_int(x) = + if x is Int then tru else fls +//│ Type: ⊤ + +is_int as Int -> Tru +is_int as ~Int -> Fls +//│ Type: (¬Int) ->{⊥} Fls + +fun is_bool(x) = if x is + Tru then tru + Fls then tru + else fls +//│ Type: ⊤ + +is_bool as Tru | Fls -> Tru +is_bool as ~(Tru | Fls) -> Fls +//│ Type: (¬Tru & ¬Fls) ->{⊥} Fls + +fun not_(x) = if x is + Fls then tru + Z then tru + else fls +//│ Type: ⊤ + +not_ as Fls | Z -> Tru +not_ as ~(Fls | Z) -> Fls +//│ Type: (¬Fls & ¬Z) ->{⊥} Fls + +fun to_bool(x) = x not_() not_() +//│ Type: ⊤ + +to_bool as Fls | Z -> Fls +to_bool as ~(Fls | Z) -> Tru +//│ Type: (¬Fls & ¬Z) ->{⊥} Tru + +fun and_(x, y) = if x is + Fls then fls + Z then fls + else to_bool(y) +//│ Type: ⊤ + +and_ as (Fls | Z, Any) -> Fls +and_ as (~(Fls | Z), ~(Fls | Z)) -> Tru +and_ as (~(Fls | Z), Fls | Z) -> Fls +//│ Type: (¬Fls & ¬Z, Fls | Z) ->{⊥} Fls + + +fun or_(x, y) = not_(x) and_(not_(y)) not_() +//│ Type: ⊤ + +or_ as (~(Fls | Z), Any) -> Tru +or_ as (Fls | Z, ~(Fls | Z)) -> Tru +or_ as (Fls | Z, Fls | Z) -> Fls +//│ Type: (Fls | Z, Fls | Z) ->{⊥} Fls + +fun strlen: Str -> Int +fun plus: (Int | Z, Int | Z) -> Int | Z +//│ Type: ⊤ + +fun example14(input, extra) = if + input is_int() and_(extra.fst is_int()) is Tru then input + extra.fst + extra.fst is_int() is Tru then input strlen() + extra.fst + else new Z() +//│ Type: ⊤ + +example14 as (Int | Str, [fst: ~Int, snd: Any]) -> Z +example14 as (~(Int | Str), [fst: ~Int, snd: Any]) -> Z +//│ Type: (¬Int & ¬Str, {fst: ¬Int, snd: ⊤}) ->{⊥} Z + +:e +example14 as (Int | Str, [fst: Int, snd: Any]) -> Int +//│ ╔══[ERROR] Type error in reference with expected type (Int | Str, {fst: Int, snd: ⊤}) ->{⊥} Int +//│ ║ l.202: example14 as (Int | Str, [fst: Int, snd: Any]) -> Int +//│ ║ ^^^^^^^^^ +//│ ╟── because: cannot constrain ('input, 'extra) ->{'eff} 'res <: (Int | Str, {fst: Int, snd: ⊤}) -> Int +//│ ╟── because: cannot constrain {fst: Int, snd: ⊤} <: 'extra +//│ ╟── because: cannot constrain {fst: Int, snd: } <: 'extra +//│ ╟── because: cannot constrain {fst: Int, snd: } <: ¬(¬{{fst: 'sel}}) +//│ ╟── because: cannot constrain Int <: 'sel +//│ ╟── because: cannot constrain Int <: 'sel +//│ ╟── because: cannot constrain Int <: ¬(¬'x) +//│ ╟── because: cannot constrain Int <: 'x +//│ ╟── because: cannot constrain Tru <: 'res1 +//│ ╟── because: cannot constrain Tru <: 'res1 +//│ ╟── because: cannot constrain 'input <: Str +//│ ╟── because: cannot constrain 'input <: ¬(¬{Str}) +//│ ╙── because: cannot constrain Int <: ¬(¬{Str}) +//│ ╔══[ERROR] Type error in reference with expected type (Int | Str, {fst: Int, snd: ⊤}) ->{⊥} Int +//│ ║ l.202: example14 as (Int | Str, [fst: Int, snd: Any]) -> Int +//│ ║ ^^^^^^^^^ +//│ ╟── because: cannot constrain ('input, 'extra) ->{'eff} 'res <: (Int | Str, {fst: Int, snd: ⊤}) -> Int +//│ ╟── because: cannot constrain {fst: Int, snd: ⊤} <: 'extra +//│ ╟── because: cannot constrain {fst: Int, snd: } <: 'extra +//│ ╟── because: cannot constrain {fst: Int, snd: } <: ¬¬{fst: 'sel1} +//│ ╟── because: cannot constrain Int <: 'sel1 +//│ ╟── because: cannot constrain Int <: 'sel1 +//│ ╟── because: cannot constrain Int <: ¬(¬⊥ & ¬'x1) +//│ ╟── because: cannot constrain Int <: 'x1 +//│ ╟── because: cannot constrain Tru <: 'res2 +//│ ╟── because: cannot constrain Tru <: 'res2 +//│ ╟── because: cannot constrain Tru <: ¬(¬⊥ & ¬'y) +//│ ╟── because: cannot constrain Tru <: 'y +//│ ╟── because: cannot constrain Fls <: 'res3 +//│ ╟── because: cannot constrain Fls <: 'res3 +//│ ╟── because: cannot constrain Fls <: ¬(¬⊥ & ¬'x2) +//│ ╟── because: cannot constrain Fls <: 'x2 +//│ ╟── because: cannot constrain Tru <: 'res4 +//│ ╟── because: cannot constrain Tru <: 'res4 +//│ ╟── because: cannot constrain Tru <: ¬(¬'res5) +//│ ╟── because: cannot constrain Tru <: 'res5 +//│ ╟── because: cannot constrain 'input <: Int +//│ ╟── because: cannot constrain 'input <: ¬(¬{Int}) +//│ ╙── because: cannot constrain Str <: ¬(¬{Int}) +//│ Type: (Int | Str, {fst: Int, snd: ⊤}) ->{⊥} Int + +fun example14_(input, extra) = if + input is Int and extra.fst is Int then input + extra.fst + extra.fst is Int then input strlen() + extra.fst + else new Z() +//│ Type: ⊤ + +example14_ as (Int | Str, [fst: ~Int, snd: Any]) -> Z +example14_ as (Int | Str, [fst: Int, snd: Any]) -> Int +example14_ as (~(Int | Str), [fst: ~Int, snd: Any]) -> Z +//│ Type: (¬Int & ¬Str, {fst: ¬Int, snd: ⊤}) ->{⊥} Z + +fun is_string: (Str -> Tru) & (~Str -> Fls) +//│ Type: ⊤ + +:e +fun example6_wrong(x: Int | Str, y: Any) = if + x is_int() and_(y is_string()) is Tru then x + strlen(y) + else strlen(x) +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.263: x is_int() and_(y is_string()) is Tru then x + strlen(y) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.264: else strlen(x) +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╙── because: cannot constrain Int | Str <: Int +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.263: x is_int() and_(y is_string()) is Tru then x + strlen(y) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.264: else strlen(x) +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╙── because: cannot constrain ⊤ <: Str +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.263: x is_int() and_(y is_string()) is Tru then x + strlen(y) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.264: else strlen(x) +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╙── because: cannot constrain Int | Str <: Str +//│ Type: ⊤ + +fun example6_ok(x, y) = if + x is_int() and_(y is_string()) is Tru then x + strlen(y) + else strlen(x) +//│ Type: ⊤ + +example6_ok as (Str, Any) -> Int +example6_ok as (Int, Str) -> Int +//│ Type: (Int, Str) ->{⊥} Int + +// fun detailed_ex(a, n: Int) = if +// a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +// a is Prod then a.Prod#snd +// a(n) is Int then a(n) < 42 +// else a(n) From 3bfe1c4a606b9ada223496447454f020314a16e8 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Tue, 22 Apr 2025 22:22:09 +0800 Subject: [PATCH 32/36] wip test explanation --- .../src/test/mlscript/logicsub/popl22.mls | 348 +++++++++++++++--- 1 file changed, 304 insertions(+), 44 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/logicsub/popl22.mls b/hkmc2/shared/src/test/mlscript/logicsub/popl22.mls index 6f91cf52ce..3d3be35005 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/popl22.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/popl22.mls @@ -2,9 +2,21 @@ //│ Type: ⊤ //│ Type: ⊤ + // On Type-Cases, Union Elimination, and Occurrence Typing // https://www.irif.fr/~gc/papers/popl22.pdf +// Occurence typing uses type test to refine the type of the term + +fun f(x) = if x is + Int then x + 1 // x: Int + else x.a // x: ~Int +//│ Type: ⊤ + +// Union elimination rule and set-theoretic types can capture occurence typing +// and the refinement can occur in any position +// instead of only by type test + fun f(x1, x2) = if x1(x2) is Int then x2 + 1 else @@ -20,19 +32,23 @@ f(id, 1) f(id, "") //│ Type: Str +fun strint: Int | Str +//│ Type: ⊤ + +// Considering x2: Int | Str, the type is splitted to Int, and Str in two branches +// thus type check the following expression + :e -f as ((Int -> Int) & (Str -> Str), Int | Str) -> Int | Str -//│ ╔══[ERROR] Type error in reference with expected type ((Int -> Int) & (Str -> Str), Int | Str) ->{⊥} Int | Str -//│ ║ l.24: f as ((Int -> Int) & (Str -> Str), Int | Str) -> Int | Str -//│ ║ ^ -//│ ╟── because: cannot constrain ('x1, 'x2) ->{'eff} 'res <: ((Int -> Int) & (Str -> Str), Int | Str) -> (Int | Str) +f(id, strint) +//│ ╔══[ERROR] Type error in reference with expected type 'x2 +//│ ║ l.42: f(id, strint) +//│ ║ ^^^^^^ //│ ╟── because: cannot constrain Int | Str <: 'x2 //│ ╟── because: cannot constrain Str <: 'x2 //│ ╙── because: cannot constrain Str <: ¬(¬{Int}) -//│ ╔══[ERROR] Type error in reference with expected type ((Int -> Int) & (Str -> Str), Int | Str) ->{⊥} Int | Str -//│ ║ l.24: f as ((Int -> Int) & (Str -> Str), Int | Str) -> Int | Str -//│ ║ ^ -//│ ╟── because: cannot constrain ('x1, 'x2) ->{'eff} 'res <: ((Int -> Int) & (Str -> Str), Int | Str) -> (Int | Str) +//│ ╔══[ERROR] Type error in reference with expected type 'x2 +//│ ║ l.42: f(id, strint) +//│ ║ ^^^^^^ //│ ╟── because: cannot constrain Int | Str <: 'x2 //│ ╟── because: cannot constrain Str <: 'x2 //│ ╟── because: cannot constrain Str <: 'app @@ -40,10 +56,9 @@ f as ((Int -> Int) & (Str -> Str), Int | Str) -> Int | Str //│ ╟── because: cannot constrain 'app1 <: Str //│ ╟── because: cannot constrain 'app1 <: ¬(¬{Str}) //│ ╙── because: cannot constrain Int <: ¬(¬{Str}) -//│ ╔══[ERROR] Type error in reference with expected type ((Int -> Int) & (Str -> Str), Int | Str) ->{⊥} Int | Str -//│ ║ l.24: f as ((Int -> Int) & (Str -> Str), Int | Str) -> Int | Str -//│ ║ ^ -//│ ╟── because: cannot constrain ('x1, 'x2) ->{'eff} 'res <: ((Int -> Int) & (Str -> Str), Int | Str) -> (Int | Str) +//│ ╔══[ERROR] Type error in reference with expected type 'x2 +//│ ║ l.42: f(id, strint) +//│ ║ ^^^^^^ //│ ╟── because: cannot constrain Int | Str <: 'x2 //│ ╟── because: cannot constrain Str <: 'x2 //│ ╟── because: cannot constrain Str <: 'app @@ -51,18 +66,27 @@ f as ((Int -> Int) & (Str -> Str), Int | Str) -> Int | Str //│ ╟── because: cannot constrain 'x2 <: Str //│ ╟── because: cannot constrain 'x2 <: ¬(¬{Str}) //│ ╙── because: cannot constrain Int <: ¬(¬{Str}) -//│ ╔══[ERROR] Type error in reference with expected type ((Int -> Int) & (Str -> Str), Int | Str) ->{⊥} Int | Str -//│ ║ l.24: f as ((Int -> Int) & (Str -> Str), Int | Str) -> Int | Str -//│ ║ ^ -//│ ╟── because: cannot constrain ('x1, 'x2) ->{'eff} 'res <: ((Int -> Int) & (Str -> Str), Int | Str) -> (Int | Str) +//│ ╔══[ERROR] Type error in reference with expected type 'x2 +//│ ║ l.42: f(id, strint) +//│ ║ ^^^^^^ //│ ╟── because: cannot constrain Int | Str <: 'x2 //│ ╟── because: cannot constrain Str <: 'x2 //│ ╟── because: cannot constrain {0: 'x2} <: {0: Str} //│ ╟── because: cannot constrain 'x2 <: Str //│ ╟── because: cannot constrain 'x2 <: ¬(¬{Str}) //│ ╙── because: cannot constrain Int <: ¬(¬{Str}) -//│ Type: ((Int -> Int) & (Str -> Str), Int | Str) ->{⊥} Int | Str +//│ Type: Str | Int +// without union elimination rule, type test on x2 is required + +fun f(x1, x2) = if x2 is + Int then x2 + 1 + else + x1(x2).Str#concat(x2) +//│ Type: ⊤ + +f(id, strint) +//│ Type: Str | Int data class Prod[A, B](val fst: A, val snd: B) //│ Type: ⊤ @@ -75,35 +99,71 @@ class let tru = new Tru() let fls = new Fls() -//│ Type: ⊤ - fun prod(p, q) = new Prod(p, q) //│ Type: ⊤ +// Maximal Sharing Canonical Forms is used in type checking + fun y: Any -> Tru | Fls //│ Type: ⊤ -prod(y(x => x), y(x => x)) as Prod[Tru, Tru] | Prod[Fls, Fls] -//│ Type: Prod[Tru, Tru] | Prod[Fls, Fls] - :e { fst: y(x => x), snd: y(x => x) } as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ] //│ ╔══[ERROR] Type error in record with expected type {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} -//│ ║ l.90: { fst: y(x => x), snd: y(x => x) } as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.111: { fst: y(x => x), snd: y(x => x) } as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain {fst: Tru | Fls, snd: Tru | Fls} <: {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} //│ ╟── because: cannot constrain {fst: Tru ∨ Fls, snd: Tru ∨ Fls} <: {snd: Fls} //│ ╙── because: cannot constrain Tru ∨ Fls <: Fls //│ ╔══[ERROR] Type error in record with expected type {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} -//│ ║ l.90: { fst: y(x => x), snd: y(x => x) } as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.111: { fst: y(x => x), snd: y(x => x) } as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain {fst: Tru | Fls, snd: Tru | Fls} <: {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} //│ ╟── because: cannot constrain {fst: Tru ∨ Fls, snd: Tru ∨ Fls} <: {snd: Tru} //│ ╙── because: cannot constrain Tru ∨ Fls <: Tru //│ Type: {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} +// The above expression is typed with the following MSC-forms + +( + let a1 = y + let a2 = x => x + let a3 = a1(a2) + let a4 = { fst: a3, snd: a3 } + a4 +) +//│ Type: {fst: Tru | Fls, snd: Tru | Fls} + +// Again, type test on a3 is required + +( + let a1 = y + let a2 = x => x + let a3 = a1(a2) + let a4 = if a3 is Tru then { fst: a3, snd: a3 } else { fst: a3, snd: a3 } + a4 +) as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ] +//│ Type: {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} + + +// Since classes are merged in union, the following term type checks + +prod(y(x => x), y(x => x)) as Prod[Tru, Tru] | Prod[Fls, Fls] +//│ Type: Prod[Tru, Tru] | Prod[Fls, Fls] + +prod(y(x => x), y(x => x)) +//│ Type: Prod['A, 'B] +//│ Where: +//│ Fls | Tru <: 'A +//│ Fls | Tru <: 'B +fun a: (Int -> (Int | Bool)) | Prod[Int, Int | Bool] +fun n: Int +//│ Type: ⊤ + +// type test `a(n) is Int` does not refine a and n, and thus a(n) + fun f(a, n) = if a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd @@ -112,6 +172,24 @@ fun f(a, n) = if else a(n) //│ Type: ⊤ +// while a(n) is Int, in the then branch, a(n) still has type Int | Bool + +:e +f(a, n) +//│ ╔══[ERROR] Type error in reference with expected type 'n +//│ ║ l.178: f(a, n) +//│ ║ ^ +//│ ╟── because: cannot constrain Int <: 'n +//│ ╟── because: cannot constrain Int <: 'n +//│ ╟── because: cannot constrain Int ∨ Bool <: 'app +//│ ╟── because: cannot constrain Int <: 'app +//│ ╟── because: cannot constrain 'app1 <: Int +//│ ╟── because: cannot constrain 'app1 <: ¬(¬{Int}) +//│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) +//│ Type: ((((Int | Bool) | Bool) | Int) | Bool) | Bool + +// the following rewrite refines x + fun f(a, n) = if a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd @@ -121,14 +199,11 @@ fun f(a, n) = if else x //│ Type: ⊤ -fun a: (Int -> (Int | Bool)) | Prod[Int, Int | Bool] -fun n: Int -//│ Type: ⊤ - f(a, n) //│ Type: (((((Int & ¬Int) | (Bool & ¬Int)) | Bool) | Int) | Bool) | Bool + fun is_int(x) = if x is Int then tru else fls //│ Type: ⊤ @@ -147,6 +222,10 @@ is_bool as Tru | Fls -> Tru is_bool as ~(Tru | Fls) -> Fls //│ Type: (¬Tru & ¬Fls) ->{⊥} Fls +// Originally, the paper defines False, empty string "" and zero 0 as Falsy +// and ~Falsy as Truthy +// Here Fls and Z are treated as falsy, and otherwise truthy + fun not_(x) = if x is Fls then tru Z then tru @@ -201,7 +280,7 @@ example14 as (~(Int | Str), [fst: ~Int, snd: Any]) -> Z :e example14 as (Int | Str, [fst: Int, snd: Any]) -> Int //│ ╔══[ERROR] Type error in reference with expected type (Int | Str, {fst: Int, snd: ⊤}) ->{⊥} Int -//│ ║ l.202: example14 as (Int | Str, [fst: Int, snd: Any]) -> Int +//│ ║ l.281: example14 as (Int | Str, [fst: Int, snd: Any]) -> Int //│ ║ ^^^^^^^^^ //│ ╟── because: cannot constrain ('input, 'extra) ->{'eff} 'res <: (Int | Str, {fst: Int, snd: ⊤}) -> Int //│ ╟── because: cannot constrain {fst: Int, snd: ⊤} <: 'extra @@ -217,7 +296,7 @@ example14 as (Int | Str, [fst: Int, snd: Any]) -> Int //│ ╟── because: cannot constrain 'input <: ¬(¬{Str}) //│ ╙── because: cannot constrain Int <: ¬(¬{Str}) //│ ╔══[ERROR] Type error in reference with expected type (Int | Str, {fst: Int, snd: ⊤}) ->{⊥} Int -//│ ║ l.202: example14 as (Int | Str, [fst: Int, snd: Any]) -> Int +//│ ║ l.281: example14 as (Int | Str, [fst: Int, snd: Any]) -> Int //│ ║ ^^^^^^^^^ //│ ╟── because: cannot constrain ('input, 'extra) ->{'eff} 'res <: (Int | Str, {fst: Int, snd: ⊤}) -> Int //│ ╟── because: cannot constrain {fst: Int, snd: ⊤} <: 'extra @@ -244,6 +323,8 @@ example14 as (Int | Str, [fst: Int, snd: Any]) -> Int //│ ╙── because: cannot constrain Str <: ¬(¬{Int}) //│ Type: (Int | Str, {fst: Int, snd: ⊤}) ->{⊥} Int +// using direct type test instead of predicate functions + fun example14_(input, extra) = if input is Int and extra.fst is Int then input + extra.fst extra.fst is Int then input strlen() + extra.fst @@ -258,30 +339,54 @@ example14_ as (~(Int | Str), [fst: ~Int, snd: Any]) -> Z fun is_string: (Str -> Tru) & (~Str -> Fls) //│ Type: ⊤ +// example6_wrong is ill typed + :e fun example6_wrong(x: Int | Str, y: Any) = if x is_int() and_(y is_string()) is Tru then x + strlen(y) else strlen(x) //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.263: x is_int() and_(y is_string()) is Tru then x + strlen(y) +//│ ║ l.346: x is_int() and_(y is_string()) is Tru then x + strlen(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.264: else strlen(x) +//│ ║ l.347: else strlen(x) //│ ║ ^^^^^^^^^^^^^^^^ //│ ╙── because: cannot constrain Int | Str <: Int //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.263: x is_int() and_(y is_string()) is Tru then x + strlen(y) +//│ ║ l.346: x is_int() and_(y is_string()) is Tru then x + strlen(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.264: else strlen(x) +//│ ║ l.347: else strlen(x) //│ ║ ^^^^^^^^^^^^^^^^ //│ ╙── because: cannot constrain ⊤ <: Str //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.263: x is_int() and_(y is_string()) is Tru then x + strlen(y) +//│ ║ l.346: x is_int() and_(y is_string()) is Tru then x + strlen(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.264: else strlen(x) +//│ ║ l.347: else strlen(x) //│ ║ ^^^^^^^^^^^^^^^^ //│ ╙── because: cannot constrain Int | Str <: Str //│ Type: ⊤ +:e +fun example6_wrong(x: Int | Str, y: Any) = if + x is Int and y is Str then x + strlen(y) + else strlen(x) +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.370: x is Int and y is Str then x + strlen(y) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.371: else strlen(x) +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain Int | Str <: 'x +//│ ╟── because: cannot constrain Int <: 'x +//│ ╙── because: cannot constrain Int <: ¬(¬{Str}) +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.370: x is Int and y is Str then x + strlen(y) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.371: else strlen(x) +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'x <: Str +//│ ╟── because: cannot constrain 'x <: ¬(¬{Str}) +//│ ╙── because: cannot constrain Int <: ¬(¬{Str}) +//│ Type: ⊤ + fun example6_ok(x, y) = if x is_int() and_(y is_string()) is Tru then x + strlen(y) else strlen(x) @@ -291,8 +396,163 @@ example6_ok as (Str, Any) -> Int example6_ok as (Int, Str) -> Int //│ Type: (Int, Str) ->{⊥} Int -// fun detailed_ex(a, n: Int) = if -// a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd -// a is Prod then a.Prod#snd -// a(n) is Int then a(n) < 42 -// else a(n) +// the same as above + +:e +fun detailed_ex(a: (Int -> (Int | Bool)) | Prod[Int, Int | Bool], n: Int) = if + a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd + a is Prod then a.Prod#snd + a(n) is Int then a(n) < 42 + else a(n) +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.406: else a(n) +//│ ║ ^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'app <: Int +//│ ╟── because: cannot constrain 'app <: ¬(¬{Int}) +//│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.406: else a(n) +//│ ║ ^^^^^^^^^^^ +//│ ╟── because: cannot constrain ¬Prod[?, ?] & ((Int -> (Int | Bool)) | Prod[Int, Int | Bool]) <: 'a +//│ ╟── because: cannot constrain (Int) ->{⊥} (Int ∨ Bool) ∧ ¬{Prod[?, ?]} <: 'a +//│ ╟── because: cannot constrain (Int) ->{⊥} (Int ∨ Bool) ∧ ¬{Prod[?, ?]} <: ¬(¬{Int ->{'eff} 'app}) +//│ ╟── because: cannot constrain Int ∨ Bool <: 'app +//│ ╟── because: cannot constrain Bool <: 'app +//│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.406: else a(n) +//│ ║ ^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'a <: Int ->{'eff} 'app +//│ ╟── because: cannot constrain 'a <: ¬(¬{Int ->{'eff} 'app}) +//│ ╟── because: cannot constrain (Int) ->{⊥} (Int ∨ Bool) ∧ ¬{Prod[?, ?]} <: ¬(¬{Int ->{'eff} 'app}) +//│ ╟── because: cannot constrain Int ∨ Bool <: 'app +//│ ╟── because: cannot constrain Bool <: 'app +//│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.406: else a(n) +//│ ║ ^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'a <: Int ->{'eff} 'app +//│ ╟── because: cannot constrain 'a <: ¬(¬{Int ->{'eff} 'app}) +//│ ╟── because: cannot constrain (Int) ->{⊥} (Int ∨ Bool) ∧ ¬{Prod[?, ?]} <: ¬(¬{Int ->{'eff} 'app}) +//│ ╟── because: cannot constrain Int ∨ Bool <: 'app +//│ ╟── because: cannot constrain Bool <: 'app +//│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.406: else a(n) +//│ ║ ^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'app <: Int +//│ ╟── because: cannot constrain 'app <: ¬(¬{Int}) +//│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.406: else a(n) +//│ ║ ^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'app <: Int +//│ ╟── because: cannot constrain 'app <: ¬(¬{Int}) +//│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.406: else a(n) +//│ ║ ^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'app <: Int +//│ ╟── because: cannot constrain 'app <: ¬(¬{Int}) +//│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.406: else a(n) +//│ ║ ^^^^^^^^^^^ +//│ ╟── because: cannot constrain 'app <: Int +//│ ╟── because: cannot constrain 'app <: ¬(¬{Int}) +//│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) +//│ Type: ⊤ + +fun detailed_ex(a: (Int -> (Int | Bool)) | Prod[Int, Int | Bool], n: Int) = if + a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd + a is Prod then a.Prod#snd + let x = a(n) + x is Int then x < 42 + else x +//│ Type: ⊤ + +detailed_ex as ((Int -> Int | Bool) | Prod[Int, Int | Bool], Int) -> Int | Bool +//│ Type: ((Int -> (Int | Bool)) | Prod[Int, Int | Bool], Int) ->{⊥} Int | Bool + +// TODO a.Prod#snd is not refined + +:todo +detailed_ex as ((Int -> Int | Bool) | Prod[Int, Int | Bool], Int) -> Bool +//│ ╔══[ERROR] Type error in reference with expected type ((Int -> (Int | Bool)) | Prod[Int, Int | Bool], Int) ->{⊥} Bool +//│ ║ l.528: detailed_ex as ((Int -> Int | Bool) | Prod[Int, Int | Bool], Int) -> Bool +//│ ║ ^^^^^^^^^^^ +//│ ╟── because: cannot constrain ((Int -> (Int | Bool)) | Prod[Int, Int | Bool], Int) ->{'eff} 'res <: ((Int -> (Int | Bool)) | Prod[Int, Int | Bool], Int) -> Bool +//│ ╟── because: cannot constrain 'res <: Bool +//│ ╟── because: cannot constrain 'res <: ¬(¬{Bool}) +//│ ╙── because: cannot constrain Int & ¬⊥ <: ¬(¬{Bool}) +//│ Type: ((Int -> (Int | Bool)) | Prod[Int, Int | Bool], Int) ->{⊥} Bool + +a +//│ Type: (Int -> (Int | Bool)) | Prod[Int, Int | Bool] + +:todo +if a is + Prod then true + else a(1) +//│ ╔══[ERROR] Type error in `if` expression +//│ ║ l.542: if a is +//│ ║ ^^^^ +//│ ║ l.543: Prod then true +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.544: else a(1) +//│ ║ ^^^^^^^^^^^ +//│ ╙── because: cannot constrain (Int -> (Int | Bool)) | Prod[Int, Int | Bool] <: Int ->{'eff} 'app +//│ Type: (Int | Bool) | Bool + +(x => if x is + Prod then true + else x(1)) of a +//│ Type: (Bool | Int) | Bool From 99b465b7c608454e60a4703a7723971cd6c1b612 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Mon, 28 Apr 2025 17:51:15 +0800 Subject: [PATCH 33/36] rcd union neg disjointess --- .../scala/hkmc2/bbml/ConstraintSolver.scala | 47 +++---- .../src/main/scala/hkmc2/bbml/bbML.scala | 22 ++-- .../src/main/scala/hkmc2/bbml/types.scala | 74 ++++++----- .../src/test/mlscript/bbml/bbBasics.mls | 17 ++- .../src/test/mlscript/bbml/bbBounds.mls | 8 +- .../src/test/mlscript/bbml/bbDisjoint.mls | 2 + .../src/test/mlscript/bbml/bbExtrude.mls | 5 +- .../shared/src/test/mlscript/bbml/bbGPCE.mls | 6 +- hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls | 4 +- hkmc2/shared/src/test/mlscript/bbml/bbRec.mls | 4 +- .../src/test/mlscript/logicsub/DisjSub.mls | 98 +++++--------- .../shared/src/test/mlscript/logicsub/If.mls | 5 +- .../src/test/mlscript/logicsub/List.mls | 4 +- .../src/test/mlscript/logicsub/popl22.mls | 124 ++++++++---------- 14 files changed, 191 insertions(+), 229 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index ab1c13c35a..e3a6d399f9 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -122,27 +122,20 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, if k.subsetOf(um.keySet) then k.foreach(k => constrainImpl(um(k), wm(k))) else cctx.err - case (Inter(S(u: RcdType)), Union(f, Nil, rs@(RcdType(w) :: _))) => - val ws = rs.foldLeft(Nil): (x, w) => - val d = Type.disjoint(w, u) - if d === S(Set.empty) then x else Ls(d -> w) ++ x - ws match - case Nil => cctx.err - case (_, w) :: Nil => constrainImpl(u, w) - case ((_, RcdType(w)) :: (_, RcdType(z)) :: _) => - val (wm, zm) = (w.toMap, z.toMap) - val k = wm.keySet & zm.keySet - val dk = k.find(k => Type.disjoint(wm(k), zm(k)) === S(Set.empty)).get - val ku = ws.foldLeft(Bot: Type): - case (ku, (_, w)) => ku | w.fields.find(_._1 === dk).get._2 - ws.foreach: - case (S(k), w) => k.foreach: k => - DisjSub(mutable.LinkedHashSet.from(k), Nil, Ls(u -> RcdType(w.fields.filter(_._1 =/= k)))).commit() - case _ => - constrainImpl(u.fields.find(_._1 === dk).get._2, ku) - ws.foreach: - case (N, w) => constrainImpl(u, RcdType(w.fields.filter(_._1 =/= dk))) - case _ => + case (Inter(S(u: RcdType)), Union(f, Nil, rs)) => + val us = u.fields.keys.toSet + val ws = rs.filter(_.fields.keys.forall(us)) + if ws.isEmpty then cctx.err + else + val q = ws.foldLeft(Bot: Type): (q, w) => + val wq = Type.discriminant(w) + Type.disjoint(wq, u) match + case N => constrainImpl(u & wq, w) + case S(k) => k.foreach(k => DisjSub(mutable.LinkedHashSet.from(k), Nil, Ls(wq -> w)).commit()) + q | wq + Type.disjoint(q.!, u) match + case N => constrainImpl(Top, Bot) + case S(k) => k.foreach(k => DisjSub(mutable.LinkedHashSet.from(k), Nil, Ls(Top -> Bot)).commit()) case (Inter(S(fs: Ls[FunType])), Union(S(FunType(args2, ret2, eff2)), Nil, Nil)) => val k = args2.flatMap(x => Type.disjoint(x, x)) if k.forall(_.nonEmpty) then @@ -154,19 +147,17 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, constrainImpl(f.ret, ret2) constrainImpl(f.eff, eff2) else - val args = f.map(x => Type.discriminant(x.args)) + val args = f.map(x => RcdType(x.args.zipWithIndex.map(u => (s"${u._2}", u._1)))) val args2r = args2.zipWithIndex.map(u => (s"${u._2}", u._1)) val args2q = RcdType(args2r) - val (cs, dss) = (args.iterator.zip(f).map: - case ((q, r), f) => - val rm = r.fields.toMap - val rcs = args2r.flatMap(u => rm.get(u._1).filter(_ =/= Top).map(u._2 -> _)) - val cs = (f.ret, ret2) :: (f.eff, eff2) :: rcs + val (cs, dss) = (args.iterator.map(Type.discriminant).zip(f).map: + case (q, f) => + val cs = (f.ret, ret2) :: (f.eff, eff2) :: Nil //rcs Type.disjoint(q, args2q) match case N => (cs, Nil) case S(k) => (Nil, k.map(k => DisjSub(mutable.LinkedHashSet.from(k), Nil, cs)))).toList.unzip - val c = (args2q, args.foldLeft(Bot: Type) { case (t, (q, _)) => t | q }) + val c = (args2q, args.foldLeft(Bot: Type)(_ | _)) if k.isEmpty then if f.isEmpty then cctx.err diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index 437c6c452f..921ce4ffc1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -173,15 +173,15 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): if !pol then val lfa = l.toDnf.conjs.flatMap(_.i.v).collect: case (f :: fs) => - val fd = Type.discriminant(f.args)._1 + val fd = Type.discriminant(f.args).flatten fs.foldLeft(fd: Type, fd.fields.keys.toSet): (x, y) => - val d = Type.discriminant(y.args)._1 + val d = Type.discriminant(y.args).flatten (x._1 | d, x._2 & d.fields.keys.toSet) val rfa = r.toDnf.conjs.flatMap(_.i.v).collect: case (f :: fs) => - val fd = Type.discriminant(f.args)._1 + val fd = Type.discriminant(f.args).flatten fs.foldLeft(fd: Type, fd.fields.keys.toSet): (x, y) => - val d = Type.discriminant(y.args)._1 + val d = Type.discriminant(y.args).flatten (x._1 | d, x._2 & d.fields.keys.toSet) val d = lfa.iterator.flatMap(x => rfa.iterator.map(y => (x, y))).exists: case ((x, u), (y, w)) => (u & w).isEmpty || Type.disjoint(x, y) =/= S(Set.empty) @@ -386,11 +386,9 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): val nestCtx = ctx.nest given BbCtx = nestCtx val (nc, dss, cs) = constraintCollector - val sv0 = HashMap.empty[Ref, InfVar] sv.keys.foreach: s => val v = freshVar(new TempSymbol(S(s), s.sym.nme)) nestCtx += s.sym -> v - sv0 += s -> v val (termTy, termEff) = typeCheck(term)(using c = nc) val sk = freshSkolem(name) nestCtx += name -> termTy @@ -398,7 +396,10 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): path.foreach: p => val m = p.toMap val d = p.flatMap { case (s, t) => sv.get(s).flatMap(st => Type.disjoint(t.!, st)) } - val sc = sv.toList.map { case (s, t) => (m.getOrElse(s, Bot).! & t, sv0(s)) } + val sc = sv.toList.map: + case (s, t) => + val v = nestCtx.get(s.sym).get + (m.getOrElse(s, Bot).! & t, monoOrErr(v, s)) if d.isEmpty then dss.foreach(c.commit(_)) (sc ++ cs).distinct.foreach(u => constrain(u._1, u._2)) @@ -411,16 +412,17 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case Split.Else(e) => val (nc, dss, cs) = constraintCollector val ctx1 = ctx.nest - val sv0 = HashMap.empty[Ref, InfVar] sv.keys.foreach: s => val v = freshVar(new TempSymbol(S(s), s.sym.nme)) ctx1 += s.sym -> v - sv0 += s -> v nc.constrain(ascribe(e, sign)(using ctx1, c = nc)._2, eff) path.foreach: p => val m = p.toMap val d = p.flatMap { case (s, t) => sv.get(s).flatMap(st => Type.disjoint(t.!, st)) } - val sc = sv.toList.map { case (s, t) => (m.getOrElse(s, Bot).! & t, sv0(s)) } + val sc = sv.toList.map: + case (s, t) => + val v = ctx1.get(s.sym).get + (m.getOrElse(s, Bot).! & t, monoOrErr(v, s)) if d.isEmpty then dss.foreach(c.commit(_)) (sc ++ cs).distinct.foreach(u => constrain(u._1, u._2)) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 24e1b0d643..95fe401d49 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -300,53 +300,57 @@ object Type: then lhs | rhs else lhs & rhs def mkNegType(ty: Type): Type = ty.! - def discriminant(a: Ls[Type]): (RcdType, RcdType) = - discriminantRcd(RcdType(a.zipWithIndex.map(u => (s"${u._2}", u._1.toBasic))).flatten) - def discriminantRcd(a: RcdType): (RcdType, RcdType) = - val (u, w) = (a.fields.map: - case (a, t) => - val (q, r) = discriminant(t.toBasic) - (RcdType(Ls(a -> q)), RcdType(Ls(a -> r))) - ).unzip - (u.reduce(_ & _), w.reduce(_ & _)) - def discriminant(a: BasicType): (BasicType, BasicType) = a.simp.toBasic match - case Bot => (Bot, Bot) - case c@ClassLikeType(_, Nil) => (c, Top) - case ClassLikeType(c, t) => (ClassLikeType(c, t.map(_ => Wildcard.empty)), a) - case a@RcdType(_ :: _) => discriminantRcd(a) - case a@ComposedType(l, r, true) => - val q = (discriminant(l.toBasic)._1 | discriminant(r.toBasic)._1).toBasic - (q, (a | q.!).toBasic) - case ComposedType(l, r, false) => - val (u, w) = discriminant(l.toBasic) - val (q, p) = discriminant(r.toBasic) - ((u & q).toBasic, (w & p).toBasic) - case NegType(t) => (a, Top) - case a => (Top, a) - def disjointIU(i: Inter, u: Union)(using TL): Opt[Set[Set[InfVar -> BasicType]]] = (i.v, u.cls) match - case (S(c: ClassLikeType), cs) if cs.exists(_.name.uid === c.name.uid) => S(Set.empty) - case (S(RcdType(u)), _) => - val kk = u.values.map(t => disjointDisj(t.toDnf)).toList - val k = kk.flatten.toList - if k.isEmpty then N + def discriminant(a: Ls[Type])(using TL): RcdType = + discriminantRcd(RcdType(a.zipWithIndex.map(u => (s"${u._2}", u._1.toBasic)))) + def discriminantRcd(a: RcdType)(using TL): RcdType = + RcdType(a.fields.flatMap: + case (a, t) => discriminant(t) match + case Top => N + case t => S(a -> t)) + def discriminantIU(i: Inter, u: Union)(using TL): BasicType = (i.v, u.cls) match + case (N, cs) => cs.reduceOption[Type](_ | _).fold(Top)(NegType(_)) + case (S(ClassLikeType(c, t)), cs) => if cs.exists(_.name.uid === c.uid) then Bot else ClassLikeType(c, t.map(_ => Wildcard.empty)) + case (S(u: RcdType), _) => discriminantRcd(u) + case _ => Top + def discriminant(t: Type)(using TL): BasicType = + t.toDnf.conjs.foldLeft(Bot: Type)((x, y) => x | discriminantIU(y.i, y.u)).simp.toBasic + def disjointIU(i: Inter, u: Union)(using TL): Opt[Set[Set[InfVar -> BasicType]]] = (i.v, u.cls, u.rcd) match + case (S(c: ClassLikeType), cs, _) if cs.exists(_.name.uid === c.name.uid) => S(Set.empty) + case (S(RcdType(u)), _, rs) => + val k = u.values.flatMap(t => disjointDisj(t.toDnf)).toList + val rd = + if rs.isEmpty then Nil + else + val um = u.toMap + val p = rs.foldLeft[Ls[Ls[Str -> Type]]](Ls(Nil)): (p, w) => + if w.fields.keys.forall(um.contains) then p.flatMap(x => w.fields.map(_ :: x)) else p + p.map: p => + val m = p.groupMapReduce(_._1)(_._2)(_ | _) + val d = p.keys.distinct.flatMap(a => Type.disjoint(m(a).!, um(a))) + if d.isEmpty then N + else S(d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y)))) + if k.isEmpty then + if rd.isEmpty || rd.contains(N) then N else S(rd.flatten.flatten.toSet) else if k.exists(_.isEmpty) then S(Set.empty) - else S(k.reduce((x, y) => y.flatMap(y => x.map(_ ++ y)))) + else + if rd.contains(N) then N + else S(k.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))) ++ rd.flatten.flatten) case _ => N def disjointConj(ty: Conj)(using TL): Opt[Set[Set[InfVar -> BasicType]]] = val d = disjointIU(ty.i, ty.u) if d.exists(_.isEmpty) then S(Set.empty) - else (ty.i.v, ty.u.cls, ty.vars.iterator.filter(_._2).keys.toList) match - case (_, _, Nil) => d - case (N, Nil, v :: Nil) => + else (ty.i.v, ty.u.cls, ty.u.rcd, ty.vars.iterator.filter(_._2).keys.toList) match + case (_, _, _, Nil) => d + case (N, Nil, Nil, v :: Nil) => val lb = v.state.lowerBounds.reduceOption(_ | _).orElse(S(Bot)).get disjointDisj(lb.toDnf).map(_ + Set(v -> v)) - case (i, c, vs) => + case (i, c, r, vs) => val j = i match case S(ClassLikeType(c, _)) => S(ClassLikeType(c, Nil)) case S(u: RcdType) => S(u) case _ => N val vd = vs.combinations(2).collect { case x :: y :: _ => Ls(x -> y, y -> x) }.flatten.toList - val ds = vs.flatMap(v => (j ++ c.reduceOption[Type](_ | _).map(_.!)).map(x => v -> x.toBasic)).toSet ++ vd + val ds = vs.flatMap(v => (j ++ (c ++ r).reduceOption[Type](_ | _).map(_.!)).map(x => v -> x.toBasic)).toSet ++ vd val lb = vs.flatMap(_.state.lowerBounds.reduceOption[Type](_ | _)).reduceOption(_ & _).orElse(S(Bot)).get val t = lb & Conj(Inter(j), Union(N, c, Nil), Nil) disjointDisj(t.toDnf).map(_ + ds) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index 14871c9d06..775a4a74a1 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -169,7 +169,7 @@ fun f() = new Printer(foofoo) f //│ Type: ['T, 'x] -> () -> Printer['T] //│ Where: -//│ 'T#'T ∨ ( 'T#'T ∨ Str <: Str ∧ ⊥ <: ⊥ ∧ 'T <: 'x){0: 'T} <: {0: ⊤} +//│ 'T#'T ∨ ( 'T#'T ∨ Str <: Str ∧ ⊥ <: ⊥){0: 'T} <: {0: 'x} //│ 'x <: Int f().Printer#f(42) @@ -184,7 +184,8 @@ f().Printer#f("oops") //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: ¬(¬'T1) //│ ╟── because: cannot constrain Str <: 'T1 -//│ ╟── because: cannot constrain 'T1 <: 'x +//│ ╟── because: cannot constrain {0: 'T1} <: {0: ¬⊥ & 'x} +//│ ╟── because: cannot constrain 'T1 <: ¬⊥ & 'x //│ ╟── because: cannot constrain 'T1 <: 'x //│ ╟── because: cannot constrain 'T1 <: Int //│ ╟── because: cannot constrain 'T1 <: ¬(¬{Int}) @@ -197,12 +198,13 @@ let ip = new Printer(foofoo) in ip.Printer#f(42) :e let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.198: let ip = new Printer(foofoo) in ip.Printer#f("42") +//│ ║ l.199: let ip = new Printer(foofoo) in ip.Printer#f("42") //│ ║ ^^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: ¬(¬'T) //│ ╟── because: cannot constrain Str <: 'T +//│ ╟── because: cannot constrain {0: 'T} <: {0: 'x} //│ ╟── because: cannot constrain 'T <: 'x //│ ╟── because: cannot constrain 'T <: 'x //│ ╟── because: cannot constrain 'T <: ¬¬Int @@ -219,7 +221,7 @@ fun inc(x) = x + 1 new TFun(inc) //│ Type: TFun['T] //│ Where: -//│ 'T#'T ∨ ( 'T#'T ∨ Int <: 'T ∧ ⊥ <: ⊥ ∧ 'T <: 'x){0: 'T} <: {0: ⊤} +//│ 'T#'T ∨ ( 'T#'T ∨ Int <: 'T ∧ ⊥ <: ⊥){0: 'T} <: {0: 'x} //│ 'x <: ¬¬Int let tf = new TFun(inc) in tf.TFun#f(1) @@ -228,12 +230,13 @@ let tf = new TFun(inc) in tf.TFun#f(1) :e let tf = new TFun(inc) in tf.TFun#f("1") //│ ╔══[ERROR] Type error in string literal with expected type 'T -//│ ║ l.229: let tf = new TFun(inc) in tf.TFun#f("1") +//│ ║ l.231: let tf = new TFun(inc) in tf.TFun#f("1") //│ ║ ^^^ //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: 'T //│ ╟── because: cannot constrain Str <: ¬(¬'T) //│ ╟── because: cannot constrain Str <: 'T +//│ ╟── because: cannot constrain {0: 'T} <: {0: 'x} //│ ╟── because: cannot constrain 'T <: 'x //│ ╟── because: cannot constrain 'T <: 'x //│ ╟── because: cannot constrain 'T <: ¬¬Int @@ -345,7 +348,7 @@ f f(x => x).Foo#x //│ Type: ('A) ->{⊥} 'A //│ Where: -//│ 'A#'A ∨ ( 'A#'A ∨ 'x <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'x){0: 'A} <: {0: ⊤} +//│ 'A#'A ∨ ( 'A#'A ∨ 'x <: 'A ∧ ⊥ <: ⊥){0: 'A} <: {0: 'x} g => (new Foo(g)).Foo#x //│ Type: ('A -> 'A) ->{⊥} ('A) ->{⊥} 'A @@ -358,7 +361,7 @@ throw new Error("oops") :e throw 42 //│ ╔══[ERROR] Type error in throw -//│ ║ l.359: throw 42 +//│ ║ l.362: throw 42 //│ ║ ^^ //│ ╙── because: cannot constrain Int <: Error //│ Type: ⊥ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls index 59c286f6bc..97ef234dcb 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBounds.mls @@ -87,7 +87,7 @@ bazbaz //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#'A ∨ 'A <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'A){0: 'A} <: {0: ⊤} +//│ 'A#'A ∨ ( 'A#'A ∨ 'A <: 'A ∧ ⊥ <: ⊥){0: 'A} <: {0: 'A} bazbaz(42)(x => x + 1) //│ Type: Int @@ -98,7 +98,7 @@ cc //│ Where: //│ 'A -> 'A <: 'B //│ 'B <: 'A -> 'A -//│ 'B#'B ∨ ( 'B#'B ∨ 'B <: 'B ∧ ⊥ <: ⊥ ∧ 'B <: 'B){0: 'B} <: {0: ⊤} +//│ 'B#'B ∨ ( 'B#'B ∨ 'B <: 'B ∧ ⊥ <: ⊥){0: 'B} <: {0: 'B} //│ 'B -> 'B <: 'A //│ 'A <: 'B -> 'B @@ -119,14 +119,14 @@ bazbaz as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#'A ∨ 'A <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'A){0: 'A} <: {0: ⊤} +//│ 'A#'A ∨ ( 'A#'A ∨ 'A <: 'A ∧ ⊥ <: ⊥){0: 'A} <: {0: 'A} (x => f => bazbaz(x)(f)) as [A extends Int] -> A -> ([B extends A -> A restricts A -> A] -> B) -> A //│ Type: ['A] -> ('A) ->{⊥} ('A -> 'A) ->{⊥} 'A //│ Where: //│ 'A <: Int -//│ 'A#'A ∨ ( 'A#'A ∨ 'A <: 'A ∧ ⊥ <: ⊥ ∧ 'A <: 'A){0: 'A} <: {0: ⊤} +//│ 'A#'A ∨ ( 'A#'A ∨ 'A <: 'A ∧ ⊥ <: ⊥){0: 'A} <: {0: 'A} h(x => f => bazbaz(x)(f))(42) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls b/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls index 54b385de67..64b9ab95dc 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls @@ -224,6 +224,7 @@ fun foo(r1) = //│ ╟── because: cannot constrain 'r1 ->{'eff} 'app <: 'foo //│ ╟── because: cannot constrain ('r1) ->{'eff} ('app) <: 'foo //│ ╟── because: cannot constrain ('r1) ->{'eff} ('app) <: Region[in 'r2 out 'r21] ->{'eff1} 'app1 +//│ ╟── because: cannot constrain {0: Region[in 'r2 out 'r21]} <: {0: 'r1} //│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: 'r1 //│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: 'r1 //│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: Region[in 'reg out 'reg1] @@ -246,6 +247,7 @@ fun foo(r1) = //│ ╟── because: cannot constrain 'r1 ->{'eff} 'app <: 'foo //│ ╟── because: cannot constrain ('r1) ->{'eff} ('app) <: 'foo //│ ╟── because: cannot constrain ('r1) ->{'eff} ('app) <: Region[in 'r2 out 'r21] ->{'eff1} 'app1 +//│ ╟── because: cannot constrain {0: Region[in 'r2 out 'r21]} <: {0: 'r1} //│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: 'r1 //│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: 'r1 //│ ╟── because: cannot constrain Region[in 'r2 out 'r21] <: Region[in 'reg out 'reg1] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls index 59b28f83bb..df3e9c8110 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbExtrude.mls @@ -74,7 +74,7 @@ g f(g) //│ Type: ('A) ->{⊥} Int //│ Where: -//│ 'A#C ∨ ( 'A#C ∨ 'D <: B ∧ ⊥ <: ⊥ ∧ C[out B] & 'A <: C[in Int out 'D]){0: C[out B] & 'A} <: {0: C[?]} +//│ 'A#C ∨ ( 'A#C ∨ 'D <: B ∧ ⊥ <: ⊥){0: C[out B] & 'A} <: {0: C[in Int out 'D]} fun foo: C[in Int out Nothing] foo @@ -94,7 +94,8 @@ f(g)(bar) //│ ║ ^^^ //│ ╟── because: cannot constrain C[Int] <: 'A //│ ╟── because: cannot constrain C[in Int out Int] <: 'A -//│ ╟── because: cannot constrain C[out B] & 'A <: C[in Int out 'D] +//│ ╟── because: cannot constrain {0: C[out B] & 'A} <: {0: C[in Int out 'D]} +//│ ╟── because: cannot constrain C[in ⊥ out B] ∧ 'A <: C[in Int out 'D] //│ ╟── because: cannot constrain 'A <: ¬C[in ⊥ out ¬⊥ & 'B1] | C[in Int out ¬⊥ & 'D1] //│ ╟── because: cannot constrain C[in Int out Int] <: ¬C[in ⊥ out ¬⊥ & 'B1] | C[in Int out ¬⊥ & 'D1] //│ ╟── because: cannot constrain (Int) & ('B1) <: ¬⊥ & 'D1 diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls index 2dace72d3c..302a64314d 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls @@ -76,15 +76,15 @@ inc inc(c => log(show(c))) //│ Type: CodeBase[out 'x -> 'cde, ⊥, ?] //│ Where: -//│ 'x1#'x ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x1#'x ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int & ¬⊥, 1: Int & ¬⊥} //│ 'x <: 'cde1 -//│ 'cde1#'cde1 ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'cde1#'cde1 ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int & ¬⊥, 1: Int & ¬⊥} //│ Int <: 'cde2 //│ 'cde <: ⊤ //│ 'app <: 'cde //│ 'app <: 'app1 //│ 'x1 <: 'x -//│ 'x#'x ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int, 1: Int} +//│ 'x#'x ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde1#Int ∨ Int <: 'app ∧ ⊥ <: ⊥){0: 'cde1, 1: 'cde2} <: {0: Int & ¬⊥, 1: Int & ¬⊥} fun body: [T, C] -> (CodeBase[out Int, out T, out Any], CodeBase[out Int, out C, out Any]) -> Int -> CodeBase[out Int, out T | C, out Any] diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls index d17db1db7f..8d600ea416 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbQQ.mls @@ -116,9 +116,9 @@ f `=> x `=> y `=> f`(x, y) x `=> `if x `== `0.0 then `1.0 else x //│ Type: CodeBase[out 'x -> ('x | Num), ⊥, ?] //│ Where: -//│ 'x#'x ∨ ( 'x#'x ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T) ∧ ( 'cde#'cde ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T){0: 'cde, 1: 'cde1} <: {0: ⊤, 1: ⊤} +//│ 'x#'x ∨ ( 'x#'x ∨ Bool <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde#'cde ∨ Bool <: 'app ∧ ⊥ <: ⊥){0: 'cde, 1: 'cde1} <: {0: 'T, 1: 'T} //│ 'x <: 'cde -//│ 'cde#'cde ∨ ( 'x#'x ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T) ∧ ( 'cde#'cde ∨ Bool <: 'app ∧ ⊥ <: ⊥ ∧ 'cde <: 'T ∧ 'cde1 <: 'T){0: 'cde, 1: 'cde1} <: {0: ⊤, 1: ⊤} +//│ 'cde#'cde ∨ ( 'x#'x ∨ Bool <: 'app ∧ ⊥ <: ⊥) ∧ ( 'cde#'cde ∨ Bool <: 'app ∧ ⊥ <: ⊥){0: 'cde, 1: 'cde1} <: {0: 'T, 1: 'T} //│ Num <: 'cde1 //│ 'cde2 <: ¬(¬{Bool}) //│ 'app <: ¬(¬'cde2) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls index c203261a58..7c44341a9f 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbRec.mls @@ -37,7 +37,7 @@ fun f(x) = f(x) f //│ Type: ['x, 'eff, 'app] -> 'x ->{'eff} 'app //│ Where: -//│ 'x#'x ∨ ( 'x#'x ∨ 'app <: 'app ∧ 'eff <: 'eff ∧ 'x <: 'x){0: 'x} <: {0: ⊤} +//│ 'x#'x ∨ ( 'x#'x ∨ 'app <: 'app ∧ 'eff <: 'eff){0: 'x} <: {0: 'x} fun f(x) = f(x.a) @@ -70,7 +70,7 @@ fun f(x) = f(x.Foo#a) f //│ Type: ['x, 'A, 'eff, 'app] -> Foo[out 'A] ->{'eff} 'app //│ Where: -//│ 'A#'A ∨ ( 'A#'A ∨ 'app <: 'app ∧ 'eff <: 'eff ∧ 'A <: 'x){0: 'A} <: {0: ⊤} +//│ 'A#'A ∨ ( 'A#'A ∨ 'app <: 'app ∧ 'eff <: 'eff){0: 'A} <: {0: 'x} //│ 'x <: Foo[out 'A] diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index f3f614476b..e19f618dde 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -116,16 +116,20 @@ idIIBB(new Pair(1, 2)) //│ ║ l.114: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) & (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app -//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] -//│ ╟── because: cannot constrain 'A <: Bool +//│ ╟── because: cannot constrain {0: Pair['A, 'B]} <: {0: Pair[in ⊥ out Int, in ⊥ out Int]} | {0: Pair[in ⊥ out Bool, in ⊥ out Bool]} +//│ ╟── because: cannot constrain {0: Pair['A, 'B]} & {0: Pair[?, ?]} <: {0: Pair[in ⊥ out Bool, in ⊥ out Bool]} +//│ ╟── because: cannot constrain (Pair['A, 'B]) & (Pair[in ⊥ out , in ⊥ out ]) <: Pair[in ⊥ out Bool, in ⊥ out Bool] +//│ ╟── because: cannot constrain ('A) & () <: Bool //│ ╟── because: cannot constrain 'A <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) //│ ╔══[ERROR] Type error in application //│ ║ l.114: idIIBB(new Pair(1, 2)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) & (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app -//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] -//│ ╟── because: cannot constrain 'B <: Bool +//│ ╟── because: cannot constrain {0: Pair['A, 'B]} <: {0: Pair[in ⊥ out Int, in ⊥ out Int]} | {0: Pair[in ⊥ out Bool, in ⊥ out Bool]} +//│ ╟── because: cannot constrain {0: Pair['A, 'B]} & {0: Pair[?, ?]} <: {0: Pair[in ⊥ out Bool, in ⊥ out Bool]} +//│ ╟── because: cannot constrain (Pair['A, 'B]) & (Pair[in ⊥ out , in ⊥ out ]) <: Pair[in ⊥ out Bool, in ⊥ out Bool] +//│ ╟── because: cannot constrain ('B) & () <: Bool //│ ╟── because: cannot constrain 'B <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) //│ Type: Bool | Int @@ -133,19 +137,23 @@ idIIBB(new Pair(1, 2)) :e idIIBB(new Pair(1, true)) //│ ╔══[ERROR] Type error in application -//│ ║ l.134: idIIBB(new Pair(1, true)) +//│ ║ l.138: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) & (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app -//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Int, in ⊥ out Int] -//│ ╟── because: cannot constrain 'B <: Int +//│ ╟── because: cannot constrain {0: Pair['A, 'B]} <: {0: Pair[in ⊥ out Int, in ⊥ out Int]} | {0: Pair[in ⊥ out Bool, in ⊥ out Bool]} +//│ ╟── because: cannot constrain {0: Pair['A, 'B]} & {0: Pair[?, ?]} <: {0: Pair[in ⊥ out Int, in ⊥ out Int]} +//│ ╟── because: cannot constrain (Pair['A, 'B]) & (Pair[in ⊥ out , in ⊥ out ]) <: Pair[in ⊥ out Int, in ⊥ out Int] +//│ ╟── because: cannot constrain ('B) & () <: Int //│ ╟── because: cannot constrain 'B <: ¬(¬{Int}) //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in application -//│ ║ l.134: idIIBB(new Pair(1, true)) +//│ ║ l.138: idIIBB(new Pair(1, true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain (Pair[out Int, out Int] -> Int) & (Pair[out Bool, out Bool] -> Bool) <: Pair['A, 'B] ->{'eff} 'app -//│ ╟── because: cannot constrain Pair['A, 'B] <: Pair[in ⊥ out Bool, in ⊥ out Bool] -//│ ╟── because: cannot constrain 'A <: Bool +//│ ╟── because: cannot constrain {0: Pair['A, 'B]} <: {0: Pair[in ⊥ out Int, in ⊥ out Int]} | {0: Pair[in ⊥ out Bool, in ⊥ out Bool]} +//│ ╟── because: cannot constrain {0: Pair['A, 'B]} & {0: Pair[?, ?]} <: {0: Pair[in ⊥ out Bool, in ⊥ out Bool]} +//│ ╟── because: cannot constrain (Pair['A, 'B]) & (Pair[in ⊥ out , in ⊥ out ]) <: Pair[in ⊥ out Bool, in ⊥ out Bool] +//│ ╟── because: cannot constrain ('A) & () <: Bool //│ ╟── because: cannot constrain 'A <: ¬(¬{Bool}) //│ ╙── because: cannot constrain Int <: ¬(¬{Bool}) //│ Type: Bool | Int @@ -189,14 +197,12 @@ k(idIB)(true, 1) :e k(idIB)("true", 1) //│ ╔══[ERROR] Type error in string literal with expected type 'x -//│ ║ l.190: k(idIB)("true", 1) +//│ ║ l.198: k(idIB)("true", 1) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Str <: 'x //│ ╟── because: cannot constrain Str <: 'x //│ ╟── because: cannot constrain {0: 'x} <: {0: Int} | {0: Bool} -//│ ╟── because: cannot constrain 'x <: Bool | Int -//│ ╟── because: cannot constrain 'x <: ¬(¬{Int | Bool}) -//│ ╙── because: cannot constrain Str <: ¬(¬{Int | Bool}) +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: {a: ⊥, b: Int} (x => x.x + idIB(x.y)) of (x:0, y:1) @@ -242,33 +248,11 @@ map(cons(1, cons(true, nil())))(idIB) let x = cons(1, cons(true, nil())) in map(cons(x, x))(idIB) //│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.243: map(cons(x, x))(idIB) +//│ ║ l.249: map(cons(x, x))(idIB) //│ ║ ^^^^ //│ ╟── because: cannot constrain (Int -> Int) & (Bool -> Bool) <: 'A -> 'B //│ ╟── because: cannot constrain {0: 'A} <: {0: Int} | {0: Bool} -//│ ╟── because: cannot constrain 'A <: Bool | Int -//│ ╟── because: cannot constrain 'A <: ¬(¬{Int | Bool}) -//│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int | Bool}) -//│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.243: map(cons(x, x))(idIB) -//│ ║ ^^^^ -//│ ╟── because: cannot constrain (Int -> Int) & (Bool -> Bool) <: 'A -> 'B -//│ ╟── because: cannot constrain {0: 'A} <: {0: Int} | {0: Bool} -//│ ╟── because: cannot constrain 'A <: Bool | Int -//│ ╟── because: cannot constrain 'A <: ¬(¬{Int | Bool}) -//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int | Bool}) -//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int | Bool}) -//│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int | Bool}) -//│ ╔══[ERROR] Type error in reference with expected type ('A) ->{⊥} 'B -//│ ║ l.243: map(cons(x, x))(idIB) -//│ ║ ^^^^ -//│ ╟── because: cannot constrain (Int -> Int) & (Bool -> Bool) <: 'A -> 'B -//│ ╟── because: cannot constrain {0: 'A} <: {0: Int} | {0: Bool} -//│ ╟── because: cannot constrain 'A <: Bool | Int -//│ ╟── because: cannot constrain 'A <: ¬(¬{Int | Bool}) -//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int | Bool}) -//│ ╟── because: cannot constrain 'A1 <: ¬(¬{Int | Bool}) -//│ ╙── because: cannot constrain Ls['A1] <: ¬(¬{Int | Bool}) +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: Ls['B] //│ Where: //│ Bool <: 'B @@ -291,14 +275,14 @@ x => k(x, x) :e fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.292: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) +//│ ║ l.276: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ :e fun id: [A] -> (A -> A) & (Int -> Int) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.299: fun id: [A] -> (A -> A) & (Int -> Int) +//│ ║ l.283: fun id: [A] -> (A -> A) & (Int -> Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -314,7 +298,7 @@ fst(cons(1, nil())) :e fun idInt: (Int -> Int) & (Int -> Int) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.315: fun idInt: (Int -> Int) & (Int -> Int) +//│ ║ l.299: fun idInt: (Int -> Int) & (Int -> Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -330,10 +314,11 @@ wf(true) :e wf(1) //│ ╔══[ERROR] Type error in application -//│ ║ l.331: wf(1) +//│ ║ l.315: wf(1) //│ ║ ^^^^^ //│ ╟── because: cannot constrain (((Int | Bool) -> Int) | (Bool -> Bool)) & (Str -> Str) <: Int ->{'eff} 'app -//│ ╙── because: cannot constrain {0: Int} <: {0: Bool} | {0: Str} +//│ ╟── because: cannot constrain {0: Int} <: {0: Bool} | {0: Str} +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: Int class @@ -347,22 +332,7 @@ fun wf: ((Z, Z) -> Z) & ((Z, S) -> S) & ((S, Z | S) -> S) fun zs: Z | S //│ Type: ⊤ -:e wf(zs, zs) -//│ ╔══[ERROR] Type error in application -//│ ║ l.351: wf(zs, zs) -//│ ║ ^^^^^^^^^^ -//│ ╟── because: cannot constrain (((Z, Z) -> Z) & ((Z, S) -> S)) & ((S, Z | S) -> S) <: (Z | S, Z | S) ->{'eff} 'app -//│ ╟── because: cannot constrain {0: Z | S, 1: Z | S} <: ({0: Z, 1: Z} | {0: Z, 1: S}) | {0: S, 1: Z | S} -//│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: {1: S} -//│ ╙── because: cannot constrain Z ∨ S <: S -//│ ╔══[ERROR] Type error in application -//│ ║ l.351: wf(zs, zs) -//│ ║ ^^^^^^^^^^ -//│ ╟── because: cannot constrain (((Z, Z) -> Z) & ((Z, S) -> S)) & ((S, Z | S) -> S) <: (Z | S, Z | S) ->{'eff} 'app -//│ ╟── because: cannot constrain {0: Z | S, 1: Z | S} <: ({0: Z, 1: Z} | {0: Z, 1: S}) | {0: S, 1: Z | S} -//│ ╟── because: cannot constrain {0: Z ∨ S, 1: Z ∨ S} <: {1: Z} -//│ ╙── because: cannot constrain Z ∨ S <: Z //│ Type: S | Z :e @@ -371,11 +341,11 @@ fun ill: (([b: Bool, c: Bool]) -> Bool) & (([a: Str, c: Str]) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.370: (([a: Int, b:Int]) -> Int) & +//│ ║ l.340: (([a: Int, b:Int]) -> Int) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.371: (([b: Bool, c: Bool]) -> Bool) & +//│ ║ l.341: (([b: Bool, c: Bool]) -> Bool) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.372: (([a: Str, c: Str]) -> Str) +//│ ║ l.342: (([a: Str, c: Str]) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -385,10 +355,10 @@ fun nested: (([tag: [b: Bool, c: Bool]]) -> Bool) & (([tag: [a: Str, c: Str]]) -> Str) //│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.384: (([tag: [a: Int, b:Int]]) -> Int) & +//│ ║ l.354: (([tag: [a: Int, b:Int]]) -> Int) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.385: (([tag: [b: Bool, c: Bool]]) -> Bool) & +//│ ║ l.355: (([tag: [b: Bool, c: Bool]]) -> Bool) & //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.386: (([tag: [a: Str, c: Str]]) -> Str) +//│ ║ l.356: (([tag: [a: Str, c: Str]]) -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/logicsub/If.mls b/hkmc2/shared/src/test/mlscript/logicsub/If.mls index 2bbbbd7da5..79e97aa16d 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/If.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/If.mls @@ -90,6 +90,7 @@ foo(1, "") //│ ╟── because: cannot constrain 'r <: (Str & 'y1, 'x, 'r) ->{'eff} 'app //│ ╟── because: cannot constrain 'r <: ¬(¬{(Str & 'y1, 'x, 'r) ->{'eff} 'app}) //│ ╟── because: cannot constrain ((¬⊥ & 'x1, ¬⊥ & 'y2, ¬⊥ & 'r1) ->{¬⊥ & 'eff1} (¬⊥ & 'res)) & ¬⊥ <: ¬(¬{(Str & 'y1, 'x, 'r) ->{'eff} 'app}) +//│ ╟── because: cannot constrain {0: Str & 'y1, 1: 'x, 2: 'r} <: {0: 'x1, 1: 'y2, 2: 'r1} //│ ╟── because: cannot constrain 'x <: 'y2 //│ ╟── because: cannot constrain 'x <: 'y2 //│ ╟── because: cannot constrain 'x <: ¬(¬{Bool}) @@ -124,7 +125,7 @@ increv' :e increv(sib) //│ ╔══[ERROR] Type error in reference with expected type 'x -//│ ║ l.125: increv(sib) +//│ ║ l.126: increv(sib) //│ ║ ^^^ //│ ╟── because: cannot constrain (Str | Int) | Bool <: 'x //│ ╟── because: cannot constrain Bool <: 'x @@ -134,7 +135,7 @@ increv(sib) :e increv'(sib) //│ ╔══[ERROR] Type error in reference with expected type 'x -//│ ║ l.135: increv'(sib) +//│ ║ l.136: increv'(sib) //│ ║ ^^^ //│ ╟── because: cannot constrain (Str | Int) | Bool <: 'x //│ ╟── because: cannot constrain Bool <: 'x diff --git a/hkmc2/shared/src/test/mlscript/logicsub/List.mls b/hkmc2/shared/src/test/mlscript/logicsub/List.mls index 0b9c643943..d84f721c61 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/List.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/List.mls @@ -53,6 +53,7 @@ cons(1, 2) map(x => x) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain 'x -> 'x <: 'f //│ ╟── because: cannot constrain ('x) ->{⊥} ('x) <: 'f +//│ ╟── because: cannot constrain {0: 'Tl, 1: 'f} <: {0: 'xs, 1: 'f} //│ ╟── because: cannot constrain 'Tl <: 'xs //│ ╟── because: cannot constrain 'Tl <: ¬(¬'xs) //│ ╟── because: cannot constrain Int <: ¬(¬'xs) @@ -96,10 +97,11 @@ c map(x => x) :e cons(1, 2) map(x => x) //│ ╔══[ERROR] Type error in function literal with expected type 'f -//│ ║ l.97: cons(1, 2) map(x => x) +//│ ║ l.98: cons(1, 2) map(x => x) //│ ║ ^^^^^^ //│ ╟── because: cannot constrain 'x -> 'x <: 'f //│ ╟── because: cannot constrain ('x) ->{⊥} ('x) <: 'f +//│ ╟── because: cannot constrain {0: 'Tl, 1: 'f1, 2: 'r} <: {0: 'xs, 1: 'f2, 2: 'r1} //│ ╟── because: cannot constrain 'Tl <: 'xs //│ ╟── because: cannot constrain 'Tl <: 'xs //│ ╙── because: cannot constrain ⊤ <: ⊥ diff --git a/hkmc2/shared/src/test/mlscript/logicsub/popl22.mls b/hkmc2/shared/src/test/mlscript/logicsub/popl22.mls index 3d3be35005..b546acb5e7 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/popl22.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/popl22.mls @@ -66,15 +66,6 @@ f(id, strint) //│ ╟── because: cannot constrain 'x2 <: Str //│ ╟── because: cannot constrain 'x2 <: ¬(¬{Str}) //│ ╙── because: cannot constrain Int <: ¬(¬{Str}) -//│ ╔══[ERROR] Type error in reference with expected type 'x2 -//│ ║ l.42: f(id, strint) -//│ ║ ^^^^^^ -//│ ╟── because: cannot constrain Int | Str <: 'x2 -//│ ╟── because: cannot constrain Str <: 'x2 -//│ ╟── because: cannot constrain {0: 'x2} <: {0: Str} -//│ ╟── because: cannot constrain 'x2 <: Str -//│ ╟── because: cannot constrain 'x2 <: ¬(¬{Str}) -//│ ╙── because: cannot constrain Int <: ¬(¬{Str}) //│ Type: Str | Int // without union elimination rule, type test on x2 is required @@ -110,17 +101,10 @@ fun y: Any -> Tru | Fls :e { fst: y(x => x), snd: y(x => x) } as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ] //│ ╔══[ERROR] Type error in record with expected type {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} -//│ ║ l.111: { fst: y(x => x), snd: y(x => x) } as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── because: cannot constrain {fst: Tru | Fls, snd: Tru | Fls} <: {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} -//│ ╟── because: cannot constrain {fst: Tru ∨ Fls, snd: Tru ∨ Fls} <: {snd: Fls} -//│ ╙── because: cannot constrain Tru ∨ Fls <: Fls -//│ ╔══[ERROR] Type error in record with expected type {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} -//│ ║ l.111: { fst: y(x => x), snd: y(x => x) } as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ] +//│ ║ l.102: { fst: y(x => x), snd: y(x => x) } as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain {fst: Tru | Fls, snd: Tru | Fls} <: {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} -//│ ╟── because: cannot constrain {fst: Tru ∨ Fls, snd: Tru ∨ Fls} <: {snd: Tru} -//│ ╙── because: cannot constrain Tru ∨ Fls <: Tru +//│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: {fst: Tru, snd: Tru} | {fst: Fls, snd: Fls} // The above expression is typed with the following MSC-forms @@ -177,7 +161,7 @@ fun f(a, n) = if :e f(a, n) //│ ╔══[ERROR] Type error in reference with expected type 'n -//│ ║ l.178: f(a, n) +//│ ║ l.162: f(a, n) //│ ║ ^ //│ ╟── because: cannot constrain Int <: 'n //│ ╟── because: cannot constrain Int <: 'n @@ -280,10 +264,11 @@ example14 as (~(Int | Str), [fst: ~Int, snd: Any]) -> Z :e example14 as (Int | Str, [fst: Int, snd: Any]) -> Int //│ ╔══[ERROR] Type error in reference with expected type (Int | Str, {fst: Int, snd: ⊤}) ->{⊥} Int -//│ ║ l.281: example14 as (Int | Str, [fst: Int, snd: Any]) -> Int +//│ ║ l.265: example14 as (Int | Str, [fst: Int, snd: Any]) -> Int //│ ║ ^^^^^^^^^ //│ ╟── because: cannot constrain ('input, 'extra) ->{'eff} 'res <: (Int | Str, {fst: Int, snd: ⊤}) -> Int -//│ ╟── because: cannot constrain {fst: Int, snd: ⊤} <: 'extra +//│ ╟── because: cannot constrain {0: Int | Str, 1: {fst: Int, snd: ⊤}} <: {0: 'input, 1: 'extra} +//│ ╟── because: cannot constrain {fst: Int, snd: } <: 'extra //│ ╟── because: cannot constrain {fst: Int, snd: } <: 'extra //│ ╟── because: cannot constrain {fst: Int, snd: } <: ¬(¬{{fst: 'sel}}) //│ ╟── because: cannot constrain Int <: 'sel @@ -296,10 +281,11 @@ example14 as (Int | Str, [fst: Int, snd: Any]) -> Int //│ ╟── because: cannot constrain 'input <: ¬(¬{Str}) //│ ╙── because: cannot constrain Int <: ¬(¬{Str}) //│ ╔══[ERROR] Type error in reference with expected type (Int | Str, {fst: Int, snd: ⊤}) ->{⊥} Int -//│ ║ l.281: example14 as (Int | Str, [fst: Int, snd: Any]) -> Int +//│ ║ l.265: example14 as (Int | Str, [fst: Int, snd: Any]) -> Int //│ ║ ^^^^^^^^^ //│ ╟── because: cannot constrain ('input, 'extra) ->{'eff} 'res <: (Int | Str, {fst: Int, snd: ⊤}) -> Int -//│ ╟── because: cannot constrain {fst: Int, snd: ⊤} <: 'extra +//│ ╟── because: cannot constrain {0: Int | Str, 1: {fst: Int, snd: ⊤}} <: {0: 'input, 1: 'extra} +//│ ╟── because: cannot constrain {fst: Int, snd: } <: 'extra //│ ╟── because: cannot constrain {fst: Int, snd: } <: 'extra //│ ╟── because: cannot constrain {fst: Int, snd: } <: ¬¬{fst: 'sel1} //│ ╟── because: cannot constrain Int <: 'sel1 @@ -346,21 +332,21 @@ fun example6_wrong(x: Int | Str, y: Any) = if x is_int() and_(y is_string()) is Tru then x + strlen(y) else strlen(x) //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.346: x is_int() and_(y is_string()) is Tru then x + strlen(y) +//│ ║ l.332: x is_int() and_(y is_string()) is Tru then x + strlen(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.347: else strlen(x) +//│ ║ l.333: else strlen(x) //│ ║ ^^^^^^^^^^^^^^^^ //│ ╙── because: cannot constrain Int | Str <: Int //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.346: x is_int() and_(y is_string()) is Tru then x + strlen(y) +//│ ║ l.332: x is_int() and_(y is_string()) is Tru then x + strlen(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.347: else strlen(x) +//│ ║ l.333: else strlen(x) //│ ║ ^^^^^^^^^^^^^^^^ //│ ╙── because: cannot constrain ⊤ <: Str //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.346: x is_int() and_(y is_string()) is Tru then x + strlen(y) +//│ ║ l.332: x is_int() and_(y is_string()) is Tru then x + strlen(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.347: else strlen(x) +//│ ║ l.333: else strlen(x) //│ ║ ^^^^^^^^^^^^^^^^ //│ ╙── because: cannot constrain Int | Str <: Str //│ Type: ⊤ @@ -370,17 +356,17 @@ fun example6_wrong(x: Int | Str, y: Any) = if x is Int and y is Str then x + strlen(y) else strlen(x) //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.370: x is Int and y is Str then x + strlen(y) +//│ ║ l.356: x is Int and y is Str then x + strlen(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.371: else strlen(x) +//│ ║ l.357: else strlen(x) //│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain Int | Str <: 'x //│ ╟── because: cannot constrain Int <: 'x //│ ╙── because: cannot constrain Int <: ¬(¬{Str}) //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.370: x is Int and y is Str then x + strlen(y) +//│ ║ l.356: x is Int and y is Str then x + strlen(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.371: else strlen(x) +//│ ║ l.357: else strlen(x) //│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── because: cannot constrain 'x <: Str //│ ╟── because: cannot constrain 'x <: ¬(¬{Str}) @@ -405,25 +391,25 @@ fun detailed_ex(a: (Int -> (Int | Bool)) | Prod[Int, Int | Bool], n: Int) = if a(n) is Int then a(n) < 42 else a(n) //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ l.389: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ l.390: a is Prod then a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ l.391: a(n) is Int then a(n) < 42 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.406: else a(n) +//│ ║ l.392: else a(n) //│ ║ ^^^^^^^^^^^ //│ ╟── because: cannot constrain 'app <: Int //│ ╟── because: cannot constrain 'app <: ¬(¬{Int}) //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ l.389: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ l.390: a is Prod then a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ l.391: a(n) is Int then a(n) < 42 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.406: else a(n) +//│ ║ l.392: else a(n) //│ ║ ^^^^^^^^^^^ //│ ╟── because: cannot constrain ¬Prod[?, ?] & ((Int -> (Int | Bool)) | Prod[Int, Int | Bool]) <: 'a //│ ╟── because: cannot constrain (Int) ->{⊥} (Int ∨ Bool) ∧ ¬{Prod[?, ?]} <: 'a @@ -432,13 +418,13 @@ fun detailed_ex(a: (Int -> (Int | Bool)) | Prod[Int, Int | Bool], n: Int) = if //│ ╟── because: cannot constrain Bool <: 'app //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ l.389: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ l.390: a is Prod then a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ l.391: a(n) is Int then a(n) < 42 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.406: else a(n) +//│ ║ l.392: else a(n) //│ ║ ^^^^^^^^^^^ //│ ╟── because: cannot constrain 'a <: Int ->{'eff} 'app //│ ╟── because: cannot constrain 'a <: ¬(¬{Int ->{'eff} 'app}) @@ -447,13 +433,13 @@ fun detailed_ex(a: (Int -> (Int | Bool)) | Prod[Int, Int | Bool], n: Int) = if //│ ╟── because: cannot constrain Bool <: 'app //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ l.389: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ l.390: a is Prod then a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ l.391: a(n) is Int then a(n) < 42 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.406: else a(n) +//│ ║ l.392: else a(n) //│ ║ ^^^^^^^^^^^ //│ ╟── because: cannot constrain 'a <: Int ->{'eff} 'app //│ ╟── because: cannot constrain 'a <: ¬(¬{Int ->{'eff} 'app}) @@ -462,49 +448,49 @@ fun detailed_ex(a: (Int -> (Int | Bool)) | Prod[Int, Int | Bool], n: Int) = if //│ ╟── because: cannot constrain Bool <: 'app //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ l.389: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ l.390: a is Prod then a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ l.391: a(n) is Int then a(n) < 42 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.406: else a(n) +//│ ║ l.392: else a(n) //│ ║ ^^^^^^^^^^^ //│ ╟── because: cannot constrain 'app <: Int //│ ╟── because: cannot constrain 'app <: ¬(¬{Int}) //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ l.389: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ l.390: a is Prod then a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ l.391: a(n) is Int then a(n) < 42 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.406: else a(n) +//│ ║ l.392: else a(n) //│ ║ ^^^^^^^^^^^ //│ ╟── because: cannot constrain 'app <: Int //│ ╟── because: cannot constrain 'app <: ¬(¬{Int}) //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ l.389: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ l.390: a is Prod then a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ l.391: a(n) is Int then a(n) < 42 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.406: else a(n) +//│ ║ l.392: else a(n) //│ ║ ^^^^^^^^^^^ //│ ╟── because: cannot constrain 'app <: Int //│ ╟── because: cannot constrain 'app <: ¬(¬{Int}) //│ ╙── because: cannot constrain Bool <: ¬(¬{Int}) //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.403: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd +//│ ║ l.389: a is Prod and a.Prod#fst is Int and a.Prod#snd is Int then a.Prod#fst == a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.404: a is Prod then a.Prod#snd +//│ ║ l.390: a is Prod then a.Prod#snd //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.405: a(n) is Int then a(n) < 42 +//│ ║ l.391: a(n) is Int then a(n) < 42 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.406: else a(n) +//│ ║ l.392: else a(n) //│ ║ ^^^^^^^^^^^ //│ ╟── because: cannot constrain 'app <: Int //│ ╟── because: cannot constrain 'app <: ¬(¬{Int}) @@ -527,7 +513,7 @@ detailed_ex as ((Int -> Int | Bool) | Prod[Int, Int | Bool], Int) -> Int | Bool :todo detailed_ex as ((Int -> Int | Bool) | Prod[Int, Int | Bool], Int) -> Bool //│ ╔══[ERROR] Type error in reference with expected type ((Int -> (Int | Bool)) | Prod[Int, Int | Bool], Int) ->{⊥} Bool -//│ ║ l.528: detailed_ex as ((Int -> Int | Bool) | Prod[Int, Int | Bool], Int) -> Bool +//│ ║ l.514: detailed_ex as ((Int -> Int | Bool) | Prod[Int, Int | Bool], Int) -> Bool //│ ║ ^^^^^^^^^^^ //│ ╟── because: cannot constrain ((Int -> (Int | Bool)) | Prod[Int, Int | Bool], Int) ->{'eff} 'res <: ((Int -> (Int | Bool)) | Prod[Int, Int | Bool], Int) -> Bool //│ ╟── because: cannot constrain 'res <: Bool @@ -543,11 +529,11 @@ if a is Prod then true else a(1) //│ ╔══[ERROR] Type error in `if` expression -//│ ║ l.542: if a is +//│ ║ l.528: if a is //│ ║ ^^^^ -//│ ║ l.543: Prod then true +//│ ║ l.529: Prod then true //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.544: else a(1) +//│ ║ l.530: else a(1) //│ ║ ^^^^^^^^^^^ //│ ╙── because: cannot constrain (Int -> (Int | Bool)) | Prod[Int, Int | Bool] <: Int ->{'eff} 'app //│ Type: (Int | Bool) | Bool From afb08c5d87ebf3a5421f8601cad6794e111dfe50 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Mon, 5 May 2025 00:58:23 +0800 Subject: [PATCH 34/36] wf check and typing function intersection --- .../src/main/scala/hkmc2/bbml/bbML.scala | 79 +++++--- .../src/main/scala/hkmc2/bbml/types.scala | 5 - .../src/test/mlscript/logicsub/DisjSub.mls | 93 +-------- .../src/test/mlscript/logicsub/elixir.mls | 27 +-- .../shared/src/test/mlscript/logicsub/wf.mls | 189 ++++++++++++++++++ 5 files changed, 249 insertions(+), 144 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/logicsub/wf.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index 2c9423ac2e..20276f9c0a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -169,24 +169,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case Neg(rhs) => mono(rhs, !pol).! case CompType(lhs, rhs, pol) => - val (l, r) = (typeMonoType(lhs), typeMonoType(rhs)) - if !pol then - val lfa = l.toDnf.conjs.flatMap(_.i.v).collect: - case (f :: fs) => - val fd = Type.discriminant(f.args).flatten - fs.foldLeft(fd: Type, fd.fields.keys.toSet): (x, y) => - val d = Type.discriminant(y.args).flatten - (x._1 | d, x._2 & d.fields.keys.toSet) - val rfa = r.toDnf.conjs.flatMap(_.i.v).collect: - case (f :: fs) => - val fd = Type.discriminant(f.args).flatten - fs.foldLeft(fd: Type, fd.fields.keys.toSet): (x, y) => - val d = Type.discriminant(y.args).flatten - (x._1 | d, x._2 & d.fields.keys.toSet) - val d = lfa.iterator.flatMap(x => rfa.iterator.map(y => (x, y))).exists: - case ((x, u), (y, w)) => (u & w).isEmpty || Type.disjoint(x, y) =/= S(Set.empty) - if d then error(msg"Ill-formed functions intersection" -> ty.toLoc :: Nil) - Type.mkComposedType(l, r, pol) + Type.mkComposedType(typeMonoType(lhs), typeMonoType(rhs), pol) case _ => ty.symbol.flatMap(_.asTpe) match case S(cls: (ClassSymbol | TypeAliasSymbol)) => typeAndSubstType(Term.TyApp(ty, Nil)(N), pol) @@ -201,17 +184,39 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): tv -> qv bds.foreach: case (tv, QuantVar(_, ub, lb)) => - ub.foreach(ub => tv.state.upperBounds ::= typeMonoType(ub)) - lb.foreach(lb => tv.state.lowerBounds ::= typeMonoType(lb)) + ub.foreach(ub => tv.state.upperBounds ::= monoOrErr(typeType(ub), ub)) + lb.foreach(lb => tv.state.lowerBounds ::= monoOrErr(typeType(lb), lb)) val lbty = tv.state.lowerBounds.foldLeft[Type](Bot)(_ | _) val ubty = tv.state.upperBounds.foldLeft[Type](Top)(_ & _) solver.constrain(lbty, ubty) PolyType(bds.map(_._1), S(outer), body) - private def typeMonoType(ty: Term)(using ctx: BbCtx, cctx: CCtx): Type = monoOrErr(typeType(ty), ty) - - private def typeType(ty: Term)(using ctx: BbCtx, cctx: CCtx): GeneralType = - typeAndSubstType(ty, pol = true)(using Map.empty) + private def typeMonoType(ty: Term)(using ctx: BbCtx, cctx: CCtx): Type = monoOrErr(typeAndSubstType(ty, true)(using Map.empty), ty) + + private def wffuns(fs: Ls[FunType]) = + val wf = fs.forall(f => (f.ret :: f.eff :: f.args).forall(wftype)) + wf && fs.combinations(2).forall: u => + Type.disjoint(Type.discriminant(u.head.args), Type.discriminant(u.tail.head.args)).exists(_.isEmpty) + private def wfrcds(rs: Ls[RcdType]) = + val wf = rs.forall(_.fields.forall(u => wftype(u._2))) + wf && rs.combinations(2).forall: u => + Type.disjoint(u.head, u.tail.head).exists(_.isEmpty) + private def wfcls(cs: Ls[ClassLikeType]) = + cs.forall(_.targs.forall(u => wftype(u.posPart) && wftype(u.negPart))) + private def wftype(ty: GeneralType): Bool = ty match + case t: PolyType => wftype(t.body) + case t: PolyFunType => (t.ret :: t.eff :: t.args).forall(wftype) + case t: Type => + val n = t.!.toDnf.conjs + val nf = n.iterator.map(_.i.v).forall: + case S(f: Ls[FunType]) => false + case _ => true + nf && wffuns(n.flatMap(_.u.fun)) && n.forall(c => wfrcds(c.u.rcd) && wfcls(c.u.cls)) + + private def typeType(ty: Term, map: Map[Uid[Symbol], TypeArg] = Map.empty)(using ctx: BbCtx, cctx: CCtx): GeneralType = + val t = typeAndSubstType(ty, pol = true)(using map) + if !wftype(t) then error(msg"Ill-formed type" -> ty.toLoc :: Nil) + t private def instantiate(ty: PolyType)(using ctx: BbCtx): GeneralType = ty.instantiate(infVarState.nextUid, freshEnv(new TempSymbol(N, "env")), ctx.lvl) @@ -486,13 +491,29 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): ascribe(term, typeType(ty)) ascribe(term, rhs) case _ => - val (lhsTy, eff) = typeCheck(lhs) rhs match case pf: PolyFunType if pf.isPoly => (error(msg"Cannot type non-function term ${lhs.toString} as ${rhs.show}" -> lhs.toLoc :: Nil), Bot) case _ => - constrain(tryMkMono(lhsTy, lhs), monoOrErr(rhs, lhs)) - (rhs, eff) + val r = monoOrErr(rhs, lhs) + val n = r.!.toDnf.conjs + if n.flatMap(_.u.fun).length > 1 then + val eff = n.foldLeft(Bot: Type): (e, c) => + (c.i.v, c.u, c.vars) match + case (i, u, v) => + val n = i.fold(Bot: Type): + case x: (ClassLikeType | RcdType) => x.! + case x: Ls[FunType] => x.reduce[Type](_ & _).! + val k = Ls(u.fun, u.cls, u.cls).flatten.foldLeft(Bot: Type)(_ | _) + val vs = v.foldLeft(Bot: Type): (x, y) => + x | (if y._2 then y._1.! else y._1) + val (_, eff) = ascribe(lhs, n | k | vs) + e | eff + (rhs, eff) + else + val (lhsTy, eff) = typeCheck(lhs) + constrain(tryMkMono(lhsTy, lhs), r) + (rhs, eff) // TODO: t -> loc when toLoc is implemented private def app(lhs: (GeneralType, Type), rhs: Ls[Elem], t: Term) @@ -620,7 +641,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case Param(_, sym, sign, _) => if sym.nme === field.name then sign else N }.filter(_.isDefined)) match - case S(res) :: Nil => (typeAndSubstType(res, pol = true)(using map.toMap), eff) + case S(res) :: Nil => (typeType(res, map.toMap), eff) case _ => (error(msg"${field.name} is not a valid member in class ${clsSym.nme}" -> t.toLoc :: Nil), Bot) case N => (error(msg"Not a valid class: ${cls.describe}" -> cls.toLoc :: Nil), Bot) @@ -650,7 +671,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): require(clsDfn.paramsOpt.forall(_.restParam.isEmpty)) args.iterator.zip(clsDfn.params.params).foreach { case (arg, Param(sign = S(sign))) => - val (ty, eff) = ascribe(arg, typeAndSubstType(sign, pol = true)(using map.toMap)) + val (ty, eff) = ascribe(arg, typeType(sign, map.toMap)) effBuff += eff case _ => ??? } diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index 95fe401d49..fbd9c7955a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -273,11 +273,6 @@ case class RcdType(fields: Ls[Str -> Type]) extends BasicType with CachedNorm[Rc RcdType(fields.mapValues(_.subst)) def & (that: RcdType): RcdType = RcdType((fields ++ that.fields).groupMapReduce(_._1)(_._2)(_ & _).toList) - def flatten: RcdType = - RcdType(fields.flatMap: u => - (u._1, u._2.toBasic.simp.toBasic) match - case (a, r: RcdType) => r.flatten.fields.map(u => (s"$a.${u._1}", u._2)) - case u => Ls(u)) case class ComposedType(lhs: Type, rhs: Type, pol: Bool) extends BasicType: // * Positive -> union override def subst(using map: Map[Uid[InfVar], InfVar]): ThisType = diff --git a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls index e19f618dde..489e0ac192 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/DisjSub.mls @@ -105,7 +105,7 @@ new Pair(1, 2) // WF check on intersection types :e fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) -//│ ╔══[ERROR] Ill-formed functions intersection +//│ ╔══[ERROR] Ill-formed type //│ ║ l.107: fun idIIBB: (Pair[Int, Int] -> Int) & (Pair[Bool, Bool] -> Bool) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -271,94 +271,3 @@ x => k(x, x) //│ Type: ('x) ->{'eff} 'app //│ Where: //│ 'x#'x ∨ ( 'x#Int ∨ Int <: 'app ∧ ⊥ <: 'eff) ∧ ( 'x#Bool ∨ Bool <: 'app ∧ ⊥ <: 'eff){0: 'x, 1: 'x} <: {0: Int, 1: Int} | {0: Bool, 1: Bool} - -:e -fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) -//│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.276: fun ill: ((Int | Bool, Int | Bool) -> Str) & ((Bool | Str, Bool | Str) -> Str) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Type: ⊤ - -:e -fun id: [A] -> (A -> A) & (Int -> Int) -//│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.283: fun id: [A] -> (A -> A) & (Int -> Int) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ -//│ Type: ⊤ - -fun fst: [A] -> (Pair[A, Int] -> Pair[A, Int]) & (Ls[A] -> A) -//│ Type: ⊤ - -fst(new Pair(true, 1)) -//│ Type: Pair[out Bool, out Int] - -fst(cons(1, nil())) -//│ Type: Int - -:e -fun idInt: (Int -> Int) & (Int -> Int) -//│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.299: fun idInt: (Int -> Int) & (Int -> Int) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Type: ⊤ - -fun wf: ((Int | Bool -> Int) | (Bool -> Bool)) & (Str -> Str) -//│ Type: ⊤ - -wf("") -//│ Type: Str - -wf(true) -//│ Type: Bool | Int - -:e -wf(1) -//│ ╔══[ERROR] Type error in application -//│ ║ l.315: wf(1) -//│ ║ ^^^^^ -//│ ╟── because: cannot constrain (((Int | Bool) -> Int) | (Bool -> Bool)) & (Str -> Str) <: Int ->{'eff} 'app -//│ ╟── because: cannot constrain {0: Int} <: {0: Bool} | {0: Str} -//│ ╙── because: cannot constrain ⊤ <: ⊥ -//│ Type: Int - -class - Z() - S() -//│ Type: ⊤ - -fun wf: ((Z, Z) -> Z) & ((Z, S) -> S) & ((S, Z | S) -> S) -//│ Type: ⊤ - -fun zs: Z | S -//│ Type: ⊤ - -wf(zs, zs) -//│ Type: S | Z - -:e -fun ill: - (([a: Int, b:Int]) -> Int) & - (([b: Bool, c: Bool]) -> Bool) & - (([a: Str, c: Str]) -> Str) -//│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.340: (([a: Int, b:Int]) -> Int) & -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.341: (([b: Bool, c: Bool]) -> Bool) & -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.342: (([a: Str, c: Str]) -> Str) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Type: ⊤ - -:e -fun nested: - (([tag: [a: Int, b:Int]]) -> Int) & - (([tag: [b: Bool, c: Bool]]) -> Bool) & - (([tag: [a: Str, c: Str]]) -> Str) -//│ ╔══[ERROR] Ill-formed functions intersection -//│ ║ l.354: (([tag: [a: Int, b:Int]]) -> Int) & -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.355: (([tag: [b: Bool, c: Bool]]) -> Bool) & -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.356: (([tag: [a: Str, c: Str]]) -> Str) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/logicsub/elixir.mls b/hkmc2/shared/src/test/mlscript/logicsub/elixir.mls index 027739f9bb..8cd54de5fd 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/elixir.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/elixir.mls @@ -55,8 +55,11 @@ fun subtract(a, b) = if //│ ╙── because: cannot constrain (Int | Tru) | Fls <: Int //│ Type: ⊤ -// TODO impl fun negate: (Int -> Int) & (Tru | Fls -> Tru | Fls) +fun negate(x) = if x is + Int then 0 - x + Tru then not(x) + Fls then not(x) //│ Type: ⊤ fun subtract: (Int, Int) -> Int @@ -91,7 +94,7 @@ fun _in(x) = if x is fun _out(x) = x.Ls#prim(() => new Nil, (x, y) => new Cons(x, y)) //│ Type: ⊤ -// fun map: [A, B] -> (Ls[A], A -> B) -> Ls[B] +fun map: [A, B] -> (Ls[A], A -> B) -> Ls[B] fun map(xs, f) = let x = _out(xs) if x is @@ -99,7 +102,7 @@ fun map(xs, f) = Nil then nil() //│ Type: ⊤ -// fun reduce: [A, B] -> (Ls[A], B, (A, B) -> B) -> B +fun reduce: [A, B] -> (Ls[A], B, (A, B) -> B) -> B fun reduce(xs, acc, f) = let x = _out(xs) if x is @@ -111,11 +114,9 @@ let xs = cons(1, cons(4, nil())) //│ Type: ⊤ xs map(negate) -//│ Type: Ls['A] | Ls['A1] +//│ Type: Ls['B] //│ Where: -//│ Int <: 'A1 -//│ 'A1 <: 'A -//│ 'A <: 'A1 +//│ Int <: 'B fun map(xs, f) = if xs is Cons then cons(f(car(xs)), map(_out(cdr(xs)), f)) @@ -141,10 +142,7 @@ xs _out() map(negate) //│ 'A1 <: 'A //│ 'A <: 'A1 - - -// TODO -// fun negate: (Int -> Int) & (Bool -> Bool) & (~(Int | Bool) -> ~(Int | Bool)) +fun negate: (Int -> Int) & (Bool -> Bool) & (~(Int | Bool) -> ~(Int | Bool)) fun negate(x) = if x is Int then 0 - x Tru then not(x) @@ -152,10 +150,3 @@ fun negate(x) = if x is else x //│ Type: ⊤ - -negate as Int -> Int -negate as Bool -> Bool -negate as ~(Int | Bool) -> ~(Int | Bool) -//│ Type: (¬Int & ¬Bool) ->{⊥} ¬Int & ¬Bool - -// type tree(a) = (a and not list()) or [tree(a)] diff --git a/hkmc2/shared/src/test/mlscript/logicsub/wf.mls b/hkmc2/shared/src/test/mlscript/logicsub/wf.mls new file mode 100644 index 0000000000..286c13e79e --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/logicsub/wf.mls @@ -0,0 +1,189 @@ +:bbml +//│ Type: ⊤ + +//│ Type: ⊤ + +// functions intersection requires disjoint parameters + +fun wf: (Int -> Int) & (Str -> Str) +//│ Type: ⊤ + +:e +fun ill: (Int -> Int) & (Int -> Any) +fun ill(x) = x +//│ ╔══[ERROR] Ill-formed type +//│ ║ l.12: fun ill: (Int -> Int) & (Int -> Any) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ + +:e +fun ill: [a: Int] -> Int & [b: Int] -> Int +//│ ╔══[ERROR] Illegal forall annotation. +//│ ║ l.20: fun ill: [a: Int] -> Int & [b: Int] -> Int +//│ ╙── ^^^^^^^^ +//│ ═══[ERROR] Invalid type +//│ Type: ⊤ + +:e +fun ill: [A] -> (A -> A) & (Int -> Int) +//│ ╔══[ERROR] Ill-formed type +//│ ║ l.28: fun ill: [A] -> (A -> A) & (Int -> Int) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ + +fun wf: [a: (Int -> Int) & (Str -> Str)] +//│ Type: ⊤ + +:e +fun ill: [a: (Int -> Int) & (Int -> Any)] +//│ ╔══[ERROR] Ill-formed type +//│ ║ l.38: fun ill: [a: (Int -> Int) & (Int -> Any)] +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ + +// intersection of the same function type may not always be simplified + +fun wf: (Int -> Int) & (Int -> Int) +//│ Type: ⊤ + +:e +fun ill: (Int -> Int) & (Str -> Str) & (Int -> Int) +//│ ╔══[ERROR] Ill-formed type +//│ ║ l.50: fun ill: (Int -> Int) & (Str -> Str) & (Int -> Int) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ + +// same rules apply on negative position +:e +fun ill: (Int -> Int) & (Int -> Any) -> Str +//│ ╔══[ERROR] Ill-formed type +//│ ║ l.58: fun ill: (Int -> Int) & (Int -> Any) -> Str +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ + +// similarly, records union requires pairwise disjointness + +fun wf: [a: Int] | [a: Str] +//│ Type: ⊤ + +:e +fun ill: [A] -> (Int | Str, A) -> [a: Int, b: A] | [a: Int, b: Str] +fun ill(x, p) = if x is + Int then { a: x, b: p } + Str then { a: 0, b: x } +//│ ╔══[ERROR] Ill-formed type +//│ ║ l.70: fun ill: [A] -> (Int | Str, A) -> [a: Int, b: A] | [a: Int, b: Str] +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type error in `if` expression with expected type {a: Int, b: A} | {a: Int, b: Str} +//│ ║ l.72: Int then { a: x, b: p } +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.73: Str then { a: 0, b: x } +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── because: cannot constrain {a: Int, b: Str & (Int | Str)} <: {a: Int, b: A} | {a: Int, b: Str} +//│ ╟── because: cannot constrain {a: Int, b: Str} & {a: Int} <: {a: Int, b: A} +//│ ╙── because: cannot constrain Str <: A +//│ Type: ⊤ + +// it is not required that all records shares the same discriminant field + +fun wf: + (([a: Int, b:Int]) -> Int) & + (([b: Bool, c: Bool]) -> Bool) & + (([a: Str, c: Str]) -> Str) +//│ Type: ⊤ + +fun wf: + (([tag: [a: Int, b:Int]]) -> Int) & + (([tag: [b: Str, c: Bool]]) -> Bool) & + (([tag: [a: Str, c: Str]]) -> Str) +//│ Type: ⊤ + +// functions union merges + +fun wf: ((([a: Int]) -> Int) | (([b: Str]) -> Str)) & (([b: Int]) -> Int) +fun wf(u) = u.b +//│ Type: ⊤ + +fun wf: ((Int | Bool -> Int) | (Bool -> Bool)) & (Str -> Str) +//│ Type: ⊤ + +wf("") +//│ Type: Str + +wf(true) +//│ Type: Bool | Int + +:e +wf(1) +//│ ╔══[ERROR] Type error in application +//│ ║ l.117: wf(1) +//│ ║ ^^^^^ +//│ ╟── because: cannot constrain (((Int | Bool) -> Int) | (Bool -> Bool)) & (Str -> Str) <: Int ->{'eff} 'app +//│ ╟── because: cannot constrain {0: Int} <: {0: Bool} | {0: Str} +//│ ╙── because: cannot constrain ⊤ <: ⊥ +//│ Type: Int + +// function negation is not wf + +:e +fun ill: ~(Int -> Int) +//│ ╔══[ERROR] Ill-formed type +//│ ║ l.129: fun ill: ~(Int -> Int) +//│ ╙── ^^^^^^^^^^ +//│ Type: ⊤ + +// class declaration has no wf check + +class F(f: (Int -> Int) & (Int -> Any)) +//│ Type: ⊤ + +// wf check on use site + +:e +fun k(f)=f.F#f +//│ ╔══[ERROR] Ill-formed type +//│ ║ l.137: class F(f: (Int -> Int) & (Int -> Any)) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ + +// Class not disjoint with itself + +class Pair[A, B](val a: A, val b: B) +class Tri[A, B, C](val a: A, val b: B, val c: C) +//│ Type: ⊤ + +:e +fun ill: (Pair[Int, Int] -> Int) & (Pair[Str, Str] -> Str) +//│ ╔══[ERROR] Ill-formed type +//│ ║ l.156: fun ill: (Pair[Int, Int] -> Int) & (Pair[Str, Str] -> Str) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ + +fun wf: [A] -> (Pair[A, Any] -> A) & (Tri[A, Any, Any] -> A) +fun wf(x) = if x is + Pair then x.Pair#a + Tri then x.Tri#a +//│ Type: ⊤ + +wf(new Pair(0, "")) +//│ Type: Int + +wf(new Tri(new Pair(0, ""), 0, "")) +//│ Type: Pair['A, 'B] +//│ Where: +//│ Int <: 'A +//│ Str <: 'B + +class + Z() + S() +//│ Type: ⊤ + +fun wf: ((Z, Z) -> Z) & ((Z, S) -> S) & ((S, Z | S) -> S) +//│ Type: ⊤ + +fun zs: Z | S +//│ Type: ⊤ + +wf(zs, zs) +//│ Type: S | Z From 69feb998768890ea2195d2b00d77c5c7f772cb0b Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Mon, 5 May 2025 01:06:16 +0800 Subject: [PATCH 35/36] test --- hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls b/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls index 035758629a..9d3badcc60 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbDisjoint.mls @@ -309,7 +309,12 @@ fun foo(f) = borrow(r) of it => foo(f) foo -//│ Type: [outer, 'n, 'eff] -> (('n ->{¬outer} ('n ∨ Int)) ->{'eff} ⊤) ->{'eff} ⊥ +//│ Type: [outer, 'f, 'n, 'eff, 'app, 'eff1, 'eff2, 'T] -> 'f ->{'eff | 'eff1} 'app //│ Where: //│ 'n <: Int -//│ 'eff <: outer +//│ 'f <: ('n ->{¬outer} ('n | Int)) ->{'eff} ⊤ +//│ 'f#'f ∨ ( 'f#'f ∨ 'T <: 'app ∧ 'eff1 <: 'eff2){0: 'f} <: {0: 'f} +//│ 'app <: 'T +//│ 'eff2 <: outer +//│ 'eff <: 'eff1 +//│ 'eff2 <: 'eff1 From 4a335ea4dabb92cb588e855dc510ed7d5cc126c3 Mon Sep 17 00:00:00 2001 From: AU Heung Tung <101095686+auht@users.noreply.github.com> Date: Wed, 28 May 2025 21:23:13 +0800 Subject: [PATCH 36/36] modify disjointness signature and impl --- .../scala/hkmc2/bbml/ConstraintSolver.scala | 30 ++++----- .../src/main/scala/hkmc2/bbml/bbML.scala | 64 +++++++++--------- .../src/main/scala/hkmc2/bbml/types.scala | 65 +++++++++---------- .../shared/src/test/mlscript/logicsub/wf.mls | 23 ++++++- 4 files changed, 95 insertions(+), 87 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala index e3a6d399f9..b77a91eaf9 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/ConstraintSolver.scala @@ -79,6 +79,7 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, }) case ft @ FunType(args, ret, eff) => FunType(args.map(arg => extrude(arg)(using lvl, !pol)), extrude(ret), extrude(eff)) + case RcdType(u) => RcdType(u.mapValues(extrude)) case ComposedType(lhs, rhs, p) => Type.mkComposedType(extrude(lhs), extrude(rhs), p) case NegType(ty) => Type.mkNegType(extrude(ty)(using lvl, !pol)) @@ -129,15 +130,15 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, else val q = ws.foldLeft(Bot: Type): (q, w) => val wq = Type.discriminant(w) - Type.disjoint(wq, u) match - case N => constrainImpl(u & wq, w) - case S(k) => k.foreach(k => DisjSub(mutable.LinkedHashSet.from(k), Nil, Ls(wq -> w)).commit()) + Type.disjoint(wq, u).foreach: k => + if k.isEmpty then constrainImpl(u & wq, w) + else DisjSub(mutable.LinkedHashSet.from(k), Nil, Ls(wq -> w)).commit() q | wq - Type.disjoint(q.!, u) match - case N => constrainImpl(Top, Bot) - case S(k) => k.foreach(k => DisjSub(mutable.LinkedHashSet.from(k), Nil, Ls(Top -> Bot)).commit()) + Type.disjoint(q.!, u).foreach: k => + if k.isEmpty then constrainImpl(Top, Bot) + else DisjSub(mutable.LinkedHashSet.from(k), Nil, Ls(Top -> Bot)).commit() case (Inter(S(fs: Ls[FunType])), Union(S(FunType(args2, ret2, eff2)), Nil, Nil)) => - val k = args2.flatMap(x => Type.disjoint(x, x)) + val k = args2.map(x => Type.disjoint(x, x)) if k.forall(_.nonEmpty) then val f = fs.filter(_.args.length === args2.length) if args2.isEmpty then @@ -152,13 +153,13 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, val args2q = RcdType(args2r) val (cs, dss) = (args.iterator.map(Type.discriminant).zip(f).map: case (q, f) => - val cs = (f.ret, ret2) :: (f.eff, eff2) :: Nil //rcs - Type.disjoint(q, args2q) match - case N => (cs, Nil) - case S(k) => - (Nil, k.map(k => DisjSub(mutable.LinkedHashSet.from(k), Nil, cs)))).toList.unzip + val cs = (f.ret, ret2) :: (f.eff, eff2) :: Nil + val ds = Type.disjoint(q, args2q) + if ds.exists(_.isEmpty) then (cs, Nil) + else (Nil, ds.map(k => DisjSub(mutable.LinkedHashSet.from(k), Nil, cs)))).toList.unzip val c = (args2q, args.foldLeft(Bot: Type)(_ | _)) - if k.isEmpty then + val u = k.foldLeft(Set(Set.empty[InfVar -> BasicType]))((x, y) => y.flatMap(y => x.map(_ ++ y))) + if u.exists(_.isEmpty) then if f.isEmpty then cctx.err else @@ -168,8 +169,7 @@ class ConstraintSolver(infVarState: InfVarUid.State, elState: Elaborator.State, else val cs0 = c :: cs.flatten val dss0 = dss.flatten - k.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - DisjSub(mutable.LinkedHashSet.from(k), dss0, cs0).commit() + u.foreach(k => DisjSub(mutable.LinkedHashSet.from(k), dss0, cs0).commit()) case _ => // raise(ErrorReport(msg"Cannot solve ${conj.i.toString()} <: ${conj.u.toString()}" -> N :: Nil)) cctx.err diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala index 20276f9c0a..ff4abd93a0 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala @@ -196,11 +196,11 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): private def wffuns(fs: Ls[FunType]) = val wf = fs.forall(f => (f.ret :: f.eff :: f.args).forall(wftype)) wf && fs.combinations(2).forall: u => - Type.disjoint(Type.discriminant(u.head.args), Type.discriminant(u.tail.head.args)).exists(_.isEmpty) + Type.disjoint(Type.discriminant(u.head.args), Type.discriminant(u.tail.head.args)).isEmpty private def wfrcds(rs: Ls[RcdType]) = val wf = rs.forall(_.fields.forall(u => wftype(u._2))) wf && rs.combinations(2).forall: u => - Type.disjoint(u.head, u.tail.head).exists(_.isEmpty) + Type.disjoint(u.head, u.tail.head).isEmpty private def wfcls(cs: Ls[ClassLikeType]) = cs.forall(_.targs.forall(u => wftype(u.posPart) && wftype(u.negPart))) private def wftype(ty: GeneralType): Bool = ty match @@ -209,7 +209,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case t: Type => val n = t.!.toDnf.conjs val nf = n.iterator.map(_.i.v).forall: - case S(f: Ls[FunType]) => false + case S(f: (Ls[FunType] | RcdType)) => false case _ => true nf && wffuns(n.flatMap(_.u.fun)) && n.forall(c => wfrcds(c.u.rcd) && wfcls(c.u.cls)) @@ -341,7 +341,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): case S(t) => (path.filterNot: p => p.find(_._1 === s).fold(false): u => - Type.disjoint(u._2.!, cls).exists(_.isEmpty)) -> t + Type.disjoint(u._2.!, cls).isEmpty) -> t if r.isEmpty then typeSplitImpl(alts, sign, eff, br, path) else val ctx1 = ctx.nest @@ -352,15 +352,14 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): sv += s -> sty if p0.contains(Nil) then typeSplitImpl(alts, sign, eff, br, path) else - Type.disjoint(cls, sty) match - case N => + Type.disjoint(cls, sty).foreach: k => + if k.isEmpty then dss.foreach(c.commit) cs.foreach(u => constrain(u._1, u._2)) - case S(k) => - if k.nonEmpty then k.foreach: k => - val ks = LinkedHashSet.from(k) - dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) - if cs.nonEmpty then c.commit(DisjSub(ks, Nil, cs.toList)) + else + val ks = LinkedHashSet.from(k) + dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) + if cs.nonEmpty then c.commit(DisjSub(ks, Nil, cs.toList)) val p = path.flatMap(x => p0.map: y => val m = (x ++ y).groupMapReduce(_._1)(_._2)(_ | _) (x.keys ++ y.keys).distinct.map(k => k -> m(k)).toList) @@ -400,19 +399,19 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): nc.constrain(termEff, eff) path.foreach: p => val m = p.toMap - val d = p.flatMap { case (s, t) => sv.get(s).flatMap(st => Type.disjoint(t.!, st)) } + val d = p.flatMap { case (s, t) => sv.get(s).map(st => Type.disjoint(t.!, st)) } val sc = sv.toList.map: case (s, t) => val v = nestCtx.get(s.sym).get (m.getOrElse(s, Bot).! & t, monoOrErr(v, s)) - if d.isEmpty then + val ds = d.foldLeft(Set(Set.empty[InfVar -> BasicType]))((x, y) => y.flatMap(y => x.map(_ ++ y))) + if ds.exists(_.isEmpty) then dss.foreach(c.commit(_)) (sc ++ cs).distinct.foreach(u => constrain(u._1, u._2)) - else - val ds = d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - val ks = LinkedHashSet.from(k) - dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) - c.commit(DisjSub(ks, Nil, (sc ++ cs).distinct)) + else ds.foreach: k => + val ks = LinkedHashSet.from(k) + dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) + c.commit(DisjSub(ks, Nil, (sc ++ cs).distinct)) typeSplitImpl(tail, sign, eff, br, path) case Split.Else(e) => val (nc, dss, cs) = constraintCollector @@ -423,32 +422,31 @@ class BBTyper(using elState: Elaborator.State, tl: TL)(using Config): nc.constrain(ascribe(e, sign)(using ctx1, c = nc)._2, eff) path.foreach: p => val m = p.toMap - val d = p.flatMap { case (s, t) => sv.get(s).flatMap(st => Type.disjoint(t.!, st)) } + val d = p.flatMap { case (s, t) => sv.get(s).map(st => Type.disjoint(t.!, st)) } val sc = sv.toList.map: case (s, t) => val v = ctx1.get(s.sym).get (m.getOrElse(s, Bot).! & t, monoOrErr(v, s)) - if d.isEmpty then + val ds = d.foldLeft(Set(Set.empty[InfVar -> BasicType]))((x, y) => y.flatMap(y => x.map(_ ++ y))) + if ds.exists(_.isEmpty) then dss.foreach(c.commit(_)) (sc ++ cs).distinct.foreach(u => constrain(u._1, u._2)) - else - val ds = d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - val ks = LinkedHashSet.from(k) - dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) - c.commit(DisjSub(ks, Nil, (sc ++ cs).distinct)) + else ds.foreach: k => + val ks = LinkedHashSet.from(k) + dss.foreach(d => c.commit(DisjSub(ks ++ d.disjoint, d.dss, d.cs))) + c.commit(DisjSub(ks, Nil, (sc ++ cs).distinct)) Nil case Split.End => if !br then path.foreach: p => val m = p.toMap - val d = p.flatMap { case (s, t) => Type.disjoint(t.!, sv(s)) } - if d.isEmpty then - constrain(Top, Bot) - else - val ds = d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))).foreach: k => - val c0 = Ls(Top -> Bot) - val ks = LinkedHashSet.from(k) - c.commit(DisjSub(ks, Nil, c0)) + val d = p.map { case (s, t) => Type.disjoint(t.!, sv(s)) } + val ds = d.foldLeft(Set(Set.empty[InfVar -> BasicType]))((x, y) => y.flatMap(y => x.map(_ ++ y))) + if ds.exists(_.isEmpty) then constrain(Top, Bot) + else ds.foreach: k => + val c0 = Ls(Top -> Bot) + val ks = LinkedHashSet.from(k) + c.commit(DisjSub(ks, Nil, c0)) Ls(Nil) private def typeSplit diff --git a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala index fbd9c7955a..c4e61bbb96 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/bbml/types.scala @@ -309,53 +309,44 @@ object Type: case _ => Top def discriminant(t: Type)(using TL): BasicType = t.toDnf.conjs.foldLeft(Bot: Type)((x, y) => x | discriminantIU(y.i, y.u)).simp.toBasic - def disjointIU(i: Inter, u: Union)(using TL): Opt[Set[Set[InfVar -> BasicType]]] = (i.v, u.cls, u.rcd) match - case (S(c: ClassLikeType), cs, _) if cs.exists(_.name.uid === c.name.uid) => S(Set.empty) + def disjointIU(i: Inter, u: Union)(using TL): Set[Set[InfVar -> BasicType]] = (i.v, u.cls, u.rcd) match + case (S(c: ClassLikeType), cs, _) if cs.exists(_.name.uid === c.name.uid) => Set.empty case (S(RcdType(u)), _, rs) => - val k = u.values.flatMap(t => disjointDisj(t.toDnf)).toList - val rd = - if rs.isEmpty then Nil - else - val um = u.toMap - val p = rs.foldLeft[Ls[Ls[Str -> Type]]](Ls(Nil)): (p, w) => - if w.fields.keys.forall(um.contains) then p.flatMap(x => w.fields.map(_ :: x)) else p - p.map: p => - val m = p.groupMapReduce(_._1)(_._2)(_ | _) - val d = p.keys.distinct.flatMap(a => Type.disjoint(m(a).!, um(a))) - if d.isEmpty then N - else S(d.reduce((x, y) => y.flatMap(y => x.map(_ ++ y)))) - if k.isEmpty then - if rd.isEmpty || rd.contains(N) then N else S(rd.flatten.flatten.toSet) - else if k.exists(_.isEmpty) then S(Set.empty) - else - if rd.contains(N) then N - else S(k.reduce((x, y) => y.flatMap(y => x.map(_ ++ y))) ++ rd.flatten.flatten) - case _ => N - def disjointConj(ty: Conj)(using TL): Opt[Set[Set[InfVar -> BasicType]]] = + val k = u.iterator.map(u => u._1 -> disjointDisj(u._2.toDnf)).toMap + val p = rs.foldLeft[Ls[Ls[Str -> Type]]](Ls(Nil)): (p, w) => + if w.fields.keys.forall(k.contains) then p.flatMap(x => w.fields.map(_ :: x)) else p + val rd = p.flatMap: p => + val m = p.groupMapReduce(_._1)(_._2)(_ | _) + val d = u.map: + case (a, t) => m.get(a).fold(k(a))(q => Type.disjoint(q.!, t)) + d.foldLeft(Set(Set.empty[InfVar -> BasicType]))((x, y) => y.flatMap(y => x.map(_ ++ y))) + if rd.exists(_.isEmpty) then Set(Set.empty) else rd.toSet + case _ => Set(Set.empty) + def disjointConj(ty: Conj)(using TL): Set[Set[InfVar -> BasicType]] = val d = disjointIU(ty.i, ty.u) - if d.exists(_.isEmpty) then S(Set.empty) + if d.isEmpty then Set.empty else (ty.i.v, ty.u.cls, ty.u.rcd, ty.vars.iterator.filter(_._2).keys.toList) match case (_, _, _, Nil) => d case (N, Nil, Nil, v :: Nil) => - val lb = v.state.lowerBounds.reduceOption(_ | _).orElse(S(Bot)).get - disjointDisj(lb.toDnf).map(_ + Set(v -> v)) + val lb = v.state.lowerBounds.foldLeft(Bot: Type)(_ | _) + disjointDisj(lb.toDnf) + Set(v -> v) case (i, c, r, vs) => val j = i match case S(ClassLikeType(c, _)) => S(ClassLikeType(c, Nil)) case S(u: RcdType) => S(u) case _ => N - val vd = vs.combinations(2).collect { case x :: y :: _ => Ls(x -> y, y -> x) }.flatten.toList + val vd = vs.combinations(2).collect { case x :: y :: _ => Ls(x -> y) }.flatten.toList val ds = vs.flatMap(v => (j ++ (c ++ r).reduceOption[Type](_ | _).map(_.!)).map(x => v -> x.toBasic)).toSet ++ vd val lb = vs.flatMap(_.state.lowerBounds.reduceOption[Type](_ | _)).reduceOption(_ & _).orElse(S(Bot)).get val t = lb & Conj(Inter(j), Union(N, c, Nil), Nil) - disjointDisj(t.toDnf).map(_ + ds) - def disjointDisj(t: Disj)(using TL): Opt[Set[Set[InfVar -> BasicType]]] = - if t.conjs.isEmpty then S(Set.empty) + disjointDisj(t.toDnf) + ds + def disjointDisj(t: Disj)(using TL): Set[Set[InfVar -> BasicType]] = + if t.conjs.isEmpty then Set.empty else - val ds = t.conjs.map(disjointConj) - if ds.contains(N) then N - else S(ds.flatten.flatten.toSet) - def disjoint(a: Type, b: Type)(using TL): Opt[Set[Set[InfVar->BasicType]]] = + val ds = t.conjs.flatMap(disjointConj) + if ds.exists(_.isEmpty) then Set(Set.empty) + else ds.toSet + def disjoint(a: Type, b: Type)(using TL): Set[Set[InfVar -> BasicType]] = disjointDisj((a & b).toDnf) @@ -483,9 +474,11 @@ case class DisjSub(disjoint: LinkedHashSet[InfVar -> BasicType], dss: Ls[DisjSub if disjoint.isEmpty then (Nil, Nil) else disjoint.keys.foreach(_.state.disjsub -= this) - val d = disjoint.toList.flatMap: u => - m.get(u._1).fold(S(Set(Set(u._1 -> u._2)))): t => - Type.disjoint(u._2, t | u._1).orElse { disjoint -= u; N } + val d = disjoint.toList.map: u => + m.get(u._1).fold(Set(Set(u._1 -> u._2))): t => + val k = Type.disjoint(u._2, t | u._1) + k.foreach(x => if x.isEmpty then disjoint -= u) + k if disjoint.isEmpty then val (dss0, cs0) = dss.map(_.check(m)).unzip (dss0.flatten, cs0.flatten ++ cs) diff --git a/hkmc2/shared/src/test/mlscript/logicsub/wf.mls b/hkmc2/shared/src/test/mlscript/logicsub/wf.mls index 286c13e79e..6772203682 100644 --- a/hkmc2/shared/src/test/mlscript/logicsub/wf.mls +++ b/hkmc2/shared/src/test/mlscript/logicsub/wf.mls @@ -123,7 +123,7 @@ wf(1) //│ ╙── because: cannot constrain ⊤ <: ⊥ //│ Type: Int -// function negation is not wf +// function negation and record negation are not wf :e fun ill: ~(Int -> Int) @@ -132,6 +132,23 @@ fun ill: ~(Int -> Int) //│ ╙── ^^^^^^^^^^ //│ Type: ⊤ +:e +fun ill: ~[a: Int] +//│ ╔══[ERROR] Ill-formed type +//│ ║ l.136: fun ill: ~[a: Int] +//│ ╙── ^^^^^^^^ +//│ Type: ⊤ + +:e +fun ill: (([a: Int]) -> Int) & (~[a: Int] -> ~Int) +//│ ╔══[ERROR] Ill-formed type +//│ ║ l.143: fun ill: (([a: Int]) -> Int) & (~[a: Int] -> ~Int) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ Type: ⊤ + +fun wf: (([a: Int]) -> Int) & (([a: ~Int]) -> ~Int) +//│ Type: ⊤ + // class declaration has no wf check class F(f: (Int -> Int) & (Int -> Any)) @@ -142,7 +159,7 @@ class F(f: (Int -> Int) & (Int -> Any)) :e fun k(f)=f.F#f //│ ╔══[ERROR] Ill-formed type -//│ ║ l.137: class F(f: (Int -> Int) & (Int -> Any)) +//│ ║ l.154: class F(f: (Int -> Int) & (Int -> Any)) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤ @@ -155,7 +172,7 @@ class Tri[A, B, C](val a: A, val b: B, val c: C) :e fun ill: (Pair[Int, Int] -> Int) & (Pair[Str, Str] -> Str) //│ ╔══[ERROR] Ill-formed type -//│ ║ l.156: fun ill: (Pair[Int, Int] -> Int) & (Pair[Str, Str] -> Str) +//│ ║ l.173: fun ill: (Pair[Int, Int] -> Int) & (Pair[Str, Str] -> Str) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊤