Skip to content

Commit

Permalink
Fix issue 1082
Browse files Browse the repository at this point in the history
  • Loading branch information
johnynek committed Dec 16, 2023
1 parent 48ed6ab commit cf55130
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 6 deletions.
17 changes: 12 additions & 5 deletions core/src/main/scala/org/bykn/bosatsu/KindFormula.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.bykn.bosatsu.rankn.{
ConstructorFn,
Ref,
RefSpace,
Type => RankNType,
TypeEnv,
DefinedType
}
Expand Down Expand Up @@ -254,13 +255,19 @@ object KindFormula {
dts: List[DefinedType[Either[KnownShape, Kind.Arg]]]
): IorNec[Error, List[DefinedType[Kind.Arg]]] =
dts
.foldM(List.empty[DefinedType[Kind.Arg]]) { (acc, dt) =>
solveKind((imports, acc), dt) match {
case Validated.Valid(good) => Ior.Right(good :: acc)
case Validated.Invalid(errs) => Ior.Both(errs, acc)
.foldM((List.empty[DefinedType[Kind.Arg]], Set.empty[RankNType.TyConst])) { case (st @ (acc, failed), dt) =>
if (dt.dependsOn.exists(failed)) {
// there was at least one failure already, just return and let that failure signal
Ior.Right(st)
}
else {
solveKind((imports, acc), dt) match {
case Validated.Valid(good) => Ior.Right((good :: acc, failed))
case Validated.Invalid(errs) => Ior.Both(errs, (acc, failed + dt.toTypeTyConst))
}
}
}
.map(_.reverse)
.map(_._1.reverse)

def solveKind[Env: IsTypeEnv](
imports: Env,
Expand Down
7 changes: 7 additions & 0 deletions core/src/main/scala/org/bykn/bosatsu/rankn/DefinedType.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ final case class DefinedType[+A](
val toTypeTyConst: Type.TyConst =
Type.TyConst(toTypeConst)

lazy val dependsOn: List[Type.TyConst] =
Type.allConsts(
for {
cfn <- constructors
(_, t) <- cfn.args
} yield t
)
/**
* A type with exactly one constructor is a struct
*/
Expand Down
23 changes: 22 additions & 1 deletion core/src/main/scala/org/bykn/bosatsu/rankn/Type.scala
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,9 @@ object Type {
case class TyApply(on: Rho, arg: Type) extends Rho {
lazy val normalize: Rho = TyApply(on.normalize, arg.normalize)
}
case class TyConst(tpe: Const) extends Leaf
case class TyConst(tpe: Const) extends Leaf {
def isPredef: Boolean = tpe.toDefined.packageName == PackageName.PredefName
}
case class TyVar(toVar: Var) extends Leaf
case class TyMeta(toMeta: Meta) extends Leaf

Expand Down Expand Up @@ -382,6 +384,25 @@ object Type {
case q: Quantified => rootConst(q.in)
}

def allConsts(ts: List[Type]): List[TyConst] = {
@annotation.tailrec
def loop(ts: List[Type], acc: List[TyConst]): List[TyConst] =
ts match {
case (tyc@TyConst(_)) :: tail =>
loop(tail, tyc :: acc)
case (TyVar(_) | TyMeta(_)) :: tail =>
loop(tail, acc)
case TyApply(left, right) :: tail =>
loop(left :: right :: tail, acc)
case (q: Quantified) :: tail =>
loop(q.in :: tail, acc)
case Nil =>
acc.reverse.distinct
}

loop(ts, Nil)
}

object RootConst {
def unapply(t: Type): Option[Type.TyConst] =
rootConst(t)
Expand Down
12 changes: 12 additions & 0 deletions core/src/test/scala/org/bykn/bosatsu/KindFormulaTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,18 @@ struct Bar(foo: Foo)
test("recursion with type constructors is allowed") {
allowed("""#
struct Tree(root: a, children: f[Tree[a, f]])
""")
}

test("we don't throw when a previous kind fails") {
disallowed("""#
struct Foo[a: -*](get: a)
struct Bar[a](foo: Foo[a])
""")
disallowed("""#
struct Bar[a](foo: Foo[a])
""")
}
}

0 comments on commit cf55130

Please sign in to comment.